diff --git a/src/hulk/apic.d b/src/hulk/apic.d index 6993265..715cfb2 100644 --- a/src/hulk/apic.d +++ b/src/hulk/apic.d @@ -17,7 +17,7 @@ struct Apic private enum DEFAULT_IO_APIC_ADDRESS = 0xFEC0_0000u; private enum uint PERIODIC_MODE = 0x2_0000u; - private enum ulong IRQ_PIT = 2u; + private enum ulong IRQ_PIT = 0u; private enum ulong IRQ_RTC = 8u; /** @@ -180,6 +180,14 @@ struct Apic case Entry.IO_APIC_INTERRUPT_SOURCE_OVERRIDE: Entry2 * e = cast(Entry2 *)entry; + if (e.global_system_interrupt < Idt.INT_APIC_COUNT) + { + irq_redirects[e.irq_source] = cast(ubyte)e.global_system_interrupt; + } + else + { + Klog.writefln("Warning: unexpected interrupt source override global system interrupt value: %u", e.global_system_interrupt); + } if (DEBUG) { Klog.writefln(" Bus %u IRQ %u GSI %u Flags: 0x%x", @@ -296,8 +304,11 @@ struct Apic ApicRegister data; } + alias ISRHandler = void function(); private static __gshared ApicRegisters * apic_registers; private static __gshared IoApicRegisters * io_apic_registers; + private static __gshared ISRHandler[Idt.INT_APIC_COUNT] irq_handlers; + private static __gshared ubyte[Idt.INT_APIC_COUNT] irq_redirects; /** * Initialize APIC. @@ -306,6 +317,10 @@ struct Apic { Klog.writefln("\a3Initializing APIC"); io_apic_registers = cast(IoApicRegisters *)DEFAULT_IO_APIC_ADDRESS; + for (ubyte i = 0u; i < Idt.INT_APIC_COUNT; i++) + { + irq_redirects[i] = i; + } MADT * madt = cast(MADT *)Acpi.get_table("APIC"); madt.scan(); Klog.writefln("APIC found at %p", apic_registers); @@ -321,21 +336,23 @@ struct Apic apic_registers.lvt_lint[0].value = Idt.INT_APIC_LINT0; apic_registers.lvt_lint[1].value = Idt.INT_APIC_LINT1; /* Enable PIT interrupt. */ - configure_io_apic_irq(IRQ_PIT, Idt.INT_APIC_BASE + IRQ_PIT); + configure_io_apic_irq(IRQ_PIT, &Pit.isr); /* Enable RTC interrupt. */ - configure_io_apic_irq(IRQ_RTC, Idt.INT_APIC_BASE + IRQ_RTC); + configure_io_apic_irq(IRQ_RTC, &Rtc.isr); } /** * Configure routing for an I/O APIC IRQ. */ - private static void configure_io_apic_irq(size_t io_apic_irq, size_t interrupt_id) + private static void configure_io_apic_irq(size_t orig_irq, ISRHandler isr_handler) { - ulong entry = interrupt_id; + size_t io_apic_irq = irq_redirects[orig_irq]; + ulong entry = Idt.INT_APIC_BASE + io_apic_irq; io_apic_registers.address.value = cast(uint)(0x10u + io_apic_irq * 2u); io_apic_registers.data.value = entry & 0xFFFF_FFFFu; io_apic_registers.address.value = cast(uint)(0x10u + io_apic_irq * 2u + 1u); io_apic_registers.data.value = entry >> 32u; + irq_handlers[io_apic_irq] = isr_handler; } /** @@ -351,19 +368,14 @@ struct Apic */ public static void isr(ulong vector) { - switch (vector) + ulong io_apic_irq = vector - Idt.INT_APIC_BASE; + if ((io_apic_irq < Idt.INT_APIC_COUNT) && (irq_handlers[io_apic_irq] != null)) + { + irq_handlers[io_apic_irq](); + } + else { - case Idt.INT_APIC_BASE + IRQ_PIT: - Pit.isr(); - break; - - case Idt.INT_APIC_BASE + IRQ_RTC: - Rtc.isr(); - break; - - default: Klog.writefln("Unhandled APIC ISR %u", vector); - break; } eoi(); }