parallel compile, SMP, swapgs, cleanup, remove useless Reserved fields

This commit is contained in:
maksw committed 2026-05-30 11:18:46 +02:00
1 parent b17c9ac854
commit bfe2b55142
42 files changed
+2131 -426

No files matched your search

+95 -3
View File
@@ -2,18 +2,25 @@
#include <kernel/hal/hal_apic.h>
#include <ntlite/ddi/hal_api.h>
#include <stdint.h>
#include <intrin.h>
extern HAL_API gApi;
// ---- Local APIC ----
static volatile uint32_t* gLapic = (volatile uint32_t *)0;
#define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off)))
#define LAPIC_ID 0x020
#define LAPIC_EOI 0x0B0
#define LAPIC_SPURIOUS 0x0F0
#define LAPIC_ICR_LO 0x300
#define LAPIC_ICR_HI 0x310
#define LAPIC_ENABLE 0x100 // bit in spurious vector register
#define APIC_VECTOR_RESCHEDULE 0xF0u
// ---- I/O APIC ----
static volatile uint32_t* gIoapic = (volatile uint32_t *)0;
static uint32_t gBspLapicId = 0;
#define IOAPIC_IDX 0x00
#define IOAPIC_DATA 0x10
@@ -26,18 +33,99 @@ static void IoapicWrite(uint8_t reg, uint32_t val) {
*(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_DATA) = val;
}
static void HalApicStallFallback(uint32_t loops) {
for (volatile uint32_t i = 0; i < loops; i++) {
_mm_pause();
}
}
static void HalApicStallUs(uint32_t us) {
if (gApi.Timer.Stall) gApi.Timer.Stall(us);
else HalApicStallFallback(us * 128u + 1u);
}
static void HalApicWaitIcrIdle(void) {
for (uint32_t i = 0; i < 1000000u; i++) {
if (!(LAPIC_REG(LAPIC_ICR_LO) & (1u << 12)))
return;
_mm_pause();
}
}
static void HalApicSendIpi(uint32_t lapicId, uint32_t low) {
HalApicWaitIcrIdle();
LAPIC_REG(LAPIC_ICR_HI) = lapicId << 24;
LAPIC_REG(LAPIC_ICR_LO) = low;
HalApicWaitIcrIdle();
}
// IRQ n -> redirection table at register 0x10 + 2*n (low), 0x11 + 2*n (high).
#define IOREDTBL_LO(n) (0x10 + 2*(n))
#define IOREDTBL_HI(n) (0x11 + 2*(n))
// Interrupt vector base: IRQ 0 -> vector 0x20, IRQ 1 -> 0x21, ...
#define IRQ_VECTOR_BASE 0x20
__declspec(dllexport) uint32_t HalGetBspLapicId(void) {
return gBspLapicId;
}
__declspec(dllexport) void HalApicEnableCurrentCpu(void) {
if (!gLapic) return;
LAPIC_REG(LAPIC_SPURIOUS) = LAPIC_ENABLE | 0xFF;
}
__declspec(dllexport) void HalApicSendPanicIpi(void) {
if (!gLapic) return;
// Stop-the-world panic IPI. Use NMI delivery instead of a normal fixed
// vector so CPUs running with IF=0 inside spinlock/high-IRQL regions still
// enter the panic path. The NMI vector is already installed in the IDT on
// every CPU that has reached kernel-owned state.
HalApicWaitIcrIdle();
LAPIC_REG(LAPIC_ICR_HI) = 0;
LAPIC_REG(LAPIC_ICR_LO) = (3u << 18) | (4u << 8); // all-excluding-self, NMI
HalApicWaitIcrIdle();
}
__declspec(dllexport) void HalApicSendRescheduleIpi(uint32_t lapicId) {
if (!gLapic) return;
HalApicSendIpi(lapicId, APIC_VECTOR_RESCHEDULE); // fixed delivery, physical destination
}
__declspec(dllexport) void HalApicSendTlbShootdownIpi(uint32_t lapicId) {
if (!gLapic) return;
// TLB shootdown must reach CPUs that may be spinning with IF=0 inside
// high-IRQL/spinlock regions, so use NMI delivery rather than a fixed
// vector. The NMI stub handles active shootdowns and returns; unexpected
// NMIs still go through the normal fault/panic path.
HalApicSendIpi(lapicId, (4u << 8)); // NMI delivery, physical destination
}
__declspec(dllexport) KSTATUS HalStartApplicationProcessor(uint32_t lapicId, uint8_t startupVector) {
if (!gLapic || !startupVector || lapicId == gBspLapicId)
return STATUS_INVALID_PARAMETER;
// INIT assert/deassert, then two SIPIs. The target begins at startupVector << 12.
HalApicSendIpi(lapicId, 0x0000C500u); // INIT, level assert, level-triggered
HalApicStallUs(10000);
HalApicSendIpi(lapicId, 0x00008500u); // INIT, level deassert
HalApicStallUs(200);
HalApicSendIpi(lapicId, 0x00000600u | startupVector); // SIPI
HalApicStallUs(200);
HalApicSendIpi(lapicId, 0x00000600u | startupVector); // SIPI retry
HalApicStallUs(200);
return STATUS_SUCCESS;
}
void HalApicRouteIrq(uint8_t irq) {
// Full initial setup of the redirection entry.
// Sets the vector and clears the mask bit in one write.
uint32_t vector = IRQ_VECTOR_BASE + irq; // e.g. IRQ 1 -> vector 0x21
IoapicWrite(IOREDTBL_HI(irq), gBspLapicId << 24); // external IRQs target the BSP
IoapicWrite(IOREDTBL_LO(irq), vector); // unmasked (bit 16 = 0), edge, fixed
IoapicWrite(IOREDTBL_HI(irq), 0); // deliver to LAPIC id 0
}
void HalApicMaskIrq(uint8_t irq) {
@@ -50,8 +138,8 @@ void HalApicUnmaskIrq(uint8_t irq) {
uint32_t lo = IoapicRead(IOREDTBL_LO(irq));
lo &= ~(1 << 16); // clear mask bit
lo = (lo & ~0xFF) | (IRQ_VECTOR_BASE + irq);
IoapicWrite(IOREDTBL_HI(irq), gBspLapicId << 24);
IoapicWrite(IOREDTBL_LO(irq), lo);
IoapicWrite(IOREDTBL_HI(irq), 0); // LAPIC id 0
}
void HalApicSendEoi(void) {
@@ -62,6 +150,10 @@ void HalApicInitialize(uintptr_t lapicPhys, uintptr_t ioapicPhys) {
gLapic = (volatile uint32_t *)(gApi.PhysToVirt(lapicPhys));
gIoapic = (volatile uint32_t *)(gApi.PhysToVirt(ioapicPhys));
// The BSP is the CPU executing HAL init. Keep all external/device IRQs
// routed to this LAPIC; CPU-local IPIs use the local APIC directly.
gBspLapicId = (LAPIC_REG(LAPIC_ID) >> 24) & 0xFF;
// Enable Local APIC, set spurious vector to 0xFF.
LAPIC_REG(LAPIC_SPURIOUS) = LAPIC_ENABLE | 0xFF;
@@ -69,6 +161,6 @@ void HalApicInitialize(uintptr_t lapicPhys, uintptr_t ioapicPhys) {
uint32_t maxRedir = (IoapicRead(1) >> 16) & 0xFF;
for (uint8_t i = 0; i <= maxRedir; i++) {
IoapicWrite(IOREDTBL_LO(i), (1 << 16) | (IRQ_VECTOR_BASE + i));
IoapicWrite(IOREDTBL_HI(i), 0);
IoapicWrite(IOREDTBL_HI(i), gBspLapicId << 24);
}
}
+84 -12
View File
@@ -40,7 +40,7 @@ typedef struct {
uint32_t Length;
uint64_t XsdtAddress;
uint8_t ExtendedChecksum;
uint8_t Reserved[3];
uint8_t Padding[3];
} RSDP;
// ACPI SDT Header
@@ -81,6 +81,7 @@ typedef struct {
static uintptr_t gLapicPhys = 0xFEE00000;
static uintptr_t gIoapicPhys = 0xFEC00000;
static uintptr_t gHpetPhys = 0xFED00000;
static HAL_CPU_TOPOLOGY gCpuTopology;
// ACPI power-off state (filled in by ParseFadt / ScanDsdtForS5)
static uint16_t gPm1aCntBlk = 0;
@@ -89,7 +90,7 @@ static uint8_t gSlpTypA = 5; // S5 SLP_TYP for PM1a; 5 is correct for QEMU
static uint8_t gSlpTypB = 5; // S5 SLP_TYP for PM1b
int debugEnabled = 0;
int _fltused; // fuckass
int _fltused; // MSVC floating-point helper anchor
static void hal_putchar(char c) {
gApi.Screen.PrintChar(c, 0x00FF00, 0x000000);
}
@@ -114,7 +115,7 @@ typedef struct {
ACPISDTHeader Header; // 0 (36 bytes)
uint32_t FirmwareCtrl; // 36
uint32_t Dsdt; // 40 - physical addr of DSDT
uint8_t Reserved1; // 44
uint8_t Ignored44; // 44
uint8_t PreferredPmProfile; // 45
uint16_t SciInt; // 46
uint32_t SmiCmd; // 48
@@ -201,16 +202,51 @@ static void ParseFadt(const FADT* fadt) {
}
}
static void HalAddCpuRecord(uint32_t uid, uint32_t lapicId, uint32_t flags) {
if (gCpuTopology.CpuCount >= HAL_MAX_CPUS)
return;
for (uint32_t i = 0; i < gCpuTopology.CpuCount; i++) {
if (gCpuTopology.Cpus[i].LapicId == lapicId)
return;
}
HAL_CPU_INFO* cpu = &gCpuTopology.Cpus[gCpuTopology.CpuCount++];
memset(cpu, 0, sizeof(*cpu));
cpu->ProcessorUid = uid;
cpu->LapicId = lapicId;
cpu->Flags = flags;
cpu->Enabled = (flags & 1u) ? 1u : 0u;
}
static void ParseMadt(MADT* madt) {
gLapicPhys = madt->LocalAPICAddress;
uint8_t* p = (uint8_t *)(madt + 1);
uint8_t* end = (uint8_t *)madt + madt->Header.Length;
while (p < end) {
while (p + 2 <= end) {
uint8_t type = p[0], len = p[1];
if (type == 1) { // I/O APIC entry
if (!len || p + len > end) break;
if (type == 0 && len >= 8) { // Processor Local APIC
uint32_t uid = p[2];
uint32_t lapicId = p[3];
uint32_t flags = *(uint32_t *)(p + 4);
if (flags & 1u)
HalAddCpuRecord(uid, lapicId, flags);
} else if (type == 1 && len >= 12) { // I/O APIC entry
gIoapicPhys = *(uint32_t *)(p + 4);
} else if (type == 5 && len >= 12) { // Local APIC Address Override
gLapicPhys = (uintptr_t)*(uint64_t *)(p + 4);
} else if (type == 9 && len >= 16) { // Processor Local x2APIC
uint32_t lapicId = *(uint32_t *)(p + 4);
uint32_t flags = *(uint32_t *)(p + 8);
uint32_t uid = *(uint32_t *)(p + 12);
if ((flags & 1u) && lapicId < 256u)
HalAddCpuRecord(uid, lapicId, flags);
}
p += len ? len : 1;
p += len;
}
}
@@ -313,6 +349,44 @@ static void HalShutdown(void) {
while (true) __halt();
}
// ---------------------------------------------------------------------------
__declspec(dllexport) KSTATUS HalGetProcessorTopology(HAL_CPU_TOPOLOGY* out) {
if (!out) return STATUS_INVALID_PARAMETER;
memset(out, 0, sizeof(*out));
*out = gCpuTopology;
if (!out->CpuCount) {
out->CpuCount = 1;
out->BspLapicId = HalGetBspLapicId();
out->Cpus[0].LapicId = out->BspLapicId;
out->Cpus[0].ProcessorUid = 0;
out->Cpus[0].Flags = 1;
out->Cpus[0].Enabled = 1;
out->Cpus[0].IsBsp = 1;
return STATUS_SUCCESS;
}
uint32_t bsp = HalGetBspLapicId();
out->BspLapicId = bsp;
int foundBsp = 0;
for (uint32_t i = 0; i < out->CpuCount; i++) {
out->Cpus[i].IsBsp = (out->Cpus[i].LapicId == bsp) ? 1u : 0u;
if (out->Cpus[i].IsBsp) foundBsp = 1;
}
if (!foundBsp && out->CpuCount < HAL_MAX_CPUS) {
HAL_CPU_INFO* cpu = &out->Cpus[out->CpuCount++];
memset(cpu, 0, sizeof(*cpu));
cpu->LapicId = bsp;
cpu->ProcessorUid = bsp;
cpu->Flags = 1;
cpu->Enabled = 1;
cpu->IsBsp = 1;
}
return STATUS_SUCCESS;
}
// ---------------------------------------------------------------------------
__declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
if (gInitialised) return STATUS_ALREADY_EXISTS;
@@ -357,12 +431,10 @@ __declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
gApi.Version = HAL_API_VERSION;
gInitialised = 1;
// This shouldn't be here but i have no other way.
// After i send 0xF4 and move the mouse the controller sends an interrupts that doesn't fire
// and because the CPU missed the IRQ 12 edge transition (cli) later when we expect it to fire, it doesn't
// leaving us with no mouse and no keyboard. The dreaded 8042 will hold the CLOCK line low forever.
// To combat this we just go about our day executing the rest of the init and just before the end
// of init we just iterate 256 times to grab whatever the controller left for us ("Drain and Pray").
// The 8042 can leave output bytes pending while the keyboard/mouse drivers
// are being brought up with interrupts temporarily disabled. Drain the
// controller before returning from HAL init so stale status/data bytes do
// not suppress the next keyboard or mouse interrupt edge.
for (int i = 0; i < 256; i++) {
if (__inbyte(0x64) & 0x01) {
__inbyte(0x60); // Consume
+1 -2
View File
@@ -271,8 +271,7 @@ void HalMouseInitialize(HAL_MOUSE* out, int screenW, int screenH) {
ack = MouseRecvByte();
} while (ack != 0xFAu && --retries > 0);
// Thanks to the increased Ps2WaitOutput timeout, we will actually
// wait long enough for the physical hardware self-test to finish here.
// The output timeout covers the physical hardware self-test latency.
MouseRecvByte(); // 0xAA - BAT passed
MouseRecvByte(); // 0x00 - device ID