/** * ACPI (Advanced Configuration and Power Interface) functionality. */ module hulk.acpi; import hulk.hurl; import hulk.klog; import hulk.memory; struct acpi { enum uint APIC_SIGNATURE = 0x43495041u; enum uint XSDT_SIGNATURE = 0x54445358u; static struct XsdtHeader { uint signature; uint length; ubyte revision; ubyte checksum; char[6] oemid; ulong oemtableid; uint oem_revision; uint creator_id; uint creator_revision; } static struct Xsdt { XsdtHeader header; uint _pad; ulong[0] tables; } static 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; } static struct MadtEntry { ubyte type; ubyte length; } public static __gshared ulong apic_address; public static void initialize(ulong acpi_xsdt_phys) { /* Map the XSDT header. */ hurl.identity_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.identity_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.identity_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.identity_map_range(address, madt_header.length, 0u); apic_address = madt_header.local_apic_address; klog.writefln("Found 32-bit APIC address: 0x%x", 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); klog.writefln("Found 64-bit APIC address: 0x%x", apic_address); } } } }