diff options
Diffstat (limited to 'hw/ioapic.c')
-rw-r--r-- | hw/ioapic.c | 177 |
1 files changed, 107 insertions, 70 deletions
diff --git a/hw/ioapic.c b/hw/ioapic.c index fb3d17329a..569327d1e9 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -39,20 +39,48 @@ #define MAX_IOAPICS 1 -#define IOAPIC_LVT_MASKED (1 << 16) -#define IOAPIC_LVT_REMOTE_IRR (1 << 14) +#define IOAPIC_VERSION 0x11 -#define IOAPIC_TRIGGER_EDGE 0 -#define IOAPIC_TRIGGER_LEVEL 1 +#define IOAPIC_LVT_DEST_SHIFT 56 +#define IOAPIC_LVT_MASKED_SHIFT 16 +#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15 +#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14 +#define IOAPIC_LVT_POLARITY_SHIFT 13 +#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12 +#define IOAPIC_LVT_DEST_MODE_SHIFT 11 +#define IOAPIC_LVT_DELIV_MODE_SHIFT 8 + +#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT) +#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT) + +#define IOAPIC_TRIGGER_EDGE 0 +#define IOAPIC_TRIGGER_LEVEL 1 /*io{apic,sapic} delivery mode*/ -#define IOAPIC_DM_FIXED 0x0 -#define IOAPIC_DM_LOWEST_PRIORITY 0x1 -#define IOAPIC_DM_PMI 0x2 -#define IOAPIC_DM_NMI 0x4 -#define IOAPIC_DM_INIT 0x5 -#define IOAPIC_DM_SIPI 0x5 -#define IOAPIC_DM_EXTINT 0x7 +#define IOAPIC_DM_FIXED 0x0 +#define IOAPIC_DM_LOWEST_PRIORITY 0x1 +#define IOAPIC_DM_PMI 0x2 +#define IOAPIC_DM_NMI 0x4 +#define IOAPIC_DM_INIT 0x5 +#define IOAPIC_DM_SIPI 0x6 +#define IOAPIC_DM_EXTINT 0x7 +#define IOAPIC_DM_MASK 0x7 + +#define IOAPIC_VECTOR_MASK 0xff + +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 + +#define IOAPIC_REG_ID 0x00 +#define IOAPIC_REG_VER 0x01 +#define IOAPIC_REG_ARB 0x02 +#define IOAPIC_REG_REDTBL_BASE 0x10 +#define IOAPIC_ID 0x00 + +#define IOAPIC_ID_SHIFT 24 +#define IOAPIC_ID_MASK 0xf + +#define IOAPIC_VER_ENTRIES_SHIFT 16 typedef struct IOAPICState IOAPICState; @@ -60,7 +88,6 @@ struct IOAPICState { SysBusDevice busdev; uint8_t id; uint8_t ioregsel; - uint32_t irr; uint64_t ioredtbl[IOAPIC_NUM_PINS]; }; @@ -84,21 +111,22 @@ static void ioapic_service(IOAPICState *s) if (s->irr & mask) { entry = s->ioredtbl[i]; if (!(entry & IOAPIC_LVT_MASKED)) { - trig_mode = ((entry >> 15) & 1); - dest = entry >> 56; - dest_mode = (entry >> 11) & 1; - delivery_mode = (entry >> 8) & 7; - polarity = (entry >> 13) & 1; + trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); + dest = entry >> IOAPIC_LVT_DEST_SHIFT; + dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; + delivery_mode = + (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; + polarity = (entry >> IOAPIC_LVT_POLARITY_SHIFT) & 1; if (trig_mode == IOAPIC_TRIGGER_EDGE) { s->irr &= ~mask; } else { s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; } - if (delivery_mode == IOAPIC_DM_EXTINT) + if (delivery_mode == IOAPIC_DM_EXTINT) { vector = pic_read_irq(isa_pic); - else - vector = entry & 0xff; - + } else { + vector = entry & IOAPIC_VECTOR_MASK; + } apic_deliver_irq(dest, dest_mode, delivery_mode, vector, polarity, trig_mode); } @@ -114,15 +142,16 @@ static void ioapic_set_irq(void *opaque, int vector, int level) * to GSI 2. GSI maps to ioapic 1-1. This is not * the cleanest way of doing it but it should work. */ - DPRINTF("%s: %s vec %x\n", __func__, level? "raise" : "lower", vector); - if (vector == 0) + DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector); + if (vector == 0) { vector = 2; - + } if (vector >= 0 && vector < IOAPIC_NUM_PINS) { uint32_t mask = 1 << vector; uint64_t entry = s->ioredtbl[vector]; - if ((entry >> 15) & 1) { + if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) == + IOAPIC_TRIGGER_LEVEL) { /* level triggered */ if (level) { s->irr |= mask; @@ -153,7 +182,8 @@ void ioapic_eoi_broadcast(int vector) } for (n = 0; n < IOAPIC_NUM_PINS; n++) { entry = s->ioredtbl[n]; - if ((entry & IOAPIC_LVT_REMOTE_IRR) && (entry & 0xff) == vector) { + if ((entry & IOAPIC_LVT_REMOTE_IRR) + && (entry & IOAPIC_VECTOR_MASK) == vector) { s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR; if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) { ioapic_service(s); @@ -169,65 +199,71 @@ static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr) int index; uint32_t val = 0; - addr &= 0xff; - if (addr == 0x00) { + switch (addr & 0xff) { + case IOAPIC_IOREGSEL: val = s->ioregsel; - } else if (addr == 0x10) { + break; + case IOAPIC_IOWIN: switch (s->ioregsel) { - case 0x00: - val = s->id << 24; - break; - case 0x01: - val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */ - break; - case 0x02: - val = 0; - break; - default: - index = (s->ioregsel - 0x10) >> 1; - if (index >= 0 && index < IOAPIC_NUM_PINS) { - if (s->ioregsel & 1) - val = s->ioredtbl[index] >> 32; - else - val = s->ioredtbl[index] & 0xffffffff; + case IOAPIC_REG_ID: + val = s->id << IOAPIC_ID_SHIFT; + break; + case IOAPIC_REG_VER: + val = IOAPIC_VERSION | + ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT); + break; + case IOAPIC_REG_ARB: + val = 0; + break; + default: + index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; + if (index >= 0 && index < IOAPIC_NUM_PINS) { + if (s->ioregsel & 1) { + val = s->ioredtbl[index] >> 32; + } else { + val = s->ioredtbl[index] & 0xffffffff; } + } } DPRINTF("read: %08x = %08x\n", s->ioregsel, val); + break; } return val; } -static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void +ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { IOAPICState *s = opaque; int index; - addr &= 0xff; - if (addr == 0x00) { + switch (addr & 0xff) { + case IOAPIC_IOREGSEL: s->ioregsel = val; - return; - } else if (addr == 0x10) { + break; + case IOAPIC_IOWIN: DPRINTF("write: %08x = %08x\n", s->ioregsel, val); switch (s->ioregsel) { - case 0x00: - s->id = (val >> 24) & 0xff; - return; - case 0x01: - case 0x02: - return; - default: - index = (s->ioregsel - 0x10) >> 1; - if (index >= 0 && index < IOAPIC_NUM_PINS) { - if (s->ioregsel & 1) { - s->ioredtbl[index] &= 0xffffffff; - s->ioredtbl[index] |= (uint64_t)val << 32; - } else { - s->ioredtbl[index] &= ~0xffffffffULL; - s->ioredtbl[index] |= val; - } - ioapic_service(s); + case IOAPIC_REG_ID: + s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK; + break; + case IOAPIC_REG_VER: + case IOAPIC_REG_ARB: + break; + default: + index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; + if (index >= 0 && index < IOAPIC_NUM_PINS) { + if (s->ioregsel & 1) { + s->ioredtbl[index] &= 0xffffffff; + s->ioredtbl[index] |= (uint64_t)val << 32; + } else { + s->ioredtbl[index] &= ~0xffffffffULL; + s->ioredtbl[index] |= val; } + ioapic_service(s); + } } + break; } } @@ -248,7 +284,7 @@ static const VMStateDescription vmstate_ioapic = { .post_load = ioapic_post_load, .minimum_version_id = 1, .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(id, IOAPICState), VMSTATE_UINT8(ioregsel, IOAPICState), VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */ @@ -266,8 +302,9 @@ static void ioapic_reset(DeviceState *d) s->id = 0; s->ioregsel = 0; s->irr = 0; - for(i = 0; i < IOAPIC_NUM_PINS; i++) - s->ioredtbl[i] = 1 << 16; /* mask LVT */ + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT; + } } static CPUReadMemoryFunc * const ioapic_mem_read[3] = { |