#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;
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;
}
// 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;
}
// 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;
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;
}
}
+
+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;
// 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");
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);
}
- 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;
// 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
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;
if (length != 4) {
- PrintError("Invalid apic write length\n");
+ PrintError("Invalid apic write length (%d)\n", length);
return -1;
}
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;
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:
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++) {
return 1;
}
}
-
return 0;
}
if (req_major & 0xff) {
for (j = 7; j >= 0; j--) {
if ((req_major >> j) == 0x1) {
- return (i * 32) + j;
+ return (i * 8) + j;
}
}
}
}
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;
+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;
}
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;
- }
+
}
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);