-static inline int v3_enable_vmx(struct vmcs_data * vmxon_ptr) {
+static inline int v3_enable_vmx(addr_t vmxon_ptr) {
uint64_t vmxon_ptr_64 __attribute__((aligned(8))) = (uint64_t)vmxon_ptr;
uint8_t ret_invalid = 0;
// No vmcall necessary - is only executed by the guest
-static inline int vmcs_clear(struct vmcs_data* vmcs_ptr) {
+static inline int vmcs_clear(addr_t vmcs_ptr) {
uint64_t vmcs_ptr_64 = (uint64_t)vmcs_ptr;
uint8_t ret_valid = 0;
uint8_t ret_invalid = 0;
}
-static inline int vmcs_load(struct vmcs_data* vmcs_ptr) {
+static inline int vmcs_load(addr_t vmcs_ptr) {
uint64_t vmcs_ptr_64 = (uint64_t)vmcs_ptr;
uint8_t ret_valid = 0;
uint8_t ret_invalid = 0;
return VMX_SUCCESS;
}
-static inline int vmcs_store(struct vmcs_data* vmcs_ptr) {
+static inline int vmcs_store(addr_t vmcs_ptr) {
uint64_t vmcs_ptr_64 = (uint64_t)vmcs_ptr;
__asm__ __volatile__ (
return VMX_SUCCESS;
}
-static inline int vmcs_read(addr_t vmcs_index, void * dst, int len) {
+static inline int vmcs_read(vmcs_field_t vmcs_field, void * dst, int len) {
uint64_t val = 0;
uint8_t ret_valid = 0;
uint8_t ret_invalid = 0;
"seteb %0;" // fail valid
"setnaeb %1;" // fail invalid
: "=q"(ret_valid), "=q"(ret_invalid), "=c"(val) // Use ECX
- : "a" (vmcs_index), "0"(ret_valid), "1"(ret_invalid)
+ : "a" (vmcs_field), "0"(ret_valid), "1"(ret_invalid)
: "memory"
);
CHECK_VMXFAIL(ret_valid, ret_invalid);
- // TODO: Fix this, will have to do a cast because dst will be variable length
switch(len)
{
case 2:
return VMX_SUCCESS;
}
-static inline int vmcs_write(addr_t vmcs_index, addr_t value) {
+static inline int vmcs_write(vmcs_field_t vmcs_field, addr_t value) {
uint8_t ret_valid = 0;
uint8_t ret_invalid = 0;
"seteb %0;" // fail valid (ZF=1)
"setnaeb %1;" // fail invalid (CF=1)
: "=q" (ret_valid), "=q" (ret_invalid)
- : "a" (vmcs_index), "c"(value), "0"(ret_valid), "1"(ret_invalid)
+ : "a" (vmcs_field), "c"(value), "0"(ret_valid), "1"(ret_invalid)
: "memory");
CHECK_VMXFAIL(ret_valid, ret_invalid);
#include <palacios/vmm.h>
-static const char * vmcs_field_to_str(vmcs_field_t field);
+// static const char * v3_vmcs_field_to_str(vmcs_field_t field);
//extern char * exception_names;
//
};
if (len == 2) {
- PrintDebug("%s: %x\n", vmcs_field_to_str(vmcs_index), (uint16_t)val);
+ PrintDebug("%s: %x\n", v3_vmcs_field_to_str(vmcs_index), (uint16_t)val);
} else if (len == 4) {
- PrintDebug("%s: %x\n", vmcs_field_to_str(vmcs_index), (uint32_t)val);
+ PrintDebug("%s: %x\n", v3_vmcs_field_to_str(vmcs_index), (uint32_t)val);
} else if (len == 8) {
- PrintDebug("%s: %p\n", vmcs_field_to_str(vmcs_index), (void *)(addr_t)val);
+ PrintDebug("%s: %p\n", v3_vmcs_field_to_str(vmcs_index), (void *)(addr_t)val);
}
}
-static inline void print_vmcs_segments() {
- // see vm_guest.c
-}
-
-
-
+void v3_print_vmcs_guest_state()
+{
+ PrintDebug("\n===== VMCS Guest State =====\n");
+ print_vmcs_field(VMCS_GUEST_RIP);
+ print_vmcs_field(VMCS_GUEST_RSP);
+ print_vmcs_field(VMCS_GUEST_CR0);
+ print_vmcs_field(VMCS_GUEST_CR3);
+ print_vmcs_field(VMCS_GUEST_CR4);
+ print_vmcs_field(VMCS_GUEST_DR7);
+
+ PrintDebug("\n=== CS Segment===\n");
+ print_vmcs_field(VMCS_GUEST_CS_SELECTOR);
+ print_vmcs_field(VMCS_GUEST_CS_BASE);
+ print_vmcs_field(VMCS_GUEST_CS_LIMIT);
+ print_vmcs_field(VMCS_GUEST_CS_ACCESS);
+
+ PrintDebug("\n=== SS Segment ===\n");
+ print_vmcs_field(VMCS_GUEST_SS_SELECTOR);
+ print_vmcs_field(VMCS_GUEST_SS_BASE);
+ print_vmcs_field(VMCS_GUEST_SS_LIMIT);
+ print_vmcs_field(VMCS_GUEST_SS_ACCESS);
+
+ PrintDebug("\n=== DS Segment ===\n");
+ print_vmcs_field(VMCS_GUEST_DS_SELECTOR);
+ print_vmcs_field(VMCS_GUEST_DS_BASE);
+ print_vmcs_field(VMCS_GUEST_DS_LIMIT);
+ print_vmcs_field(VMCS_GUEST_DS_ACCESS);
+
+ PrintDebug("\n=== ES Segment ===\n");
+ print_vmcs_field(VMCS_GUEST_ES_SELECTOR);
+ print_vmcs_field(VMCS_GUEST_ES_BASE);
+ print_vmcs_field(VMCS_GUEST_ES_LIMIT);
+ print_vmcs_field(VMCS_GUEST_ES_ACCESS);
+
+ PrintDebug("\n=== FS Segment ===\n");
+ print_vmcs_field(VMCS_GUEST_FS_SELECTOR);
+ print_vmcs_field(VMCS_GUEST_FS_BASE);
+ print_vmcs_field(VMCS_GUEST_FS_LIMIT);
+ print_vmcs_field(VMCS_GUEST_FS_ACCESS);
+
+ PrintDebug("\n=== GS Segment ===\n");
+ print_vmcs_field(VMCS_GUEST_GS_SELECTOR);
+ print_vmcs_field(VMCS_GUEST_GS_BASE);
+ print_vmcs_field(VMCS_GUEST_GS_LIMIT);
+ print_vmcs_field(VMCS_GUEST_GS_ACCESS);
+
+ PrintDebug("\n=== LDTR Segment ===\n");
+ print_vmcs_field(VMCS_GUEST_LDTR_SELECTOR);
+ print_vmcs_field(VMCS_GUEST_LDTR_BASE);
+ print_vmcs_field(VMCS_GUEST_LDTR_LIMIT);
+ print_vmcs_field(VMCS_GUEST_LDTR_ACCESS);
+
+ PrintDebug("\n=== TR Segment ===\n");
+ print_vmcs_field(VMCS_GUEST_TR_SELECTOR);
+ print_vmcs_field(VMCS_GUEST_TR_BASE);
+ print_vmcs_field(VMCS_GUEST_TR_LIMIT);
+ print_vmcs_field(VMCS_GUEST_TR_ACCESS);
+
+ PrintDebug("\n=== GDTR ===\n");
+ print_vmcs_field(VMCS_GUEST_GDTR_BASE);
+ print_vmcs_field(VMCS_GUEST_GDTR_LIMIT);
+
+ PrintDebug("\n=== IDTR ===\n");
+ print_vmcs_field(VMCS_GUEST_IDTR_BASE);
+ print_vmcs_field(VMCS_GUEST_IDTR_LIMIT);
+
+ PrintDebug("\n");
+ print_vmcs_field(VMCS_GUEST_RFLAGS);
+ print_vmcs_field(VMCS_GUEST_ACTIVITY_STATE);
+ print_vmcs_field(VMCS_GUEST_INT_STATE);
+ print_vmcs_field(VMCS_GUEST_PENDING_DBG_EXCP);
+
+ print_vmcs_field(VMCS_GUEST_DBG_CTL);
+ print_vmcs_field(VMCS_GUEST_SYSENTER_CS);
+ print_vmcs_field(VMCS_GUEST_SYSENTER_ESP);
+ print_vmcs_field(VMCS_GUEST_SYSENTER_EIP);
+ print_vmcs_field(VMCS_GUEST_PERF_GLOBAL_CTRL);
+ print_vmcs_field(VMCS_LINK_PTR);
+
+ PrintDebug("\n");
+}
+
/*
void print_debug_vmcs_load_guest() {
const int wordsize = sizeof(addr_t);
-static const char * vmcs_field_to_str(vmcs_field_t field) {
+const char * v3_vmcs_field_to_str(vmcs_field_t field) {
switch (field) {
case VMCS_GUEST_ES_SELECTOR:
return VMCS_GUEST_ES_SELECTOR_STR;
-static struct vmcs_data* vmxon_ptr;
+static addr_t vmxon_ptr_phys;
#if 0
}
+#endif
static void setup_v8086_mode_for_boot(struct guest_info* vm_info)
{
- ((struct vmx_data*)vm_info->vmm_data)->state = VMXASSIST_V8086_BIOS;
- ((struct rflags*)&(vm_info->ctrl_regs.rflags))->vm = 1;
- ((struct rflags*)&(vm_info->ctrl_regs.rflags))->iopl = 3;
-
+ ((struct vmx_data *)vm_info->vmm_data)->state = VMXASSIST_V8086_BIOS;
+ ((struct rflags *)&(vm_info->ctrl_regs.rflags))->vm = 1;
+ ((struct rflags *)&(vm_info->ctrl_regs.rflags))->iopl = 3;
vm_info->rip = 0xfff0;
vm_info->segments.cs.selector = 0xf000;
- vm_info->segments.cs.base = 0xf000<<4;
+ vm_info->segments.cs.base = 0xf000 << 4;
vm_info->segments.cs.limit = 0xffff;
vm_info->segments.cs.type = 3;
vm_info->segments.cs.system = 1;
vm_info->segments.cs.present = 1;
vm_info->segments.cs.granularity = 0;
- vm_info->segments.ss.selector = 0x0000;
- vm_info->segments.ss.base = 0x0000<<4;
- vm_info->segments.ss.limit = 0xffff;
- vm_info->segments.ss.type = 3;
- vm_info->segments.ss.system = 1;
- vm_info->segments.ss.dpl = 3;
- vm_info->segments.ss.present = 1;
- vm_info->segments.ss.granularity = 0;
-
- vm_info->segments.es.selector = 0x0000;
- vm_info->segments.es.base = 0x0000<<4;
- vm_info->segments.es.limit = 0xffff;
- vm_info->segments.es.type = 3;
- vm_info->segments.es.system = 1;
- vm_info->segments.es.dpl = 3;
- vm_info->segments.es.present = 1;
- vm_info->segments.es.granularity = 0;
-
- vm_info->segments.fs.selector = 0x0000;
- vm_info->segments.fs.base = 0x0000<<4;
- vm_info->segments.fs.limit = 0xffff;
- vm_info->segments.fs.type = 3;
- vm_info->segments.fs.system = 1;
- vm_info->segments.fs.dpl = 3;
- vm_info->segments.fs.present = 1;
- vm_info->segments.fs.granularity = 0;
-
- vm_info->segments.gs.selector = 0x0000;
- vm_info->segments.gs.base = 0x0000<<4;
- vm_info->segments.gs.limit = 0xffff;
- vm_info->segments.gs.type = 3;
- vm_info->segments.gs.system = 1;
- vm_info->segments.gs.dpl = 3;
- vm_info->segments.gs.present = 1;
- vm_info->segments.gs.granularity = 0;
+ int i = 0;
+ struct v3_segment * seg_ptr = (struct v3_segment *)&(vm_info->segments);
+
+ /* Set values for selectors ds through ss */
+ for(i = 1; i < 6 ; i++) {
+ seg_ptr[i].selector = 0x0000;
+ seg_ptr[i].base = 0x00000;
+ seg_ptr[i].type = 3;
+ seg_ptr[i].system = 1;
+ seg_ptr[i].dpl = 3;
+ seg_ptr[i].present = 1;
+ seg_ptr[i].granularity = 0;
+ }
}
-#endif
-static struct vmcs_data* allocate_vmcs()
+static addr_t allocate_vmcs()
{
reg_ex_t msr;
PrintDebug("Allocating page\n");
- struct vmcs_data* vmcs_page = (struct vmcs_data*)V3_VAddr(V3_AllocPages(1));
+ struct vmcs_data * vmcs_page = (struct vmcs_data *)V3_VAddr(V3_AllocPages(1));
+
memset(vmcs_page, 0, 4096);
vmcs_page->revision = ((struct vmx_basic_msr*)&msr)->revision;
PrintDebug("VMX Revision: 0x%x\n",vmcs_page->revision);
- return (struct vmcs_data*)V3_PAddr((void*)vmcs_page);
+ return (addr_t)V3_PAddr((void*)vmcs_page);
}
static void init_vmcs_bios(struct guest_info * vm_info)
{
+ setup_v8086_mode_for_boot(vm_info);
+ // TODO: Fix vmcs fields so they're 32-bit
+
}
struct vmx_data* data;
- PrintDebug("Allocating vmx_data\n");
data = (struct vmx_data*)V3_Malloc(sizeof(struct vmx_data));
+ PrintDebug("vmx_data pointer: %p\n",(void*)data);
+
PrintDebug("Allocating VMCS\n");
- data->vmcs = allocate_vmcs();
+ data->vmcs_ptr_phys = allocate_vmcs();
+ PrintDebug("VMCS pointer: %p\n",(void*)data->vmcs_ptr_phys);
- info->vmm_data = (void*)data;
+ info->vmm_data = (void *)data;
PrintDebug("Initializing VMCS (addr=%p)\n", info->vmm_data);
init_vmcs_bios(info);
- v3_post_config_guest(info, config_ptr);
+ // v3_post_config_guest(info, config_ptr);
+
+ return 0;
+}
+
+
+static int inline check_vmcs_write(vmcs_field_t field, addr_t val)
+{
+ int ret = 0;
+ ret = vmcs_write(field,val);
+
+ if (ret != VMX_SUCCESS) {
+ PrintError("VMWRITE error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
+ return 1;
+ }
return 0;
}
+static void inline translate_segment_access(struct v3_segment * v3_seg,
+ struct vmcs_segment_access * access)
+{
+ access->type = v3_seg->type;
+ access->desc_type = v3_seg->system;
+ access->dpl = v3_seg->dpl;
+ access->present = v3_seg->present;
+ access->avail = v3_seg->avail;
+ access->long_mode = v3_seg->long_mode;
+ access->db = v3_seg->db;
+ access->granularity = v3_seg->granularity;
+}
+
+static int inline vmcs_write_guest_segments(struct guest_info* info)
+{
+ int ret = 0;
+ struct vmcs_segment_access access;
+
+ /* CS Segment */
+ translate_segment_access(&(info->segments.cs), &access);
+
+ ret &= check_vmcs_write(VMCS_GUEST_CS_BASE, info->segments.cs.base);
+ ret &= check_vmcs_write(VMCS_GUEST_CS_SELECTOR, info->segments.cs.selector);
+ ret &= check_vmcs_write(VMCS_GUEST_CS_LIMIT, info->segments.cs.limit);
+ ret &= check_vmcs_write(VMCS_GUEST_CS_ACCESS, access.value);
+
+ /* SS Segment */
+ translate_segment_access(&(info->segments.ss), &access);
+
+ ret &= check_vmcs_write(VMCS_GUEST_SS_BASE, info->segments.ss.base);
+ ret &= check_vmcs_write(VMCS_GUEST_SS_SELECTOR, info->segments.ss.selector);
+ ret &= check_vmcs_write(VMCS_GUEST_SS_LIMIT, info->segments.ss.limit);
+ ret &= check_vmcs_write(VMCS_GUEST_SS_ACCESS, access.value);
+
+ /* DS Segment */
+ translate_segment_access(&(info->segments.ds), &access);
+
+ ret &= check_vmcs_write(VMCS_GUEST_DS_BASE, info->segments.ds.base);
+ ret &= check_vmcs_write(VMCS_GUEST_DS_SELECTOR, info->segments.ds.selector);
+ ret &= check_vmcs_write(VMCS_GUEST_DS_LIMIT, info->segments.ds.limit);
+ ret &= check_vmcs_write(VMCS_GUEST_DS_ACCESS, access.value);
+ /* ES Segment */
+ translate_segment_access(&(info->segments.es), &access);
-static int start_vmx_guest(struct guest_info *info) {
- struct vmx_data* vmx_data = (struct vmx_data*)info->vmm_data;
+ ret &= check_vmcs_write(VMCS_GUEST_ES_BASE, info->segments.es.base);
+ ret &= check_vmcs_write(VMCS_GUEST_ES_SELECTOR, info->segments.es.selector);
+ ret &= check_vmcs_write(VMCS_GUEST_ES_LIMIT, info->segments.es.limit);
+ ret &= check_vmcs_write(VMCS_GUEST_ES_ACCESS, access.value);
+
+ /* FS Segment */
+ translate_segment_access(&(info->segments.fs), &access);
+
+ ret &= check_vmcs_write(VMCS_GUEST_FS_BASE, info->segments.fs.base);
+ ret &= check_vmcs_write(VMCS_GUEST_FS_SELECTOR, info->segments.fs.selector);
+ ret &= check_vmcs_write(VMCS_GUEST_FS_LIMIT, info->segments.fs.limit);
+ ret &= check_vmcs_write(VMCS_GUEST_FS_ACCESS, access.value);
+
+ /* GS Segment */
+ translate_segment_access(&(info->segments.gs), &access);
+
+ ret &= check_vmcs_write(VMCS_GUEST_GS_BASE, info->segments.gs.base);
+ ret &= check_vmcs_write(VMCS_GUEST_GS_SELECTOR, info->segments.gs.selector);
+ ret &= check_vmcs_write(VMCS_GUEST_GS_LIMIT, info->segments.gs.limit);
+ ret &= check_vmcs_write(VMCS_GUEST_GS_ACCESS, access.value);
+
+ return ret;
+}
+
+static int start_vmx_guest(struct guest_info* info) {
+ struct vmx_data * vmx_data = (struct vmx_data *)info->vmm_data;
int vmx_ret;
// Have to do a whole lot of flag setting here
PrintDebug("Clearing VMCS\n");
- vmx_ret = vmcs_clear(vmx_data->vmcs);
- if(vmx_ret != VMX_SUCCESS) {
- PrintDebug("VMCLEAR failed\n");
+ vmx_ret = vmcs_clear(vmx_data->vmcs_ptr_phys);
+
+ if (vmx_ret != VMX_SUCCESS) {
+ PrintError("VMCLEAR failed\n");
return -1;
}
+
PrintDebug("Loading VMCS\n");
- vmx_ret = vmcs_load(vmx_data->vmcs);
- if(vmx_ret != VMX_SUCCESS) {
- PrintDebug("VMPTRLD failed\n");
+ vmx_ret = vmcs_load(vmx_data->vmcs_ptr_phys);
+
+ if (vmx_ret != VMX_SUCCESS) {
+ PrintError("VMPTRLD failed\n");
return -1;
}
update_vmcs_host_state(info);
- // Setup guest state
+ // Setup guest state
+ // TODO: This is not 32-bit safe!
+ vmx_ret &= check_vmcs_write(VMCS_GUEST_RIP, info->rip);
+
+ vmx_ret &= vmcs_write_guest_segments(info);
+
+ if (vmx_ret != 0) {
+ PrintError("Could not initialize VMCS segments\n");
+ return -1;
+ }
+
+ v3_print_vmcs_guest_state();
+
return -1;
}
-// We set up the global host state that is unlikely to change across processes here
-// Segment Descriptors mainly
-
-struct seg_descriptor {
-
-};
-
-
-
-
void v3_init_vmx(struct v3_ctrl_ops * vm_ops) {
extern v3_cpu_arch_t v3_cpu_type;
);
// Setup VMXON Region
- vmxon_ptr = allocate_vmcs();
- PrintDebug("VMXON pointer: 0x%p\n", (void*)vmxon_ptr);
+ vmxon_ptr_phys = allocate_vmcs();
+ PrintDebug("VMXON pointer: 0x%p\n", (void*)vmxon_ptr_phys);
- if (v3_enable_vmx(vmxon_ptr) == VMX_SUCCESS) {
+ if (v3_enable_vmx(vmxon_ptr_phys) == VMX_SUCCESS) {
PrintDebug("VMX Enabled\n");
} else {
PrintError("VMX initialization failure\n");