Rework scanning MADT table entries

Get I/O APIC address from MADT entry.
Add DEBUG flag for APIC.
Show number of CPUs found.
This commit is contained in:
Josh Holtrop 2023-10-31 13:29:23 -04:00
parent c0a00b528e
commit 7264a31ff3

View File

@ -13,6 +13,8 @@ import hulk.memory;
struct Apic struct Apic
{ {
private enum DEBUG = false;
private enum DEFAULT_IO_APIC_ADDRESS = 0xFEC0_0000u;
private enum uint PERIODIC_MODE = 0x2_0000u; private enum uint PERIODIC_MODE = 0x2_0000u;
private enum ulong IRQ_PIT = 2u; private enum ulong IRQ_PIT = 2u;
@ -28,16 +30,112 @@ struct Apic
*/ */
static struct Entry static struct Entry
{ {
enum PROCESSOR_LOCAL_APIC = 0;
enum IO_APIC = 1;
enum IO_APIC_INTERRUPT_SOURCE_OVERRIDE = 2;
enum IO_APIC_NMI_SOURCE = 3;
enum LOCAL_APIC_NMI = 4;
enum LOCAL_APIC_ADDRESS_OVERRIDE = 5; enum LOCAL_APIC_ADDRESS_OVERRIDE = 5;
enum PROCESSOR_LOCAL_X2APIC = 9;
ubyte type; ubyte type;
ubyte length; ubyte length;
} }
/**
* Processor Local APIC.
*/
static struct Entry0
{
Entry header;
ubyte acpi_processor_id;
ubyte apic_id;
uint flags;
}
static assert(Entry0.sizeof == 8);
/**
* I/O APIC.
*/
static struct Entry1
{
Entry header;
ubyte io_apic_id;
ubyte _reserved;
uint io_apic_address;
uint global_system_interrupt_base;
}
static assert(Entry1.sizeof == 12);
/**
* IO/APIC Interrupt Source Override.
*/
static struct Entry2
{
Entry header;
ubyte bus_source;
ubyte irq_source;
uint global_system_interrupt;
ushort flags;
ushort _reserved;
}
static assert(Entry2.sizeof == 12);
/**
* IO/APIC Non-maskable interrupt source.
*/
static struct Entry3
{
Entry header;
ubyte nmi_source;
ubyte _reserved;
ushort flags;
ubyte[4] global_system_interrupt;
}
static assert(Entry3.sizeof == 10);
/**
* Local APIC Non-maskable interrupts.
*/
static struct Entry4
{
Entry header;
ubyte acpi_processor_id;
ubyte[2] flags;
ubyte lint_nr;
}
static assert(Entry4.sizeof == 6);
/**
* Local APIC Address Override.
*/
static struct Entry5
{
Entry header;
ushort _reserved;
ubyte[8] local_apic_address;
}
static assert(Entry5.sizeof == 12);
/**
* Processor Local x2APIC.
*/
static struct Entry9
{
Entry header;
ushort _reserved;
uint local_x2apic_id;
uint flags;
uint acpi_id;
}
static assert(Entry9.sizeof == 16);
Acpi.Header header; Acpi.Header header;
uint local_apic_address; uint local_apic_address;
uint flags; uint flags;
static assert(MADT.sizeof == 0x2C);
/** /**
* Scan the MADT table. * Scan the MADT table.
*/ */
@ -46,14 +144,99 @@ struct Apic
apic_registers = cast(ApicRegisters *)local_apic_address; apic_registers = cast(ApicRegisters *)local_apic_address;
const(void) * end = cast(const(void) *)(&this) + header.length; const(void) * end = cast(const(void) *)(&this) + header.length;
const(Entry) * entry = cast(const(Entry) *)(cast(ulong)&this + MADT.sizeof); const(Entry) * entry = cast(const(Entry) *)(cast(ulong)&this + MADT.sizeof);
bool first_io_apic = true;
size_t n_cpus = 0u;
while (entry < end) while (entry < end)
{ {
entry = cast(const(Entry) *)(cast(size_t)entry + entry.length); if (DEBUG)
if (entry.type == Entry.LOCAL_APIC_ADDRESS_OVERRIDE)
{ {
/* Found a 64-bit Local APIC Address Override entry. */ Klog.writefln("MADT entry type %u, length %u", entry.type, entry.length);
memcpy(cast(void *)&apic_registers, cast(const(void) *)entry + 4u, apic_registers.sizeof);
} }
switch (entry.type)
{
case Entry.PROCESSOR_LOCAL_APIC:
Entry0 * e = cast(Entry0 *)entry;
n_cpus++;
if (DEBUG)
{
Klog.writefln(" ACPI processor ID: %u, APIC ID: %u, Flags: 0x%x",
e.acpi_processor_id, e.apic_id, e.flags);
}
break;
case Entry.IO_APIC:
Entry1 * e = cast(Entry1 *)entry;
if (first_io_apic)
{
io_apic_registers = cast(IoApicRegisters *)e.io_apic_address;
first_io_apic = false;
}
if (DEBUG)
{
Klog.writefln(" I/O APIC ID: %u, I/O APIC Address: 0x%x, GSIB: %u",
e.io_apic_id, e.io_apic_address, e.global_system_interrupt_base);
}
break;
case Entry.IO_APIC_INTERRUPT_SOURCE_OVERRIDE:
Entry2 * e = cast(Entry2 *)entry;
if (DEBUG)
{
Klog.writefln(" Bus %u IRQ %u GSI %u Flags: 0x%x",
e.bus_source, e.irq_source, e.global_system_interrupt, e.flags);
}
break;
case Entry.IO_APIC_NMI_SOURCE:
Entry3 * e = cast(Entry3 *)entry;
if (DEBUG)
{
uint global_system_interrupt;
memcpy(&global_system_interrupt, &e.global_system_interrupt, 4u);
Klog.writefln(" NMI Source: %u, Flags: 0x%x, GSI: %u",
e.nmi_source, e.flags, global_system_interrupt);
}
break;
case Entry.LOCAL_APIC_NMI:
Entry4 * e = cast(Entry4 *)entry;
if (DEBUG)
{
ushort flags;
memcpy(&flags, &e.flags, 2u);
Klog.writefln(" ACPI Processor ID: %u, Flags: 0x%x, LINT#: %u",
e.acpi_processor_id, flags, e.lint_nr);
}
break;
case Entry.LOCAL_APIC_ADDRESS_OVERRIDE:
Entry5 * e = cast(Entry5 *)entry;
if (DEBUG)
{
memcpy(&apic_registers, &e.local_apic_address, 8u);
Klog.writefln(" Local APIC Address: 0x%x", apic_registers);
}
break;
case Entry.PROCESSOR_LOCAL_X2APIC:
Entry9 * e = cast(Entry9 *)entry;
if (DEBUG)
{
Klog.writefln(" x2APIC ID: %u, Flags: 0x%x, ACPI ID: %u",
e.local_x2apic_id, e.flags, e.acpi_id);
}
break;
default:
break;
}
/* Move to next entry. */
entry = cast(const(Entry) *)(cast(size_t)entry + entry.length);
}
if (n_cpus > 0u)
{
Klog.writefln("%u CPU(s) found", n_cpus);
} }
} }
} }
@ -122,7 +305,7 @@ struct Apic
public static void initialize() public static void initialize()
{ {
Klog.writefln("\a3Initializing APIC"); Klog.writefln("\a3Initializing APIC");
io_apic_registers = cast(IoApicRegisters *)0xFEC0_0000u; io_apic_registers = cast(IoApicRegisters *)DEFAULT_IO_APIC_ADDRESS;
MADT * madt = cast(MADT *)Acpi.get_table("APIC"); MADT * madt = cast(MADT *)Acpi.get_table("APIC");
madt.scan(); madt.scan();
Klog.writefln("APIC found at %p", apic_registers); Klog.writefln("APIC found at %p", apic_registers);