X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fapic.c;h=77f727bf9b21cab91ec1d64130239f4e74170c35;hb=5f8e40759876e33eb20e4868c51a0773464e2770;hp=41f4daa17534054373bf807b8cb56e7a26d8987a;hpb=7bb4a918835892e9071ffbdef1ea8e57f9a12950;p=palacios-OLD.git diff --git a/palacios/src/devices/apic.c b/palacios/src/devices/apic.c index 41f4daa..77f727b 100644 --- a/palacios/src/devices/apic.c +++ b/palacios/src/devices/apic.c @@ -24,6 +24,12 @@ #include +#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; } } } @@ -751,7 +812,7 @@ static int apic_lower_intr(void * private_data, int 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; - 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; @@ -765,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; @@ -822,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; - } + }