X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/9d861fa595c93f22d1d55b723a691531c36c9672..93f43c48887a4e5b651965955eedd8e838e53db3:/hw/apic.c diff --git a/hw/apic.c b/hw/apic.c index a5a53fb963..8289eef5b8 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -18,10 +18,12 @@ */ #include "hw.h" #include "apic.h" +#include "ioapic.h" #include "qemu-timer.h" #include "host-utils.h" #include "sysbus.h" #include "trace.h" +#include "pc.h" /* APIC Local Vector Table */ #define APIC_LVT_TIMER 0 @@ -57,7 +59,8 @@ #define ESR_ILLEGAL_ADDRESS (1 << 7) -#define APIC_SV_ENABLE (1 << 8) +#define APIC_SV_DIRECTED_IO (1<<12) +#define APIC_SV_ENABLE (1<<8) #define MAX_APICS 255 #define MAX_APIC_WORDS 8 @@ -78,6 +81,7 @@ typedef struct APICState APICState; struct APICState { SysBusDevice busdev; + MemoryRegion io_memory; void *cpu_env; uint32_t apicbase; uint8_t id; @@ -220,8 +224,7 @@ void apic_deliver_pic_intr(DeviceState *d, int level) } static void apic_bus_deliver(const uint32_t *deliver_bitmask, - uint8_t delivery_mode, - uint8_t vector_num, uint8_t polarity, + uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) { APICState *apic_iter; @@ -278,18 +281,16 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, apic_set_irq(apic_iter, vector_num, trigger_mode) ); } -void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, - uint8_t delivery_mode, uint8_t vector_num, - uint8_t polarity, uint8_t trigger_mode) +void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, + uint8_t vector_num, uint8_t trigger_mode) { uint32_t deliver_bitmask[MAX_APIC_WORDS]; trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num, - polarity, trigger_mode); + trigger_mode); apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); - apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity, - trigger_mode); + apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode); } void cpu_set_apic_base(DeviceState *d, uint64_t val) @@ -370,19 +371,39 @@ static int apic_get_arb_pri(APICState *s) return 0; } -/* signal the CPU if an irq is pending */ -static void apic_update_irq(APICState *s) + +/* + * <0 - low prio interrupt, + * 0 - no interrupt, + * >0 - interrupt number + */ +static int apic_irq_pending(APICState *s) { int irrv, ppr; - if (!(s->spurious_vec & APIC_SV_ENABLE)) - return; irrv = get_highest_priority_int(s->irr); - if (irrv < 0) - return; + if (irrv < 0) { + return 0; + } ppr = apic_get_ppr(s); - if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) + if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) { + return -1; + } + + return irrv; +} + +/* signal the CPU if an irq is pending */ +static void apic_update_irq(APICState *s) +{ + if (!(s->spurious_vec & APIC_SV_ENABLE)) { return; - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + } + if (apic_irq_pending(s) > 0) { + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + } else if (apic_accept_pic_intr(&s->busdev.qdev) && + pic_get_output(isa_pic)) { + apic_deliver_pic_intr(&s->busdev.qdev, 1); + } } void apic_reset_irq_delivered(void) @@ -420,8 +441,9 @@ static void apic_eoi(APICState *s) if (isrv < 0) return; reset_bit(s->isr, isrv); - /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to - set the remote IRR bit for level triggered interrupts. */ + if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) { + ioapic_eoi_broadcast(isrv); + } apic_update_irq(s); } @@ -528,7 +550,7 @@ void apic_sipi(DeviceState *d) static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, - uint8_t polarity, uint8_t trigger_mode) + uint8_t trigger_mode) { APICState *s = DO_UPCAST(APICState, busdev.qdev, d); uint32_t deliver_bitmask[MAX_APIC_WORDS]; @@ -571,8 +593,7 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode, return; } - apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity, - trigger_mode); + apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode); } int apic_get_interrupt(DeviceState *d) @@ -587,12 +608,13 @@ int apic_get_interrupt(DeviceState *d) if (!(s->spurious_vec & APIC_SV_ENABLE)) return -1; - /* XXX: spurious IRQ handling */ - intno = get_highest_priority_int(s->irr); - if (intno < 0) + intno = apic_irq_pending(s); + + if (intno == 0) { return -1; - if (s->tpr && intno <= s->tpr) + } else if (intno < 0) { return s->spurious_vec & 0xff; + } reset_bit(s->irr, intno); set_bit(s->isr, intno); apic_update_irq(s); @@ -620,7 +642,7 @@ static uint32_t apic_get_current_count(APICState *s) { int64_t d; uint32_t val; - d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> + d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >> s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { /* periodic */ @@ -765,7 +787,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) return val; } -static void apic_send_msi(target_phys_addr_t addr, uint32 data) +static void apic_send_msi(target_phys_addr_t addr, uint32_t data) { uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; @@ -773,7 +795,7 @@ static void apic_send_msi(target_phys_addr_t addr, uint32 data) uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7; /* XXX: Ignore redirection hint. */ - apic_deliver_irq(dest, dest_mode, delivery, vector, 0, trigger_mode); + apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode); } static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -834,7 +856,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) s->icr[0] = val; apic_deliver(d, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1, (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff), - (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1); + (s->icr[0] >> 15) & 1); break; case 0x31: s->icr[1] = val; @@ -844,12 +866,12 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) int n = index - 0x32; s->lvt[n] = val; if (n == APIC_LVT_TIMER) - apic_timer_update(s, qemu_get_clock(vm_clock)); + apic_timer_update(s, qemu_get_clock_ns(vm_clock)); } break; case 0x38: s->initial_count = val; - s->initial_count_load_time = qemu_get_clock(vm_clock); + s->initial_count_load_time = qemu_get_clock_ns(vm_clock); apic_timer_update(s, s->initial_count_load_time); break; case 0x39: @@ -958,33 +980,27 @@ static void apic_reset(DeviceState *d) } } -static CPUReadMemoryFunc * const apic_mem_read[3] = { - apic_mem_readb, - apic_mem_readw, - apic_mem_readl, -}; - -static CPUWriteMemoryFunc * const apic_mem_write[3] = { - apic_mem_writeb, - apic_mem_writew, - apic_mem_writel, +static const MemoryRegionOps apic_io_ops = { + .old_mmio = { + .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, }, + .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, }; static int apic_init1(SysBusDevice *dev) { APICState *s = FROM_SYSBUS(APICState, dev); - int apic_io_memory; static int last_apic_idx; if (last_apic_idx >= MAX_APICS) { return -1; } - apic_io_memory = cpu_register_io_memory(apic_mem_read, - apic_mem_write, NULL, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, MSI_ADDR_SIZE, apic_io_memory); + memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic", + MSI_ADDR_SIZE); + sysbus_init_mmio_region(dev, &s->io_memory); - s->timer = qemu_new_timer(vm_clock, apic_timer, s); + s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s); s->idx = last_apic_idx++; local_apics[s->idx] = s; return 0;