Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


SVM Bug Fixes and Enhancements
[palacios.git] / palacios / src / palacios / svm.c
index 15eed50..6ecdb12 100644 (file)
@@ -12,6 +12,7 @@
  * All rights reserved.
  *
  * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *         Peter Dinda <jarusl@cs.northwestern.edu> (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
@@ -859,6 +897,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 +967,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 +995,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;
        }
     }
@@ -1123,6 +1164,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 +1208,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;
@@ -1221,6 +1262,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;
        }
     }