Compare commits

..

2 Commits

Author SHA1 Message Date
7264a31ff3 Rework scanning MADT table entries
Get I/O APIC address from MADT entry.
Add DEBUG flag for APIC.
Show number of CPUs found.
2023-10-31 13:29:23 -04:00
c0a00b528e Run in QEMU with 4 CPUs by default 2023-10-31 11:56:39 -04:00
2 changed files with 189 additions and 5 deletions

View File

@ -199,6 +199,7 @@ task "run", desc: "Run HOS in QEMU" do
qemu-system-x86_64
-machine q35
-cpu max
-smp cpus=4
-serial file:qemu/serial.out
-bios #{ovmf}
-drive file=qemu/HOS.img,format=raw

View File

@ -13,6 +13,8 @@ import hulk.memory;
struct Apic
{
private enum DEBUG = false;
private enum DEFAULT_IO_APIC_ADDRESS = 0xFEC0_0000u;
private enum uint PERIODIC_MODE = 0x2_0000u;
private enum ulong IRQ_PIT = 2u;
@ -28,16 +30,112 @@ struct Apic
*/
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 PROCESSOR_LOCAL_X2APIC = 9;
ubyte type;
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;
uint local_apic_address;
uint flags;
static assert(MADT.sizeof == 0x2C);
/**
* Scan the MADT table.
*/
@ -46,14 +144,99 @@ struct Apic
apic_registers = cast(ApicRegisters *)local_apic_address;
const(void) * end = cast(const(void) *)(&this) + header.length;
const(Entry) * entry = cast(const(Entry) *)(cast(ulong)&this + MADT.sizeof);
bool first_io_apic = true;
size_t n_cpus = 0u;
while (entry < end)
{
entry = cast(const(Entry) *)(cast(size_t)entry + entry.length);
if (entry.type == Entry.LOCAL_APIC_ADDRESS_OVERRIDE)
if (DEBUG)
{
/* Found a 64-bit Local APIC Address Override entry. */
memcpy(cast(void *)&apic_registers, cast(const(void) *)entry + 4u, apic_registers.sizeof);
Klog.writefln("MADT entry type %u, length %u", entry.type, entry.length);
}
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()
{
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.scan();
Klog.writefln("APIC found at %p", apic_registers);