parallel compile, SMP, swapgs, cleanup, remove useless Reserved fields
This commit is contained in:
1 parent
b17c9ac854
commit
bfe2b55142
42 files changed
+2131
-426
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in new issue
Block a user