int start_svm_guest(struct guest_info * info);
+inline addr_t get_rip_linear(struct guest_info * info, addr_t rip, addr_t cs_base);
+
#endif
uint_t sz8 : 1 PACKED; // 8 bit op size
uint_t sz16 : 1 PACKED; // 16 bit op size
uint_t sz32 : 1 PACKED; // 32 bit op size
- uint_t A16 : 1 PACKED; // 16 bit addr
- uint_t A32 : 1 PACKED; // 32 bit addr
- uint_t A64 : 1 PACKED; // 64 bit addr
+ uint_t addr16 : 1 PACKED; // 16 bit addr
+ uint_t addr32 : 1 PACKED; // 32 bit addr
+ uint_t addr64 : 1 PACKED; // 64 bit addr
uint_t rsvd2 : 6 PACKED; // Should be Zero
ushort_t port PACKED; // port number
};
uint_t rsvd2 : 32;
};
+
+
+struct rflags {
+ uint_t cf : 1; // carry flag
+ uint_t rsvd1 : 1; // Must be 1
+ uint_t pf : 1; // parity flag
+ uint_t rsvd2 : 1; // Read as 0
+ uint_t af : 1; // Auxillary flag
+ uint_t rsvd3 : 1; // Read as 0
+ uint_t zf : 1; // zero flag
+ uint_t sf : 1; // sign flag
+ uint_t tf : 1; // trap flag
+ uint_t intr : 1; // interrupt flag
+ uint_t df : 1; // direction flag
+ uint_t of : 1; // overflow flag
+ uint_t iopl : 2; // IO privilege level
+ uint_t nt : 1; // nested task
+ uint_t rsvd4 : 1; // read as 0
+ uint_t rf : 1; // resume flag
+ uint_t vm : 1; // Virtual-8086 mode
+ uint_t ac : 1; // alignment check
+ uint_t vif : 1; // virtual interrupt flag
+ uint_t vip : 1; // virtual interrupt pending
+ uint_t id : 1; // ID flag
+ uint_t rsvd5 : 10; // Read as 0
+ uint_t rsvd6 : 32; // Read as 0
+};
+
+
#endif
+static inline addr_t get_rip_linear(struct guest_info * info, addr_t rip, addr_t cs_base) {
+ switch (info->cpu_mode) {
+ case REAL:
+ return rip + (cs_base << 4);
+ break;
+ case PROTECTED:
+ case PROTECTED_PG:
+ return rip + cs_base;
+ break;
+ default:
+ return 0;
+ }
+}
+
+
typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t;
typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t;
typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND} operand_type_t;
ushort_t port;
// Reads data into the IO port (IN, INS)
- int (*read)(ushort_t port, void * dst, uint_t length, uint_t io_width);
+ int (*read)(ushort_t port, void * dst, uint_t length);
// Writes data from the IO port (OUT, OUTS)
- int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width);
+ int (*write)(ushort_t port, void * src, uint_t length);
struct vmm_io_hook * next;
struct vmm_io_hook * prev;
/* External API */
void hook_io_port(vmm_io_map_t * io_map, uint_t port,
- int (*read)(ushort_t port, void * dst, uint_t length, uint_t io_width),
- int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width));
+ int (*read)(ushort_t port, void * dst, uint_t length),
+ int (*write)(ushort_t port, void * src, uint_t length));
void init_vmm_io_map(vmm_io_map_t * io_map);
* Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
* Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
* Copyright (c) 2004, Iulian Neamtiu <neamtiu@cs.umd.edu>
- * $Revision: 1.29 $
+ * $Revision: 1.30 $
*
* This is free software. You are permitted to use,
* redistribute, and modify it as specified in the file "COPYING".
-int IO_Read(ushort_t port, void * dst, uint_t length, uint_t io_width) {
+int IO_Read(ushort_t port, void * dst, uint_t length) {
uchar_t * iter = dst;
uint_t i;
-int IO_Write(ushort_t port, void * src, uint_t length, uint_t io_width) {
+int IO_Write(ushort_t port, void * src, uint_t length) {
uchar_t * iter = src;
uint_t i;
-int IO_Write_to_Serial(ushort_t port, void * src, uint_t length, uint_t io_width) {
- SerialPrint("Output from Guest on port %d (0x%x) Length=%d\n", port, port, length);
- SerialMemDump(src, length);
+int IO_Write_to_Serial(ushort_t port, void * src, uint_t length) {
+ PrintBoth("Output from Guest on port %d (0x%x) Length=%d\n", port, port, length);
+ switch (length) {
+
+ case 1:
+ PrintBoth(">0x%.2x\n", *(char*)src);
+ break;
+ case 2:
+ PrintBoth(">0x%.4x\n", *(ushort_t*)src);
+ break;
+ case 4:
+ PrintBoth(">0x%.8x\n", *(uint_t*)src);
+ break;
+ default:
+ break;
+ }
+
+ // SerialMemDump(src, length);
return length;
}
int ret;
// The real rip address is actually a combination of the rip + CS base
- ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + (guest_state->cs.base << 4), 15, instr);
+ ret = read_guest_pa_memory(info, get_rip_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
if (ret != 15) {
// I think we should inject a GPF into the guest
PrintDebug("Could not read instruction (ret=%d)\n", ret);
PrintDebug("Protected Mode write to CR0\n");
// The real rip address is actually a combination of the rip + CS base
- ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + guest_state->cs.base, 15, instr);
+ ret = read_guest_pa_memory(info, get_rip_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
if (ret != 0) {
// I think we should inject a GPF into the guest
PrintDebug("Could not read instruction (ret=%d)\n", ret);
index++;
}
+
+ /* CHECK IF MOV_TO_CR CAN TAKE MEMORY OPERANDS... */
if ((instr[index] == cr_access_byte) &&
(instr[index + 1] == mov_to_cr_byte)) {
int ret;
// The real rip address is actually a combination of the rip + CS base
- ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + (guest_state->cs.base << 4), 15, instr);
+ ret = read_guest_pa_memory(info, get_rip_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
if (ret != 15) {
// I think we should inject a GPF into the guest
PrintDebug("Could not read instruction (ret=%d)\n", ret);
int ret;
// The real rip address is actually a combination of the rip + CS base
- ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + guest_state->cs.base, 15, instr);
+ ret = read_guest_pa_memory(info, get_rip_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
if (ret != 15) {
// I think we should inject a GPF into the guest
PrintDebug("Could not read instruction (ret=%d)\n", ret);
#include <geekos/svm_io.h>
#include <geekos/vmm_io.h>
-
+#include <geekos/vmm_ctrl_regs.h>
+#include <geekos/vmm_emulate.h>
+#include <geekos/vm_guest_mem.h>
// This should package up an IO request and call vmm_handle_io
}
- if (hook->read(io_info->port, &(info->vm_regs.rax), read_size, read_size) != read_size) {
+ if (hook->read(io_info->port, &(info->vm_regs.rax), read_size) != read_size) {
// not sure how we handle errors.....
return -1;
}
}
+
+
+
+/* We might not handle wrap around of the RDI register correctly...
+ * In that if we do wrap around the effect will manifest in the higher bits of the register
+ */
int handle_svm_io_ins(struct guest_info * info) {
+ vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
+ vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
+
+ struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
+
+ vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
+ uint_t read_size = 0;
+ addr_t base_addr = guest_state->es.base;
+ addr_t dst_addr = 0;
+ uint_t rep_num = 1;
+ ullong_t mask = 0;
+
+ // This is kind of hacky...
+ // direction can equal either 1 or -1
+ // We will multiply the final added offset by this value to go the correct direction
+ int direction = 1;
+ struct rflags * flags = (struct rflags *)&(guest_state->rflags);
+ if (flags->df) {
+ direction = -1;
+ }
+
+
+ if (hook == NULL) {
+ // error, we should not have exited on this port
+ return -1;
+ }
+
+ PrintDebug("INS on port %d (0x%x)\n", io_info->port, io_info->port);
+
+ if (io_info->sz8) {
+ read_size = 1;
+ } else if (io_info->sz16) {
+ read_size = 2;
+ } else if (io_info->sz32) {
+ read_size = 4;
+ }
+
+
+ if (io_info->addr16) {
+ mask = 0xffff;
+ } else if (io_info->addr32) {
+ mask = 0xffffffff;
+ } else if (io_info->addr64) {
+ mask = 0xffffffffffffffffLL;
+ } else {
+ // should never happen
+ return -1;
+ }
+
+ if (io_info->rep) {
+ rep_num = info->vm_regs.rcx & mask;
+ }
+
- // PrintDebug("INS on port %d (0x%x)\n", io_info->port, io_info->port);
- return -1;
+ while (rep_num > 0) {
+ addr_t host_addr;
+ dst_addr = base_addr + (info->vm_regs.rdi & mask);
+
+ if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
+ // either page fault or gpf...
+ }
+ if (hook->read(io_info->port, (char*)host_addr, read_size) != read_size) {
+ // not sure how we handle errors.....
+ return -1;
+ }
+
+ info->vm_regs.rdi += read_size * direction;
+
+ if (io_info->rep)
+ info->vm_regs.rcx--;
+
+ rep_num--;
+ }
+
+
+ info->rip = ctrl_area->exit_info2;
+
+ return 0;
}
int handle_svm_io_out(struct guest_info * info) {
}
- if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, write_size) != write_size) {
+ if (hook->write(io_info->port, &(info->vm_regs.rax), write_size) != write_size) {
// not sure how we handle errors.....
return -1;
}
}
+/* We might not handle wrap around of the RSI register correctly...
+ * In that if we do wrap around the effect will manifest in the higher bits of the register
+ */
+
int handle_svm_io_outs(struct guest_info * info) {
- return -1;
+ vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
+ vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
+
+ struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
+
+ vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
+ uint_t write_size = 0;
+ addr_t base_addr = guest_state->ds.base;
+ addr_t dst_addr = 0;
+ uint_t rep_num = 1;
+ ullong_t mask = 0;
+
+ // This is kind of hacky...
+ // direction can equal either 1 or -1
+ // We will multiply the final added offset by this value to go the correct direction
+ int direction = 1;
+ struct rflags * flags = (struct rflags *)&(guest_state->rflags);
+ if (flags->df) {
+ direction = -1;
+ }
+
+
+ if (hook == NULL) {
+ // error, we should not have exited on this port
+ return -1;
+ }
+
+ PrintDebug("OUTS on port %d (0x%x)\n", io_info->port, io_info->port);
+
+ if (io_info->sz8) {
+ write_size = 1;
+ } else if (io_info->sz16) {
+ write_size = 2;
+ } else if (io_info->sz32) {
+ write_size = 4;
+ }
+
+
+ if (io_info->addr16) {
+ mask = 0xffff;
+ } else if (io_info->addr32) {
+ mask = 0xffffffff;
+ } else if (io_info->addr64) {
+ mask = 0xffffffffffffffffLL;
+ } else {
+ // should never happen
+ return -1;
+ }
+
+ if (io_info->rep) {
+ rep_num = info->vm_regs.rcx & mask;
+ }
+
+
+ while (rep_num > 0) {
+ addr_t host_addr;
+ dst_addr = base_addr + (info->vm_regs.rsi & mask);
+
+ if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
+ // either page fault or gpf...
+ }
+
+ if (hook->write(io_info->port, (char*)host_addr, write_size) != write_size) {
+ // not sure how we handle errors.....
+ return -1;
+ }
+
+ info->vm_regs.rsi += write_size * direction;
+
+ if (io_info->rep)
+ info->vm_regs.rcx--;
+
+ rep_num--;
+ }
+
+
+ info->rip = ctrl_area->exit_info2;
+
+
+ return 0;
+
+
+
}
;; mov eax, [esp + 4] ;; mov guest GPR pointer to eax
- Restore_SVM_Registers [esp + 4] ;; Restore Guest GPR state
+ ;; this is plus 8 because we push eax in the macro
+ Restore_SVM_Registers [esp + 8] ;; Restore Guest GPR state
pop eax ;; pop VMCB pointer into eax
vmload
vmsave
;; pop eax ;; pop Guest GPR pointer into eax
- Save_SVM_Registers [esp] ;; save guest GPRs
+ ;; this is plus 4 because we push eax in the macro NEED TO CHANGE
+ Save_SVM_Registers [esp+4] ;; save guest GPRs
add esp, 4 ;; skip past the gpr ptr
}
void hook_io_port(vmm_io_map_t * io_map, uint_t port,
- int (*read)(ushort_t port, void * dst, uint_t length, uint_t io_width),
- int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width)) {
+ int (*read)(ushort_t port, void * dst, uint_t length),
+ int (*write)(ushort_t port, void * src, uint_t length)) {
vmm_io_hook_t * io_hook = os_hooks->malloc(sizeof(vmm_io_hook_t));
io_hook->port = port;