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.


APIC and CR8 changes for vector priorization vs TPR
Peter Dinda [Fri, 3 Aug 2012 16:47:30 +0000 (11:47 -0500)]
This patch does the following:

- It moves the TPR into the guest core structure, replacing CR8
- It intercepts CR8 reads/writes to update the TPR accordingly
- It moves prioritization into the APIC, away from the architecture-specific
  SVM or VMX handling
- It computes APIC PPR and APR dynamically in the APIC
- It does vector to PPR priority comparison (this was not done before at all)
- It does vector to APR comparison for IPI delivery
- It updates checkpointing, etc, to reflect these changes

17 files changed:
linux_module/iface-host-hypercall.c
linux_module/palacios-vnet-brg.c
palacios/include/interfaces/vmm_host_hypercall.h
palacios/include/palacios/vm_guest.h
palacios/include/palacios/vmm_ctrl_regs.h
palacios/include/palacios/vmm_regs.h
palacios/include/palacios/vmx_ctrl_regs.h
palacios/src/devices/apic.c
palacios/src/interfaces/vmm_host_hypercall.c
palacios/src/palacios/svm.c
palacios/src/palacios/svm_handler.c
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_checkpoint.c
palacios/src/palacios/vmm_ctrl_regs.c
palacios/src/palacios/vmx.c
palacios/src/palacios/vmx_ctrl_regs.c
palacios/src/palacios/vmx_handler.c

index 76f2f2d..b998b90 100644 (file)
@@ -45,12 +45,12 @@ static int host_hypercall_nop(palacios_core_t core,
         (void*)(acc->get_r13(core)),
         (void*)(acc->get_r14(core)),
         (void*)(acc->get_r15(core)));
-  DEBUG(" cr0=%p\n cr2=%p\n cr3=%p\n cr4=%p\n cr8=%p\n efer=%p\n",
+  DEBUG(" cr0=%p\n cr2=%p\n cr3=%p\n cr4=%p\n apic_tpr=%p\n efer=%p\n",
         (void*)(acc->get_cr0(core)),
         (void*)(acc->get_cr2(core)),
         (void*)(acc->get_cr3(core)),
         (void*)(acc->get_cr4(core)),
-        (void*)(acc->get_cr8(core)),
+        (void*)(acc->get_apic_tpr(core)),
         (void*)(acc->get_efer(core)));
   return 0;
 }
index efb7d18..00f0996 100644 (file)
@@ -94,7 +94,7 @@ static inline struct vnet_link * _link_by_idx(int idx) {
 
 
 static void _delete_link(struct vnet_link * link){
-    unsigned long flags;
+    unsigned long flags = 0;
 
     link->sock->ops->release(link->sock);
 
@@ -122,7 +122,7 @@ void vnet_brg_delete_link(uint32_t idx){
 }
 
 static void deinit_links_list(void){
-    struct vnet_link * link, * tmp_link;
+    struct vnet_link * link = NULL, * tmp_link = NULL;
 
     list_for_each_entry_safe(link, tmp_link, &(vnet_brg_s.link_list), node) {
        _delete_link(link);
@@ -296,7 +296,9 @@ send_to_palacios(unsigned char * buf,
                 int len,
                 int link_id){
     struct v3_vnet_pkt pkt;
+    memset(pkt,0,sizeof(struct v3_vnet_pkt));
     pkt.size = len;
+    pkt.dst_type = LINK_NOSET;
     pkt.src_type = LINK_EDGE;
     pkt.src_id = link_id;
     memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
@@ -321,7 +323,7 @@ static int
 bridge_send_pkt(struct v3_vm_info * vm, 
                struct v3_vnet_pkt * pkt, 
                void * private_data) {
-    struct vnet_link * link;
+    struct vnet_link * link = NULL;
 
     if(net_debug >= 2){
        DEBUG("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
index 611e700..5fd2525 100644 (file)
@@ -74,7 +74,7 @@ struct guest_accessors {
   GET_SET_REG_DECL(cr2)
   GET_SET_REG_DECL(cr3)
   GET_SET_REG_DECL(cr4)
-  GET_SET_REG_DECL(cr8)
+  GET_SET_REG_DECL(apic_tpr)
   GET_SET_REG_DECL(efer)
 
   int (*gva_to_hva)(palacios_core_t core, uint64_t gva, uint64_t *hva);
index 9e6ea21..468434f 100644 (file)
@@ -139,7 +139,7 @@ struct guest_info {
     
     /* The virtual core # of this cpu (what the guest sees this core as) */
     uint32_t vcpu_id;
-     
+
 };
 
 
index e072a04..e487711 100644 (file)
@@ -186,7 +186,6 @@ struct rflags {
 
 
 
-
 /*
 // First opcode byte
 static const uchar_t cr_access_byte = 0x0f;
@@ -211,6 +210,9 @@ int v3_handle_cr3_read(struct guest_info * info);
 int v3_handle_cr4_write(struct guest_info * info);
 int v3_handle_cr4_read(struct guest_info * info);
 
+int v3_handle_cr8_write(struct guest_info * info);
+int v3_handle_cr8_read(struct guest_info * info);
+
 
 int v3_handle_efer_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data);
 int v3_handle_efer_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data);
index 32a870e..e116d43 100644 (file)
@@ -51,7 +51,7 @@ struct v3_ctrl_regs {
     v3_reg_t cr2;
     v3_reg_t cr3;
     v3_reg_t cr4;
-    v3_reg_t cr8;
+    v3_reg_t apic_tpr;  // cr8 is (apic_tpr >> 4) & 0xf
     v3_reg_t rflags;
     v3_reg_t efer;
 };
index 789ff4e..441b1e5 100644 (file)
@@ -33,6 +33,8 @@ int v3_vmx_handle_cr3_access(struct guest_info * info,
                             struct vmx_exit_cr_qual * cr_qual);
 int v3_vmx_handle_cr4_access(struct guest_info * info, 
                             struct vmx_exit_cr_qual * cr_qual);
+int v3_vmx_handle_cr8_access(struct guest_info * info, 
+                            struct vmx_exit_cr_qual * cr_qual);
 
 #endif
 
index 9e636b6..5576499 100644 (file)
@@ -215,9 +215,9 @@ struct apic_state {
     struct int_cmd_reg int_cmd;
     struct log_dst_reg log_dst;
     struct dst_fmt_reg dst_fmt;
-    struct arb_prio_reg arb_prio;
-    struct task_prio_reg task_prio;
-    struct proc_prio_reg proc_prio;
+    //struct arb_prio_reg arb_prio;     // computed on the fly
+    //struct task_prio_reg task_prio;   // stored in core.ctrl_regs.apic_tpr
+    //struct proc_prio_reg proc_prio;   // computed on the fly
     struct ext_apic_feature_reg ext_apic_feature;
     struct spec_eoi_reg spec_eoi;
   
@@ -280,6 +280,9 @@ struct apic_dev_state {
 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
 
+static void set_apic_tpr(struct apic_state *apic, uint32_t val);
+
+
 // No lcoking done
 static void init_apic_state(struct apic_state * apic, uint32_t id) {
     apic->base_addr = DEFAULT_BASE_ADDR;
@@ -321,9 +324,10 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) {
     // The P6 has 6 LVT entries, so we set the value to (6-1)...
     apic->apic_ver.val = 0x80050010;
 
-    apic->task_prio.val = 0x00000000;
-    apic->arb_prio.val = 0x00000000;
-    apic->proc_prio.val = 0x00000000;
+    set_apic_tpr(apic,0x00000000);
+    // note that arbitration priority and processor priority are derived values
+    // and are computed on the fly
+
     apic->log_dst.val = 0x00000000;
     apic->dst_fmt.val = 0xffffffff;
     apic->spurious_int.val = 0x000000ff;
@@ -501,7 +505,6 @@ static void drain_irq_entries(struct apic_state * apic) {
 
 
 
-
 static int get_highest_isr(struct apic_state * apic) {
     int i = 0, j = 0;
 
@@ -546,6 +549,88 @@ static int get_highest_irr(struct apic_state * apic) {
 }
  
 
+static uint32_t get_isrv(struct apic_state *apic)
+{
+    int isr = get_highest_isr(apic);
+    
+    if (isr>=0) { 
+       return (uint32_t) isr;
+    } else {
+       return 0;
+    }
+}
+
+static uint32_t get_irrv(struct apic_state *apic)
+{
+    int irr = get_highest_irr(apic);
+    
+    if (irr>=0) { 
+       return (uint32_t) irr;
+    } else {
+       return 0;
+    }
+}
+
+
+static uint32_t get_apic_tpr(struct apic_state *apic)
+{
+    return (uint32_t) (apic->core->ctrl_regs.apic_tpr); // see comment in vmm_ctrl_regs.c for how this works
+
+}
+
+static void set_apic_tpr(struct apic_state *apic, uint32_t val)
+{
+    PrintDebug("Set apic_tpr to 0x%x from apic reg path\n",val);
+    apic->core->ctrl_regs.apic_tpr = (uint64_t) val; // see comment in vmm_ctrl_regs.c for how this works
+}
+
+static uint32_t get_apic_ppr(struct apic_state *apic)
+{
+    uint32_t tpr = get_apic_tpr(apic);
+    uint32_t isrv = get_isrv(apic);
+    uint32_t tprlevel, isrlevel;
+    uint32_t ppr;
+
+    tprlevel = (tpr >> 4) & 0xf;
+    isrlevel = (isrv >> 4) & 0xf;
+
+    if (tprlevel>=isrlevel) { 
+       ppr = tpr;  // get class and subclass
+    } else { 
+       ppr = (isrlevel << 4); // get class only
+    }
+    
+    return ppr;
+}
+
+
+
+static uint32_t get_apic_apr(struct apic_state *apic)
+{
+    uint32_t tpr = get_apic_tpr(apic);
+    uint32_t isrv = get_isrv(apic);
+    uint32_t irrv = get_irrv(apic);
+    uint32_t tprlevel, isrlevel, irrlevel;
+
+    tprlevel = (tpr >> 4) & 0xf;
+    isrlevel = (isrv >> 4) & 0xf;
+    irrlevel = (irrv >> 4) & 0xf;
+
+    if (tprlevel >= isrlevel) { 
+       if (tprlevel >= irrlevel) { 
+           return tpr;  // get both class and subclass
+       } else {
+           return irrlevel << 4; // get class only
+       }
+    } else {
+       if (isrlevel >= irrlevel) {
+           return isrlevel << 4; // get class only
+       } else {
+           return irrlevel << 4; // get class only
+       }
+    }
+    
+}
 
 
 static int apic_do_eoi(struct guest_info * core, struct apic_state * apic) {
@@ -939,6 +1024,7 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                    }
                } else {  // APIC_LOWEST_DELIVERY
                    struct apic_state * cur_best_apic = NULL;
+                   uint32_t cur_best_apr;
                    uint8_t mda = ipi->dst;
                    int i;
 
@@ -963,8 +1049,13 @@ static int route_ipi(struct apic_dev_state * apic_dev,
 
                            if (cur_best_apic == 0) {
                                cur_best_apic = dest_apic;  
-                           } else if (dest_apic->task_prio.val < cur_best_apic->task_prio.val) {
-                               cur_best_apic = dest_apic;
+                               cur_best_apr = get_apic_apr(dest_apic) & 0xf0;
+                           } else {
+                               uint32_t dest_apr = get_apic_apr(dest_apic) & 0xf0;
+                               if (dest_apr < cur_best_apr) {
+                                   cur_best_apic = dest_apic;
+                                   cur_best_apr = dest_apr;
+                               }
                            } 
 
                            v3_unlock_irqrestore(apic_dev->state_lock, flags);
@@ -1081,13 +1172,13 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
            val = apic->apic_ver.val;
            break;
        case TPR_OFFSET:
-           val = apic->task_prio.val;
+           val = get_apic_tpr(apic);
            break;
        case APR_OFFSET:
-           val = apic->arb_prio.val;
+           val = get_apic_apr(apic);
            break;
        case PPR_OFFSET:
-           val = apic->proc_prio.val;
+           val = get_apic_ppr(apic);
            break;
        case REMOTE_READ_OFFSET:
            val = apic->rem_rd_data;
@@ -1375,7 +1466,7 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            apic->lapic_id.val = op_val;
            break;
        case TPR_OFFSET:
-           apic->task_prio.val = op_val;
+           set_apic_tpr(apic,op_val);
            break;
        case LDR_OFFSET:
            PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
@@ -1543,12 +1634,33 @@ static int apic_intr_pending(struct guest_info * core, void * private_data) {
 
     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->vcpu_id,req_irq,svc_irq);
 
+
     if ((req_irq >= 0) && 
        (req_irq > svc_irq)) {
-       return 1;
-    }
 
-    return 0;
+       // We have a new requested vector that is higher priority than
+       // the vector that is in-service
+
+       uint32_t ppr = get_apic_ppr(apic);
+
+       if ((req_irq & 0xf0) > (ppr & 0xf0)) {
+           // it's also higher priority than the current
+           // processor priority.  Therefore this
+           // interrupt can go in now.
+           return 1;
+       } else {
+           // processor priority is currently too high
+           // for this interrupt to go in now.  
+           // note that if tpr=0xf?, then ppr=0xf?
+           // and thus all vectors will be masked
+           // as required (tpr=0xf? => all masked)
+           return 0;
+       }
+    } else {
+       // the vector that is in service is higher
+       // priority than any new requested vector
+       return 0;
+    }
 }
 
 
@@ -1559,13 +1671,23 @@ static int apic_get_intr_number(struct guest_info * core, void * private_data) {
     int req_irq = get_highest_irr(apic);
     int svc_irq = get_highest_isr(apic);
 
-    if (svc_irq == -1) {
-       return req_irq;
-    } else if (svc_irq < req_irq) {
-       return req_irq;
-    }
 
-    return -1;
+    // for the logic here, see the comments for apic_intr_pending
+    if ((req_irq >=0) &&
+       (req_irq > svc_irq)) { 
+       
+       uint32_t ppr = get_apic_ppr(apic);
+       
+       if ((req_irq & 0xf0) > (ppr & 0xf0)) {
+           return req_irq;
+       } else {
+           // hmm, this should not have happened, but, anyway,
+           // no interrupt is currently ready to go in
+           return -1;
+       }
+    } else {
+       return -1;
+    }
 }
 
 
@@ -1579,7 +1701,6 @@ int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev
 
 
 
-
 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
@@ -1765,6 +1886,7 @@ static int apic_free(struct apic_dev_state * apic_dev) {
 static int apic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
     struct apic_dev_state * apic_state = (struct apic_dev_state *)private_data;
     int i = 0;
+    uint32_t temp;
 
     V3_CHKPT_STD_SAVE(ctx, apic_state->num_apics);
 
@@ -1789,9 +1911,17 @@ static int apic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
        V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_cmd);
        V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].log_dst);
        V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].dst_fmt);
-       V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].arb_prio);
-       V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].task_prio);
-       V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].proc_prio);
+
+       // APR and PPR are stored only for compatability
+       // TPR is in APIC_TPR, APR and PPR are derived
+       
+       temp = get_apic_apr(&(apic_state->apics[i]));
+       V3_CHKPT_STD_SAVE(ctx, temp);
+       temp = get_apic_tpr(&(apic_state->apics[i]));
+       V3_CHKPT_STD_SAVE(ctx, temp);
+       temp = get_apic_ppr(&(apic_state->apics[i]));
+       V3_CHKPT_STD_SAVE(ctx, temp);
+
        V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_apic_feature);
        V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].spec_eoi);
        V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_cur_cnt);
@@ -1813,6 +1943,7 @@ static int apic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
 static int apic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
     struct apic_dev_state *apic_state = (struct apic_dev_state *)private_data;
     int i = 0;
+    uint32_t temp;
 
     V3_CHKPT_STD_LOAD(ctx,apic_state->num_apics);
 
@@ -1835,9 +1966,15 @@ static int apic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
        V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_cmd);
        V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].log_dst);
        V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].dst_fmt);
-       V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].arb_prio);
-       V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].task_prio);
-       V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].proc_prio);
+
+       // APR is ignored
+       V3_CHKPT_STD_LOAD(ctx, temp);
+       // TPR is written back to APIC_TPR
+       V3_CHKPT_STD_LOAD(ctx, temp);
+       set_apic_tpr(&(apic_state->apics[i]),temp);
+       // PPR is ignored
+       V3_CHKPT_STD_LOAD(ctx, temp);
+
        V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_apic_feature);
        V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].spec_eoi);
        V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_cur_cnt);
index ab57698..a053184 100644 (file)
@@ -64,7 +64,7 @@ GET_SET_CR_IMPL(cr0)
 GET_SET_CR_IMPL(cr2)
 GET_SET_CR_IMPL(cr3)
 GET_SET_CR_IMPL(cr4)
-GET_SET_CR_IMPL(cr8)
+GET_SET_CR_IMPL(apic_tpr)
 GET_SET_CR_IMPL(efer)
 GET_SET_CR_IMPL(rflags)
 
@@ -93,7 +93,7 @@ DECL_IT(cr0)
 DECL_IT(cr2)
 DECL_IT(cr3)
 DECL_IT(cr4)
-DECL_IT(cr8)
+DECL_IT(apic_tpr)
 DECL_IT(efer)
 DECL_IT(rflags)
 
index 996ed2b..a4e9443 100644 (file)
@@ -243,8 +243,20 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
     PrintDebug("Exiting on interrupts\n");
     ctrl_area->guest_ctrl.V_INTR_MASKING = 1;
     ctrl_area->instrs.INTR = 1;
+    // The above also assures the TPR changes (CR8) are only virtual
 
 
+    // However, we need to see TPR writes since they will
+    // affect the virtual apic
+    // we reflect out cr8 to ctrl_regs->apic_tpr
+    ctrl_area->cr_reads.cr8 = 1;
+    ctrl_area->cr_writes.cr8 = 1;
+    // We will do all TPR comparisons in the virtual apic
+    // We also do not want the V_TPR to be able to mask the PIC
+    ctrl_area->guest_ctrl.V_IGN_TPR = 1;
+
+    
+
     v3_hook_msr(core->vm_info, EFER_MSR, 
                &v3_handle_efer_read,
                &v3_svm_handle_efer_write, 
@@ -279,7 +291,6 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
        ctrl_area->cr_writes.cr3 = 1;
 
 
-
        ctrl_area->instrs.INVLPG = 1;
 
        ctrl_area->exceptions.pf = 1;
@@ -287,7 +298,6 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
        guest_state->g_pat = 0x7040600070406ULL;
 
 
-
     } else if (core->shdw_pg_mode == NESTED_PAGING) {
        // Flush the TLB on entries/exits
        ctrl_area->TLB_CONTROL = 1;
@@ -477,8 +487,11 @@ static int update_irq_entry_state(struct guest_info * info) {
 #endif
        guest_ctrl->guest_ctrl.V_IRQ = 1;
        guest_ctrl->guest_ctrl.V_INTR_VECTOR = info->intr_core_state.irq_vector;
+
+       // We ignore the virtual TPR on this injection
+       // TPR/PPR tests have already been done in the APIC.
        guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
-       guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
+       guest_ctrl->guest_ctrl.V_INTR_PRIO = info->intr_core_state.irq_vector >> 4 ;  // 0xf;
 
     } else {
        switch (v3_intr_pending(info)) {
@@ -487,8 +500,11 @@ static int update_irq_entry_state(struct guest_info * info) {
 
                guest_ctrl->guest_ctrl.V_IRQ = 1;
                guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
+
+               // We ignore the virtual TPR on this injection
+               // TPR/PPR tests have already been done in the APIC.
                guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
-               guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
+               guest_ctrl->guest_ctrl.V_INTR_PRIO = info->intr_core_state.irq_vector >> 4 ;  // 0xf;
 
 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
                PrintDebug("Injecting Interrupt %d (EIP=%p)\n", 
@@ -587,7 +603,17 @@ int v3_svm_enter(struct guest_info * info) {
     guest_state->cr4 = info->ctrl_regs.cr4;
     guest_state->dr6 = info->dbg_regs.dr6;
     guest_state->dr7 = info->dbg_regs.dr7;
-    guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
+
+    // CR8 is now updated by read/writes and it contains the APIC TPR
+    // the V_TPR should be just the class part of that.
+    // This update is here just for completeness.  We currently
+    // are ignoring V_TPR on all injections and doing the priority logivc
+    // in the APIC.
+    // guest_ctrl->guest_ctrl.V_TPR = ((info->ctrl_regs.apic_tpr) >> 4) & 0xf;
+
+    //guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
+    // 
+    
     guest_state->rflags = info->ctrl_regs.rflags;
     guest_state->efer = info->ctrl_regs.efer;
     
@@ -668,7 +694,11 @@ int v3_svm_enter(struct guest_info * info) {
     info->ctrl_regs.cr4 = guest_state->cr4;
     info->dbg_regs.dr6 = guest_state->dr6;
     info->dbg_regs.dr7 = guest_state->dr7;
-    info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
+    //
+    // We do not track this anymore
+    // V_TPR is ignored and we do the logic in the APIC
+    //info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
+    //
     info->ctrl_regs.rflags = guest_state->rflags;
     info->ctrl_regs.efer = guest_state->efer;
     
index 14f4454..4ea49c9 100644 (file)
@@ -165,6 +165,25 @@ int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_i
                return -1;
            }
            break;
+
+       case SVM_EXIT_CR8_WRITE:
+#ifdef V3_CONFIG_DEBUG_CTRL_REGS
+           PrintDebug("CR8 Read\n");
+#endif
+           if (v3_handle_cr8_read(info) == -1) {
+               return -1;
+           }
+           break;
+
+       case SVM_EXIT_CR8_READ:
+#ifdef V3_CONFIG_DEBUG_CTRL_REGS
+           PrintDebug("CR8 Read\n");
+#endif
+           if (v3_handle_cr8_read(info) == -1) {
+               return -1;
+           }
+           break;
+
        case SVM_EXIT_EXCP14: {
            addr_t fault_addr = exit_info2;
            pf_error_t * error_code = (pf_error_t *)&(exit_info1);
index ba4a8b0..ee85811 100644 (file)
@@ -730,7 +730,7 @@ void v3_yield_cond(struct guest_info * info, int usec) {
         info->yield_start_cycle +=  info->vm_info->yield_cycle_period;
     }
 }
-
 
 /* 
  * unconditional cpu yield 
index e2baf42..9a49149 100644 (file)
@@ -609,7 +609,7 @@ static int load_core(struct guest_info * info, struct v3_chkpt * chkpt) {
     V3_CHKPT_STD_LOAD(ctx, info->ctrl_regs.cr0);
     V3_CHKPT_STD_LOAD(ctx, info->ctrl_regs.cr2);
     V3_CHKPT_STD_LOAD(ctx, info->ctrl_regs.cr4);
-    V3_CHKPT_STD_LOAD(ctx, info->ctrl_regs.cr8);
+    V3_CHKPT_STD_LOAD(ctx, info->ctrl_regs.apic_tpr);
     V3_CHKPT_STD_LOAD(ctx, info->ctrl_regs.rflags);
     V3_CHKPT_STD_LOAD(ctx, info->ctrl_regs.efer);
 
@@ -727,7 +727,7 @@ static int save_core(struct guest_info * info, struct v3_chkpt * chkpt) {
     V3_CHKPT_STD_SAVE(ctx, info->ctrl_regs.cr0);
     V3_CHKPT_STD_SAVE(ctx, info->ctrl_regs.cr2);
     V3_CHKPT_STD_SAVE(ctx, info->ctrl_regs.cr4);
-    V3_CHKPT_STD_SAVE(ctx, info->ctrl_regs.cr8);
+    V3_CHKPT_STD_SAVE(ctx, info->ctrl_regs.apic_tpr);
     V3_CHKPT_STD_SAVE(ctx, info->ctrl_regs.rflags);
     V3_CHKPT_STD_SAVE(ctx, info->ctrl_regs.efer);
 
index c80f605..acf95a7 100644 (file)
@@ -549,6 +549,119 @@ int v3_handle_cr4_write(struct guest_info * info) {
 }
 
 
+/*
+  The CR8 and APIC TPR interaction are kind of crazy.
+
+  CR8 mandates that the priority class is in bits 3:0
+
+  The interaction of CR8 and an actual APIC is somewhat implementation dependent, but
+  a basic current APIC has the priority class at 7:4 and the *subclass* at 3:0
+
+  The APIC TPR (both fields) can be written as the APIC register
+  A write to CR8 sets the priority class field, and should zero the subclass
+  A read from CR8 gets just the priority class field
+
+  In the apic_tpr storage location, we have:
+
+     zeros [class] [subclass]
+
+  Because of this, an APIC implementation should use apic_tpr to store its TPR
+  In fact, it *should* do this, otherwise its TPR may get out of sync with the architected TPR
+
+  On a CR8 read, we return just 
+
+     zeros 0000  [class]
+
+  On a CR8 write, we set the register to
+
+     zeros [class] 0000
+
+*/
+
+int v3_handle_cr8_write(struct guest_info * info) {
+    int ret;
+    uchar_t instr[15];
+    struct x86_instr dec_instr;
+    
+    if (info->mem_mode == PHYSICAL_MEM) { 
+       ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+    } else { 
+       ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+    }
+    
+    if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
+       PrintError("Could not decode instruction\n");
+       return -1;
+    }
+    
+    if (dec_instr.op_type == V3_OP_MOV2CR) {
+       PrintDebug("MOV2CR8 (cpu_mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
+       
+       if ((info->cpu_mode == LONG) ||
+           (info->cpu_mode == LONG_32_COMPAT)) {
+           uint64_t *val = (uint64_t *)(dec_instr.src_operand.operand);
+
+           info->ctrl_regs.apic_tpr = (*val & 0xf) << 4;
+
+           V3_Print("Write of CR8 sets apic_tpr to 0x%llx\n",info->ctrl_regs.apic_tpr);
+
+       }  else {
+           // probably should raise exception here
+       }
+    } else {
+       PrintError("Unhandled opcode in handle_cr8_write\n");
+       return -1;
+    }
+    
+    info->rip += dec_instr.instr_length;
+    
+    return 0;
+}
+
+
+
+int v3_handle_cr8_read(struct guest_info * info) {
+    uchar_t instr[15];
+    int ret;
+    struct x86_instr dec_instr;
+    
+    if (info->mem_mode == PHYSICAL_MEM) { 
+       ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+    } else { 
+       ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+    }
+    
+    if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
+       PrintError("Could not decode instruction\n");
+       return -1;
+    }
+    
+    if (dec_instr.op_type == V3_OP_MOVCR2) {
+       PrintDebug("MOVCR82 (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
+       
+       if ((info->cpu_mode == LONG) || 
+           (info->cpu_mode == LONG_32_COMPAT)) {
+           uint64_t *dst_reg = (uint64_t *)(dec_instr.dst_operand.operand);
+
+           *dst_reg = (info->ctrl_regs.apic_tpr >> 4) & 0xf;
+
+           V3_Print("Read of CR8 (apic_tpr) returns 0x%llx\n",*dst_reg);
+
+       } else {
+           // probably should raise exception
+       }
+           
+    } else {
+       PrintError("Unhandled opcode in handle_cr8_read\n");
+       return -1;
+    }
+    
+    info->rip += dec_instr.instr_length;
+    
+    return 0;
+}
+
+
 int v3_handle_efer_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
     PrintDebug("EFER Read HI=%x LO=%x\n", core->shdw_pg_state.guest_efer.hi, core->shdw_pg_state.guest_efer.lo);
     
index ed5140f..3fede2b 100644 (file)
@@ -187,6 +187,7 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state)
     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");
@@ -239,6 +240,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");
@@ -524,6 +530,7 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state)
 #endif
 
 
+
  
 
     if (v3_update_vmcs_ctrl_fields(core)) {
index 01c5dfe..2b0bfb5 100644 (file)
@@ -100,6 +100,28 @@ int v3_vmx_handle_cr4_access(struct guest_info * info, struct vmx_exit_cr_qual *
     return -1;
 }
 
+int v3_vmx_handle_cr8_access(struct guest_info * info, struct vmx_exit_cr_qual * cr_qual) {
+    if (cr_qual->access_type < 2) {
+
+       if (cr_qual->access_type == 0) {
+           if (v3_handle_cr8_write(info) != 0) {
+               PrintError("Could not handle CR8 write\n");
+               return -1;
+           }
+       } else {
+           if (v3_handle_cr8_read(info) != 0) {
+               PrintError("Could not handle CR8 read\n");
+               return -1;
+           }
+       }
+       
+       return 0;
+    }
+    
+    PrintError("Invalid CR8 Access type?? (type=%d)\n", cr_qual->access_type);
+    return -1;
+}
+
 static int handle_mov_to_cr3(struct guest_info * info, v3_reg_t * cr3_reg) {
 
     if (info->shdw_pg_mode == SHADOW_PAGING) {
index 0cf500f..8f7665d 100644 (file)
@@ -237,6 +237,12 @@ int v3_handle_vmx_exit(struct guest_info * info, struct vmx_exit_info * exit_inf
                        return -1;
                    }
                    break;
+               case 8:
+                   if (v3_vmx_handle_cr8_access(info, cr_qual) == -1) {
+                       PrintError("Error in CR8 access handler\n");
+                       return -1;
+                   }
+                   break;
                default:
                    PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
                    return -1;