/** * ACPI (Advanced Configuration and Power Interface) functionality. */ module hulk.acpi; import hulk.hurl; import hulk.klog; import hulk.memory; import hulk.hurl.a1; struct Acpi { /** * List of ACPI tables. */ private static __gshared Header *[] tables; enum uint XSDT_SIGNATURE = signature("XSDT"); /** * ACPI table header structure. */ public static struct Header { uint signature; uint length; ubyte revision; ubyte checksum; char[6] oemid; char[8] oemtableid; uint oem_revision; uint creator_id; uint creator_revision; } /** * XSDT table. */ static struct XSDT { Header header; /* Table pointers are not ulong-aligned! They begin at offset 36. */ align(4) ulong[1] tables; } static assert(XSDT.tables.offsetof == 36); /** * Initialize ACPI. */ public static void initialize(ulong acpi_xsdt_phys) { Klog.writefln("\a3Initializing ACPI"); /* Map the XSDT header. */ map_table(acpi_xsdt_phys, PAGE_SIZE); const(XSDT) * xsdt = cast(const(XSDT) *)acpi_xsdt_phys; if (xsdt.header.signature != XSDT_SIGNATURE) { Klog.fatal_error("XSDT signature invalid"); return; } /* Map the entire XSDT. */ if (xsdt.header.length > PAGE_SIZE) { map_table(acpi_xsdt_phys, xsdt.header.length); } size_t n_entries = (xsdt.header.length - xsdt.header.sizeof) / xsdt.tables[0].sizeof; Header ** table_pointers = cast(Header **)A1.allocate(n_entries * (Header *).sizeof); tables = table_pointers[0..n_entries]; for (size_t i = 0u; i < n_entries; i++) { ulong address = xsdt.tables[i]; map_table(address, PAGE_SIZE); Header * header = cast(Header *)address; uint length = header.length; if (length > PAGE_SIZE) { map_table(address, length); } tables[i] = header; uint signature = header.signature; Klog.writefln("Found ACPI table '%c%c%c%c' at %p", signature & 0xFFu, (signature >> 8u) & 0xFFu, (signature >> 16u) & 0xFFu, (signature >> 24u) & 0xFFu, address); } } /** * Get pointer to ACPI table by name. * * @param name * Table name. */ public static Header * get_table(string name) { uint signature = signature(name); foreach (table; tables) { if (table.signature == signature) { return table; } } Klog.fatal_error("Could not find requested ACPI table"); return null; } /** * Map an ACPI table. */ private static void map_table(ulong address, ulong length) { Hurl.identity_map_range(address, length, PT_WRITABLE | PT_DISABLE_CACHE | PT_NO_EXECUTE); } /** * Convert table signature from string to 32-bit unsigned integer. */ private static uint signature(string s) { return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); } }