127 lines
3.3 KiB
D
127 lines
3.3 KiB
D
/**
|
|
* 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);
|
|
}
|
|
}
|