X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmx.c;h=6d50ff3ad4721dd72e00a68d6c9bb01401b5e122;hb=2a9554f33cc3bdaab08d59ac54d6dd1f4472285d;hp=aba565635db79b294d09e4cff7f2c2338b5143c0;hpb=0121a4503305424096e2b5c5bd3b6c3af2d813e5;p=palacios.git diff --git a/palacios/src/palacios/vmx.c b/palacios/src/palacios/vmx.c index aba5656..6d50ff3 100644 --- a/palacios/src/palacios/vmx.c +++ b/palacios/src/palacios/vmx.c @@ -33,6 +33,13 @@ #include #include + +#ifndef CONFIG_DEBUG_VMX +#undef PrintDebug +#define PrintDebug(fmt, args...) +#endif + + static addr_t host_vmcs_ptrs[CONFIG_MAX_CPUS] = { [0 ... CONFIG_MAX_CPUS - 1] = 0}; @@ -199,8 +206,7 @@ static int init_vmcs_bios(struct guest_info * info, struct vmx_data * vmx_state) /********** Setup and VMX Control Fields from MSR ***********/ /* Setup IO map */ - v3_init_vmx_io_map(info); - v3_init_vmx_msr_map(info); + struct v3_msr tmp_msr; @@ -219,12 +225,17 @@ static int init_vmcs_bios(struct guest_info * info, struct vmx_data * vmx_state) vmx_state->pri_proc_ctrls.invlpg_exit = 1; vmx_state->pri_proc_ctrls.use_msr_bitmap = 1; vmx_state->pri_proc_ctrls.pause_exit = 1; + vmx_state->pri_proc_ctrls.tsc_offset = 1; +#ifdef CONFIG_TIME_VIRTUALIZE_TSC + vmx_state->pri_proc_ctrls.rdtsc_exit = 1; +#endif - vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_A_ADDR, (addr_t)V3_PAddr(info->io_map.arch_data)); + vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_A_ADDR, (addr_t)V3_PAddr(info->vm_info->io_map.arch_data)); vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_B_ADDR, - (addr_t)V3_PAddr(info->io_map.arch_data) + PAGE_SIZE_4KB); + (addr_t)V3_PAddr(info->vm_info->io_map.arch_data) + PAGE_SIZE_4KB); - vmx_ret |= check_vmcs_write(VMCS_MSR_BITMAP, (addr_t)V3_PAddr(info->msr_map.arch_data)); + + vmx_ret |= check_vmcs_write(VMCS_MSR_BITMAP, (addr_t)V3_PAddr(info->vm_info->msr_map.arch_data)); v3_get_msr(VMX_EXIT_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); vmx_state->exit_ctrls.value = tmp_msr.lo; @@ -341,7 +352,7 @@ static int init_vmcs_bios(struct guest_info * info, struct vmx_data * vmx_state) #define VMXASSIST_GDT 0x10000 addr_t vmxassist_gdt = 0; - if (guest_pa_to_host_va(info, VMXASSIST_GDT, &vmxassist_gdt) == -1) { + if (v3_gpa_to_hva(info, VMXASSIST_GDT, &vmxassist_gdt) == -1) { PrintError("Could not find VMXASSIST GDT destination\n"); return -1; } @@ -375,7 +386,7 @@ static int init_vmcs_bios(struct guest_info * info, struct vmx_data * vmx_state) extern uint8_t v3_vmxassist_end[]; addr_t vmxassist_dst = 0; - if (guest_pa_to_host_va(info, VMXASSIST_START, &vmxassist_dst) == -1) { + if (v3_gpa_to_hva(info, VMXASSIST_START, &vmxassist_dst) == -1) { PrintError("Could not find VMXASSIST destination\n"); return -1; } @@ -391,8 +402,12 @@ static int init_vmcs_bios(struct guest_info * info, struct vmx_data * vmx_state) info->dbg_regs.dr7 = 0x400; +#ifdef __V3_64BIT__ vmx_ret |= check_vmcs_write(VMCS_LINK_PTR, (addr_t)0xffffffffffffffffULL); - +#else + vmx_ret |= check_vmcs_write(VMCS_LINK_PTR, (addr_t)0xffffffffUL); + vmx_ret |= check_vmcs_write(VMCS_LINK_PTR_HIGH, (addr_t)0xffffffffUL); +#endif if (v3_update_vmcs_ctrl_fields(info)) { PrintError("Could not write control fields!\n"); @@ -448,17 +463,29 @@ int v3_init_vmx_vmcs(struct guest_info * info, v3_vm_class_t vm_class) { return 0; } + +int v3_deinit_vmx_vmcs(struct guest_info * core) { + struct vmx_data * vmx_state = core->vmm_data; + + V3_FreePages((void *)(vmx_state->vmcs_ptr_phys), 1); + + V3_Free(vmx_state); + + return 0; +} + + static int update_irq_exit_state(struct guest_info * info) { struct vmx_exit_idt_vec_info idt_vec_info; check_vmcs_read(VMCS_IDT_VECTOR_INFO, &(idt_vec_info.value)); - if ((info->intr_state.irq_started == 1) && (idt_vec_info.valid == 0)) { + if ((info->intr_core_state.irq_started == 1) && (idt_vec_info.valid == 0)) { #ifdef CONFIG_DEBUG_INTERRUPTS PrintDebug("Calling v3_injecting_intr\n"); #endif - info->intr_state.irq_started = 0; - v3_injecting_intr(info, info->intr_state.irq_vector, V3_EXTERNAL_IRQ); + info->intr_core_state.irq_started = 0; + v3_injecting_intr(info, info->intr_core_state.irq_vector, V3_EXTERNAL_IRQ); } return 0; @@ -466,11 +493,11 @@ static int update_irq_exit_state(struct guest_info * info) { static int update_irq_entry_state(struct guest_info * info) { struct vmx_exit_idt_vec_info idt_vec_info; - struct vmcs_interrupt_state intr_state; + struct vmcs_interrupt_state intr_core_state; struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data); check_vmcs_read(VMCS_IDT_VECTOR_INFO, &(idt_vec_info.value)); - check_vmcs_read(VMCS_GUEST_INT_STATE, &(intr_state)); + check_vmcs_read(VMCS_GUEST_INT_STATE, &(intr_core_state)); /* Check for pending exceptions to inject */ if (v3_excp_pending(info)) { @@ -494,16 +521,16 @@ static int update_irq_entry_state(struct guest_info * info) { int_info.valid = 1; #ifdef CONFIG_DEBUG_INTERRUPTS - PrintDebug("Injecting exception %d (EIP=%p)\n", int_info.vector, (void *)info->rip); + PrintDebug("Injecting exception %d (EIP=%p)\n", int_info.vector, (void *)(addr_t)info->rip); #endif check_vmcs_write(VMCS_ENTRY_INT_INFO, int_info.value); v3_injecting_excp(info, int_info.vector); } else if ((((struct rflags *)&(info->ctrl_regs.rflags))->intr == 1) && - (intr_state.val == 0)) { + (intr_core_state.val == 0)) { - if ((info->intr_state.irq_started == 1) && (idt_vec_info.valid == 1)) { + if ((info->intr_core_state.irq_started == 1) && (idt_vec_info.valid == 1)) { #ifdef CONFIG_DEBUG_INTERRUPTS PrintDebug("IRQ pending from previous injection\n"); @@ -526,21 +553,21 @@ static int update_irq_entry_state(struct guest_info * info) { switch (v3_intr_pending(info)) { case V3_EXTERNAL_IRQ: { - info->intr_state.irq_vector = v3_get_intr(info); - ent_int.vector = info->intr_state.irq_vector; + info->intr_core_state.irq_vector = v3_get_intr(info); + ent_int.vector = info->intr_core_state.irq_vector; ent_int.type = 0; ent_int.error_code = 0; ent_int.valid = 1; #ifdef CONFIG_DEBUG_INTERRUPTS PrintDebug("Injecting Interrupt %d at exit %u(EIP=%p)\n", - info->intr_state.irq_vector, + info->intr_core_state.irq_vector, (uint32_t)info->num_exits, - (void *)info->rip); + (void *)(addr_t)info->rip); #endif check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value); - info->intr_state.irq_started = 1; + info->intr_core_state.irq_started = 1; break; } @@ -629,12 +656,15 @@ static void print_exit_log(struct guest_info * info) { */ int v3_vmx_enter(struct guest_info * info) { int ret = 0; - uint64_t tmp_tsc = 0; + uint32_t tsc_offset_low, tsc_offset_high; struct vmx_exit_info exit_info; // Conditionally yield the CPU if the timeslice has expired v3_yield_cond(info); + /* If this guest is frequency-lagged behind host time, wait + * for the appropriate host time before resuming the guest. */ + v3_adjust_time(info); // v3_print_guest_state(info); @@ -644,8 +674,8 @@ int v3_vmx_enter(struct guest_info * info) { v3_vmx_restore_vmcs(info); -#ifdef CONFIG_SYMBIOTIC - if (info->sym_state.sym_call_active == 0) { +#ifdef CONFIG_SYMCALL + if (info->sym_core_state.symcall_state.sym_call_active == 0) { update_irq_entry_state(info); } #else @@ -658,10 +688,15 @@ int v3_vmx_enter(struct guest_info * info) { vmcs_write(VMCS_GUEST_CR3, guest_cr3); } - rdtscll(info->time_state.cached_host_tsc); + v3_update_timers(info); + + tsc_offset_high = (uint32_t)((v3_tsc_host_offset(&info->time_state) >> 32) & 0xffffffff); + tsc_offset_low = (uint32_t)(v3_tsc_host_offset(&info->time_state) & 0xffffffff); + check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high); + check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low); - if (info->run_state == VM_STOPPED) { - info->run_state = VM_RUNNING; + if (info->vm_info->run_state == VM_STOPPED) { + info->vm_info->run_state = VM_RUNNING; ret = v3_vmx_launch(&(info->vm_regs), info, &(info->ctrl_regs)); } else { ret = v3_vmx_resume(&(info->vm_regs), info, &(info->ctrl_regs)); @@ -678,12 +713,8 @@ int v3_vmx_enter(struct guest_info * info) { return -1; } - rdtscll(tmp_tsc); - info->num_exits++; - v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc); - /* Update guest state */ v3_vmx_save_vmcs(info); @@ -706,8 +737,8 @@ int v3_vmx_enter(struct guest_info * info) { exit_log[info->num_exits % 10] = exit_info; -#ifdef CONFIG_SYMBIOTIC - if (info->sym_state.sym_call_active == 0) { +#ifdef CONFIG_SYMCALL + if (info->sym_core_state.symcall_state.sym_call_active == 0) { update_irq_exit_state(info); } #else @@ -729,21 +760,54 @@ int v3_vmx_enter(struct guest_info * info) { } -int v3_start_vmx_guest(struct guest_info* info) { +int v3_start_vmx_guest(struct guest_info * info) { + + PrintDebug("Starting VMX core %u\n", info->cpu_id); + + if (info->cpu_id == 0) { + info->core_run_state = CORE_RUNNING; + info->vm_info->run_state = VM_RUNNING; + } else { + + PrintDebug("VMX core %u: Waiting for core initialization\n", info->cpu_id); + + while (info->core_run_state == CORE_STOPPED) { + v3_yield(info); + //PrintDebug("VMX core %u: still waiting for INIT\n",info->cpu_id); + } + + PrintDebug("VMX core %u initialized\n", info->cpu_id); + } + + PrintDebug("VMX core %u: I am starting at CS=0x%x (base=0x%p, limit=0x%x), RIP=0x%p\n", + info->cpu_id, info->segments.cs.selector, (void *)(info->segments.cs.base), + info->segments.cs.limit, (void *)(info->rip)); - PrintDebug("Launching VMX guest\n"); - rdtscll(info->time_state.cached_host_tsc); + PrintDebug("VMX core %u: Launching VMX VM\n", info->cpu_id); + v3_start_time(info); while (1) { + + if (info->vm_info->run_state == VM_STOPPED) { + info->core_run_state = CORE_STOPPED; + break; + } + if (v3_vmx_enter(info) == -1) { v3_print_vmcs(); print_exit_log(info); return -1; } + + + if (info->vm_info->run_state == VM_STOPPED) { + info->core_run_state = CORE_STOPPED; + break; + } /* if ((info->num_exits % 5000) == 0) { V3_Print("VMX Exit number %d\n", (uint32_t)info->num_exits); @@ -794,7 +858,7 @@ void v3_init_vmx_cpu(int cpu_id) { uint64_t ret = 0; v3_get_msr(VMX_CR4_FIXED0_MSR,&(tmp_msr.hi),&(tmp_msr.lo)); - +#ifdef __V3_64BIT__ __asm__ __volatile__ ( "movq %%cr4, %%rbx;" "orq $0x00002000, %%rbx;" @@ -823,6 +887,38 @@ void v3_init_vmx_cpu(int cpu_id) { : : "%rbx" ); +#elif __V3_32BIT__ + __asm__ __volatile__ ( + "movl %%cr4, %%ecx;" + "orl $0x00002000, %%ecx;" + "movl %%ecx, %0;" + : "=m"(ret) + : + : "%ecx" + ); + + if ((~ret & tmp_msr.value) == 0) { + __asm__ __volatile__ ( + "movl %0, %%cr4;" + : + : "q"(ret) + ); + } else { + PrintError("Invalid CR4 Settings!\n"); + return; + } + + __asm__ __volatile__ ( + "movl %%cr0, %%ecx; " + "orl $0x00000020,%%ecx; " + "movl %%ecx, %%cr0;" + : + : + : "%ecx" + ); + +#endif + // // Should check and return Error here....