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.


correctly handle NMI exits on VMX architectures
[palacios.git] / palacios / src / palacios / vmx.c
index d9fc081..c341982 100644 (file)
@@ -92,11 +92,17 @@ static int inline check_vmcs_read(vmcs_field_t field, void * val) {
 
 
 static addr_t allocate_vmcs() {
+    void *temp;
     struct vmcs_data * vmcs_page = NULL;
 
     PrintDebug("Allocating page\n");
 
-    vmcs_page = (struct vmcs_data *)V3_VAddr(V3_AllocPages(1));
+    temp = V3_AllocPages(1);
+    if (!temp) { 
+       PrintError("Cannot allocate VMCS\n");
+       return -1;
+    }
+    vmcs_page = (struct vmcs_data *)V3_VAddr(temp);
     memset(vmcs_page, 0, 4096);
 
     vmcs_page->revision = hw_info.basic_info.revision;
@@ -178,9 +184,11 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state)
 
     /* Add external interrupts, NMI exiting, and virtual NMI */
     vmx_state->pin_ctrls.nmi_exit = 1;
+    vmx_state->pin_ctrls.virt_nmi = 1;
     vmx_state->pin_ctrls.ext_int_exit = 1;
 
 
+
     /* We enable the preemption timer by default to measure accurate guest time */
     if (avail_pin_ctrls.active_preempt_timer) {
        V3_Print("VMX Preemption Timer is available\n");
@@ -188,10 +196,17 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state)
        vmx_state->exit_ctrls.save_preempt_timer = 1;
     }
 
+    // we want it to use this when halting
     vmx_state->pri_proc_ctrls.hlt_exit = 1;
 
+    // cpuid tells it that it does not have these instructions
+    vmx_state->pri_proc_ctrls.monitor_exit = 1;
+    vmx_state->pri_proc_ctrls.mwait_exit = 1;
 
+    // we don't need to handle a pause, although this is where
+    // we could pull out of a spin lock acquire or schedule to find its partner
     vmx_state->pri_proc_ctrls.pause_exit = 0;
+
     vmx_state->pri_proc_ctrls.tsc_offset = 1;
 #ifdef V3_CONFIG_TIME_VIRTUALIZE_TSC
     vmx_state->pri_proc_ctrls.rdtsc_exit = 1;
@@ -233,6 +248,11 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state)
     // Setup Guests initial PAT field
     vmx_ret |= check_vmcs_write(VMCS_GUEST_PAT, 0x0007040600070406LL);
 
+    // Capture CR8 mods so that we can keep the apic_tpr correct
+    vmx_state->pri_proc_ctrls.cr8_ld_exit = 1;
+    vmx_state->pri_proc_ctrls.cr8_str_exit = 1;
+
+
     /* Setup paging */
     if (core->shdw_pg_mode == SHADOW_PAGING) {
         PrintDebug("Creating initial shadow page table\n");
@@ -518,6 +538,7 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state)
 #endif
 
 
+
  
 
     if (v3_update_vmcs_ctrl_fields(core)) {
@@ -547,6 +568,12 @@ static void __init_vmx_vmcs(void * arg) {
     int vmx_ret = 0;
     
     vmx_state = (struct vmx_data *)V3_Malloc(sizeof(struct vmx_data));
+
+    if (!vmx_state) {
+       PrintError("Unable to allocate in initializing vmx vmcs\n");
+       return;
+    }
+
     memset(vmx_state, 0, sizeof(struct vmx_data));
 
     PrintDebug("vmx_data pointer: %p\n", (void *)vmx_state);
@@ -936,7 +963,7 @@ int v3_vmx_enter(struct guest_info * info) {
     uint64_t guest_cycles = 0;
 
     // Conditionally yield the CPU if the timeslice has expired
-    v3_yield_cond(info);
+    v3_yield_cond(info,-1);
 
     // Update timer devices late after being in the VM so that as much 
     // of the time in the VM is accounted for as possible. Also do it before
@@ -1089,11 +1116,23 @@ int v3_vmx_enter(struct guest_info * info) {
 #endif
     }
 
+
+    // Lastly we check for an NMI exit, and reinject if so
+    {
+       struct vmx_basic_exit_info * basic_info = (struct vmx_basic_exit_info *)&(exit_info.exit_reason);
+
+       if (basic_info->reason == VMX_EXIT_INFO_EXCEPTION_OR_NMI) {
+           if ((uint8_t)exit_info.int_info == 2) {
+               asm("int $2");
+           }
+       }
+    }
+
     // reenable global interrupts after vm exit
     v3_enable_ints();
 
     // Conditionally yield the CPU if the timeslice has expired
-    v3_yield_cond(info);
+    v3_yield_cond(info,-1);
     v3_advance_time(info, NULL);
     v3_update_timers(info);
 
@@ -1128,7 +1167,7 @@ int v3_start_vmx_guest(struct guest_info * info) {
                return 0;
            }
 
-            v3_yield(info);
+            v3_yield(info,-1);
             //PrintDebug("VMX core %u: still waiting for INIT\n",info->vcpu_id);
         }