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.


Devices updated for revised checkpoint interface
[palacios.git] / palacios / src / devices / apic.c
index 508f221..50757cf 100644 (file)
@@ -72,14 +72,6 @@ static char * deliverymode_str[] = {
 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
               APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
 
-#define APIC_FIXED_DELIVERY  0x0
-#define APIC_LOWEST_DELIVERY 0x1
-#define APIC_SMI_DELIVERY    0x2
-#define APIC_RES1_DELIVERY   0x3
-#define APIC_NMI_DELIVERY    0x4
-#define APIC_INIT_DELIVERY   0x5
-#define APIC_SIPI_DELIVERY   0x6
-#define APIC_EXTINT_DELIVERY 0x7
 
 #define APIC_SHORTHAND_NONE        0x0
 #define APIC_SHORTHAND_SELF        0x1
@@ -180,6 +172,18 @@ struct apic_msr {
 
 
 
+
+struct irq_queue_entry {
+    uint32_t vector;
+    int (*ack)(struct guest_info * core, uint32_t irq, void * private_data);
+    void * private_data;
+
+    struct list_head list_node;
+};
+
+
+
+
 typedef enum {INIT_ST, 
              SIPI, 
              STARTED} ipi_state_t; 
@@ -211,16 +215,16 @@ 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;
   
 
     uint32_t tmr_cur_cnt;
     uint32_t tmr_init_cnt;
-
+    uint32_t missed_ints;
 
     struct local_vec_tbl_reg ext_intr_vec_tbl[4];
 
@@ -234,6 +238,11 @@ struct apic_state {
     uint8_t int_en_reg[32];
     uint8_t trig_mode_reg[32];
 
+    struct {
+       int (*ack)(struct guest_info * core, uint32_t irq, void * private_data);
+       void * private_data;
+    } irq_ack_cbs[256];
+
     struct guest_info * core;
 
     void * controller_handle;
@@ -241,7 +250,12 @@ struct apic_state {
     struct v3_timer * timer;
 
 
-    struct v3_queue irq_queue;
+    struct {
+       v3_lock_t lock;
+       
+       uint64_t num_entries;
+       struct list_head entries;
+    } irq_queue ;
 
     uint32_t eoi;
 
@@ -266,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;
@@ -295,17 +312,22 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) {
     apic->rem_rd_data = 0x00000000;
     apic->tmr_init_cnt = 0x00000000;
     apic->tmr_cur_cnt = 0x00000000;
+    apic->missed_ints = 0;
 
-    apic->lapic_id.val = id;
+    // note that it's the *lower* 24 bits that are
+    // reserved, not the upper 24.  
+    apic->lapic_id.val = 0;
+    apic->lapic_id.apic_id = id;
     
     apic->ipi_state = INIT_ST;
 
     // 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;
@@ -324,8 +346,9 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) {
     apic->spec_eoi.val = 0x00000000;
 
 
-    v3_init_queue(&(apic->irq_queue));
-
+    INIT_LIST_HEAD(&(apic->irq_queue.entries));
+    v3_lock_init(&(apic->irq_queue.lock));
+    apic->irq_queue.num_entries = 0;
 
 }
 
@@ -384,7 +407,9 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo
 
 
 // irq_num is the bit offset into a 256 bit buffer...
-static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
+static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num, 
+                            int (*ack)(struct guest_info * core, uint32_t irq, void * private_data), 
+                            void * private_data) {
     int major_offset = (irq_num & ~0x00000007) >> 3;
     int minor_offset = irq_num & 0x00000007;
     uint8_t * req_location = apic->int_req_reg + major_offset;
@@ -401,6 +426,9 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
 
     if (*en_location & flag) {
        *req_location |= flag;
+       apic->irq_ack_cbs[irq_num].ack = ack;
+       apic->irq_ack_cbs[irq_num].private_data = private_data;
+
        return 1;
     } else {
        PrintDebug("apic %u: core %d: Interrupt  not enabled... %.2x\n", 
@@ -411,7 +439,12 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
 }
 
 
-static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) {
+
+static int add_apic_irq_entry(struct apic_state * apic, uint32_t irq_num, 
+                             int (*ack)(struct guest_info * core, uint32_t irq, void * private_data),
+                             void * private_data) {
+    unsigned int flags = 0;
+    struct irq_queue_entry * entry = NULL;
 
     if (irq_num <= 15) {
        PrintError("core %d: Attempting to raise an invalid interrupt: %d\n", 
@@ -419,27 +452,63 @@ static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) {
        return -1;
     }
 
-    v3_enqueue(&(apic->irq_queue), (addr_t)irq_num);
+    entry = V3_Malloc(sizeof(struct irq_queue_entry));
+
+    if (entry == NULL) {
+       PrintError("Could not allocate irq queue entry\n");
+       return -1;
+    }
+
+    entry->vector = irq_num;
+    entry->ack = ack;
+    entry->private_data = private_data;
+
+    flags = v3_lock_irqsave(apic->irq_queue.lock);
+    
+    list_add_tail(&(entry->list_node), &(apic->irq_queue.entries));
+    apic->irq_queue.num_entries++;
+
+    v3_unlock_irqrestore(apic->irq_queue.lock, flags);
+  
 
     return 0;
 }
 
 static void drain_irq_entries(struct apic_state * apic) {
-    uint32_t irq = 0;
 
-    while ((irq = (uint32_t)v3_dequeue(&(apic->irq_queue))) != 0) {
-       activate_apic_irq(apic, irq);
+    while (1) {
+       unsigned int flags = 0;
+       struct irq_queue_entry * entry = NULL;
+    
+       flags = v3_lock_irqsave(apic->irq_queue.lock);
+       
+       if (!list_empty(&(apic->irq_queue.entries))) {
+           struct list_head * q_entry = apic->irq_queue.entries.next;
+           entry = list_entry(q_entry, struct irq_queue_entry, list_node);
+
+           apic->irq_queue.num_entries--;
+           list_del(q_entry);
+       }
+       
+       v3_unlock_irqrestore(apic->irq_queue.lock, flags);
+
+       if (entry == NULL) {
+           break;
+       }
+
+       activate_apic_irq(apic, entry->vector, entry->ack, entry->private_data);
+
+       V3_Free(entry);
     }
 
 }
 
 
 
-
 static int get_highest_isr(struct apic_state * apic) {
     int i = 0, j = 0;
 
-    // We iterate backwards to find the highest priority
+    // We iterate backwards to find the highest priority in-service request
     for (i = 31; i >= 0; i--) {
        uint8_t  * svc_major = apic->int_svc_reg + i;
     
@@ -461,14 +530,15 @@ static int get_highest_isr(struct apic_state * apic) {
 static int get_highest_irr(struct apic_state * apic) {
     int i = 0, j = 0;
 
-    // We iterate backwards to find the highest priority
+    // We iterate backwards to find the highest priority enabled requested interrupt
     for (i = 31; i >= 0; i--) {
        uint8_t  * req_major = apic->int_req_reg + i;
-    
+       uint8_t  * en_major = apic->int_en_reg + i;
+       
        if ((*req_major) & 0xff) {
            for (j = 7; j >= 0; j--) {
                uint8_t flag = 0x1 << j;
-               if ((*req_major) & flag) {
+               if ((*req_major & *en_major) & flag) {
                    return ((i * 8) + j);
                }
            }
@@ -479,9 +549,91 @@ 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;
 
-static int apic_do_eoi(struct apic_state * apic) {
+    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) {
     int isr_irq = get_highest_isr(apic);
 
     if (isr_irq != -1) {
@@ -494,6 +646,10 @@ static int apic_do_eoi(struct apic_state * apic) {
        
        *svc_location &= ~flag;
 
+       if (apic->irq_ack_cbs[isr_irq].ack) {
+           apic->irq_ack_cbs[isr_irq].ack(core, isr_irq, apic->irq_ack_cbs[isr_irq].private_data);
+       }
+
 #ifdef V3_CONFIG_CRAY_XT
        
        if ((isr_irq == 238) || 
@@ -522,7 +678,7 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
     switch (int_type) {
        case APIC_TMR_INT:
            vec_num = apic->tmr_vec_tbl.vec;
-           del_mode = APIC_FIXED_DELIVERY;
+           del_mode = IPI_FIXED;
            masked = apic->tmr_vec_tbl.mask;
            break;
        case APIC_THERM_INT:
@@ -547,7 +703,7 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
            break;
        case APIC_ERR_INT:
            vec_num = apic->err_vec_tbl.vec;
-           del_mode = APIC_FIXED_DELIVERY;
+           del_mode = IPI_FIXED;
            masked = apic->err_vec_tbl.mask;
            break;
        default:
@@ -561,9 +717,9 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
        return 0;
     }
 
-    if (del_mode == APIC_FIXED_DELIVERY) {
+    if (del_mode == IPI_FIXED) {
        //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
-       return add_apic_irq_entry(apic, vec_num);
+       return add_apic_irq_entry(apic, vec_num, NULL, NULL);
     } else {
        PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
        return -1;
@@ -677,34 +833,31 @@ static int should_deliver_ipi(struct apic_dev_state * apic_dev,
 // Only the src_apic pointer is used
 static int deliver_ipi(struct apic_state * src_apic, 
                       struct apic_state * dst_apic, 
-                      uint32_t vector, uint8_t del_mode) {
+                      struct v3_gen_ipi * ipi) {
 
 
     struct guest_info * dst_core = dst_apic->core;
 
 
-    switch (del_mode) {
+    switch (ipi->mode) {
 
-       case APIC_FIXED_DELIVERY:  
-       case APIC_LOWEST_DELIVERY: {
+       case IPI_FIXED:  
+       case IPI_LOWEST_PRIO: {
            // lowest priority - 
            // caller needs to have decided which apic to deliver to!
 
-           PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->vcpu_id); 
+           PrintDebug("delivering IRQ %d to core %u\n", ipi->vector, dst_core->vcpu_id); 
 
-           add_apic_irq_entry(dst_apic, vector);
+           add_apic_irq_entry(dst_apic, ipi->vector, ipi->ack, ipi->private_data);
            
-#ifdef V3_CONFIG_MULTITHREAD_OS
            if (dst_apic != src_apic) { 
                PrintDebug(" non-local core with new interrupt, forcing it to exit now\n"); 
                v3_interrupt_cpu(dst_core->vm_info, dst_core->pcpu_id, 0);
            }
-#endif
-
 
            break;
        }
-       case APIC_INIT_DELIVERY: { 
+       case IPI_INIT: { 
 
            PrintDebug(" INIT delivery to core %u\n", dst_core->vcpu_id);
 
@@ -731,7 +884,7 @@ static int deliver_ipi(struct apic_state * src_apic,
 
            break;                                                      
        }
-       case APIC_SIPI_DELIVERY: { 
+       case IPI_SIPI: { 
 
            // Sanity check
            if (dst_apic->ipi_state != SIPI) { 
@@ -740,10 +893,10 @@ static int deliver_ipi(struct apic_state * src_apic,
                break;
            }
 
-           v3_reset_vm_core(dst_core, vector);
+           v3_reset_vm_core(dst_core, ipi->vector);
 
            PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
-                      vector, dst_core->segments.cs.selector, dst_core->vcpu_id);
+                      ipi->vector, dst_core->segments.cs.selector, dst_core->vcpu_id);
            // Maybe need to adjust the APIC?
            
            // We transition the target core to SIPI state
@@ -757,7 +910,7 @@ static int deliver_ipi(struct apic_state * src_apic,
            break;                                                      
        }
 
-       case APIC_EXTINT_DELIVERY: // EXTINT
+       case IPI_EXTINT: // EXTINT
            /* Two possible things to do here: 
             * 1. Ignore the IPI and assume the 8259a (PIC) will handle it
             * 2. Add 32 to the vector and inject it...
@@ -765,11 +918,11 @@ static int deliver_ipi(struct apic_state * src_apic,
             */
            return 0;
 
-       case APIC_SMI_DELIVERY: 
-       case APIC_RES1_DELIVERY: // reserved                                            
-       case APIC_NMI_DELIVERY:
+       case IPI_SMI: 
+       case IPI_RES1: // reserved                                              
+       case IPI_NMI:
        default:
-           PrintError("IPI %d delivery is unsupported\n", del_mode); 
+           PrintError("IPI %d delivery is unsupported\n", ipi->mode); 
            return -1;
     }
     
@@ -786,13 +939,13 @@ static struct apic_state * find_physical_apic(struct apic_dev_state * apic_dev,
 
     if ( (dst_idx > 0) && (dst_idx < apic_dev->num_apics) ) { 
        // see if it simply is the core id
-       if (apic_dev->apics[dst_idx].lapic_id.val == dst_idx) { 
+       if (apic_dev->apics[dst_idx].lapic_id.apic_id == dst_idx) { 
             dst_apic = &(apic_dev->apics[dst_idx]);
        }
     }
 
     for (i = 0; i < apic_dev->num_apics; i++) { 
-       if (apic_dev->apics[i].lapic_id.val == dst_idx) { 
+       if (apic_dev->apics[i].lapic_id.apic_id == dst_idx) { 
            dst_apic =  &(apic_dev->apics[i]);
        }
     }
@@ -806,34 +959,32 @@ static struct apic_state * find_physical_apic(struct apic_dev_state * apic_dev,
 
 static int route_ipi(struct apic_dev_state * apic_dev,
                     struct apic_state * src_apic, 
-                    struct int_cmd_reg * icr) {
+                    struct v3_gen_ipi * ipi) {
     struct apic_state * dest_apic = NULL;
 
 
-    PrintDebug("apic: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
-              deliverymode_str[icr->del_mode], 
-              icr->vec, 
+    PrintDebug("apic: IPI %s %u from apic %p to %s %s %u\n",
+              deliverymode_str[ipi->mode], 
+              ipi->vector, 
               src_apic,               
-              (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
-              shorthand_str[icr->dst_shorthand], 
-              icr->dst,
-              icr->val);
+              (ipi->logical == 0) ? "(physical)" : "(logical)", 
+              shorthand_str[ipi->dst_shorthand], 
+              ipi->dst);
 
 
-    switch (icr->dst_shorthand) {
+    switch (ipi->dst_shorthand) {
 
        case APIC_SHORTHAND_NONE:  // no shorthand
-           if (icr->dst_mode == APIC_DEST_PHYSICAL) { 
+           if (ipi->logical == APIC_DEST_PHYSICAL) { 
 
-               dest_apic = find_physical_apic(apic_dev, icr->dst);
+               dest_apic = find_physical_apic(apic_dev, ipi->dst);
                
                if (dest_apic == NULL) { 
-                   PrintError("apic: Attempted send to unregistered apic id=%u\n", icr->dst);
+                   PrintError("apic: Attempted send to unregistered apic id=%u\n", ipi->dst);
                    return -1;
                }
 
-               if (deliver_ipi(src_apic, dest_apic, 
-                               icr->vec, icr->del_mode) == -1) {
+               if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
                    PrintError("apic: Could not deliver IPI\n");
                    return -1;
                }
@@ -841,11 +992,11 @@ static int route_ipi(struct apic_dev_state * apic_dev,
 
                PrintDebug("apic: done\n");
 
-           } else if (icr->dst_mode == APIC_DEST_LOGICAL) {
+           } else if (ipi->logical == APIC_DEST_LOGICAL) {
                
-               if (icr->del_mode != APIC_LOWEST_DELIVERY) { 
+               if (ipi->mode != IPI_LOWEST_PRIO) { 
                    int i;
-                   uint8_t mda = icr->dst;
+                   uint8_t mda = ipi->dst;
 
                    // logical, but not lowest priority
                    // we immediately trigger
@@ -865,8 +1016,7 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                            return -1;
                        } else if (del_flag == 1) {
 
-                           if (deliver_ipi(src_apic, dest_apic, 
-                                           icr->vec, icr->del_mode) == -1) {
+                           if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
                                PrintError("apic: Error: Could not deliver IPI\n");
                                return -1;
                            }
@@ -874,7 +1024,8 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                    }
                } else {  // APIC_LOWEST_DELIVERY
                    struct apic_state * cur_best_apic = NULL;
-                   uint8_t mda = icr->dst;
+                   uint32_t cur_best_apr;
+                   uint8_t mda = ipi->dst;
                    int i;
 
                    // logical, lowest priority
@@ -898,21 +1049,25 @@ 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);
 
-                       }                       
+                       }
                    }
 
                    // now we will deliver to the best one if it exists
                    if (!cur_best_apic) { 
                        PrintDebug("apic: lowest priority deliver, but no destinations!\n");
                    } else {
-                       if (deliver_ipi(src_apic, cur_best_apic, 
-                                       icr->vec, icr->del_mode) == -1) {
+                       if (deliver_ipi(src_apic, cur_best_apic, ipi) == -1) {
                            PrintError("apic: Error: Could not deliver IPI\n");
                            return -1;
                        }
@@ -932,15 +1087,15 @@ static int route_ipi(struct apic_dev_state * apic_dev,
 
 
 
-           if (icr->dst_mode == APIC_DEST_PHYSICAL)  {  /* physical delivery */
-               if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
+           if (ipi->logical == APIC_DEST_PHYSICAL)  {  /* physical delivery */
+               if (deliver_ipi(src_apic, src_apic, ipi) == -1) {
                    PrintError("apic: Could not deliver IPI to self (physical)\n");
                    return -1;
                }
-           } else if (icr->dst_mode == APIC_DEST_LOGICAL) {  /* logical delivery */
+           } else if (ipi->logical == APIC_DEST_LOGICAL) {  /* logical delivery */
                PrintError("apic: use of logical delivery in self (untested)\n");
 
-               if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
+               if (deliver_ipi(src_apic, src_apic, ipi) == -1) {
                    PrintError("apic: Could not deliver IPI to self (logical)\n");
                    return -1;
                }
@@ -957,8 +1112,8 @@ static int route_ipi(struct apic_dev_state * apic_dev,
            for (i = 0; i < apic_dev->num_apics; i++) { 
                dest_apic = &(apic_dev->apics[i]);
                
-               if ((dest_apic != src_apic) || (icr->dst_shorthand == APIC_SHORTHAND_ALL)) { 
-                   if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
+               if ((dest_apic != src_apic) || (ipi->dst_shorthand == APIC_SHORTHAND_ALL)) { 
+                   if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
                        PrintError("apic: Error: Could not deliver IPI\n");
                        return -1;
                    }
@@ -968,7 +1123,7 @@ static int route_ipi(struct apic_dev_state * apic_dev,
            break;
        }
        default:
-           PrintError("apic: Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
+           PrintError("apic: Error routing IPI, invalid Mode (%d)\n", ipi->dst_shorthand);
            return -1;
     }
  
@@ -1017,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;
@@ -1311,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",
@@ -1406,23 +1561,32 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            // Action Registers
        case EOI_OFFSET:
            // do eoi 
-           apic_do_eoi(apic);
+           apic_do_eoi(core, apic);
            break;
 
        case INT_CMD_LO_OFFSET: {
            // execute command 
 
-           struct int_cmd_reg tmp_icr;
+           struct v3_gen_ipi tmp_ipi;
 
            apic->int_cmd.lo = op_val;
 
-           tmp_icr = apic->int_cmd;
+           tmp_ipi.vector = apic->int_cmd.vec;
+           tmp_ipi.mode = apic->int_cmd.del_mode;
+           tmp_ipi.logical = apic->int_cmd.dst_mode;
+           tmp_ipi.trigger_mode = apic->int_cmd.trig_mode;
+           tmp_ipi.dst_shorthand = apic->int_cmd.dst_shorthand;
+           tmp_ipi.dst = apic->int_cmd.dst;
+               
+           tmp_ipi.ack = NULL;
+           tmp_ipi.private_data = NULL;
+           
 
            //      V3_Print("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
            //       apic->lapic_id.val, core->vcpu_id,
            //       apic->int_cmd.val, apic->int_cmd.dst);
 
-           if (route_ipi(apic_dev, apic, &tmp_icr) == -1) { 
+           if (route_ipi(apic_dev, apic, &tmp_ipi) == -1) { 
                PrintError("IPI Routing failure\n");
                return -1;
            }
@@ -1431,8 +1595,7 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
        }
        case INT_CMD_HI_OFFSET: {
            apic->int_cmd.hi = op_val;
-           V3_Print("apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->vcpu_id,apic->int_cmd.hi);
-
+           //V3_Print("apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->vcpu_id,apic->int_cmd.hi);
            break;
        }
        // Unhandled Registers
@@ -1471,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;
+    }
 }
 
 
@@ -1487,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;
+    }
 }
 
 
@@ -1501,39 +1695,8 @@ static int apic_get_intr_number(struct guest_info * core, void * private_data) {
 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
        (((struct vm_device *)dev_data)->private_data);
-    struct int_cmd_reg tmp_icr;
-
-    // zero out all the fields
-    tmp_icr.val = 0;
-
-    tmp_icr.vec = ipi->vector;
-    tmp_icr.del_mode = ipi->mode;
-    tmp_icr.dst_mode = ipi->logical;
-    tmp_icr.trig_mode = ipi->trigger_mode;
-    tmp_icr.dst_shorthand = ipi->dst_shorthand;
-    tmp_icr.dst = ipi->dst;
 
-
-    return route_ipi(apic_dev, NULL, &tmp_icr);
-}
-
-
-int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
-    struct apic_dev_state * apic_dev = (struct apic_dev_state *)
-       (((struct vm_device*)dev_data)->private_data);
-    struct apic_state * apic = &(apic_dev->apics[dst]); 
-
-    PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
-
-    add_apic_irq_entry(apic, irq);
-
-#ifdef V3_CONFIG_MULTITHREAD_OS   
-    if ((V3_Get_CPU() != dst)) {
-       v3_interrupt_cpu(vm, dst, 0);
-    }
-#endif
-
-    return 0;
+    return route_ipi(apic_dev, NULL, ipi);
 }
 
 
@@ -1562,10 +1725,33 @@ static int apic_begin_irq(struct guest_info * core, void * private_data, int irq
 }
 
 
+/* Timer Functions */
 
+static void apic_inject_timer_intr(struct guest_info *core,
+                                  void * priv_data) {
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
+    // raise irq
+    PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d)\n",
+              apic->lapic_id.val, core->vcpu_id,
+              apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt);
+
+    if (apic_intr_pending(core, priv_data)) {
+        PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
+                  apic->lapic_id.val, core->vcpu_id, 
+                  apic_get_intr_number(core, priv_data));
+    }
+
+    if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
+       PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
+                  apic->lapic_id.val, core->vcpu_id);
+    }
+
+    return;
+}
+       
 
 
-/* Timer Functions */
 
 static void apic_update_time(struct guest_info * core, 
                             uint64_t cpu_cycles, uint64_t cpu_freq, 
@@ -1631,49 +1817,31 @@ static void apic_update_time(struct guest_info * core,
 
     if (tmr_ticks < apic->tmr_cur_cnt) {
        apic->tmr_cur_cnt -= tmr_ticks;
+#ifdef V3_CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS
+       if (apic->missed_ints && !apic_intr_pending(core, priv_data)) {
+           PrintDebug("apic %u: core %u: Injecting queued APIC timer interrupt.\n",
+                      apic->lapic_id.val, core->vcpu_id);
+           apic_inject_timer_intr(core, priv_data);
+           apic->missed_ints--;
+       }
+#endif /* CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS */ 
     } else {
        tmr_ticks -= apic->tmr_cur_cnt;
        apic->tmr_cur_cnt = 0;
 
-       // raise irq
-       PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
-                  apic->lapic_id.val, core->vcpu_id,
-                  apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
+       apic_inject_timer_intr(core, priv_data);
 
-       if (apic_intr_pending(core, priv_data)) {
-           PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
-                      apic->lapic_id.val, core->vcpu_id, 
-                      apic_get_intr_number(core, priv_data));
-       }
-
-       if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
-           PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
-                      apic->lapic_id.val, core->vcpu_id);
-       }
-    
        if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
-           static unsigned int nexits = 0;
-           static unsigned int missed_ints = 0;
-
-           nexits++;
-           missed_ints += tmr_ticks / apic->tmr_init_cnt;
-
-           if ((missed_ints > 0) && (nexits >= 5000)) {
-               V3_Print("apic %u: core %u: missed %u timer interrupts total in last %u exits.\n",
-                        apic->lapic_id.val, core->vcpu_id, missed_ints, nexits); 
-               missed_ints = 0;
-               nexits = 0;
-           }
-
+           int queued_ints = tmr_ticks / apic->tmr_init_cnt;
            tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
            apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
+           apic->missed_ints += queued_ints;
        }
     }
 
     return;
 }
 
-
 static struct intr_ctrl_ops intr_ops = {
     .intr_pending = apic_intr_pending,
     .get_intr_number = apic_get_intr_number,
@@ -1714,9 +1882,134 @@ static int apic_free(struct apic_dev_state * apic_dev) {
     return 0;
 }
 
+#ifdef V3_CONFIG_CHECKPOINT
+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_SAVE_AUTOTAG(ctx, apic_state->num_apics,savefailout);
+
+    //V3_CHKPT_STD_SAVE(ctx,apic_state->state_lock);
+    for (i = 0; i < apic_state->num_apics; i++) {
+
+        V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].base_addr,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].base_addr_msr,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].lapic_id,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].apic_ver,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].ext_apic_ctrl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].local_vec_tbl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].tmr_vec_tbl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].tmr_div_cfg,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].lint0_vec_tbl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].lint1_vec_tbl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].perf_ctr_loc_vec_tbl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].therm_loc_vec_tbl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].err_vec_tbl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].err_status,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].spurious_int,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].int_cmd,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].log_dst,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].dst_fmt,savefailout);
+
+       // 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_SAVE_AUTOTAG(ctx, temp,savefailout);
+       temp = get_apic_tpr(&(apic_state->apics[i]));
+       V3_CHKPT_SAVE_AUTOTAG(ctx,temp,savefailout);
+       temp = get_apic_ppr(&(apic_state->apics[i]));
+       V3_CHKPT_SAVE_AUTOTAG(ctx, temp,savefailout);
+
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].ext_apic_feature,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].spec_eoi,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].tmr_cur_cnt,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].tmr_init_cnt,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].ext_intr_vec_tbl,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].rem_rd_data,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].ipi_state,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].int_req_reg,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].int_svc_reg,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].int_en_reg,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].trig_mode_reg,savefailout);
+       V3_CHKPT_SAVE_AUTOTAG(ctx, apic_state->apics[i].eoi,savefailout);
+
+    }
+
+    return 0;
+
+ savefailout:
+    PrintError("Failed to save apic\n");
+    return -1;
+}
+
+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_LOAD_AUTOTAG(ctx,apic_state->num_apics, loadfailout);
+
+    for (i = 0; i < apic_state->num_apics; i++) {
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].base_addr, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].base_addr_msr, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].lapic_id, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].apic_ver, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].ext_apic_ctrl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].local_vec_tbl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].tmr_vec_tbl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].tmr_div_cfg, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].lint0_vec_tbl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].lint1_vec_tbl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].perf_ctr_loc_vec_tbl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].therm_loc_vec_tbl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].err_vec_tbl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].err_status, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].spurious_int, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].int_cmd, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].log_dst, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].dst_fmt, loadfailout);
+
+       // APR is ignored
+       V3_CHKPT_LOAD_AUTOTAG(ctx, temp, loadfailout);
+       // TPR is written back to APIC_TPR
+       V3_CHKPT_LOAD_AUTOTAG(ctx, temp, loadfailout);
+       set_apic_tpr(&(apic_state->apics[i]),temp);
+       // PPR is ignored
+       V3_CHKPT_LOAD_AUTOTAG(ctx, temp, loadfailout);
+
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].ext_apic_feature, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].spec_eoi, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].tmr_cur_cnt, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].tmr_init_cnt, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].ext_intr_vec_tbl, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].rem_rd_data, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].ipi_state, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].int_req_reg, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].int_svc_reg, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].int_en_reg, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].trig_mode_reg, loadfailout);
+       V3_CHKPT_LOAD_AUTOTAG(ctx, apic_state->apics[i].eoi, loadfailout);
+    }
+
+
+    return 0;
+
+ loadfailout:
+    PrintError("Failed to load apic\n");
+    return -1;
+
+}
+
+#endif
 
 static struct v3_device_ops dev_ops = {
     .free = (int (*)(void *))apic_free,
+#ifdef V3_CONFIG_CHECKPOINT
+    .save = apic_save,
+    .load = apic_load
+#endif
 };
 
 
@@ -1731,6 +2024,12 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
                                                  sizeof(struct apic_state) * vm->num_cores);
 
+
+    if (!apic_dev) {
+       PrintError("Failed to allocate space for APIC\n");
+       return -1;
+    }
+
     apic_dev->num_apics = vm->num_cores;
     v3_lock_init(&(apic_dev->state_lock));