diff --git a/src/hulk/acpi.d b/src/hulk/acpi.d new file mode 100644 index 0000000..487f611 --- /dev/null +++ b/src/hulk/acpi.d @@ -0,0 +1,101 @@ +/** + * ACPI (Advanced Configuration and Power Interface) functionality. + */ +module hulk.acpi; + +import hulk.klog; +import hulk.hurl; +import hulk.klog; +import hos.memory; + +struct acpi +{ + enum uint APIC_SIGNATURE = 0x43495041u; + enum uint XSDT_SIGNATURE = 0x54445358u; + + struct XsdtHeader + { + uint signature; + uint length; + ubyte revision; + ubyte checksum; + char[6] oemid; + ulong oemtableid; + uint oem_revision; + uint creator_id; + uint creator_revision; + }; + + struct Xsdt + { + XsdtHeader header; + uint _pad; + ulong[0] tables; + } + + struct MadtHeader + { + uint signature; + uint length; + ubyte revision; + ubyte checksum; + char[6] oemid; + ulong oemtableid; + uint oem_revision; + uint creator_id; + uint creator_revision; + uint local_apic_address; + uint flags; + } + + struct MadtEntry + { + ubyte type; + ubyte length; + } + + private static ulong apic_address; + + public static void initialize(ulong acpi_xsdt_phys) + { + /* Map the XSDT header. */ + Hurl.map_range(acpi_xsdt_phys, Xsdt.sizeof, 0u); + const(Xsdt) * xsdt = cast(const(Xsdt) *)acpi_xsdt_phys; + if (xsdt.header.signature != XSDT_SIGNATURE) + { + klog.writef("XSDT signature invalid\n"); + return; + } + /* Map the entire XSDT. */ + Hurl.map_range(acpi_xsdt_phys, xsdt.header.length, 0u); + size_t n_entries = (xsdt.header.length - xsdt.header.sizeof) / xsdt.tables[0].sizeof; + for (size_t i = 0u; i < n_entries; i++) + { + ulong address = xsdt.tables[i]; + Hurl.map_range(address, 4u, 0u); + uint signature = *cast(const(uint) *)address; + if (signature == APIC_SIGNATURE) + { + parse_apic_table(address); + } + } + } + + private static parse_apic_table(ulong address) + { + const(MadtHeader) * madt_header = cast(const(MadtHeader) *)address; + Hurl.map_range(address, madt_header.length, 0u); + apic_address = madt_header.local_apic_address; + const(void) * madt_end = cast(const(void) *)(address + madt_header.length); + const(MadtEntry) * madt_entry = cast(const(MadtEntry) *)(address + 0x2Cu); + while (madt_entry < madt_end) + { + madt_entry = cast(const(MadtEntry) *)(cast(size_t)madt_entry + madt_entry.length); + if (madt_entry.type == 5u) + { + /* Found a 64-bit Local APIC Address Override entry. */ + memcpy(cast(void *)&apic_address, cast(const(void) *)madt_entry + 4u, 8u); + } + } + } +} diff --git a/src/hulk/hulk.d b/src/hulk/hulk.d index eab7d4b..3dca180 100644 --- a/src/hulk/hulk.d +++ b/src/hulk/hulk.d @@ -18,6 +18,7 @@ import hulk.idt; import hos.cpu; import ldc.llvmasm; import hulk.pic; +import hulk.acpi; extern extern(C) __gshared ubyte _hulk_total_size; @@ -49,6 +50,7 @@ void hulk_start() hippo.initialize(&hulk_header); pci.initialize(); pic.initialize(); + acpi.initialize(hulk_header.bootinfo.acpi_xsdt_phys); sti(); for (;;)