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.


Merge branch 'devel' of ssh://palacios@newskysaw/home/palacios/palacios into devel
[palacios.git] / palacios / src / palacios / svm.c
index 945aa70..bb65a6f 100644 (file)
 #include <palacios/vmm_sprintf.h>
 
 
+#ifndef CONFIG_DEBUG_SVM
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+
 uint32_t v3_last_exit;
 
 // This is a global pointer to the host's VMCB
@@ -58,7 +64,15 @@ extern int v3_svm_launch(vmcb_t * vmcb, struct v3_gprs * vm_regs, vmcb_t * host_
 
 
 static vmcb_t * Allocate_VMCB() {
-    vmcb_t * vmcb_page = (vmcb_t *)V3_VAddr(V3_AllocPages(1));
+    vmcb_t * vmcb_page = NULL;
+    addr_t vmcb_pa = (addr_t)V3_AllocPages(1);
+
+    if ((void *)vmcb_pa == NULL) {
+       PrintError("Error allocating VMCB\n");
+       return NULL;
+    }
+
+    vmcb_page = (vmcb_t *)V3_VAddr((void *)vmcb_pa);
 
     memset(vmcb_page, 0, 4096);
 
@@ -67,15 +81,13 @@ static vmcb_t * Allocate_VMCB() {
 
 
 
-static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
+static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
     uint_t i;
 
 
     //
-
-
     ctrl_area->svm_instrs.VMRUN = 1;
     ctrl_area->svm_instrs.VMMCALL = 1;
     ctrl_area->svm_instrs.VMLOAD = 1;
@@ -83,7 +95,6 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
     ctrl_area->svm_instrs.STGI = 1;
     ctrl_area->svm_instrs.CLGI = 1;
     ctrl_area->svm_instrs.SKINIT = 1;
-    ctrl_area->svm_instrs.RDTSCP = 1;
     ctrl_area->svm_instrs.ICEBP = 1;
     ctrl_area->svm_instrs.WBINVD = 1;
     ctrl_area->svm_instrs.MONITOR = 1;
@@ -93,6 +104,12 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
     ctrl_area->instrs.CPUID = 1;
 
     ctrl_area->instrs.HLT = 1;
+
+#ifdef CONFIG_TIME_VIRTUALIZE_TSC
+    ctrl_area->instrs.RDTSC = 1;
+    ctrl_area->svm_instrs.RDTSCP = 1;
+#endif
+
     // guest_state->cr0 = 0x00000001;    // PE 
   
     /*
@@ -113,7 +130,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
     
 
     ctrl_area->instrs.NMI = 1;
-    ctrl_area->instrs.SMI = 1;
+    ctrl_area->instrs.SMI = 0; // allow SMIs to run in guest
     ctrl_area->instrs.INIT = 1;
     ctrl_area->instrs.PAUSE = 1;
     ctrl_area->instrs.shutdown_evts = 1;
@@ -125,37 +142,37 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
 
     /* Setup Guest Machine state */
 
-    vm_info->vm_regs.rsp = 0x00;
-    vm_info->rip = 0xfff0;
+    core->vm_regs.rsp = 0x00;
+    core->rip = 0xfff0;
 
-    vm_info->vm_regs.rdx = 0x00000f00;
+    core->vm_regs.rdx = 0x00000f00;
 
 
-    vm_info->cpl = 0;
+    core->cpl = 0;
 
-    vm_info->ctrl_regs.rflags = 0x00000002; // The reserved bit is always 1
-    vm_info->ctrl_regs.cr0 = 0x60010010; // Set the WP flag so the memory hooks work in real-mode
-    vm_info->ctrl_regs.efer |= EFER_MSR_svm_enable;
+    core->ctrl_regs.rflags = 0x00000002; // The reserved bit is always 1
+    core->ctrl_regs.cr0 = 0x60010010; // Set the WP flag so the memory hooks work in real-mode
+    core->ctrl_regs.efer |= EFER_MSR_svm_enable;
 
 
 
 
 
-    vm_info->segments.cs.selector = 0xf000;
-    vm_info->segments.cs.limit = 0xffff;
-    vm_info->segments.cs.base = 0x0000000f0000LL;
+    core->segments.cs.selector = 0xf000;
+    core->segments.cs.limit = 0xffff;
+    core->segments.cs.base = 0x0000000f0000LL;
 
     // (raw attributes = 0xf3)
-    vm_info->segments.cs.type = 0x3;
-    vm_info->segments.cs.system = 0x1;
-    vm_info->segments.cs.dpl = 0x3;
-    vm_info->segments.cs.present = 1;
+    core->segments.cs.type = 0x3;
+    core->segments.cs.system = 0x1;
+    core->segments.cs.dpl = 0x3;
+    core->segments.cs.present = 1;
 
 
 
-    struct v3_segment * segregs [] = {&(vm_info->segments.ss), &(vm_info->segments.ds), 
-                                     &(vm_info->segments.es), &(vm_info->segments.fs), 
-                                     &(vm_info->segments.gs), NULL};
+    struct v3_segment * segregs [] = {&(core->segments.ss), &(core->segments.ds), 
+                                     &(core->segments.es), &(core->segments.fs), 
+                                     &(core->segments.gs), NULL};
 
     for ( i = 0; segregs[i] != NULL; i++) {
        struct v3_segment * seg = segregs[i];
@@ -172,31 +189,28 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
        seg->present = 1;
     }
 
-    vm_info->segments.gdtr.limit = 0x0000ffff;
-    vm_info->segments.gdtr.base = 0x0000000000000000LL;
-    vm_info->segments.idtr.limit = 0x0000ffff;
-    vm_info->segments.idtr.base = 0x0000000000000000LL;
+    core->segments.gdtr.limit = 0x0000ffff;
+    core->segments.gdtr.base = 0x0000000000000000LL;
+    core->segments.idtr.limit = 0x0000ffff;
+    core->segments.idtr.base = 0x0000000000000000LL;
 
-    vm_info->segments.ldtr.selector = 0x0000;
-    vm_info->segments.ldtr.limit = 0x0000ffff;
-    vm_info->segments.ldtr.base = 0x0000000000000000LL;
-    vm_info->segments.tr.selector = 0x0000;
-    vm_info->segments.tr.limit = 0x0000ffff;
-    vm_info->segments.tr.base = 0x0000000000000000LL;
+    core->segments.ldtr.selector = 0x0000;
+    core->segments.ldtr.limit = 0x0000ffff;
+    core->segments.ldtr.base = 0x0000000000000000LL;
+    core->segments.tr.selector = 0x0000;
+    core->segments.tr.limit = 0x0000ffff;
+    core->segments.tr.base = 0x0000000000000000LL;
 
 
-    vm_info->dbg_regs.dr6 = 0x00000000ffff0ff0LL;
-    vm_info->dbg_regs.dr7 = 0x0000000000000400LL;
+    core->dbg_regs.dr6 = 0x00000000ffff0ff0LL;
+    core->dbg_regs.dr7 = 0x0000000000000400LL;
 
 
-    v3_init_svm_io_map(vm_info);
-    ctrl_area->IOPM_BASE_PA = (addr_t)V3_PAddr(vm_info->io_map.arch_data);
+    ctrl_area->IOPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->io_map.arch_data);
     ctrl_area->instrs.IOIO_PROT = 1;
-
-
-    v3_init_svm_msr_map(vm_info);
-    ctrl_area->MSRPM_BASE_PA = (addr_t)V3_PAddr(vm_info->msr_map.arch_data);
-    ctrl_area->instrs.MSR_PROT = 1;
+           
+    ctrl_area->MSRPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->msr_map.arch_data);
+    ctrl_area->instrs.MSR_PROT = 1;   
 
 
     PrintDebug("Exiting on interrupts\n");
@@ -204,7 +218,12 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
     ctrl_area->instrs.INTR = 1;
 
 
-    if (vm_info->shdw_pg_mode == SHADOW_PAGING) {
+    v3_hook_msr(core->vm_info, EFER_MSR, 
+               &v3_handle_efer_read,
+               &v3_handle_efer_write, 
+               core);
+
+    if (core->shdw_pg_mode == SHADOW_PAGING) {
        PrintDebug("Creating initial shadow page table\n");
        
        /* JRL: This is a performance killer, and a simplistic solution */
@@ -213,17 +232,17 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
        ctrl_area->guest_ASID = 1;
        
        
-       if (v3_init_passthrough_pts(vm_info) == -1) {
+       if (v3_init_passthrough_pts(core) == -1) {
            PrintError("Could not initialize passthrough page tables\n");
            return ;
        }
 
 
-       vm_info->shdw_pg_state.guest_cr0 = 0x0000000000000010LL;
+       core->shdw_pg_state.guest_cr0 = 0x0000000000000010LL;
        PrintDebug("Created\n");
        
-       vm_info->ctrl_regs.cr0 |= 0x80000000;
-       vm_info->ctrl_regs.cr3 = vm_info->direct_map_pt;
+       core->ctrl_regs.cr0 |= 0x80000000;
+       core->ctrl_regs.cr3 = core->direct_map_pt;
 
        ctrl_area->cr_reads.cr0 = 1;
        ctrl_area->cr_writes.cr0 = 1;
@@ -232,10 +251,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
        ctrl_area->cr_reads.cr3 = 1;
        ctrl_area->cr_writes.cr3 = 1;
 
-       v3_hook_msr(vm_info, EFER_MSR, 
-                   &v3_handle_efer_read,
-                   &v3_handle_efer_write, 
-                   vm_info);
+
 
        ctrl_area->instrs.INVLPG = 1;
 
@@ -245,7 +261,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
 
 
 
-    } else if (vm_info->shdw_pg_mode == NESTED_PAGING) {
+    } else if (core->shdw_pg_mode == NESTED_PAGING) {
        // Flush the TLB on entries/exits
        ctrl_area->TLB_CONTROL = 1;
        ctrl_area->guest_ASID = 1;
@@ -256,26 +272,37 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * vm_info) {
        PrintDebug("NP_Enable at 0x%p\n", (void *)&(ctrl_area->NP_ENABLE));
 
        // Set the Nested Page Table pointer
-       if (v3_init_passthrough_pts(vm_info) == -1) {
+       if (v3_init_passthrough_pts(core) == -1) {
            PrintError("Could not initialize Nested page tables\n");
            return ;
        }
 
-       ctrl_area->N_CR3 = vm_info->direct_map_pt;
+       ctrl_area->N_CR3 = core->direct_map_pt;
 
        guest_state->g_pat = 0x7040600070406ULL;
     }
+    
+    /* tell the guest that we don't support SVM */
+    v3_hook_msr(core->vm_info, SVM_VM_CR_MSR, 
+       &v3_handle_vm_cr_read,
+       &v3_handle_vm_cr_write, 
+       core);
 }
 
 
-int v3_init_svm_vmcb(struct guest_info * info, v3_vm_class_t vm_class) {
+int v3_init_svm_vmcb(struct guest_info * core, v3_vm_class_t vm_class) {
 
     PrintDebug("Allocating VMCB\n");
-    info->vmm_data = (void*)Allocate_VMCB();
+    core->vmm_data = (void *)Allocate_VMCB();
     
+    if (core->vmm_data == NULL) {
+       PrintError("Could not allocate VMCB, Exiting...\n");
+       return -1;
+    }
+
     if (vm_class == V3_PC_VM) {
-       PrintDebug("Initializing VMCB (addr=%p)\n", (void *)info->vmm_data);
-       Init_VMCB_BIOS((vmcb_t*)(info->vmm_data), info);
+       PrintDebug("Initializing VMCB (addr=%p)\n", (void *)core->vmm_data);
+       Init_VMCB_BIOS((vmcb_t*)(core->vmm_data), core);
     } else {
        PrintError("Invalid VM class\n");
        return -1;
@@ -285,31 +312,39 @@ int v3_init_svm_vmcb(struct guest_info * info, v3_vm_class_t vm_class) {
 }
 
 
+int v3_deinit_svm_vmcb(struct guest_info * core) {
+    V3_FreePages(V3_PAddr(core->vmm_data), 1);
+    return 0;
+}
+
 
 static int update_irq_exit_state(struct guest_info * info) {
     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
 
-    if ((info->intr_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) {
+    // Fix for QEMU bug using EVENTINJ as an internal cache
+    guest_ctrl->EVENTINJ.valid = 0;
+
+    if ((info->intr_core_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) {
        
 #ifdef CONFIG_DEBUG_INTERRUPTS
-       PrintDebug("INTAK cycle completed for irq %d\n", info->intr_state.irq_vector);
+       PrintDebug("INTAK cycle completed for irq %d\n", info->intr_core_state.irq_vector);
 #endif
 
-       info->intr_state.irq_started = 1;
-       info->intr_state.irq_pending = 0;
+       info->intr_core_state.irq_started = 1;
+       info->intr_core_state.irq_pending = 0;
 
-       v3_injecting_intr(info, info->intr_state.irq_vector, V3_EXTERNAL_IRQ);
+       v3_injecting_intr(info, info->intr_core_state.irq_vector, V3_EXTERNAL_IRQ);
     }
 
-    if ((info->intr_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 0)) {
+    if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 0)) {
 #ifdef CONFIG_DEBUG_INTERRUPTS
-       PrintDebug("Interrupt %d taken by guest\n", info->intr_state.irq_vector);
+       PrintDebug("Interrupt %d taken by guest\n", info->intr_core_state.irq_vector);
 #endif
 
        // Interrupt was taken fully vectored
-       info->intr_state.irq_started = 0;
+       info->intr_core_state.irq_started = 0;
 
-    } else {
+    } else if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 1)) {
 #ifdef CONFIG_DEBUG_INTERRUPTS
        PrintDebug("EXIT INT INFO is set (vec=%d)\n", guest_ctrl->exit_int_info.vector);
 #endif
@@ -322,6 +357,12 @@ 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 (info->intr_core_state.irq_pending == 0) {
+       guest_ctrl->guest_ctrl.V_IRQ = 0;
+       guest_ctrl->guest_ctrl.V_INTR_VECTOR = 0;
+    }
+    
     if (v3_excp_pending(info)) {
        uint_t excp = v3_get_excp_number(info);
        
@@ -348,12 +389,12 @@ static int update_irq_entry_state(struct guest_info * info) {
 #endif
 
        v3_injecting_excp(info, excp);
-    } else if (info->intr_state.irq_started == 1) {
+    } else if (info->intr_core_state.irq_started == 1) {
 #ifdef CONFIG_DEBUG_INTERRUPTS
        PrintDebug("IRQ pending from previous injection\n");
 #endif
        guest_ctrl->guest_ctrl.V_IRQ = 1;
-       guest_ctrl->guest_ctrl.V_INTR_VECTOR = info->intr_state.irq_vector;
+       guest_ctrl->guest_ctrl.V_INTR_VECTOR = info->intr_core_state.irq_vector;
        guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
        guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
 
@@ -373,8 +414,8 @@ static int update_irq_entry_state(struct guest_info * info) {
                           (void *)(addr_t)info->rip);
 #endif
 
-               info->intr_state.irq_pending = 1;
-               info->intr_state.irq_vector = irq;
+               info->intr_core_state.irq_pending = 1;
+               info->intr_core_state.irq_vector = irq;
                
                break;
            }
@@ -410,15 +451,20 @@ static int update_irq_entry_state(struct guest_info * info) {
 int v3_svm_enter(struct guest_info * info) {
     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); 
-    ullong_t tmp_tsc;
     addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
 
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
+    // Perform any additional yielding needed for time adjustment
+    v3_adjust_time(info);
+
     // disable global interrupts for vm state transition
     v3_clgi();
 
+    // Update timer devices prior to entering VM.
+    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;
@@ -438,8 +484,8 @@ int v3_svm_enter(struct guest_info * info) {
     guest_state->rip = info->rip;
     guest_state->rsp = info->vm_regs.rsp;
 
-#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 
@@ -455,36 +501,30 @@ int v3_svm_enter(struct guest_info * info) {
       (void *)(addr_t)info->rip);
     */
 
-#ifdef CONFIG_SYMBIOTIC
-    if (info->sym_state.sym_call_active == 1) {
+#ifdef 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");
        }
     }
 #endif
 
-
-    rdtscll(info->time_state.cached_host_tsc);
-    guest_ctrl->TSC_OFFSET = info->time_state.guest_tsc - info->time_state.cached_host_tsc;
+    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->cpu_id]);
-    
-    //V3_Print("SVM Returned: Exit Code: %x, guest_rip=%lx\n", (uint32_t)(guest_ctrl->exit_code), (unsigned long)guest_state->rip);
 
+    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);
 
-    rdtscll(tmp_tsc);
+    // Immediate exit from VM time bookkeeping
+    v3_time_exit_vm(info);
 
-    //PrintDebug("SVM Returned\n");
-    
     info->num_exits++;
 
-    v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
-
-
     // Save Guest state from VMCB
     info->rip = guest_state->rip;
     info->vm_regs.rsp = guest_state->rsp;
@@ -514,8 +554,8 @@ int v3_svm_enter(struct guest_info * info) {
     exit_info2 = guest_ctrl->exit_info2;
 
 
-#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
@@ -531,8 +571,10 @@ int v3_svm_enter(struct guest_info * info) {
     v3_yield_cond(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;
     }
 
@@ -541,56 +583,87 @@ int v3_svm_enter(struct guest_info * info) {
 }
 
 
-int v3_start_svm_guest(struct guest_info *info) {
+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);
+
+    if (info->cpu_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);
+
+       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 initialized\n", info->cpu_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), 
+              info->segments.cs.limit, (void *)(info->rip));
 
 
-    PrintDebug("Launching SVM VM (vmcb=%p)\n", (void *)info->vmm_data);
+
+    PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p)\n", info->cpu_id, (void *)info->vmm_data);
     //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
     
-    info->run_state = VM_RUNNING;
-    rdtscll(info->yield_start_cycle);
-
+    v3_start_time(info);
 
     while (1) {
+
+       if (info->vm_info->run_state == VM_STOPPED) {
+           info->core_run_state = CORE_STOPPED;
+           break;
+       }
+       
        if (v3_svm_enter(info) == -1) {
            vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
            addr_t host_addr;
            addr_t linear_addr = 0;
            
-           info->run_state = VM_ERROR;
+           info->vm_info->run_state = VM_ERROR;
            
-           V3_Print("SVM ERROR!!\n"); 
+           V3_Print("SVM core %u: SVM ERROR!!\n", info->cpu_id); 
            
            v3_print_guest_state(info);
            
-           V3_Print("SVM Exit Code: %p\n", (void *)(addr_t)guest_ctrl->exit_code); 
+           V3_Print("SVM core %u: SVM Exit Code: %p\n", info->cpu_id, (void *)(addr_t)guest_ctrl->exit_code); 
            
-           V3_Print("exit_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
-           V3_Print("exit_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
+           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("exit_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
-           V3_Print("exit_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 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));
            
            linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
            
            if (info->mem_mode == PHYSICAL_MEM) {
-               guest_pa_to_host_va(info, linear_addr, &host_addr);
+               v3_gpa_to_hva(info, linear_addr, &host_addr);
            } else if (info->mem_mode == VIRTUAL_MEM) {
-               guest_va_to_host_va(info, linear_addr, &host_addr);
+               v3_gva_to_hva(info, linear_addr, &host_addr);
            }
            
-           V3_Print("Host Address of rip = 0x%p\n", (void *)host_addr);
+           V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->cpu_id, (void *)host_addr);
            
-           V3_Print("Instr (15 bytes) at %p:\n", (void *)host_addr);
+           V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->cpu_id, (void *)host_addr);
            v3_dump_mem((uint8_t *)host_addr, 15);
            
            v3_print_stack(info);
 
            break;
        }
+
+
+       if (info->vm_info->run_state == VM_STOPPED) {
+           info->core_run_state = CORE_STOPPED;
+           break;
+       }
+
        
 /*
        if ((info->num_exits % 5000) == 0) {
@@ -599,6 +672,9 @@ int v3_start_svm_guest(struct guest_info *info) {
 */
        
     }
+
+    // Need to take down the other cores on error... 
+
     return 0;
 }
 
@@ -701,7 +777,27 @@ void v3_init_svm_cpu(int cpu_id) {
 
 
 
+void v3_deinit_svm_cpu(int cpu_id) {
+    reg_ex_t msr;
+    extern v3_cpu_arch_t v3_cpu_types[];
 
+    // reset SVM_VM_HSAVE_PA_MSR
+    // Does setting it to NULL disable??
+    msr.r_reg = 0;
+    v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
+
+    // Disable SVM?
+    v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
+    msr.e_reg.low &= ~EFER_MSR_svm_enable;
+    v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
+
+    v3_cpu_types[cpu_id] = V3_INVALID_CPU;
+
+    V3_FreePages((void *)host_vmcbs[cpu_id], 4);
+
+    V3_Print("Host CPU %d host area freed, and SVM disabled\n", cpu_id);
+    return;
+}