X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fsvm.c;h=6e8bece6b439c577a1a86930753564743c1d9d91;hb=3b0d98aaf40fd7a1bfc3bc736144386636cc7a73;hp=384b355d62a4abe85d9da46235a318bd0d5d5052;hpb=d54fc24e6cfb62cc2fedfb63d3ae68ff636e3a01;p=palacios.git diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 384b355..6e8bece 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -1,3 +1,4 @@ + /* * This file is part of the Palacios Virtual Machine Monitor developed * by the V3VEE Project with funding from the United States National @@ -44,7 +45,7 @@ #include -#ifndef CONFIG_DEBUG_SVM +#ifndef V3_CONFIG_DEBUG_SVM #undef PrintDebug #define PrintDebug(fmt, args...) #endif @@ -53,7 +54,7 @@ uint32_t v3_last_exit; // This is a global pointer to the host's VMCB -static addr_t host_vmcbs[CONFIG_MAX_CPUS] = { [0 ... CONFIG_MAX_CPUS - 1] = 0}; +static addr_t host_vmcbs[V3_CONFIG_MAX_CPUS] = { [0 ... V3_CONFIG_MAX_CPUS - 1] = 0}; @@ -105,7 +106,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) { ctrl_area->instrs.HLT = 1; -#ifdef CONFIG_TIME_VIRTUALIZE_TSC +#ifdef V3_CONFIG_TIME_VIRTUALIZE_TSC ctrl_area->instrs.RDTSC = 1; ctrl_area->svm_instrs.RDTSCP = 1; #endif @@ -326,7 +327,7 @@ static int update_irq_exit_state(struct guest_info * info) { if ((info->intr_core_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) { -#ifdef CONFIG_DEBUG_INTERRUPTS +#ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug("INTAK cycle completed for irq %d\n", info->intr_core_state.irq_vector); #endif @@ -337,7 +338,7 @@ static int update_irq_exit_state(struct guest_info * info) { } if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 0)) { -#ifdef CONFIG_DEBUG_INTERRUPTS +#ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug("Interrupt %d taken by guest\n", info->intr_core_state.irq_vector); #endif @@ -345,7 +346,7 @@ static int update_irq_exit_state(struct guest_info * info) { info->intr_core_state.irq_started = 0; } else if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 1)) { -#ifdef CONFIG_DEBUG_INTERRUPTS +#ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug("EXIT INT INFO is set (vec=%d)\n", guest_ctrl->exit_int_info.vector); #endif } @@ -371,7 +372,7 @@ static int update_irq_entry_state(struct guest_info * info) { if (info->excp_state.excp_error_code_valid) { guest_ctrl->EVENTINJ.error_code = info->excp_state.excp_error_code; guest_ctrl->EVENTINJ.ev = 1; -#ifdef CONFIG_DEBUG_INTERRUPTS +#ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug("Injecting exception %d with error code %x\n", excp, guest_ctrl->EVENTINJ.error_code); #endif } @@ -380,7 +381,7 @@ static int update_irq_entry_state(struct guest_info * info) { guest_ctrl->EVENTINJ.valid = 1; -#ifdef CONFIG_DEBUG_INTERRUPTS +#ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug("<%d> Injecting Exception %d (CR2=%p) (EIP=%p)\n", (int)info->num_exits, guest_ctrl->EVENTINJ.vector, @@ -390,7 +391,7 @@ static int update_irq_entry_state(struct guest_info * info) { v3_injecting_excp(info, excp); } else if (info->intr_core_state.irq_started == 1) { -#ifdef CONFIG_DEBUG_INTERRUPTS +#ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug("IRQ pending from previous injection\n"); #endif guest_ctrl->guest_ctrl.V_IRQ = 1; @@ -408,7 +409,7 @@ static int update_irq_entry_state(struct guest_info * info) { guest_ctrl->guest_ctrl.V_IGN_TPR = 1; guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf; -#ifdef CONFIG_DEBUG_INTERRUPTS +#ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug("Injecting Interrupt %d (EIP=%p)\n", guest_ctrl->guest_ctrl.V_INTR_VECTOR, (void *)(addr_t)info->rip); @@ -459,12 +460,14 @@ int v3_svm_enter(struct guest_info * info) { // Perform any additional yielding needed for time adjustment v3_adjust_time(info); - // Update timer devices prior to entering VM. - v3_update_timers(info); - // disable global interrupts for vm state transition v3_clgi(); + // Update timer devices right before entering the VM. Doing it + // here makes sure the guest sees any timers that fired while + // it was in the VMM + v3_update_timers(info); + // Synchronize the guest state to the VMCB guest_state->cr0 = info->ctrl_regs.cr0; guest_state->cr2 = info->ctrl_regs.cr2; @@ -484,7 +487,7 @@ int v3_svm_enter(struct guest_info * info) { guest_state->rip = info->rip; guest_state->rsp = info->vm_regs.rsp; -#ifdef CONFIG_SYMCALL +#ifdef V3_CONFIG_SYMCALL if (info->sym_core_state.symcall_state.sym_call_active == 0) { update_irq_entry_state(info); } @@ -501,7 +504,7 @@ int v3_svm_enter(struct guest_info * info) { (void *)(addr_t)info->rip); */ -#ifdef CONFIG_SYMCALL +#ifdef V3_CONFIG_SYMCALL if (info->sym_core_state.symcall_state.sym_call_active == 1) { if (guest_ctrl->guest_ctrl.V_IRQ == 1) { V3_Print("!!! Injecting Interrupt during Sym call !!!\n"); @@ -509,28 +512,20 @@ int v3_svm_enter(struct guest_info * info) { } #endif -#ifdef CONFIG_TIME_HIDE_VM_COST - v3_restart_time(info); -#endif + v3_time_enter_vm(info); guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state); //V3_Print("Calling v3_svm_launch\n"); - v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->host_cpu_id]); + v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[V3_Get_CPU()]); //V3_Print("SVM Returned: Exit Code: %x, guest_rip=%lx\n", (uint32_t)(guest_ctrl->exit_code), (unsigned long)guest_state->rip); v3_last_exit = (uint32_t)(guest_ctrl->exit_code); -#ifdef CONFIG_TIME_HIDE_VM_COST - v3_pause_time(info); -#ifdef CONFIG_TIME_HIDE_EXIT_COST - v3_offset_time(info, -CONFIG_TIME_EXIT_COST_ADJUST); -#endif -#endif + // Immediate exit from VM time bookkeeping + v3_time_exit_vm(info); - //PrintDebug("SVM Returned\n"); - info->num_exits++; // Save Guest state from VMCB @@ -562,7 +557,7 @@ int v3_svm_enter(struct guest_info * info) { exit_info2 = guest_ctrl->exit_info2; -#ifdef CONFIG_SYMCALL +#ifdef V3_CONFIG_SYMCALL if (info->sym_core_state.symcall_state.sym_call_active == 0) { update_irq_exit_state(info); } @@ -582,6 +577,7 @@ int v3_svm_enter(struct guest_info * info) { if (v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2) != 0) { PrintError("Error in SVM exit handler\n"); + PrintError(" last exit was %d\n", v3_last_exit); return -1; } @@ -594,29 +590,31 @@ int v3_start_svm_guest(struct guest_info * info) { // vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); // vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); - PrintDebug("Starting SVM core %u\n", info->cpu_id); + PrintDebug("Starting SVM core %u (on logical core %u)\n", info->vcpu_id, info->pcpu_id); - if (info->cpu_id == 0) { + if (info->vcpu_id == 0) { info->core_run_state = CORE_RUNNING; info->vm_info->run_state = VM_RUNNING; } else { - PrintDebug("SVM core %u: Waiting for core initialization\n", info->cpu_id); + PrintDebug("SVM core %u (on %u): Waiting for core initialization\n", info->vcpu_id, info->pcpu_id); while (info->core_run_state == CORE_STOPPED) { v3_yield(info); - //PrintDebug("SVM core %u: still waiting for INIT\n",info->cpu_id); + //PrintDebug("SVM core %u: still waiting for INIT\n", info->vcpu_id); } - PrintDebug("SVM core %u initialized\n", info->cpu_id); + PrintDebug("SVM core %u(on %u) initialized\n", info->vcpu_id, info->pcpu_id); } - PrintDebug("SVM 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), + PrintDebug("SVM core %u(on %u): I am starting at CS=0x%x (base=0x%p, limit=0x%x), RIP=0x%p\n", + info->vcpu_id, info->pcpu_id, + info->segments.cs.selector, (void *)(info->segments.cs.base), info->segments.cs.limit, (void *)(info->rip)); - PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p)\n", info->cpu_id, (void *)info->vmm_data); + PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p) (on cpu %u)\n", + info->vcpu_id, (void *)info->vmm_data, info->pcpu_id); //PrintDebugVMCB((vmcb_t*)(info->vmm_data)); v3_start_time(info); @@ -635,17 +633,17 @@ int v3_start_svm_guest(struct guest_info * info) { info->vm_info->run_state = VM_ERROR; - V3_Print("SVM core %u: SVM ERROR!!\n", info->cpu_id); + V3_Print("SVM core %u: SVM ERROR!!\n", info->vcpu_id); v3_print_guest_state(info); - V3_Print("SVM core %u: SVM Exit Code: %p\n", info->cpu_id, (void *)(addr_t)guest_ctrl->exit_code); + V3_Print("SVM core %u: SVM Exit Code: %p\n", info->vcpu_id, (void *)(addr_t)guest_ctrl->exit_code); - V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info1)); - V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4)); + V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info1)); + V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->vcpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4)); - V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info2)); - V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4)); + V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info2)); + V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->vcpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4)); linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs)); @@ -655,9 +653,9 @@ int v3_start_svm_guest(struct guest_info * info) { v3_gva_to_hva(info, linear_addr, &host_addr); } - V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->cpu_id, (void *)host_addr); + V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->vcpu_id, (void *)host_addr); - V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->cpu_id, (void *)host_addr); + V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->vcpu_id, (void *)host_addr); v3_dump_mem((uint8_t *)host_addr, 15); v3_print_stack(info); @@ -672,9 +670,11 @@ int v3_start_svm_guest(struct guest_info * info) { } + /* - if ((info->num_exits % 5000) == 0) { + if ((info->num_exits % 50000) == 0) { V3_Print("SVM Exit number %d\n", (uint32_t)info->num_exits); + v3_print_guest_state(info); } */ @@ -688,6 +688,31 @@ int v3_start_svm_guest(struct guest_info * info) { +int v3_reset_svm_vm_core(struct guest_info * core, addr_t rip) { + // init vmcb_bios + + // Write the RIP, CS, and descriptor + // assume the rest is already good to go + // + // vector VV -> rip at 0 + // CS = VV00 + // This means we start executing at linear address VV000 + // + // So the selector needs to be VV00 + // and the base needs to be VV000 + // + core->rip = 0; + core->segments.cs.selector = rip << 8; + core->segments.cs.limit = 0xffff; + core->segments.cs.base = rip << 12; + + return 0; +} + + + + + /* Checks machine SVM capability */ /* Implemented from: AMD Arch Manual 3, sect 15.4 */ @@ -752,6 +777,7 @@ static int has_svm_nested_paging() { } + void v3_init_svm_cpu(int cpu_id) { reg_ex_t msr; extern v3_cpu_arch_t v3_cpu_types[];