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
[palacios.releases.git] / palacios / src / devices / apic.c
index 7434b7d..77f727b 100644 (file)
 #include <palacios/vmm_msr.h>
 
 
+#ifndef DEBUG_APIC
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+
 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
               APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
 
@@ -228,7 +234,7 @@ 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;
-  PrintDebug("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_msr.hi, apic->base_addr_msr.lo);
+  PrintError("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_msr.hi, apic->base_addr_msr.lo);
 
   return -1;
 }
@@ -238,7 +244,7 @@ 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;
 
-  PrintDebug("WRITING APIC BASE ADDR: HI=%x LO=%x\n", src.hi, src.lo);
+  PrintError("WRITING APIC BASE ADDR: HI=%x LO=%x\n", src.hi, src.lo);
 
   return -1;
 }
@@ -246,7 +252,7 @@ static int write_apic_msr(uint_t msr, v3_msr_t src, void * priv_data) {
 
 // irq_num is the bit offset into a 256 bit buffer...
 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
-  int major_offset = irq_num & ~0x00000007;
+  int major_offset = (irq_num & ~0x00000007) >> 3;
   int minor_offset = irq_num & 0x00000007;
   uchar_t * req_location = apic->int_req_reg + major_offset;
   uchar_t * en_location = apic->int_en_reg + major_offset;
@@ -257,9 +263,12 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
     return -1;
   }
 
+  PrintDebug("Raising APIC IRQ %d\n", irq_num);
+
   if (*en_location & flag) {
     *req_location |= flag;
   } else {
+    PrintDebug("Interrupt  not enabled... %.2x\n", *en_location);
     return 0;
   }
 
@@ -267,6 +276,29 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
 }
 
 
+
+static int apic_do_eoi(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  * svc_major = apic->int_svc_reg + i;
+    
+    if ((*svc_major) & 0xff) {
+      for (j = 7; j >= 0; j--) {
+       uchar_t flag = 0x1 << j;
+       if ((*svc_major) & flag) {
+         *svc_major &= ~flag;
+         return 0;
+       }
+      }
+    }
+  }
+
+  return 0;
+}
+
 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
   uint32_t vec_num = 0;
   uint32_t del_mode = 0;
@@ -311,11 +343,12 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
 
   // interrupt is masked, don't send
   if (masked == 1) {
+    PrintDebug("Inerrupt is masked\n");
     return 0;
   }
 
   if (del_mode == APIC_FIXED_DELIVERY) {
-    PrintDebug("Activating internal APIC IRQ\n");
+    //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
     return activate_apic_irq(apic, vec_num);
   } else {
     PrintError("Unhandled Delivery Mode\n");
@@ -329,7 +362,8 @@ static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_d
   struct apic_state * apic = (struct apic_state *)dev->private_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_ptr = (uint32_t *)dst;
+  uint32_t val = 0;
+
 
   PrintDebug("Read apic address space (%p)\n", 
             (void *)guest_addr);
@@ -340,12 +374,13 @@ static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_d
   }
 
 
-  if (length != 4) {
-    PrintError("Invalid apic readlength\n");
-    return -1;
-  }
+  /* Because "May not be supported" doesn't matter to Linux developers... */
+  /*   if (length != 4) { */
+  /*     PrintError("Invalid apic read length (%d)\n", length); */
+  /*     return -1; */
+  /*   } */
 
-  switch (reg_addr) {
+  switch (reg_addr & ~0x3) {
   case EOI_OFFSET:
     PrintError("Attempting to read from write only register\n");
     return -1;
@@ -353,173 +388,173 @@ static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_d
 
     // data registers
   case APIC_ID_OFFSET:
-    *val_ptr = apic->lapic_id.val;
+    val = apic->lapic_id.val;
     break;
   case APIC_VERSION_OFFSET:
-    *val_ptr = apic->apic_ver.val;
+    val = apic->apic_ver.val;
     break;
   case TPR_OFFSET:
-    *val_ptr = apic->task_prio.val;
+    val = apic->task_prio.val;
     break;
   case APR_OFFSET:
-    *val_ptr = apic->arb_prio.val;
+    val = apic->arb_prio.val;
     break;
   case PPR_OFFSET:
-    *val_ptr = apic->proc_prio.val;
+    val = apic->proc_prio.val;
     break;
   case REMOTE_READ_OFFSET:
-    *val_ptr = apic->rem_rd_data;
+    val = apic->rem_rd_data;
     break;
   case LDR_OFFSET:
-    *val_ptr = apic->log_dst.val;
+    val = apic->log_dst.val;
     break;
   case DFR_OFFSET:
-    *val_ptr = apic->dst_fmt.val;
+    val = apic->dst_fmt.val;
     break;
   case SPURIOUS_INT_VEC_OFFSET:
-    *val_ptr = apic->spurious_int.val;
+    val = apic->spurious_int.val;
     break;
   case ESR_OFFSET:
-    *val_ptr = apic->err_status.val;
+    val = apic->err_status.val;
     break;
   case TMR_LOC_VEC_TBL_OFFSET:
-    *val_ptr = apic->tmr_vec_tbl.val;
+    val = apic->tmr_vec_tbl.val;
     break;
   case LINT0_VEC_TBL_OFFSET:
-    *val_ptr = apic->lint0_vec_tbl.val;
+    val = apic->lint0_vec_tbl.val;
     break;
   case LINT1_VEC_TBL_OFFSET:
-    *val_ptr = apic->lint1_vec_tbl.val;
+    val = apic->lint1_vec_tbl.val;
     break;
   case ERR_VEC_TBL_OFFSET:
-    *val_ptr = apic->err_vec_tbl.val;
+    val = apic->err_vec_tbl.val;
     break;
   case TMR_INIT_CNT_OFFSET:
-    *val_ptr = apic->tmr_init_cnt;
+    val = apic->tmr_init_cnt;
     break;
   case TMR_DIV_CFG_OFFSET:
-    *val_ptr = apic->tmr_div_cfg.val;
+    val = apic->tmr_div_cfg.val;
     break;
 
   case IER_OFFSET0:
-    *val_ptr = *(uint32_t *)(apic->int_en_reg);
+    val = *(uint32_t *)(apic->int_en_reg);
     break;
   case IER_OFFSET1:
-    *val_ptr = *(uint32_t *)(apic->int_en_reg + 4);
+    val = *(uint32_t *)(apic->int_en_reg + 4);
     break;
   case IER_OFFSET2:
-    *val_ptr = *(uint32_t *)(apic->int_en_reg + 8);
+    val = *(uint32_t *)(apic->int_en_reg + 8);
     break;
   case IER_OFFSET3:
-    *val_ptr = *(uint32_t *)(apic->int_en_reg + 12);
+    val = *(uint32_t *)(apic->int_en_reg + 12);
     break;
   case IER_OFFSET4:
-    *val_ptr = *(uint32_t *)(apic->int_en_reg + 16);
+    val = *(uint32_t *)(apic->int_en_reg + 16);
     break;
   case IER_OFFSET5:
-    *val_ptr = *(uint32_t *)(apic->int_en_reg + 20);
+    val = *(uint32_t *)(apic->int_en_reg + 20);
     break;
   case IER_OFFSET6:
-    *val_ptr = *(uint32_t *)(apic->int_en_reg + 24);
+    val = *(uint32_t *)(apic->int_en_reg + 24);
     break;
   case IER_OFFSET7:
-    *val_ptr = *(uint32_t *)(apic->int_en_reg + 28);
+    val = *(uint32_t *)(apic->int_en_reg + 28);
     break;
 
   case ISR_OFFSET0:
-    *val_ptr = *(uint32_t *)(apic->int_svc_reg);
+    val = *(uint32_t *)(apic->int_svc_reg);
     break;
   case ISR_OFFSET1:
-    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 4);
+    val = *(uint32_t *)(apic->int_svc_reg + 4);
     break;
   case ISR_OFFSET2:
-    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 8);
+    val = *(uint32_t *)(apic->int_svc_reg + 8);
     break;
   case ISR_OFFSET3:
-    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 12);
+    val = *(uint32_t *)(apic->int_svc_reg + 12);
     break;
   case ISR_OFFSET4:
-    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 16);
+    val = *(uint32_t *)(apic->int_svc_reg + 16);
     break;
   case ISR_OFFSET5:
-    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 20);
+    val = *(uint32_t *)(apic->int_svc_reg + 20);
     break;
   case ISR_OFFSET6:
-    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 24);
+    val = *(uint32_t *)(apic->int_svc_reg + 24);
     break;
   case ISR_OFFSET7:
-    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 28);
+    val = *(uint32_t *)(apic->int_svc_reg + 28);
     break;
    
   case TRIG_OFFSET0:
-    *val_ptr = *(uint32_t *)(apic->trig_mode_reg);
+    val = *(uint32_t *)(apic->trig_mode_reg);
     break;
   case TRIG_OFFSET1:
-    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 4);
+    val = *(uint32_t *)(apic->trig_mode_reg + 4);
     break;
   case TRIG_OFFSET2:
-    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 8);
+    val = *(uint32_t *)(apic->trig_mode_reg + 8);
     break;
   case TRIG_OFFSET3:
-    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 12);
+    val = *(uint32_t *)(apic->trig_mode_reg + 12);
     break;
   case TRIG_OFFSET4:
-    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 16);
+    val = *(uint32_t *)(apic->trig_mode_reg + 16);
     break;
   case TRIG_OFFSET5:
-    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 20);
+    val = *(uint32_t *)(apic->trig_mode_reg + 20);
     break;
   case TRIG_OFFSET6:
-    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 24);
+    val = *(uint32_t *)(apic->trig_mode_reg + 24);
     break;
   case TRIG_OFFSET7:
-    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 28);
+    val = *(uint32_t *)(apic->trig_mode_reg + 28);
     break;
 
   case IRR_OFFSET0:
-    *val_ptr = *(uint32_t *)(apic->int_req_reg);
+    val = *(uint32_t *)(apic->int_req_reg);
     break;
   case IRR_OFFSET1:
-    *val_ptr = *(uint32_t *)(apic->int_req_reg + 4);
+    val = *(uint32_t *)(apic->int_req_reg + 4);
     break;
   case IRR_OFFSET2:
-    *val_ptr = *(uint32_t *)(apic->int_req_reg + 8);
+    val = *(uint32_t *)(apic->int_req_reg + 8);
     break;
   case IRR_OFFSET3:
-    *val_ptr = *(uint32_t *)(apic->int_req_reg + 12);
+    val = *(uint32_t *)(apic->int_req_reg + 12);
     break;
   case IRR_OFFSET4:
-    *val_ptr = *(uint32_t *)(apic->int_req_reg + 16);
+    val = *(uint32_t *)(apic->int_req_reg + 16);
     break;
   case IRR_OFFSET5:
-    *val_ptr = *(uint32_t *)(apic->int_req_reg + 20);
+    val = *(uint32_t *)(apic->int_req_reg + 20);
     break;
   case IRR_OFFSET6:
-    *val_ptr = *(uint32_t *)(apic->int_req_reg + 24);
+    val = *(uint32_t *)(apic->int_req_reg + 24);
     break;
   case IRR_OFFSET7:
-    *val_ptr = *(uint32_t *)(apic->int_req_reg + 28);
+    val = *(uint32_t *)(apic->int_req_reg + 28);
     break;
   case TMR_CUR_CNT_OFFSET:
-    *val_ptr = apic->tmr_cur_cnt;
+    val = apic->tmr_cur_cnt;
     break;
 
     // We are not going to implement these....
   case THERM_LOC_VEC_TBL_OFFSET:
-    *val_ptr = apic->therm_loc_vec_tbl.val;
+    val = apic->therm_loc_vec_tbl.val;
     break;
   case PERF_CTR_LOC_VEC_TBL_OFFSET:
-    *val_ptr = apic->perf_ctr_loc_vec_tbl.val;
+    val = apic->perf_ctr_loc_vec_tbl.val;
     break;
 
  
 
     // handled registers
   case INT_CMD_LO_OFFSET:    
-    *val_ptr = apic->int_cmd.lo;
+    val = apic->int_cmd.lo;
     break;
   case INT_CMD_HI_OFFSET:
-    *val_ptr = apic->int_cmd.hi;
+    val = apic->int_cmd.hi;
     break;
 
     // handle current timer count
@@ -538,6 +573,28 @@ static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_d
     return -1;
   }
 
+
+  if (length == 1) {
+    uint_t byte_addr = reg_addr & 0x3;
+    uint8_t * val_ptr = (uint8_t *)dst;
+    
+    *val_ptr = *(((uint8_t *)&val) + byte_addr);
+
+  } else if ((length == 2) && 
+            ((reg_addr & 0x3) == 0x3)) {
+    uint_t byte_addr = reg_addr & 0x3;
+    uint16_t * val_ptr = (uint16_t *)dst;
+    *val_ptr = *(((uint16_t *)&val) + byte_addr);
+
+  } else if (length == 4) {
+    uint32_t * val_ptr = (uint32_t *)dst;
+    *val_ptr = val;
+
+  } else {
+    PrintError("Invalid apic read length (%d)\n", length);
+    return -1;
+  }
+
   PrintDebug("Read finished (val=%x)\n", *(uint32_t *)dst);
 
   return length;
@@ -561,7 +618,7 @@ static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_
 
 
   if (length != 4) {
-    PrintError("Invalid apic write length\n");
+    PrintError("Invalid apic write length (%d)\n", length);
     return -1;
   }
 
@@ -595,7 +652,7 @@ static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_
   case TRIG_OFFSET7:
   case PPR_OFFSET:
   case EXT_APIC_FEATURE_OFFSET:
-    PrintError("Attempting to write to read only register\n");
+    PrintError("Attempting to write to read only register %p\n", (void *)reg_addr);
     return -1;
     break;
 
@@ -679,8 +736,12 @@ 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:
   case EOI_OFFSET:
-    // do eoi
+    {
+      // do eoi
+      apic_do_eoi(apic);
+      break;
 
+    }
     // Unhandled Registers
   case EXT_INT_LOC_VEC_TBL_OFFSET0:
   case EXT_INT_LOC_VEC_TBL_OFFSET1:
@@ -707,6 +768,7 @@ static int apic_intr_pending(void * private_data) {
   struct apic_state * apic = (struct apic_state *)dev->private_data;
   int i = 0;
 
+
   // 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++) {
@@ -714,7 +776,6 @@ static int apic_intr_pending(void * private_data) {
       return 1;
     }
   }
-
   return 0;
 }
 
@@ -731,7 +792,7 @@ static int apic_get_intr_number(void * private_data) {
     if (req_major & 0xff) {
       for (j = 7; j >= 0; j--) {
        if ((req_major >> j) == 0x1) {
-         return (i * 32) + j;
+         return (i * 8) + j;
        }
       }
     }
@@ -741,29 +802,17 @@ static int apic_get_intr_number(void * private_data) {
 }
 
 static int apic_raise_intr(void * private_data, int irq) {
-  struct vm_device * dev = (struct vm_device *)private_data;
-  struct apic_state * apic = (struct apic_state *)dev->private_data;
-
-  return activate_apic_irq(apic, irq);
+  return 0;
 }
 
 static int apic_lower_intr(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;
-  int minor_offset = irq & 0x00000007;
-  uchar_t * req_location = apic->int_req_reg + major_offset;
-  uchar_t flag = 0x01 << minor_offset;
-
-  *req_location &= ~flag;
-
   return 0;
 }
 
 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;
-  int major_offset = irq & ~0x00000007;
+  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;
@@ -777,6 +826,13 @@ static int apic_begin_irq(void * private_data, int 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);
+}
+
+
+
 /* 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;
@@ -834,24 +890,28 @@ 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) {
+  if (tmr_ticks < apic->tmr_cur_cnt) {
     apic->tmr_cur_cnt -= tmr_ticks;
   } else {
     tmr_ticks -= apic->tmr_cur_cnt;
     apic->tmr_cur_cnt = 0;
 
     // raise irq
+    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 (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
       PrintError("Could not raise Timer interrupt\n");
     }
+    
+    if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
+      tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
+      apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
+    }
   }
 
-  if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
-    tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
-    apic->tmr_init_cnt = apic->tmr_init_cnt - tmr_ticks;
-  }
+
 }
 
 
@@ -874,7 +934,7 @@ 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_set_intr_controller(dev->vm, &intr_ops, dev);
+  v3_register_intr_controller(dev->vm, &intr_ops, dev);
   v3_add_timer(dev->vm, &timer_ops, dev);
 
   init_apic_state(apic);