From: Andy Gocke Date: Thu, 23 Jul 2009 20:19:42 +0000 (-0500) Subject: vmx_patch5 X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=a1d3e2f36e9ef64ca62c611c4f0aa050726e186b vmx_patch5 --- diff --git a/palacios/include/palacios/vmcs.h b/palacios/include/palacios/vmcs.h index b3e1bb8..d0cc867 100644 --- a/palacios/include/palacios/vmcs.h +++ b/palacios/include/palacios/vmcs.h @@ -202,6 +202,8 @@ typedef enum { } vmcs_field_t; int v3_vmcs_get_field_len(vmcs_field_t field); +const char* v3_vmcs_field_to_str(vmcs_field_t field); +void v3_print_vmcs_guest_state(); /* VMCS Exit QUALIFICATIONs */ @@ -287,7 +289,7 @@ struct vmcs_segment_access { uint32_t rsvd1 : 4; uint32_t avail : 1; uint32_t long_mode : 1; // CS only (64 bit active), reserved otherwise - uint32_t DB : 1; + uint32_t db : 1; uint32_t granularity : 1; uint32_t unusable : 1; uint32_t rsvd2 : 15; diff --git a/palacios/include/palacios/vmx.h b/palacios/include/palacios/vmx.h index bdf5bb8..2b50a04 100644 --- a/palacios/include/palacios/vmx.h +++ b/palacios/include/palacios/vmx.h @@ -77,7 +77,7 @@ typedef enum { struct vmx_data { vmx_state_t state; - struct vmcs_data* vmcs; + addr_t vmcs_ptr_phys; }; diff --git a/palacios/include/palacios/vmx_lowlevel.h b/palacios/include/palacios/vmx_lowlevel.h index 6817ccc..0a6ac3e 100644 --- a/palacios/include/palacios/vmx_lowlevel.h +++ b/palacios/include/palacios/vmx_lowlevel.h @@ -56,7 +56,7 @@ -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; @@ -77,7 +77,7 @@ static inline int v3_enable_vmx(struct vmcs_data * vmxon_ptr) { // 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; @@ -115,7 +115,7 @@ static inline int vmcs_resume() { } -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; @@ -134,7 +134,7 @@ static inline int vmcs_load(struct vmcs_data* vmcs_ptr) { 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__ ( @@ -147,7 +147,7 @@ static inline int vmcs_store(struct vmcs_data* vmcs_ptr) { 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; @@ -158,13 +158,12 @@ static inline int vmcs_read(addr_t vmcs_index, void * dst, int len) { "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: @@ -182,7 +181,7 @@ static inline int vmcs_read(addr_t vmcs_index, void * dst, int len) { 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; @@ -192,7 +191,7 @@ static inline int vmcs_write(addr_t vmcs_index, addr_t value) { "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); diff --git a/palacios/src/palacios/vmcs.c b/palacios/src/palacios/vmcs.c index 5ab9a0c..af8bc2e 100644 --- a/palacios/src/palacios/vmcs.c +++ b/palacios/src/palacios/vmcs.c @@ -22,7 +22,7 @@ #include -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; // @@ -40,22 +40,98 @@ static inline void print_vmcs_field(vmcs_field_t vmcs_index) { }; 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); @@ -459,7 +535,7 @@ static const char VMCS_HOST_RIP_STR[] = "HOST_RIP"; -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; diff --git a/palacios/src/palacios/vmx.c b/palacios/src/palacios/vmx.c index df610fa..841f5dc 100644 --- a/palacios/src/palacios/vmx.c +++ b/palacios/src/palacios/vmx.c @@ -431,7 +431,7 @@ static int update_vmcs_host_state(struct guest_info * info) { -static struct vmcs_data* vmxon_ptr; +static addr_t vmxon_ptr_phys; #if 0 @@ -485,19 +485,19 @@ static int setup_base_host_state() { } +#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; @@ -505,50 +505,28 @@ static void setup_v8086_mode_for_boot(struct guest_info* vm_info) 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); @@ -557,7 +535,7 @@ static struct vmcs_data* allocate_vmcs() 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); } @@ -565,7 +543,10 @@ static struct vmcs_data* allocate_vmcs() 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 + } @@ -576,46 +557,144 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config 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; } @@ -656,16 +735,6 @@ static int has_vmx_nested_paging() { -// 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; @@ -692,10 +761,10 @@ void v3_init_vmx(struct v3_ctrl_ops * vm_ops) { ); // 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");