165 lines
5.0 KiB
D
165 lines
5.0 KiB
D
/**
|
|
* ACPI (Advanced Configuration and Power Interface) functionality.
|
|
*/
|
|
module hulk.acpi;
|
|
|
|
import hulk.hurl;
|
|
import hulk.klog;
|
|
import hulk.memory;
|
|
|
|
struct Acpi
|
|
{
|
|
static uint signature(string s)
|
|
{
|
|
return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
|
|
}
|
|
|
|
enum uint APIC_SIGNATURE = signature("APIC");
|
|
enum uint MCFG_SIGNATURE = signature("MCFG");
|
|
enum uint XSDT_SIGNATURE = signature("XSDT");
|
|
|
|
static align(4) struct Header
|
|
{
|
|
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
|
|
{
|
|
Header header;
|
|
/* Table pointers are not ulong-aligned! They begin at offset 36. */
|
|
align(4) ulong[1] tables;
|
|
}
|
|
|
|
static struct MADT
|
|
{
|
|
static struct Entry
|
|
{
|
|
enum LOCAL_APIC_ADDRESS_OVERRIDE = 5;
|
|
|
|
ubyte type;
|
|
ubyte length;
|
|
}
|
|
|
|
Header header;
|
|
uint local_apic_address;
|
|
uint flags;
|
|
|
|
void initialize()
|
|
{
|
|
apic_address = local_apic_address;
|
|
Klog.writefln("Found 32-bit APIC address: 0x%x", apic_address);
|
|
const(void) * end = cast(const(void) *)(&this) + header.length;
|
|
const(Entry) * entry = cast(const(Entry) *)(cast(ulong)&this + MADT.sizeof);
|
|
while (entry < end)
|
|
{
|
|
entry = cast(const(Entry) *)(cast(size_t)entry + entry.length);
|
|
if (entry.type == Entry.LOCAL_APIC_ADDRESS_OVERRIDE)
|
|
{
|
|
/* Found a 64-bit Local APIC Address Override entry. */
|
|
Klog.writefln("Found 64-bit APIC address: 0x%x", apic_address);
|
|
memcpy(cast(void *)&apic_address, cast(const(void) *)entry + 4u, apic_address.sizeof);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static struct MCFG
|
|
{
|
|
/* PCI Segment Group Memory Area Descriptor. */
|
|
static struct SGMADesc
|
|
{
|
|
uint[2] base_address_a;
|
|
ushort pci_segment_group_number;
|
|
ubyte start_pci_bus_number;
|
|
ubyte end_pci_bus_number;
|
|
uint _reserved;
|
|
|
|
public @property ulong base_address() const
|
|
{
|
|
return base_address_a[0] | (cast(ulong)base_address_a[1] << 32);
|
|
}
|
|
}
|
|
static assert(SGMADesc.sizeof == 16);
|
|
static assert(SGMADesc.alignof == 4);
|
|
|
|
Header header;
|
|
uint[2] _reserved;
|
|
SGMADesc[0] sgma_descs;
|
|
|
|
void initialize()
|
|
{
|
|
Klog.writefln("MCFG length = %u", header.length);
|
|
size_t n_sgma_descs = (header.length - MCFG.sgma_descs.offsetof) / MCFG.SGMADesc.sizeof;
|
|
Klog.writefln("# SGMA descriptors = %u", (header.length - MCFG.sgma_descs.offsetof) / MCFG.SGMADesc.sizeof);
|
|
for (size_t i = 0; i < n_sgma_descs; i++)
|
|
{
|
|
Klog.writefln("SGMA %u: SG %u; Bus %u-%u; addr %p",
|
|
i,
|
|
sgma_descs[i].pci_segment_group_number,
|
|
sgma_descs[i].start_pci_bus_number,
|
|
sgma_descs[i].end_pci_bus_number,
|
|
sgma_descs[i].base_address);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static __gshared ulong apic_address;
|
|
|
|
public static void initialize(ulong acpi_xsdt_phys)
|
|
{
|
|
/* 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.writef("XSDT signature invalid\n");
|
|
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;
|
|
for (size_t i = 0u; i < n_entries; i++)
|
|
{
|
|
ulong address = xsdt.tables[i];
|
|
map_table(address, PAGE_SIZE);
|
|
const(Header) * header = cast(const(Header) *)address;
|
|
uint length = header.length;
|
|
if (length > PAGE_SIZE)
|
|
{
|
|
map_table(address, length);
|
|
}
|
|
uint signature = header.signature;
|
|
Klog.writefln("Found ACPI table %08x (%c%c%c%c)",
|
|
signature,
|
|
signature & 0xFFu,
|
|
(signature >> 8u) & 0xFFu,
|
|
(signature >> 16u) & 0xFFu,
|
|
(signature >> 24u) & 0xFFu);
|
|
if (signature == APIC_SIGNATURE)
|
|
{
|
|
(cast(MADT *)address).initialize();
|
|
}
|
|
else if (signature == MCFG_SIGNATURE)
|
|
{
|
|
(cast(MCFG *)address).initialize();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void map_table(ulong address, ulong length)
|
|
{
|
|
Hurl.identity_map_range(address, length, PT_DISABLE_CACHE | PT_NO_EXECUTE);
|
|
}
|
|
}
|