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.


integrated new configuration system
[palacios.git] / palacios / src / devices / apic.c
index 5963e59..ccb89e3 100644 (file)
@@ -22,9 +22,9 @@
 #include <devices/apic_regs.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_msr.h>
+#include <palacios/vm_guest.h>
 
-
-#ifndef DEBUG_APIC
+#ifndef CONFIG_DEBUG_APIC
 #undef PrintDebug
 #define PrintDebug(fmt, args...)
 #endif
@@ -168,6 +168,7 @@ struct apic_state {
     uint32_t tmr_init_cnt;
 
 
+    struct local_vec_tbl_reg ext_intr_vec_tbl[4];
 
     uint32_t rem_rd_data;
 
@@ -182,6 +183,8 @@ struct apic_state {
 
 };
 
+static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data);
+static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data);
 
 static void init_apic_state(struct apic_state * apic) {
     apic->base_addr = DEFAULT_BASE_ADDR;
@@ -223,6 +226,7 @@ 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;
@@ -234,19 +238,32 @@ static void init_apic_state(struct apic_state * apic) {
 static int read_apic_msr(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);
-
-    return -1;
+    dst->value = apic->base_addr;
+    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;
+    struct vm_device * dev = (struct vm_device *)priv_data;
+    struct apic_state * apic = (struct apic_state *)dev->private_data;
+    struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, apic->base_addr);
 
-    PrintError("WRITING APIC BASE ADDR: HI=%x LO=%x\n", src.hi, src.lo);
+    if (old_reg == NULL) {
+       // uh oh...
+       PrintError("APIC Base address region does not exit...\n");
+       return -1;
+    }
+    
+    v3_delete_shadow_region(dev->vm, old_reg);
 
-    return -1;
+    apic->base_addr = src.value;
+
+    if (v3_hook_full_mem(dev->vm, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev) == -1) {
+       PrintError("Could not hook new APIC Base address\n");
+       return -1;
+    }
+
+    return 0;
 }
 
 
@@ -265,6 +282,10 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
 
     PrintDebug("Raising APIC IRQ %d\n", irq_num);
 
+    if (*req_location & flag) {
+       V3_Print("Interrupts coallescing\n");
+    }
+
     if (*en_location & flag) {
        *req_location |= flag;
     } else {
@@ -277,11 +298,9 @@ 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;
 
-    PrintDebug("Received APIC EOI\n");
-
     // We iterate backwards to find the highest priority
     for (i = 31; i >= 0; i--) {
        uchar_t  * svc_major = apic->int_svc_reg + i;
@@ -290,25 +309,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;
-
-#ifdef CRAY_XT
-
-                   if ((((i * 8) + j) == 238) || 
-                       (((i * 8) + j) == 239)) {
-                       PrintError("Acking IRQ %d\n");
-                   }
-                   
-                   if (((i * 8) + j) == 238) {
-                       V3_ACK_IRQ(238);
-                   }
-#endif
-                   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("Received APIC EOI for IRQ %d\n", isr_irq);
+       
+       *svc_location &= ~flag;
+
+#ifdef CONFIG_CRAY_XT
+       
+       if ((isr_irq == 238) || 
+           (isr_irq == 239)) {
+           PrintError("Acking IRQ %d\n", isr_irq);
+       }
+       
+       if (isr_irq == 238) {
+           V3_ACK_IRQ(238);
+       }
+#endif
+    } else {
+       PrintError("Spurious EOI...\n");
+    }
+       
     return 0;
 }
  
@@ -577,9 +639,19 @@ 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:
@@ -750,7 +822,20 @@ 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;
-   
+
+       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:
@@ -761,10 +846,7 @@ static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_
        case INT_CMD_LO_OFFSET:
        case INT_CMD_HI_OFFSET:
            // Unhandled Registers
-       case EXT_INT_LOC_VEC_TBL_OFFSET0:
-       case EXT_INT_LOC_VEC_TBL_OFFSET1:
-       case EXT_INT_LOC_VEC_TBL_OFFSET2:
-       case EXT_INT_LOC_VEC_TBL_OFFSET3:
+
        case EXT_APIC_CMD_OFFSET:
        case SEOI_OFFSET:
        default:
@@ -781,46 +863,38 @@ 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) {
+// returns 1 if an interrupt is pending, 0 otherwise
+static int apic_intr_pending(struct guest_info * info, 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;
-
+    int req_irq = get_highest_irr(apic);
+    int svc_irq = get_highest_isr(apic);
 
-    // 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) {
+static int apic_get_intr_number(struct guest_info * info, 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;
-
+    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) {
-#ifdef CRAY_XT
+static int apic_raise_intr(struct guest_info * info, void * private_data, int irq) {
+#ifdef CONFIG_CRAY_XT
     // The Seastar is connected directly to the LAPIC via LINT0 on the ICC bus
 
     if (irq == 238) {
@@ -830,14 +904,15 @@ static int apic_raise_intr(void * private_data, int irq) {
        return activate_apic_irq(apic, irq);
     }
 #endif
+
     return 0;
 }
 
-static int apic_lower_intr(void * private_data, int irq) {
+static int apic_lower_intr(struct guest_info * info, void * private_data, int irq) {
     return 0;
 }
 
-static int apic_begin_irq(void * private_data, int irq) {
+static int apic_begin_irq(struct guest_info * info, void * private_data, int irq) {
     struct vm_device * dev = (struct vm_device *)private_data;
     struct apic_state * apic = (struct apic_state *)dev->private_data;
     int major_offset = (irq & ~0x00000007) >> 3;
@@ -849,7 +924,7 @@ static int apic_begin_irq(void * private_data, int irq) {
     *svc_location |= flag;
     *req_location &= ~flag;
 
-#ifdef CRAY_XT
+#ifdef CONFIG_CRAY_XT
     if ((irq == 238) || (irq == 239)) {
        PrintError("APIC: Begin IRQ %d (ISR=%x), (IRR=%x)\n", irq, *svc_location, *req_location);
     }
@@ -860,9 +935,17 @@ static int apic_begin_irq(void * private_data, int irq) {
 
 
 
-int v3_apic_raise_intr(struct vm_device * apic_dev, int intr_num) {
+int v3_apic_raise_intr(struct guest_info * info, 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);
+
+    if (activate_apic_irq(apic, intr_num) == -1) {
+       PrintError("Error: Could not activate apic_irq\n");
+       return -1;
+    } 
+
+    v3_interrupt_cpu(info, 0);
+
+    return 0;
 }
 
 
@@ -924,7 +1007,7 @@ static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv
     }
 
     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;
@@ -936,6 +1019,10 @@ static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv
        PrintDebug("Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", 
                   apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
 
+       if (apic_intr_pending(dev->vm, priv_data)) {
+           PrintDebug("Overriding pending IRQ %d\n", apic_get_intr_number(dev->vm, priv_data));
+       }
+
        if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
            PrintError("Could not raise Timer interrupt\n");
        }
@@ -965,23 +1052,9 @@ 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);
-
-    v3_hook_msr(info, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
 
-    v3_hook_full_mem(info, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev);
 
-    return 0;
-}
-
-static int apic_deinit(struct vm_device * dev) {
+static int apic_free(struct vm_device * dev) {
     struct guest_info * info = dev->vm;
 
     v3_unhook_msr(info, BASE_ADDR_MSR);
@@ -990,21 +1063,40 @@ static int apic_deinit(struct vm_device * dev) {
 }
 
 
-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() {
+
+static int apic_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
     PrintDebug("Creating APIC\n");
+    char * name = v3_cfg_val(cfg, "name");
 
     struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
 
-    struct vm_device * device = v3_create_device("APIC", &dev_ops, apic);
-  
-    return device;
+    struct vm_device * dev = v3_allocate_device(name, &dev_ops, apic);
+
+    if (v3_attach_device(vm, dev) == -1) {
+       PrintError("Could not attach device %s\n", name);
+       return -1;
+    }
+
+    v3_register_intr_controller(vm, &intr_ops, dev);
+    v3_add_timer(vm, &timer_ops, dev);
+
+    init_apic_state(apic);
+
+    v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
+
+    v3_hook_full_mem(vm, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev);
+
+    return 0;
 }
+
+
+
+device_register("LAPIC", apic_init)