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.


Removed spurious PrintError for red storm from apic.c, fixed large page
[palacios.git] / palacios / src / devices / apic.c
index cb58823..0f0b117 100644 (file)
 
 #include <devices/apic.h>
 #include <devices/apic_regs.h>
+#include <devices/icc_bus.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_msr.h>
+#include <palacios/vmm_sprintf.h>
+#include <palacios/vm_guest.h>
 
 
-#ifndef DEBUG_APIC
+#ifndef CONFIG_DEBUG_APIC
 #undef PrintDebug
 #define PrintDebug(fmt, args...)
 #endif
@@ -117,7 +120,7 @@ typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT,
 
 struct apic_msr {
     union {
-       uint64_t val;
+       uint64_t value;
        struct {
            uchar_t rsvd;
            uint_t bootstrap_cpu : 1;
@@ -136,7 +139,7 @@ struct apic_state {
     addr_t base_addr;
 
     /* MSRs */
-    v3_msr_t base_addr_msr;
+    struct apic_msr base_addr_msr;
 
 
     /* memory map registers */
@@ -168,6 +171,7 @@ struct apic_state {
     uint32_t tmr_init_cnt;
 
 
+    struct local_vec_tbl_reg ext_intr_vec_tbl[4];
 
     uint32_t rem_rd_data;
 
@@ -179,17 +183,31 @@ struct apic_state {
   
     uint32_t eoi;
 
+    struct vm_device * icc_bus;
 
+    v3_lock_t  lock;
 };
 
+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 init_apic_state(struct apic_state * apic) {
+static void init_apic_state(struct apic_state * apic, uint32_t id, struct vm_device * icc) {
     apic->base_addr = DEFAULT_BASE_ADDR;
-    apic->base_addr_msr.value = 0x0000000000000900LL;
+    if (id==0) { 
+       // boot processor, enabled
+       apic->base_addr_msr.value = 0x0000000000000900LL;
+    } else {
+       // ap processor, enabled
+       apic->base_addr_msr.value = 0x0000000000000800LL;
+    }
+
+    // same base address regardless of ap or main
     apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
 
-    PrintDebug("Sizeof Interrupt Request Register %d, should be 32\n", 
-              (uint_t)sizeof(apic->int_req_reg));
+    PrintDebug("apic %u: (init_apic_state): msr=0x%llx\n",id, apic->base_addr_msr.value);
+
+    PrintDebug("apic %u: (init_apic_state): Sizeof Interrupt Request Register %d, should be 32\n",
+              id, (uint_t)sizeof(apic->int_req_reg));
 
     memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
     memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
@@ -201,9 +219,9 @@ static void init_apic_state(struct apic_state * apic) {
     apic->tmr_init_cnt = 0x00000000;
     apic->tmr_cur_cnt = 0x00000000;
 
-    // TODO:
-    // We need to figure out what the APIC ID is....
-    apic->lapic_id.val = 0x00000000;
+    apic->lapic_id.val = id;
+    
+    apic->icc_bus = icc;
 
     // The P6 has 6 LVT entries, so we set the value to (6-1)...
     apic->apic_ver.val = 0x80050010;
@@ -223,30 +241,59 @@ static void init_apic_state(struct apic_state * apic) {
     apic->lint1_vec_tbl.val = 0x00010000;
     apic->err_vec_tbl.val = 0x00010000;
     apic->tmr_div_cfg.val = 0x00000000;
+    //apic->ext_apic_feature.val = 0x00000007;
     apic->ext_apic_feature.val = 0x00040007;
     apic->ext_apic_ctrl.val = 0x00000000;
     apic->spec_eoi.val = 0x00000000;
+
+    v3_lock_init(&(apic->lock));
 }
 
 
 
 
-static int read_apic_msr(uint_t msr, v3_msr_t * dst, void * priv_data) {
+static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
     struct vm_device * dev = (struct vm_device *)priv_data;
-    struct apic_state * apic = (struct apic_state *)dev->private_data;
-    PrintError("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_msr.hi, apic->base_addr_msr.lo);
+    struct apic_state * apics = (struct apic_state *)(dev->private_data);
+    struct apic_state * apic = &(apics[core->cpu_id]);
 
-    return -1;
+    PrintDebug("apic %u: core %u: MSR read\n",apic->lapic_id.val,core->cpu_id);
+    v3_lock(apic->lock);
+    dst->value = apic->base_addr;
+    v3_unlock(apic->lock);
+    return 0;
 }
 
 
-static int write_apic_msr(uint_t msr, v3_msr_t src, void * priv_data) {
-    //  struct vm_device * dev = (struct vm_device *)priv_data;
-    //  struct apic_state * apic = (struct apic_state *)dev->private_data;
+static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+    struct vm_device * dev = (struct vm_device *)priv_data;
+    struct apic_state * apics = (struct apic_state *)(dev->private_data);
+    struct apic_state * apic = &(apics[core->cpu_id]);
+    struct v3_mem_region * old_reg = v3_get_mem_region(dev->vm, core->cpu_id, apic->base_addr);
 
-    PrintError("WRITING APIC BASE ADDR: HI=%x LO=%x\n", src.hi, src.lo);
 
-    return -1;
+    PrintDebug("apic %u: core %u: MSR write\n",apic->lapic_id.val,core->cpu_id);
+
+    if (old_reg == NULL) {
+       // uh oh...
+       PrintError("apic %u: core %u: APIC Base address region does not exit...\n",apic->lapic_id.val,core->cpu_id);
+       return -1;
+    }
+    
+    v3_lock(apic->lock);
+
+    v3_delete_mem_region(dev->vm, old_reg);
+
+    apic->base_addr = src.value;
+
+    if (v3_hook_full_mem(dev->vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev) == -1) {
+       PrintError("apic %u: core %u: Could not hook new APIC Base address\n",apic->lapic_id.val,core->cpu_id);
+       v3_unlock(apic->lock);
+       return -1;
+    }
+
+    v3_unlock(apic->lock);
+    return 0;
 }
 
 
@@ -258,17 +305,27 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
     uchar_t * en_location = apic->int_en_reg + major_offset;
     uchar_t flag = 0x1 << minor_offset;
 
+
+#if 1
+
     if (irq_num <= 15) {
-       PrintError("Attempting to raise an invalid interrupt: %d\n", irq_num);
+       PrintError("apic %u: core ?: Attempting to raise an invalid interrupt: %d\n", apic->lapic_id.val,irq_num);
        return -1;
     }
 
-    PrintDebug("Raising APIC IRQ %d\n", irq_num);
+#endif
+
+
+    PrintDebug("apic %u: core ?: Raising APIC IRQ %d\n", apic->lapic_id.val,irq_num);
+
+    if (*req_location & flag) {
+       //V3_Print("Interrupts coallescing\n");
+    }
 
     if (*en_location & flag) {
        *req_location |= flag;
     } else {
-       PrintDebug("Interrupt  not enabled... %.2x\n", *en_location);
+       PrintDebug("apic %u: core ?: Interrupt  not enabled... %.2x\n", apic->lapic_id.val, *en_location);
        return 0;
     }
 
@@ -277,7 +334,7 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
 
 
 
-static int apic_do_eoi(struct apic_state * apic) {
+static int get_highest_isr(struct apic_state * apic) {
     int i = 0, j = 0;
 
     // We iterate backwards to find the highest priority
@@ -288,13 +345,68 @@ static int apic_do_eoi(struct apic_state * apic) {
            for (j = 7; j >= 0; j--) {
                uchar_t flag = 0x1 << j;
                if ((*svc_major) & flag) {
-                   *svc_major &= ~flag;
-                   return 0;
+                   return ((i * 8) + j);
+               }
+           }
+       }
+    }
+
+    return -1;
+}
+
+
+static int get_highest_irr(struct apic_state * apic) {
+    int i = 0, j = 0;
+
+    // We iterate backwards to find the highest priority
+    for (i = 31; i >= 0; i--) {
+       uchar_t  * req_major = apic->int_req_reg + i;
+    
+       if ((*req_major) & 0xff) {
+           for (j = 7; j >= 0; j--) {
+               uchar_t flag = 0x1 << j;
+               if ((*req_major) & flag) {
+                   return ((i * 8) + j);
                }
            }
        }
     }
 
+    return -1;
+}
+
+
+
+static int apic_do_eoi(struct apic_state * apic) {
+    int isr_irq = get_highest_isr(apic);
+
+    if (isr_irq != -1) {
+       int major_offset = (isr_irq & ~0x00000007) >> 3;
+       int minor_offset = isr_irq & 0x00000007;
+       uchar_t flag = 0x1 << minor_offset;
+       uchar_t * svc_location = apic->int_svc_reg + major_offset;
+       
+       PrintDebug("apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
+       
+       *svc_location &= ~flag;
+
+#ifdef CONFIG_CRAY_XT
+       
+       if ((isr_irq == 238) || 
+           (isr_irq == 239)) {
+           PrintDebug("apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
+       }
+       
+       if (isr_irq == 238) {
+           V3_ACK_IRQ(238);
+       }
+#endif
+    } else {
+       //PrintError("apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
+    }
+       
     return 0;
 }
  
@@ -337,13 +449,13 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
            masked = apic->err_vec_tbl.mask;
            break;
        default:
-           PrintError("Invalid APIC interrupt type\n");
+           PrintError("apic %u: core ?: Invalid APIC interrupt type\n",apic->lapic_id.val);
            return -1;
     }
 
     // interrupt is masked, don't send
     if (masked == 1) {
-       PrintDebug("Inerrupt is masked\n");
+       PrintDebug("apic %u: core ?: Inerrupt is masked\n",apic->lapic_id.val);
        return 0;
     }
 
@@ -351,25 +463,24 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
        //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
        return activate_apic_irq(apic, vec_num);
     } else {
-       PrintError("Unhandled Delivery Mode\n");
+       PrintError("apic %u: core ?: Unhandled Delivery Mode\n",apic->lapic_id.val);
        return -1;
     }
 }
 
 
-static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
-    struct vm_device * dev = (struct vm_device *)priv_data;
-    struct apic_state * apic = (struct apic_state *)dev->private_data;
+static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
+    struct apic_state * apic = (struct apic_state *)(priv_data);
     addr_t reg_addr  = guest_addr - apic->base_addr;
     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
     uint32_t val = 0;
 
 
-    PrintDebug("Read apic address space (%p)\n", 
-              (void *)guest_addr);
+    PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",apic->lapic_id.val,core->cpu_id, apic, (void *)guest_addr);
 
     if (msr->apic_enable == 0) {
-       PrintError("Write to APIC address space with disabled APIC\n");
+       PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",apic->lapic_id.val,core->cpu_id,apic->base_addr_msr.value);
+
        return -1;
     }
 
@@ -563,16 +674,27 @@ static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_d
 
            // Unhandled Registers
        case EXT_INT_LOC_VEC_TBL_OFFSET0:
+           val = apic->ext_intr_vec_tbl[0].val;
+           break;
        case EXT_INT_LOC_VEC_TBL_OFFSET1:
+           val = apic->ext_intr_vec_tbl[1].val;
+           break;
        case EXT_INT_LOC_VEC_TBL_OFFSET2:
+           val = apic->ext_intr_vec_tbl[2].val;
+           break;
        case EXT_INT_LOC_VEC_TBL_OFFSET3:
+           val = apic->ext_intr_vec_tbl[3].val;
+           break;
+    
+
        case EXT_APIC_FEATURE_OFFSET:
        case EXT_APIC_CMD_OFFSET:
        case SEOI_OFFSET:
 
        default:
-           PrintError("Read from Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
-           return -1;
+           PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", apic->lapic_id.val,core->cpu_id, (uint32_t)reg_addr);
+           //      return -1;
+           val=0;
     }
 
 
@@ -593,34 +715,37 @@ static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_d
        *val_ptr = val;
 
     } else {
-       PrintError("Invalid apic read length (%d)\n", length);
+       PrintError("apic %u: core %u: Invalid apic read length (%d)\n", apic->lapic_id.val,core->cpu_id, length);
        return -1;
     }
 
-    PrintDebug("Read finished (val=%x)\n", *(uint32_t *)dst);
+    PrintDebug("apic %u: core %u: Read finished (val=%x)\n", apic->lapic_id.val,core->cpu_id, *(uint32_t *)dst);
 
     return length;
 }
 
 
-static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
-    struct vm_device * dev = (struct vm_device *)priv_data;
-    struct apic_state * apic = (struct apic_state *)dev->private_data;
+/**
+ *
+ */
+static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
+    struct apic_state * apic = (struct apic_state *)(priv_data);
     addr_t reg_addr  = guest_addr - apic->base_addr;
     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
     uint32_t op_val = *(uint32_t *)src;
 
-    PrintDebug("Write to apic address space (%p) (val=%x)\n", 
+    PrintDebug("apic %u: core %u: at %p and priv_data is at %p: Write to address space (%p) (val=%x)\n", 
+              apic->lapic_id.val, core->cpu_id, apic,priv_data,
               (void *)guest_addr, *(uint32_t *)src);
 
     if (msr->apic_enable == 0) {
-       PrintError("Write to APIC address space with disabled APIC\n");
+       PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",apic->lapic_id.val,core->cpu_id,apic->base_addr_msr.value);
        return -1;
     }
 
 
     if (length != 4) {
-       PrintError("Invalid apic write length (%d)\n", length);
+       PrintError("apic %u: core %u: Invalid apic write length (%d)\n", apic->lapic_id.val, length,core->cpu_id);
        return -1;
     }
 
@@ -655,15 +780,16 @@ static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_
        case PPR_OFFSET:
        case EXT_APIC_FEATURE_OFFSET:
 #if 1
-           PrintError("Attempting to write to read only register %p (ignored)\n", (void *)reg_addr);
+           PrintError("apic %u: core %u: Attempting to write to read only register %p (ignored)\n", apic->lapic_id.val,core->cpu_id, (void *)reg_addr);
 #else   
-           PrintError("Attempting to write to read only register %p (error)\n", (void *)reg_addr);
+           PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", apic->lapic_id.val,core->cpu_id, (void *)reg_addr);
            return -1;
 #endif
            break;
 
            // Data registers
        case APIC_ID_OFFSET:
+           PrintDebug("apic %u: core %u: my id is being changed to %u\n",apic->lapic_id.val,core->cpu_id,op_val);
            apic->lapic_id.val = op_val;
            break;
        case TPR_OFFSET:
@@ -736,30 +862,47 @@ static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_
        case IER_OFFSET7:
            *(uint32_t *)(apic->int_en_reg + 28) = op_val;
            break;
-   
 
-           // Action Registers
-       case INT_CMD_LO_OFFSET:
-       case INT_CMD_HI_OFFSET:
-       case EOI_OFFSET:
-           {
-               // do eoi
-               apic_do_eoi(apic);
-               break;
-           }
-           // Unhandled Registers
        case EXT_INT_LOC_VEC_TBL_OFFSET0:
+           apic->ext_intr_vec_tbl[0].val = op_val;
+           break;
        case EXT_INT_LOC_VEC_TBL_OFFSET1:
+           apic->ext_intr_vec_tbl[1].val = op_val;
+           break;
        case EXT_INT_LOC_VEC_TBL_OFFSET2:
+           apic->ext_intr_vec_tbl[2].val = op_val;
+           break;
        case EXT_INT_LOC_VEC_TBL_OFFSET3:
+           apic->ext_intr_vec_tbl[3].val = op_val;
+           break;
+
+
+           // Action Registers
+       case EOI_OFFSET:
+           // do eoi
+           apic_do_eoi(apic);
+           break;
+
+       case INT_CMD_LO_OFFSET:
+           apic->int_cmd.lo = op_val;
+           // ICC???
+           PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n",apic->lapic_id.val,core->cpu_id,
+                      apic->int_cmd.val, apic->int_cmd.dst);
+           v3_icc_send_ipi(apic->icc_bus, apic->lapic_id.val, apic->int_cmd.val,0);
+           break;
+       case INT_CMD_HI_OFFSET:
+           apic->int_cmd.hi = op_val;
+           break;
+           // Unhandled Registers
+
        case EXT_APIC_CMD_OFFSET:
        case SEOI_OFFSET:
        default:
-           PrintError("Write to Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
-           return -1;
+           PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", apic->lapic_id.val,core->cpu_id, (uint32_t)reg_addr);
+           //      return -1;
     }
 
-    PrintDebug("Write finished\n");
+    PrintDebug("apic %u: core %u: Write finished\n",apic->lapic_id.val,core->cpu_id);
 
     return length;
 }
@@ -768,80 +911,75 @@ static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_
 
 /* Interrupt Controller Functions */
 
-static int apic_intr_pending(void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct apic_state * apic = (struct apic_state *)dev->private_data;
-    int i = 0;
+// returns 1 if an interrupt is pending, 0 otherwise
+static int apic_intr_pending(struct guest_info * info, void * private_data) {
+    struct apic_state * apic = (struct apic_state *)private_data;
+    int req_irq = get_highest_irr(apic);
+    int svc_irq = get_highest_isr(apic);
 
+    //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->cpu_id,req_irq,svc_irq);
 
-    // just scan the request register looking for any set bit
-    // we should probably just do this with uint64 casts 
-    for (i = 0; i < 32; i++) {
-       if (apic->int_req_reg[i] & 0xff) {
-           return 1;
-       }
+    if ((req_irq >= 0) && 
+       (req_irq > svc_irq)) {
+       return 1;
     }
+
     return 0;
 }
 
-static int apic_get_intr_number(void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct apic_state * apic = (struct apic_state *)dev->private_data;
-    int i = 0, j = 0;
+static int apic_get_intr_number(struct guest_info * info, void * private_data) {
+    struct apic_state * apic = (struct apic_state *)private_data;
+    int req_irq = get_highest_irr(apic);
+    int svc_irq = get_highest_isr(apic);
 
-
-    // We iterate backwards to find the highest priority
-    for (i = 31; i >= 0; i--) {
-       uchar_t req_major = apic->int_req_reg[i];
-    
-       if (req_major & 0xff) {
-           for (j = 7; j >= 0; j--) {
-               if ((req_major >> j) == 0x1) {
-                   return (i * 8) + j;
-               }
-           }
-       }
+    if (svc_irq == -1) {
+       return req_irq;
+    } else if (svc_irq < req_irq) {
+       return req_irq;
     }
 
     return -1;
 }
 
-static int apic_raise_intr(void * private_data, int irq) {
-    return 0;
-}
 
-static int apic_lower_intr(void * private_data, int irq) {
-    return 0;
+static int apic_raise_intr(struct guest_info * info, int irq, void * private_data) {
+  struct apic_state * apic = (struct apic_state *)private_data;
+
+  return activate_apic_irq(apic, irq);
 }
 
-static int apic_begin_irq(void * private_data, int irq) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct apic_state * apic = (struct apic_state *)dev->private_data;
+
+
+static int apic_begin_irq(struct guest_info * info, void * private_data, int irq) {
+    struct apic_state * apic = (struct apic_state *)private_data;
     int major_offset = (irq & ~0x00000007) >> 3;
     int minor_offset = irq & 0x00000007;
     uchar_t * req_location = apic->int_req_reg + major_offset;
     uchar_t * svc_location = apic->int_svc_reg + major_offset;
     uchar_t flag = 0x01 << minor_offset;
 
-    *svc_location |= flag;
-    *req_location &= ~flag;
-
-    return 0;
-}
+    if (*req_location & flag) {
+       // we will only pay attention to a begin irq if we
+       // know that we initiated it!
+       *svc_location |= flag;
+       *req_location &= ~flag;
+    } else {
+       // do nothing... 
+       PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
+                  apic->lapic_id.val,info->cpu_id,irq);
+    }
 
 
 
-int v3_apic_raise_intr(struct vm_device * apic_dev, int intr_num) {
-    struct apic_state * apic = (struct apic_state *)apic_dev->private_data;
-    return activate_apic_irq(apic, intr_num);
+    return 0;
 }
 
 
 
+
 /* Timer Functions */
-static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
-    struct vm_device * dev = (struct vm_device *)priv_data;
-    struct apic_state * apic = (struct apic_state *)dev->private_data;
+static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
+    struct apic_state * apic = (struct apic_state *)(priv_data);
     // The 32 bit GCC runtime is a pile of shit
 #ifdef __V3_64BIT__
     uint64_t tmr_ticks = 0;
@@ -859,7 +997,7 @@ static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv
     if ((apic->tmr_init_cnt == 0) || 
        ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
          (apic->tmr_cur_cnt == 0))) {
-       //PrintDebug("APIC timer not yet initialized\n");
+       //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
        return;
     }
 
@@ -890,12 +1028,12 @@ static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv
            shift_num = 7;
            break;
        default:
-           PrintError("Invalid Timer Divider configuration\n");
+           PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",apic->lapic_id.val,info->cpu_id);
            return;
     }
 
     tmr_ticks = cpu_cycles >> shift_num;
-    //  PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
+    //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
 
     if (tmr_ticks < apic->tmr_cur_cnt) {
        apic->tmr_cur_cnt -= tmr_ticks;
@@ -904,10 +1042,15 @@ static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv
        apic->tmr_cur_cnt = 0;
 
        // raise irq
-       PrintDebug("Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", 
+       PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", apic->lapic_id.val,info->cpu_id,
                   apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
+
+       if (apic_intr_pending(info, priv_data)) {
+           PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", apic->lapic_id.val,info->cpu_id, apic_get_intr_number(info, priv_data));
+       }
+
        if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
-           PrintError("Could not raise Timer interrupt\n");
+           PrintError("apic %u: core %u: Could not raise Timer interrupt\n",apic->lapic_id.val,info->cpu_id);
        }
     
        if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
@@ -920,13 +1063,10 @@ static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv
 }
 
 
-
 static struct intr_ctrl_ops intr_ops = {
     .intr_pending = apic_intr_pending,
     .get_intr_number = apic_get_intr_number,
-    .raise_intr = apic_raise_intr,
     .begin_irq = apic_begin_irq,
-    .lower_intr = apic_lower_intr, 
 };
 
 
@@ -935,46 +1075,88 @@ static struct vm_timer_ops timer_ops = {
 };
 
 
-static int apic_init(struct vm_device * dev) {
-    struct guest_info * info = dev->vm;
-    struct apic_state * apic = (struct apic_state *)(dev->private_data);
 
-    v3_register_intr_controller(dev->vm, &intr_ops, dev);
-    v3_add_timer(dev->vm, &timer_ops, dev);
 
-    init_apic_state(apic);
+static int apic_free(struct vm_device * dev) {
 
-    v3_hook_msr(info, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
+    /* TODO: This should crosscall to force an unhook on each CPU */
 
-    v3_hook_full_mem(info, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev);
+    //   struct apic_state * apic = (struct apic_state *)dev->private_data;
 
-    return 0;
-}
-
-static int apic_deinit(struct vm_device * dev) {
-    struct guest_info * info = dev->vm;
-
-    v3_unhook_msr(info, BASE_ADDR_MSR);
+    v3_unhook_msr(dev->vm, BASE_ADDR_MSR);
 
     return 0;
 }
 
 
-static struct vm_device_ops dev_ops = {
-    .init = apic_init,
-    .deinit = apic_deinit,
+static struct v3_device_ops dev_ops = {
+    .free = apic_free,
     .reset = NULL,
     .start = NULL,
     .stop = NULL,
 };
 
 
-struct vm_device * v3_create_apic() {
-    PrintDebug("Creating APIC\n");
 
-    struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
+static struct v3_icc_ops icc_ops = {
+    .raise_intr = apic_raise_intr,
+};
+
+
+
+static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+    PrintDebug("apic: creating an APIC for each core\n");
+    char * dev_id = v3_cfg_val(cfg, "ID");
+    char * icc_bus_id = v3_cfg_val(cfg,"bus");
+    struct vm_device * icc = v3_find_dev(vm, icc_bus_id);
+    int i;
 
-    struct vm_device * device = v3_create_device("APIC", &dev_ops, apic);
-  
-    return device;
+    if (!icc) {
+        PrintError("apic: Cannot find ICC Bus (%s)\n", icc_bus_id);
+        return -1;
+    }
+
+    // We allocate one apic per core
+    // APICs are accessed via index which correlates with the core's cpu_id 
+    // 0..num_cores-1   at num_cores is the ioapic (one only)
+    struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state) * vm->num_cores);
+
+    struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, apic);
+
+    if (v3_attach_device(vm, dev) == -1) {
+       PrintError("apic: Could not attach device %s\n", dev_id);
+       return -1;
+    }
+
+    
+    for (i = 0; i < vm->num_cores; i++) {
+       struct guest_info * core = &(vm->cores[i]);
+
+       init_apic_state(&(apic[i]),i,icc);
+
+       v3_register_intr_controller(core, &intr_ops, &(apic[i]));
+
+       v3_add_timer(core, &timer_ops, &(apic[i]));
+
+       v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, &(apic[i]));
+
+       v3_icc_register_apic(core, icc, i, &icc_ops, &(apic[i]));
+
+       PrintDebug("apic %u: (setup device): done, my id is %u\n",i,apic[i].lapic_id.val);
+
+    }
+
+    for (i=0;i<vm->num_cores;i++) {
+       PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
+                  i, &(apic[i]), apic[i].lapic_id.val, apic[i].base_addr_msr.value);
+    }
+    PrintDebug("apic: priv_data is at %p\n", apic);
+
+    v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
+
+    return 0;
 }
+
+
+
+device_register("LAPIC", apic_init)