X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fsvm.c;h=28c8a701f0b987d5c0bec6410b013b0d381624e7;hb=4e43946f01f687361197dc9571b7df02ae20de30;hp=15eed502e5696d16a20c6af005d085d58cc40fc0;hpb=e4d65eb1a4af57179bd00c397120c78c9e5b32b1;p=palacios.git diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 15eed50..28c8a70 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -12,6 +12,7 @@ * All rights reserved. * * Author: Jack Lange + * Peter Dinda (Reset) * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "V3VEE_LICENSE". @@ -164,7 +165,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) { ctrl_area->svm_instrs.MONITOR = 1; ctrl_area->svm_instrs.MWAIT_always = 1; ctrl_area->svm_instrs.MWAIT_if_armed = 1; - ctrl_area->instrs.INVLPGA = 1; // invalidate page in asid... why? + ctrl_area->instrs.INVLPGA = 1; // invalidate page in asid... AMD ERRATA ctrl_area->instrs.CPUID = 1; ctrl_area->instrs.HLT = 1; @@ -363,8 +364,6 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) { // Enable Nested Paging ctrl_area->NP_ENABLE = 1; - PrintDebug(core->vm_info, core, "NP_Enable at 0x%p\n", (void *)&(ctrl_area->NP_ENABLE)); - // Set the Nested Page Table pointer if (core->core_run_state == CORE_INVALID) { if (v3_init_passthrough_pts(core) == -1) { @@ -438,7 +437,7 @@ int v3_init_svm_vmcb(struct guest_info * core, v3_vm_class_t vm_class) { int v3_deinit_svm_vmcb(struct guest_info * core) { - if (core->vmm_data) { + if (core && core->vmm_data) { V3_FreePages(V3_PAddr(core->vmm_data), 1); } return 0; @@ -463,12 +462,22 @@ static int svm_handle_standard_reset(struct guest_info *core) // I could be a ROS core, or I could be in a non-HVM // either way, if I'm core 0, I'm the leader if (core->vcpu_id==0) { + uint64_t mem_size=core->vm_info->mem_size; + +#ifdef V3_CONFIG_HVM + // on a ROS reset, we should only + // manipulate the part of the memory seen by + // the ROS + if (core->vm_info->hvm_state.is_hvm) { + mem_size=v3_get_hvm_ros_memsize(core->vm_info); + } +#endif core->vm_info->run_state = VM_RESETTING; // copy bioses again because some, // like seabios, assume // this should also blow away the BDA and EBDA PrintDebug(core->vm_info,core,"Clear memory (%p bytes)\n",(void*)core->vm_info->mem_size); - if (v3_set_gpa_memory(core, 0, core->vm_info->mem_size, 0)!=core->vm_info->mem_size) { + if (v3_set_gpa_memory(core, 0, mem_size, 0)!=mem_size) { PrintError(core->vm_info,core,"Clear of memory failed\n"); } PrintDebug(core->vm_info,core,"Copying bioses\n"); @@ -484,7 +493,7 @@ static int svm_handle_standard_reset(struct guest_info *core) core->cpl = 0; core->cpu_mode = REAL; core->mem_mode = PHYSICAL_MEM; - core->num_exits=0; + //core->num_exits=0; PrintDebug(core->vm_info,core,"Machine reset to REAL/PHYSICAL\n"); @@ -614,6 +623,15 @@ static int update_irq_exit_state(struct guest_info * info) { static int update_irq_entry_state(struct guest_info * info) { vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); + if (guest_ctrl->exit_int_info.valid) { + // We need to complete the previous injection + guest_ctrl->EVENTINJ = guest_ctrl->exit_int_info; + + PrintDebug(info->vm_info,info,"Continuing injection of event - eventinj=0x%llx\n",*(uint64_t*)&guest_ctrl->EVENTINJ); + + return 0; + } + if (info->intr_core_state.irq_pending == 0) { guest_ctrl->guest_ctrl.V_IRQ = 0; @@ -621,20 +639,24 @@ static int update_irq_entry_state(struct guest_info * info) { } if (v3_excp_pending(info)) { + uint_t excp = v3_get_excp_number(info); guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION; - + guest_ctrl->EVENTINJ.vector = excp; + 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 V3_CONFIG_DEBUG_INTERRUPTS PrintDebug(info->vm_info, info, "Injecting exception %d with error code %x\n", excp, guest_ctrl->EVENTINJ.error_code); #endif + } else { + guest_ctrl->EVENTINJ.error_code = 0; + guest_ctrl->EVENTINJ.ev = 0; } - - guest_ctrl->EVENTINJ.vector = excp; - + + guest_ctrl->EVENTINJ.rsvd = 0; guest_ctrl->EVENTINJ.valid = 1; #ifdef V3_CONFIG_DEBUG_INTERRUPTS @@ -646,7 +668,9 @@ static int update_irq_entry_state(struct guest_info * info) { #endif v3_injecting_excp(info, excp); + } else if (info->intr_core_state.irq_started == 1) { + #ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug(info->vm_info, info, "IRQ pending from previous injection\n"); #endif @@ -683,23 +707,38 @@ static int update_irq_entry_state(struct guest_info * info) { info->intr_core_state.irq_pending = 1; info->intr_core_state.irq_vector = irq; + + break; } case V3_NMI: +#ifdef V3_CONFIG_DEBUG_INTERRUPTS + PrintDebug(info->vm_info, info, "Injecting NMI\n"); +#endif guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI; + guest_ctrl->EVENTINJ.ev = 0; + guest_ctrl->EVENTINJ.error_code = 0; + guest_ctrl->EVENTINJ.rsvd = 0; + guest_ctrl->EVENTINJ.valid = 1; + break; + case V3_SOFTWARE_INTR: - guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR; #ifdef V3_CONFIG_DEBUG_INTERRUPTS PrintDebug(info->vm_info, info, "Injecting software interrupt -- type: %d, vector: %d\n", SVM_INJECTION_SOFT_INTR, info->intr_core_state.swintr_vector); #endif + guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR; guest_ctrl->EVENTINJ.vector = info->intr_core_state.swintr_vector; + guest_ctrl->EVENTINJ.ev = 0; + guest_ctrl->EVENTINJ.error_code = 0; + guest_ctrl->EVENTINJ.rsvd = 0; guest_ctrl->EVENTINJ.valid = 1; /* reset swintr state */ info->intr_core_state.swintr_posted = 0; info->intr_core_state.swintr_vector = 0; + break; case V3_VIRTUAL_IRQ: guest_ctrl->EVENTINJ.type = SVM_INJECTION_IRQ; @@ -751,7 +790,6 @@ int v3_svm_enter(struct guest_info * info) { vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0; uint64_t guest_cycles = 0; - struct Interrupt_Info exit_int_info; // Conditionally yield the CPU if the timeslice has expired @@ -761,6 +799,10 @@ int v3_svm_enter(struct guest_info * info) { v3_mem_track_entry(info); #endif +#ifdef V3_CONFIG_HVM + v3_handle_hvm_entry(info); +#endif + // Update timer devices after being in the VM before doing // IRQ updates, so that any interrupts they raise get seen // immediately. @@ -859,6 +901,12 @@ int v3_svm_enter(struct guest_info * info) { #endif + if (guest_ctrl->EVENTINJ.valid && guest_ctrl->interrupt_shadow) { +#ifdef V3_CONFIG_DEBUG_INTERRUPTS + PrintDebug(info->vm_info,info,"Event injection during an interrupt shadow\n"); +#endif + } + rdtscll(entry_tsc); v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[V3_Get_CPU()]); @@ -923,7 +971,6 @@ int v3_svm_enter(struct guest_info * info) { exit_code = guest_ctrl->exit_code; exit_info1 = guest_ctrl->exit_info1; exit_info2 = guest_ctrl->exit_info2; - exit_int_info = guest_ctrl->exit_int_info; #ifdef V3_CONFIG_SYMCALL if (info->sym_core_state.symcall_state.sym_call_active == 0) { @@ -952,8 +999,6 @@ int v3_svm_enter(struct guest_info * info) { PrintError(info->vm_info, info, "Error in SVM exit handler (ret=%d)\n", ret); PrintError(info->vm_info, info, " last Exit was %d (exit code=0x%llx)\n", v3_last_exit, (uint64_t) exit_code); - //V3_Sleep(5*1000000); - return -1; } } @@ -964,6 +1009,10 @@ int v3_svm_enter(struct guest_info * info) { v3_handle_timeouts(info, guest_cycles); } +#ifdef V3_CONFIG_HVM + v3_handle_hvm_exit(info); +#endif + #ifdef V3_CONFIG_MEM_TRACK v3_mem_track_exit(info); #endif @@ -1104,9 +1153,15 @@ int v3_start_svm_guest(struct guest_info * info) { linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs)); if (info->mem_mode == PHYSICAL_MEM) { - v3_gpa_to_hva(info, linear_addr, &host_addr); + if (v3_gpa_to_hva(info, linear_addr, &host_addr)) { + PrintError(info->vm_info, info, "Cannot translate address\n"); + break; + } } else if (info->mem_mode == VIRTUAL_MEM) { - v3_gva_to_hva(info, linear_addr, &host_addr); + if (v3_gva_to_hva(info, linear_addr, &host_addr)) { + PrintError(info->vm_info, info, "Cannot translate address\n"); + break; + } } V3_Print(info->vm_info, info, "SVM core %u: Host Address of rip = 0x%p\n", info->vcpu_id, (void *)host_addr); @@ -1123,6 +1178,7 @@ int v3_start_svm_guest(struct guest_info * info) { if (info->vm_info->run_state == VM_STOPPED) { + PrintDebug(info->vm_info,info,"Stopping core as VM is stopped\n"); info->core_run_state = CORE_STOPPED; break; } @@ -1166,7 +1222,6 @@ int v3_reset_svm_vm_core(struct guest_info * core, addr_t rip) { // So the selector needs to be VV00 // and the base needs to be VV000 // - V3_Print(core->vm_info,core,"SVM Reset to RIP %p\n",(void*)rip); core->rip = 0; core->segments.cs.selector = rip << 8; core->segments.cs.limit = 0xffff; @@ -1198,7 +1253,7 @@ int v3_is_svm_capable() { PrintDebug(VM_NONE, VCORE_NONE, "SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low); - if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) { + if (vm_cr_low & SVM_VM_CR_MSR_svmdis) { V3_Print(VM_NONE, VCORE_NONE, "SVM is available but is disabled.\n"); v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx); @@ -1221,6 +1276,10 @@ int v3_is_svm_capable() { PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx); PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx); + if (!(edx & 0x8)) { + PrintError(VM_NONE,VCORE_NONE, "WARNING: NO SVM SUPPORT FOR NRIP - SW INTR INJECTION WILL LIKELY FAIL\n"); + } + return 1; } }