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.


Cleanup and sanity-checking of before/after null-check and copy+paste errors (Coverit...
[palacios.git] / palacios / src / devices / apic.c
index 7b68ae5..a325006 100644 (file)
@@ -275,6 +275,8 @@ struct apic_dev_state {
 
 
 
+static void dump_all_apic_state(struct v3_vm_info *vm, struct apic_dev_state *a);
+static void dump_apic_state(struct guest_info *core, struct apic_state * a) ;
 
 
 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
@@ -366,10 +368,10 @@ static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, v
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
 
-    PrintDebug(core->vm_info, core, "apic %u: core %u: MSR read\n", apic->lapic_id.val, core->vcpu_id);
-
-    dst->value = apic->base_addr;
-
+    PrintDebug(core->vm_info, core, "apic %u: core %u: MSR read getting %llx\n", apic->lapic_id.apic_id, core->vcpu_id, apic->base_addr_msr.value);
+    dst->value = apic->base_addr_msr.value;
     return 0;
 }
 
@@ -380,26 +382,28 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo
     struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, apic->base_addr);
 
 
-    PrintDebug(core->vm_info, core, "apic %u: core %u: MSR write\n", apic->lapic_id.val, core->vcpu_id);
-
     if (old_reg == NULL) {
        // uh oh...
        PrintError(core->vm_info, core, "apic %u: core %u: APIC Base address region does not exit...\n",
-                  apic->lapic_id.val, core->vcpu_id);
+                  apic->lapic_id.apic_id, core->vcpu_id);
        return -1;
     }
-    
 
+    PrintDebug(core->vm_info, core, "apic %u: core %u: MSR write of %llx old=(gs=%p,ge=%p,flags=%u,host_addr=%p, unhandled=%p)\n", apic->lapic_id.apic_id, core->vcpu_id, src.value,(void*)old_reg->guest_start,(void*)old_reg->guest_end,old_reg->flags.value,(void*)(old_reg->host_addr),old_reg->unhandled);
+
+    apic->base_addr_msr.value = src.value;
 
-    v3_delete_mem_region(core->vm_info, old_reg);
+    // unhook from old location - this will also delete memory region
+    v3_unhook_mem(core->vm_info,core->vcpu_id,apic->base_addr);
 
-    apic->base_addr = src.value;
+    apic->base_addr = src.value & ~0xfffULL;
 
+    // hook to new location
     if (v3_hook_full_mem(core->vm_info, core->vcpu_id, apic->base_addr, 
                         apic->base_addr + PAGE_SIZE_4KB, 
                         apic_read, apic_write, apic_dev) == -1) {
        PrintError(core->vm_info, core, "apic %u: core %u: Could not hook new APIC Base address\n",
-                  apic->lapic_id.val, core->vcpu_id);
+                  apic->lapic_id.apic_id, core->vcpu_id);
 
        return -1;
     }
@@ -423,7 +427,7 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num,
     uint8_t flag = 0x1 << minor_offset;
 
 
-    PrintDebug(VM_NONE, VCORE_NONE, "apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->vcpu_id, irq_num);
+    PrintDebug(VM_NONE, VCORE_NONE, "apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.apic_id, apic->core->vcpu_id, irq_num);
 
     if (*req_location & flag) {
        PrintDebug(VM_NONE, VCORE_NONE, "Interrupt %d  coallescing\n", irq_num);
@@ -438,7 +442,7 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num,
        return 1;
     } else {
        PrintDebug(VM_NONE, VCORE_NONE, "apic %u: core %d: Interrupt  not enabled... %.2x\n", 
-                  apic->lapic_id.val, apic->core->vcpu_id, *en_location);
+                  apic->lapic_id.apic_id, apic->core->vcpu_id, *en_location);
     }
 
     return 0;
@@ -648,7 +652,7 @@ static int apic_do_eoi(struct guest_info * core, struct apic_state * apic) {
        uint8_t flag = 0x1 << minor_offset;
        uint8_t * svc_location = apic->int_svc_reg + major_offset;
        
-       PrintDebug(core->vm_info, core, "apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
+       PrintDebug(core->vm_info, core, "apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.apic_id,isr_irq);
        
        *svc_location &= ~flag;
 
@@ -660,7 +664,7 @@ static int apic_do_eoi(struct guest_info * core, struct apic_state * apic) {
        
        if ((isr_irq == 238) || 
            (isr_irq == 239)) {
-           PrintDebug(core->vm_info, core, "apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
+           PrintDebug(core->vm_info, core, "apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.apic_id,isr_irq);
        }
        
        if (isr_irq == 238) {
@@ -668,7 +672,7 @@ static int apic_do_eoi(struct guest_info * core, struct apic_state * apic) {
        }
 #endif
     } else {
-       //PrintError(core->vm_info, core, "apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
+       //PrintError(core->vm_info, core, "apic %u: core ?: Spurious EOI...\n",apic->lapic_id.apic_id);
     }
        
     return 0;
@@ -713,13 +717,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(VM_NONE, VCORE_NONE, "apic %u: core ?: Invalid APIC interrupt type\n", apic->lapic_id.val);
+           PrintError(VM_NONE, VCORE_NONE, "apic %u: core ?: Invalid APIC interrupt type\n", apic->lapic_id.apic_id);
            return -1;
     }
 
     // interrupt is masked, don't send
     if (masked == 1) {
-       PrintDebug(VM_NONE, VCORE_NONE, "apic %u: core ?: Inerrupt is masked\n", apic->lapic_id.val);
+       PrintDebug(VM_NONE, VCORE_NONE, "apic %u: core ?: Inerrupt is masked\n", apic->lapic_id.apic_id);
        return 0;
     }
 
@@ -727,7 +731,7 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
        //PrintDebug(VM_NONE, VCORE_NONE, "Activating internal APIC IRQ %d\n", vec_num);
        return add_apic_irq_entry(apic, vec_num, NULL, NULL);
     } else {
-       PrintError(VM_NONE, VCORE_NONE, "apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
+       PrintError(VM_NONE, VCORE_NONE, "apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.apic_id);
        return -1;
     }
 }
@@ -751,11 +755,11 @@ static inline int should_deliver_cluster_ipi(struct apic_dev_state * apic_dev,
 
     if (ret == 1) {
        PrintDebug(VM_NONE, VCORE_NONE, "apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
-                  dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
+                  dst_apic->lapic_id.apic_id, dst_core->vcpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
     } else {
        PrintDebug(VM_NONE, VCORE_NONE, "apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n",
-                  dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
+                  dst_apic->lapic_id.apic_id, dst_core->vcpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
     }
 
@@ -779,11 +783,11 @@ static inline int should_deliver_flat_ipi(struct apic_dev_state * apic_dev,
 
     if (ret == 1) {
        PrintDebug(VM_NONE, VCORE_NONE, "apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
-                  dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
+                  dst_apic->lapic_id.apic_id, dst_core->vcpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
     } else {
        PrintDebug(VM_NONE, VCORE_NONE, "apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
-                  dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
+                  dst_apic->lapic_id.apic_id, dst_core->vcpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
     }
 
@@ -827,7 +831,7 @@ static int should_deliver_ipi(struct apic_dev_state * apic_dev,
 
     if (ret == -1) {
        PrintError(VM_NONE, VCORE_NONE, "apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", 
-                  dst_apic->lapic_id.val, dst_core->vcpu_id, dst_apic->dst_fmt.model);
+                  dst_apic->lapic_id.apic_id, dst_core->vcpu_id, dst_apic->dst_fmt.model);
     }
 
     return ret;
@@ -836,7 +840,6 @@ 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, 
                       struct v3_gen_ipi * ipi) {
@@ -844,6 +847,24 @@ static int deliver_ipi(struct apic_state * src_apic,
 
     struct guest_info * dst_core = dst_apic->core;
 
+#ifdef V3_CONFIG_HVM
+
+    // this is the ultimate place where we discrard IPIs that should
+    // not be going to the HRT.  We should have previously
+    // filtered by priority as well - that is, an HRT apic
+    // is not involved in priority calculation for an IPI originating
+    // from a ROS apic or an ioapic or MSI.   On the other hand
+    // an IPI sent from an HRT apic can go anywhere
+    //
+    if (!v3_hvm_should_deliver_ipi(src_apic ? src_apic->core : 0, 
+                                  dst_apic->core)) {
+       PrintDebug(VM_NONE,VCORE_NONE,  
+                  "apic: HVM skipping delivery of IPI from core %u to core %u\n",
+                  src_apic ? src_apic->core ? src_apic->core->vcpu_id : -1 : -1, 
+                  dst_apic->core->vcpu_id);
+       return 0;
+    }
+#endif
 
     switch (ipi->mode) {
 
@@ -873,6 +894,11 @@ static int deliver_ipi(struct apic_state * src_apic,
            }
 
 
+           if (!src_apic) { 
+               PrintError(VM_NONE, VCORE_NONE, "Attempting to INIT from somewhere other than an APIC...  Ignoring\n");
+               break;
+           }
+
            if (dst_apic->ipi_state != INIT_ST) { 
                v3_raise_barrier(dst_core->vm_info, src_apic->core);
                dst_core->core_run_state = CORE_STOPPED;
@@ -1012,7 +1038,8 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                    // we immediately trigger
                    // fixed, smi, reserved, nmi, init, sipi, etc
 
-                   
+                   // HVM is handled here within deliver_ipi 
+
                    for (i = 0; i < apic_dev->num_apics; i++) { 
                        int del_flag = 0;
                        
@@ -1037,10 +1064,21 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                    uint32_t cur_best_apr;
                    uint8_t mda = ipi->dst;
                    int i;
+                   uint32_t start_apic = 0;
+                   uint32_t num_apics = apic_dev->num_apics;
+
+#ifdef V3_CONFIG_HVM
+                   // Need to limit lowest priority search to ROS apics
+                   // if this is coming from a ROS apic or ioapic, etc. 
+                   v3_hvm_find_apics_seen_by_core(src_apic ? src_apic->core : 0, 
+                                                  apic_dev->apics[0].core->vm_info,
+                                                  &start_apic,
+                                                  &num_apics);
+#endif
 
                    // logical, lowest priority
 
-                   for (i = 0; i < apic_dev->num_apics; i++) { 
+                   for (i = start_apic; i < num_apics; i++) { 
                        int del_flag = 0;
 
                        dest_apic = &(apic_dev->apics[i]);
@@ -1075,13 +1113,13 @@ static int route_ipi(struct apic_dev_state * apic_dev,
 
                    // now we will deliver to the best one if it exists
                    if (!cur_best_apic) { 
-                       PrintDebug(VM_NONE, VCORE_NONE, "apic: lowest priority deliver, but no destinations!\n");
+                       PrintDebug(VM_NONE, VCORE_NONE, "apic: lowest priority delivery, but no destinations!\n");
                    } else {
                        if (deliver_ipi(src_apic, cur_best_apic, ipi) == -1) {
                            PrintError(VM_NONE, VCORE_NONE, "apic: Error: Could not deliver IPI\n");
                            return -1;
                        }
-                       //V3_Print(VM_NONE, VCORE_NONE, "apic: logical, lowest priority delivery to apic %u\n",cur_best_apic->lapic_id.val);
+                       //V3_Print(VM_NONE, VCORE_NONE, "apic: logical, lowest priority delivery to apic %u\n",cur_best_apic->lapic_id.apic_id);
                    }
                }
            }
@@ -1118,8 +1156,17 @@ static int route_ipi(struct apic_dev_state * apic_dev,
            /* assuming that logical verus physical doesn't matter
               although it is odd that both are used */
            int i;
+           uint32_t start_apic = 0;
+           uint32_t num_apics = apic_dev->num_apics;
+
+#ifdef V3_CONFIG_HVM
+           v3_hvm_find_apics_seen_by_core(src_apic ? src_apic->core : 0, 
+                                          apic_dev->apics[0].core->vm_info,
+                                          &start_apic,
+                                          &num_apics);
+#endif
 
-           for (i = 0; i < apic_dev->num_apics; i++) { 
+           for (i = start_apic; i < num_apics; i++) { 
                dest_apic = &(apic_dev->apics[i]);
                
                if ((dest_apic != src_apic) || (ipi->dst_shorthand == APIC_SHORTHAND_ALL)) { 
@@ -1151,11 +1198,11 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
 
 
     PrintDebug(core->vm_info, core, "apic %u: core %u: at %p: Read apic address space (%p)\n",
-              apic->lapic_id.val, core->vcpu_id, apic, (void *)guest_addr);
+              apic->lapic_id.apic_id, core->vcpu_id, apic, (void *)guest_addr);
 
     if (msr->apic_enable == 0) {
        PrintError(core->vm_info, core, "apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
-                  apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
+                  apic->lapic_id.apic_id, core->vcpu_id, apic->base_addr_msr.value);
        return -1;
     }
 
@@ -1368,8 +1415,9 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
 
        default:
            PrintError(core->vm_info, core, "apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
-                      apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
-           return -1;
+                      apic->lapic_id.apic_id, core->vcpu_id, (uint32_t)reg_addr);
+           memset(dst,0,length);
+           return length;
     }
 
 
@@ -1391,12 +1439,12 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
 
     } else {
        PrintError(core->vm_info, core, "apic %u: core %u: Invalid apic read length (%d)\n", 
-                  apic->lapic_id.val, core->vcpu_id, length);
+                  apic->lapic_id.apic_id, core->vcpu_id, length);
        return -1;
     }
 
     PrintDebug(core->vm_info, core, "apic %u: core %u: Read finished (val=%x)\n", 
-              apic->lapic_id.val, core->vcpu_id, *(uint32_t *)dst);
+              apic->lapic_id.apic_id, core->vcpu_id, *(uint32_t *)dst);
 
     return length;
 }
@@ -1414,21 +1462,21 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
     addr_t flags = 0;
 
     PrintDebug(core->vm_info, core, "apic %u: core %u: at %p and priv_data is at %p\n",
-              apic->lapic_id.val, core->vcpu_id, apic, priv_data);
+              apic->lapic_id.apic_id, core->vcpu_id, apic, priv_data);
 
     PrintDebug(core->vm_info, core, "apic %u: core %u: write to address space (%p) (val=%x)\n", 
-              apic->lapic_id.val, core->vcpu_id, (void *)guest_addr, *(uint32_t *)src);
+              apic->lapic_id.apic_id, core->vcpu_id, (void *)guest_addr, *(uint32_t *)src);
 
     if (msr->apic_enable == 0) {
        PrintError(core->vm_info, core, "apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
-                  apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
+                  apic->lapic_id.apic_id, core->vcpu_id, apic->base_addr_msr.value);
        return -1;
     }
 
 
     if (length != 4) {
        PrintError(core->vm_info, core, "apic %u: core %u: Invalid apic write length (%d)\n", 
-                  apic->lapic_id.val, length, core->vcpu_id);
+                  apic->lapic_id.apic_id, length, core->vcpu_id);
        return -1;
     }
 
@@ -1464,14 +1512,14 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
        case EXT_APIC_FEATURE_OFFSET:
 
            PrintError(core->vm_info, core, "apic %u: core %u: Attempting to write to read only register %p (error)\n", 
-                      apic->lapic_id.val, core->vcpu_id, (void *)reg_addr);
+                      apic->lapic_id.apic_id, core->vcpu_id, (void *)reg_addr);
 
            break;
 
            // Data registers
        case APIC_ID_OFFSET:
-           //V3_Print(core->vm_info, core, "apic %u: core %u: my id is being changed to %u\n", 
-           //       apic->lapic_id.val, core->vcpu_id, op_val);
+           //V3_Print(core->vm_info, core, "apic %u: core %u: my id is being changed to 0x%x\n", 
+           //       apic->lapic_id.apic_id, core->vcpu_id, op_val);
 
            apic->lapic_id.val = op_val;
            break;
@@ -1480,7 +1528,7 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            break;
        case LDR_OFFSET:
            PrintDebug(core->vm_info, core, "apic %u: core %u: setting log_dst.val to 0x%x\n",
-                      apic->lapic_id.val, core->vcpu_id, op_val);
+                      apic->lapic_id.apic_id, core->vcpu_id, op_val);
            flags = v3_lock_irqsave(apic_dev->state_lock);
            apic->log_dst.val = op_val;
            v3_unlock_irqrestore(apic_dev->state_lock, flags);
@@ -1523,7 +1571,7 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            break;
        case TMR_DIV_CFG_OFFSET:
            PrintDebug(core->vm_info, core, "apic %u: core %u: setting tmr_div_cfg to 0x%x\n",
-                      apic->lapic_id.val, core->vcpu_id, op_val);
+                      apic->lapic_id.apic_id, core->vcpu_id, op_val);
            apic->tmr_div_cfg.val = op_val;
            break;
 
@@ -1593,7 +1641,7 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            
 
            //      V3_Print(core->vm_info, core, "apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
-           //       apic->lapic_id.val, core->vcpu_id,
+           //       apic->lapic_id.apic_id, core->vcpu_id,
            //       apic->int_cmd.val, apic->int_cmd.dst);
 
            if (route_ipi(apic_dev, apic, &tmp_ipi) == -1) { 
@@ -1605,7 +1653,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(core->vm_info, core, "apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->vcpu_id,apic->int_cmd.hi);
+           //V3_Print(core->vm_info, core, "apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.apic_id, core->vcpu_id,apic->int_cmd.hi);
            break;
        }
        // Unhandled Registers
@@ -1613,12 +1661,12 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
        case SEOI_OFFSET:
        default:
            PrintError(core->vm_info, core, "apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
-                      apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
+                      apic->lapic_id.apic_id, core->vcpu_id, (uint32_t)reg_addr);
 
-           return -1;
+           return length;
     }
 
-    PrintDebug(core->vm_info, core, "apic %u: core %u: Write finished\n", apic->lapic_id.val, core->vcpu_id);
+    PrintDebug(core->vm_info, core, "apic %u: core %u: Write finished\n", apic->lapic_id.apic_id, core->vcpu_id);
 
     return length;
 
@@ -1642,7 +1690,7 @@ static int apic_intr_pending(struct guest_info * core, void * private_data) {
     req_irq = get_highest_irr(apic);
     svc_irq = get_highest_isr(apic);
 
-    //    PrintDebug(core->vm_info, core, "apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->vcpu_id,req_irq,svc_irq);
+    //    PrintDebug(core->vm_info, core, "apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.apic_id,info->vcpu_id,req_irq,svc_irq);
 
 
     if ((req_irq >= 0) && 
@@ -1728,7 +1776,7 @@ static int apic_begin_irq(struct guest_info * core, void * private_data, int irq
     } else {
        // do nothing... 
        //PrintDebug(core->vm_info, core, "apic %u: core %u: begin irq for %d ignored since I don't own it\n",
-       //         apic->lapic_id.val, core->vcpu_id, irq);
+       //         apic->lapic_id.apic_id, core->vcpu_id, irq);
     }
 
     return 0;
@@ -1743,18 +1791,18 @@ static void apic_inject_timer_intr(struct guest_info *core,
     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
     // raise irq
     PrintDebug(core->vm_info, core, "apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d)\n",
-              apic->lapic_id.val, core->vcpu_id,
+              apic->lapic_id.apic_id, core->vcpu_id,
               apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt);
 
     if (apic_intr_pending(core, priv_data)) {
         PrintDebug(core->vm_info, core, "apic %u: core %u: Overriding pending IRQ %d\n", 
-                  apic->lapic_id.val, core->vcpu_id, 
+                  apic->lapic_id.apic_id, core->vcpu_id, 
                   apic_get_intr_number(core, priv_data));
     }
 
     if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
        PrintError(core->vm_info, core, "apic %u: core %u: Could not raise Timer interrupt\n",
-                  apic->lapic_id.val, core->vcpu_id);
+                  apic->lapic_id.apic_id, core->vcpu_id);
     }
 
     return;
@@ -1786,7 +1834,7 @@ static void apic_update_time(struct guest_info * core,
     if ((apic->tmr_init_cnt == 0) || 
        ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
          (apic->tmr_cur_cnt == 0))) {
-       //PrintDebug(core->vm_info, core, "apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->vcpu_id);
+       //PrintDebug(core->vm_info, core, "apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.apic_id,info->vcpu_id);
        return;
     }
 
@@ -1818,7 +1866,7 @@ static void apic_update_time(struct guest_info * core,
            break;
        default:
            PrintError(core->vm_info, core, "apic %u: core %u: Invalid Timer Divider configuration\n",
-                      apic->lapic_id.val, core->vcpu_id);
+                      apic->lapic_id.apic_id, core->vcpu_id);
            return;
     }
 
@@ -1830,7 +1878,7 @@ static void apic_update_time(struct guest_info * core,
 #ifdef V3_CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS
        if (apic->missed_ints && !apic_intr_pending(core, priv_data)) {
            PrintDebug(core->vm_info, core, "apic %u: core %u: Injecting queued APIC timer interrupt.\n",
-                      apic->lapic_id.val, core->vcpu_id);
+                      apic->lapic_id.apic_id, core->vcpu_id);
            apic_inject_timer_intr(core, priv_data);
            apic->missed_ints--;
        }
@@ -1884,7 +1932,7 @@ static int apic_free(struct apic_dev_state * apic_dev) {
 
        v3_lock_deinit(&(apic->irq_queue.lock));
 
-       // unhook memory
+       v3_unhook_mem(vm,core->vcpu_id,apic->base_addr);
 
     }
 
@@ -2161,16 +2209,17 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
            return -1;
        }
 
+       // hook to initial location
        v3_hook_full_mem(vm, core->vcpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
 
-       PrintDebug(vm, VCORE_NONE, "apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
+       PrintDebug(vm, VCORE_NONE, "apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.apic_id);
     }
 
 #ifdef V3_CONFIG_DEBUG_APIC
     for (i = 0; i < vm->num_cores; i++) {
        struct apic_state * apic = &(apic_dev->apics[i]);
        PrintDebug(vm, VCORE_NONE, "apic: sanity check: apic %u (at %p) has id %u and msr value %llx and core at %p\n",
-                  i, apic, apic->lapic_id.val, apic->base_addr_msr.value,apic->core);
+                  i, apic, apic->lapic_id.apic_id, apic->base_addr_msr.value,apic->core);
     }
 #endif
 
@@ -2182,6 +2231,283 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     return 0;
 }
 
+static char hexify_nybble(char c)
+{
+    if (c>=0 && c<=9) { 
+       return '0'+c;
+    } else if (c>=0xa && c<=0xf) { 
+       return 'a'+(c-0xa);
+    } else {
+       return -1;
+    }
+}
+
+
+static int hexify_byte(char *c, char b)
+{
+    char n;
+    n = hexify_nybble( (b >> 4) & 0xf);
+    if (n==-1) { 
+       return -1;
+    }
+    c[0] = n;
+    n = hexify_nybble( b & 0xf);
+    if (n==-1) { 
+       return -1;
+    }
+    c[1] = n;
+    return 0;
+}
+
+// dest must be of length at least 2*n+1
+static int hexify_byte_string(char *dest, char *src, int n)
+{
+    int i;
+    for (i=0;i<n;i++) { 
+       if (hexify_byte(dest,src[i])) { 
+           return -1;
+       }
+       dest+=2;
+    }
+    *dest=0;
+    return 0;
+}
+
+
+static __attribute__((unused)) void dump_all_apic_state(struct v3_vm_info *vm, struct apic_dev_state *a)
+{
+    int i;
+    for (i=0;i<a->num_apics;i++) { 
+       dump_apic_state(&(vm->cores[i]),&(a->apics[i]));
+    }
+}
+       
+static void dump_apic_state(struct guest_info *core, struct apic_state * a) 
+{
+    char buf[80];
+    struct irq_queue_entry *ie;
+
+    V3_Print(core->vm_info, core, "APIC (vcore %d) {\n", core->vcpu_id);
+    V3_Print(core->vm_info, core, "\tbase_addr: %llx\n", (uint64_t)(a->base_addr));
+    V3_Print(core->vm_info, core, "\tlapic_id_reg {\n");
+    V3_Print(core->vm_info, core, "\t\trsvd: 0x%x\n", a->lapic_id.rsvd);
+    V3_Print(core->vm_info, core, "\t\tapic_id: 0x%x\n", a->lapic_id.apic_id);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tapic_ver_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tver: 0x%x\n", a->apic_ver.ver);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->apic_ver.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tmax_lvts: 0x%x\n", a->apic_ver.max_lvts);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->apic_ver.rsvd2);
+    V3_Print(core->vm_info, core, "\t\text_reg_present: 0x%x\n", a->apic_ver.ext_reg_present);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\text_apic_ctrl_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tver: 0x%x\n", a->ext_apic_ctrl.ver);
+    V3_Print(core->vm_info, core, "\t\tseoi_enable: 0x%x\n", a->ext_apic_ctrl.seoi_enable);
+    V3_Print(core->vm_info, core, "\t\text_id_enable: 0x%x\n", a->ext_apic_ctrl.ext_id_enable);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->ext_apic_ctrl.rsvd2);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tlocal_vec_tbl_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->local_vec_tbl.vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->local_vec_tbl.msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->local_vec_tbl.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->local_vec_tbl.del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->local_vec_tbl.rsvd2);
+    V3_Print(core->vm_info, core, "\t\trem_irr: 0x%x\n", a->local_vec_tbl.rem_irr);
+    V3_Print(core->vm_info, core, "\t\ttrig_mode: 0x%x\n", a->local_vec_tbl.trig_mode);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->local_vec_tbl.mask);
+    V3_Print(core->vm_info, core, "\t\ttmr_mode: 0x%x\n", a->local_vec_tbl.tmr_mode);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->local_vec_tbl.rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\ttmr_vec_tbl_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->tmr_vec_tbl.vec);
+    V3_Print(core->vm_info, core, "\t\trsvd: 0x%x\n", a->tmr_vec_tbl.rsvd);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->tmr_vec_tbl.del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->tmr_vec_tbl.rsvd2);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->tmr_vec_tbl.mask);
+    V3_Print(core->vm_info, core, "\t\ttmr_mode: 0x%x\n", a->tmr_vec_tbl.tmr_mode);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->tmr_vec_tbl.rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\ttmr_div_cfg_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tdiv_val: 0x%x\n", a->tmr_div_cfg.div_val);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->tmr_div_cfg.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdiv_val2: 0x%x\n", a->tmr_div_cfg.div_val2);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->tmr_div_cfg.rsvd2);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tlint_vec_tbl_reg 0 {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->lint0_vec_tbl.vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->lint0_vec_tbl.msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->lint0_vec_tbl.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->lint0_vec_tbl.del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->lint0_vec_tbl.rsvd2);
+    V3_Print(core->vm_info, core, "\t\trem_irr: 0x%x\n", a->lint0_vec_tbl.rem_irr);
+    V3_Print(core->vm_info, core, "\t\ttrig_mode: 0x%x\n", a->lint0_vec_tbl.trig_mode);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->lint0_vec_tbl.mask);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->lint0_vec_tbl.rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tlint_vec_tbl_reg 1 {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->lint1_vec_tbl.vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->lint1_vec_tbl.msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->lint1_vec_tbl.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->lint1_vec_tbl.del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->lint1_vec_tbl.rsvd2);
+    V3_Print(core->vm_info, core, "\t\trem_irr: 0x%x\n", a->lint1_vec_tbl.rem_irr);
+    V3_Print(core->vm_info, core, "\t\ttrig_mode: 0x%x\n", a->lint1_vec_tbl.trig_mode);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->lint1_vec_tbl.mask);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->lint1_vec_tbl.rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tperf_ctr_loc_vec_tbl_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->perf_ctr_loc_vec_tbl.vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->perf_ctr_loc_vec_tbl.msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->perf_ctr_loc_vec_tbl.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->perf_ctr_loc_vec_tbl.del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->perf_ctr_loc_vec_tbl.rsvd2);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->perf_ctr_loc_vec_tbl.mask);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->perf_ctr_loc_vec_tbl.rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\ttherm_loc_vec_tbl_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->therm_loc_vec_tbl.vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->therm_loc_vec_tbl.msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->therm_loc_vec_tbl.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->therm_loc_vec_tbl.del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->therm_loc_vec_tbl.rsvd2);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->therm_loc_vec_tbl.mask);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->therm_loc_vec_tbl.rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\terr_vec_tbl_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->err_vec_tbl.vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->err_vec_tbl.msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->err_vec_tbl.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->err_vec_tbl.del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->err_vec_tbl.rsvd2);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->err_vec_tbl.mask);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->err_vec_tbl.rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\terr_status_reg {\n");
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->err_status.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tsent_acc_err: 0x%x\n", a->err_status.sent_acc_err);
+    V3_Print(core->vm_info, core, "\t\trecv_acc_err: 0x%x\n", a->err_status.recv_acc_err);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->err_status.rsvd2);
+    V3_Print(core->vm_info, core, "\t\tsent_ill_err: 0x%x\n", a->err_status.sent_ill_err);
+    V3_Print(core->vm_info, core, "\t\trecv_ill_err: 0x%x\n", a->err_status.recv_ill_err);
+    V3_Print(core->vm_info, core, "\t\till_reg_addr: 0x%x\n", a->err_status.ill_reg_addr);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->err_status.rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tspurious_int_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->spurious_int.vec);
+    V3_Print(core->vm_info, core, "\t\tapic_soft_en: 0x%x\n", a->spurious_int.apic_soft_en);
+    V3_Print(core->vm_info, core, "\t\tfoc_cpu_chk: 0x%x\n", a->spurious_int.foc_cpu_chk);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->spurious_int.rsvd1);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tint_cmd_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->int_cmd.vec);
+    V3_Print(core->vm_info, core, "\t\tdel_mode: 0x%x\n", a->int_cmd.del_mode);
+    V3_Print(core->vm_info, core, "\t\tdst_mode: 0x%x\n", a->int_cmd.dst_mode);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->int_cmd.del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->int_cmd.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tlvl: 0x%x\n", a->int_cmd.lvl);
+    V3_Print(core->vm_info, core, "\t\ttrig_mode: 0x%x\n", a->int_cmd.trig_mode);
+    V3_Print(core->vm_info, core, "\t\trm_rd_status: 0x%x\n", a->int_cmd.rem_rd_status);
+    V3_Print(core->vm_info, core, "\t\tdst_shorthand: 0x%x\n", a->int_cmd.dst_shorthand);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%llx\n", (uint64_t)(a->int_cmd.rsvd2));
+    V3_Print(core->vm_info, core, "\t\tdst: 0x%x\n", a->int_cmd.dst);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tlog_dst_reg {\n");
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->log_dst.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdst_log_id: 0x%x\n", a->log_dst.dst_log_id);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tdst_fmt_reg {\n");
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->dst_fmt.rsvd1);
+    V3_Print(core->vm_info, core, "\t\tmodel: 0x%x\n", a->dst_fmt.model);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tarb_prio_reg: 0x%x\n",get_apic_apr(a));
+    V3_Print(core->vm_info, core, "\ttask_prio_reg: 0x%x\n", get_apic_tpr(a));
+    V3_Print(core->vm_info, core, "\tproc_prio_reg: 0x%x\n",get_apic_ppr(a));
+    V3_Print(core->vm_info, core, "\text_apic_feature_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tint_en_reg_cap: 0x%x\n", a->ext_apic_feature.int_en_reg_cap);
+    V3_Print(core->vm_info, core, "\t\tspec_eoi_cap: 0x%x\n", a->ext_apic_feature.spec_eoi_cap);
+    V3_Print(core->vm_info, core, "\t\text_apic_id_cap: 0x%x\n", a->ext_apic_feature.ext_apic_id_cap);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->ext_apic_feature.rsvd1);
+    V3_Print(core->vm_info, core, "\t\text_lvt_cnt: 0x%x\n", a->ext_apic_feature.ext_lvt_cnt);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->ext_apic_feature.rsvd2);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\tspec_eoi_reg {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->spec_eoi.vec);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->spec_eoi.rsvd1);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\ttmr_cur_cnt: 0x%x\n", a->tmr_cur_cnt);
+    V3_Print(core->vm_info, core, "\ttmr_init_cnt: 0x%x\n", a->tmr_init_cnt);
+    V3_Print(core->vm_info, core, "\tmissed_ints: 0x%x\n", a->missed_ints);
+    V3_Print(core->vm_info, core, "\text_vec_tbl_reg 0 {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->ext_intr_vec_tbl[0].vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->ext_intr_vec_tbl[0].msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->ext_intr_vec_tbl[0].rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->ext_intr_vec_tbl[0].del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->ext_intr_vec_tbl[0].rsvd2);
+    V3_Print(core->vm_info, core, "\t\trem_irr: 0x%x\n", a->ext_intr_vec_tbl[0].rem_irr);
+    V3_Print(core->vm_info, core, "\t\ttrig_mode: 0x%x\n", a->ext_intr_vec_tbl[0].trig_mode);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->ext_intr_vec_tbl[0].mask);
+    V3_Print(core->vm_info, core, "\t\ttmr_mode: 0x%x\n", a->ext_intr_vec_tbl[0].tmr_mode);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->ext_intr_vec_tbl[0].rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\text_vec_tbl_reg 1 {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->ext_intr_vec_tbl[1].vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->ext_intr_vec_tbl[1].msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->ext_intr_vec_tbl[1].rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->ext_intr_vec_tbl[1].del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->ext_intr_vec_tbl[1].rsvd2);
+    V3_Print(core->vm_info, core, "\t\trem_irr: 0x%x\n", a->ext_intr_vec_tbl[1].rem_irr);
+    V3_Print(core->vm_info, core, "\t\ttrig_mode: 0x%x\n", a->ext_intr_vec_tbl[1].trig_mode);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->ext_intr_vec_tbl[1].mask);
+    V3_Print(core->vm_info, core, "\t\ttmr_mode: 0x%x\n", a->ext_intr_vec_tbl[1].tmr_mode);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->ext_intr_vec_tbl[1].rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\text_vec_tbl_reg 2 {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->ext_intr_vec_tbl[2].vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->ext_intr_vec_tbl[2].msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->ext_intr_vec_tbl[2].rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->ext_intr_vec_tbl[2].del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->ext_intr_vec_tbl[2].rsvd2);
+    V3_Print(core->vm_info, core, "\t\trem_irr: 0x%x\n", a->ext_intr_vec_tbl[2].rem_irr);
+    V3_Print(core->vm_info, core, "\t\ttrig_mode: 0x%x\n", a->ext_intr_vec_tbl[2].trig_mode);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->ext_intr_vec_tbl[2].mask);
+    V3_Print(core->vm_info, core, "\t\ttmr_mode: 0x%x\n", a->ext_intr_vec_tbl[2].tmr_mode);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->ext_intr_vec_tbl[2].rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\text_vec_tbl_reg 3 {\n");
+    V3_Print(core->vm_info, core, "\t\tvec: 0x%x\n", a->ext_intr_vec_tbl[3].vec);
+    V3_Print(core->vm_info, core, "\t\tmsg_type: 0x%x\n", a->ext_intr_vec_tbl[3].msg_type);
+    V3_Print(core->vm_info, core, "\t\trsvd1: 0x%x\n", a->ext_intr_vec_tbl[3].rsvd1);
+    V3_Print(core->vm_info, core, "\t\tdel_status: 0x%x\n", a->ext_intr_vec_tbl[3].del_status);
+    V3_Print(core->vm_info, core, "\t\trsvd2: 0x%x\n", a->ext_intr_vec_tbl[3].rsvd2);
+    V3_Print(core->vm_info, core, "\t\trem_irr: 0x%x\n", a->ext_intr_vec_tbl[3].rem_irr);
+    V3_Print(core->vm_info, core, "\t\ttrig_mode: 0x%x\n", a->ext_intr_vec_tbl[3].trig_mode);
+    V3_Print(core->vm_info, core, "\t\tmask: 0x%x\n", a->ext_intr_vec_tbl[3].mask);
+    V3_Print(core->vm_info, core, "\t\ttmr_mode: 0x%x\n", a->ext_intr_vec_tbl[3].tmr_mode);
+    V3_Print(core->vm_info, core, "\t\trsvd3: 0x%x\n", a->ext_intr_vec_tbl[3].rsvd3);
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\trem_rd_data: 0x%x\n", a->rem_rd_data);
+    hexify_byte_string(buf,a->int_req_reg,32);
+    V3_Print(core->vm_info, core, "\tint_req_reg: 0x%s\n",buf);
+    hexify_byte_string(buf,a->int_svc_reg,32);
+    V3_Print(core->vm_info, core, "\tint_svc_reg: 0x%s\n",buf);
+    hexify_byte_string(buf,a->int_en_reg,32);
+    V3_Print(core->vm_info, core, "\tint_en_reg: 0x%s\n",buf);
+    hexify_byte_string(buf,a->trig_mode_reg,32);
+    V3_Print(core->vm_info, core, "\ttrig_mode_reg: 0x%s\n",buf);
+    V3_Print(core->vm_info, core, "\tirq_ack_cbs: SKIPPED\n");
+    V3_Print(core->vm_info, core, "\tirq_queue: (follows)\n");
+    // note we do not hold the lock for purposes of printing this list... 
+    list_for_each_entry(ie,&(a->irq_queue.entries), list_node) {
+       V3_Print(core->vm_info,core,"\t\tvector 0x%x ack %p priv %p\n", ie->vector, ie->ack, ie->private_data);
+    }
+    V3_Print(core->vm_info, core, "\t}\n");
+    V3_Print(core->vm_info, core, "\teoi: 0x%x\n", a->eoi);
+    V3_Print(core->vm_info, core,"}\n");
+}
+
+
+
+
 
 
 device_register("LAPIC", apic_init)