diff --git a/src/hulk/apic.d b/src/hulk/apic.d index e0a7947..6993265 100644 --- a/src/hulk/apic.d +++ b/src/hulk/apic.d @@ -13,6 +13,8 @@ import hulk.memory; struct Apic { + private enum DEBUG = false; + private enum DEFAULT_IO_APIC_ADDRESS = 0xFEC0_0000u; private enum uint PERIODIC_MODE = 0x2_0000u; private enum ulong IRQ_PIT = 2u; @@ -28,16 +30,112 @@ struct Apic */ static struct Entry { + enum PROCESSOR_LOCAL_APIC = 0; + enum IO_APIC = 1; + enum IO_APIC_INTERRUPT_SOURCE_OVERRIDE = 2; + enum IO_APIC_NMI_SOURCE = 3; + enum LOCAL_APIC_NMI = 4; enum LOCAL_APIC_ADDRESS_OVERRIDE = 5; + enum PROCESSOR_LOCAL_X2APIC = 9; ubyte type; ubyte length; } + /** + * Processor Local APIC. + */ + static struct Entry0 + { + Entry header; + ubyte acpi_processor_id; + ubyte apic_id; + uint flags; + } + static assert(Entry0.sizeof == 8); + + /** + * I/O APIC. + */ + static struct Entry1 + { + Entry header; + ubyte io_apic_id; + ubyte _reserved; + uint io_apic_address; + uint global_system_interrupt_base; + } + static assert(Entry1.sizeof == 12); + + /** + * IO/APIC Interrupt Source Override. + */ + static struct Entry2 + { + Entry header; + ubyte bus_source; + ubyte irq_source; + uint global_system_interrupt; + ushort flags; + ushort _reserved; + } + static assert(Entry2.sizeof == 12); + + /** + * IO/APIC Non-maskable interrupt source. + */ + static struct Entry3 + { + Entry header; + ubyte nmi_source; + ubyte _reserved; + ushort flags; + ubyte[4] global_system_interrupt; + } + static assert(Entry3.sizeof == 10); + + /** + * Local APIC Non-maskable interrupts. + */ + static struct Entry4 + { + Entry header; + ubyte acpi_processor_id; + ubyte[2] flags; + ubyte lint_nr; + } + static assert(Entry4.sizeof == 6); + + /** + * Local APIC Address Override. + */ + static struct Entry5 + { + Entry header; + ushort _reserved; + ubyte[8] local_apic_address; + } + static assert(Entry5.sizeof == 12); + + /** + * Processor Local x2APIC. + */ + static struct Entry9 + { + Entry header; + ushort _reserved; + uint local_x2apic_id; + uint flags; + uint acpi_id; + } + static assert(Entry9.sizeof == 16); + Acpi.Header header; uint local_apic_address; uint flags; + static assert(MADT.sizeof == 0x2C); + /** * Scan the MADT table. */ @@ -46,14 +144,99 @@ struct Apic apic_registers = cast(ApicRegisters *)local_apic_address; const(void) * end = cast(const(void) *)(&this) + header.length; const(Entry) * entry = cast(const(Entry) *)(cast(ulong)&this + MADT.sizeof); + bool first_io_apic = true; + size_t n_cpus = 0u; while (entry < end) { - entry = cast(const(Entry) *)(cast(size_t)entry + entry.length); - if (entry.type == Entry.LOCAL_APIC_ADDRESS_OVERRIDE) + if (DEBUG) { - /* Found a 64-bit Local APIC Address Override entry. */ - memcpy(cast(void *)&apic_registers, cast(const(void) *)entry + 4u, apic_registers.sizeof); + Klog.writefln("MADT entry type %u, length %u", entry.type, entry.length); } + switch (entry.type) + { + case Entry.PROCESSOR_LOCAL_APIC: + Entry0 * e = cast(Entry0 *)entry; + n_cpus++; + if (DEBUG) + { + Klog.writefln(" ACPI processor ID: %u, APIC ID: %u, Flags: 0x%x", + e.acpi_processor_id, e.apic_id, e.flags); + } + break; + + case Entry.IO_APIC: + Entry1 * e = cast(Entry1 *)entry; + if (first_io_apic) + { + io_apic_registers = cast(IoApicRegisters *)e.io_apic_address; + first_io_apic = false; + } + if (DEBUG) + { + Klog.writefln(" I/O APIC ID: %u, I/O APIC Address: 0x%x, GSIB: %u", + e.io_apic_id, e.io_apic_address, e.global_system_interrupt_base); + } + break; + + case Entry.IO_APIC_INTERRUPT_SOURCE_OVERRIDE: + Entry2 * e = cast(Entry2 *)entry; + if (DEBUG) + { + Klog.writefln(" Bus %u IRQ %u GSI %u Flags: 0x%x", + e.bus_source, e.irq_source, e.global_system_interrupt, e.flags); + } + break; + + case Entry.IO_APIC_NMI_SOURCE: + Entry3 * e = cast(Entry3 *)entry; + if (DEBUG) + { + uint global_system_interrupt; + memcpy(&global_system_interrupt, &e.global_system_interrupt, 4u); + Klog.writefln(" NMI Source: %u, Flags: 0x%x, GSI: %u", + e.nmi_source, e.flags, global_system_interrupt); + } + break; + + case Entry.LOCAL_APIC_NMI: + Entry4 * e = cast(Entry4 *)entry; + if (DEBUG) + { + ushort flags; + memcpy(&flags, &e.flags, 2u); + Klog.writefln(" ACPI Processor ID: %u, Flags: 0x%x, LINT#: %u", + e.acpi_processor_id, flags, e.lint_nr); + } + break; + + case Entry.LOCAL_APIC_ADDRESS_OVERRIDE: + Entry5 * e = cast(Entry5 *)entry; + if (DEBUG) + { + memcpy(&apic_registers, &e.local_apic_address, 8u); + Klog.writefln(" Local APIC Address: 0x%x", apic_registers); + } + break; + + case Entry.PROCESSOR_LOCAL_X2APIC: + Entry9 * e = cast(Entry9 *)entry; + if (DEBUG) + { + Klog.writefln(" x2APIC ID: %u, Flags: 0x%x, ACPI ID: %u", + e.local_x2apic_id, e.flags, e.acpi_id); + } + break; + + default: + break; + } + + /* Move to next entry. */ + entry = cast(const(Entry) *)(cast(size_t)entry + entry.length); + } + if (n_cpus > 0u) + { + Klog.writefln("%u CPU(s) found", n_cpus); } } } @@ -122,7 +305,7 @@ struct Apic public static void initialize() { Klog.writefln("\a3Initializing APIC"); - io_apic_registers = cast(IoApicRegisters *)0xFEC0_0000u; + io_apic_registers = cast(IoApicRegisters *)DEFAULT_IO_APIC_ADDRESS; MADT * madt = cast(MADT *)Acpi.get_table("APIC"); madt.scan(); Klog.writefln("APIC found at %p", apic_registers);