replace nob with ms' build, move disk creation to build.bat, major comment cleanup, remove old and stupid tests, overhaul interrupt management with per-CPU vector allocation, affinity migration and safe teardown, add proper IOAPIC routing and PCI MSI/MSI-X/INTx support, migrate drivers to the new interrupt API, integrate ACPICA with a proper OS services layer, move ACPI firmware events, power button handling and S5 shutdown into acpi.sys, add parallel driver startup and atomic publication, replace PnP arrays with dynamic lists, redesign service startup again to be asynchronous, add delayed startup mode for services, allow omitting keys in services.ini, fix acpi ec deferred work handling, fix kernel threads having garbage exit code.
This commit is contained in:
1 parent
d36f19509c
commit
36eef8f58d
696 files changed
+147281
-7530
No files matched your search
+161
-109
@@ -4,6 +4,8 @@
|
||||
#include <kernel/hal/hal_internal.h>
|
||||
#include <kernel/hal/hal_api.h>
|
||||
#include <kernel/hal/hal_timer.h>
|
||||
#include <kernel/hal/hal_processor.h>
|
||||
#include <kernel/ke_vectors.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <intrin.h>
|
||||
@@ -14,6 +16,9 @@ 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_TPR 0x080
|
||||
#define LAPIC_ISR_BASE 0x100
|
||||
#define LAPIC_IRR_BASE 0x200
|
||||
#define LAPIC_SPURIOUS 0x0F0
|
||||
#define LAPIC_ICR_LO 0x300
|
||||
#define LAPIC_ICR_HI 0x310
|
||||
@@ -24,38 +29,70 @@ static volatile uint32_t* gLapic = (volatile uint32_t*)0;
|
||||
#define IA32_APIC_BASE_X2APIC (1ULL << 10)
|
||||
#define IA32_X2APIC_ID 0x00000802u
|
||||
#define IA32_X2APIC_EOI 0x0000080Bu
|
||||
#define IA32_X2APIC_TPR 0x00000808u
|
||||
#define IA32_X2APIC_ISR_BASE 0x00000810u
|
||||
#define IA32_X2APIC_IRR_BASE 0x00000820u
|
||||
#define IA32_X2APIC_SVR 0x0000080Fu
|
||||
#define IA32_X2APIC_ICR 0x00000830u
|
||||
|
||||
#define CPUID_FEATURE_ECX_X2APIC (1u << 21)
|
||||
|
||||
|
||||
// ---- I/O APIC ----.
|
||||
static volatile uint32_t* gIoapic = (volatile uint32_t*)0;
|
||||
static uint32_t gBspLapicId = 0;
|
||||
static uint8_t gX2ApicSupported = 0;
|
||||
static uint8_t gX2ApicEnabled = 0;
|
||||
static uint32_t gIoapicGsiBase = 0;
|
||||
static uint32_t gIoapicRedirectionCount = 0;
|
||||
// ---- I/O APIC interrupt domains ----.
|
||||
#define HAL_IOAPIC_MAX 8u
|
||||
#define IOAPIC_IDX 0x00u
|
||||
#define IOAPIC_DATA 0x10u
|
||||
|
||||
typedef struct HAL_IOAPIC {
|
||||
volatile uint32_t* Registers;
|
||||
uintptr_t Physical;
|
||||
uint32_t GsiBase;
|
||||
uint32_t Pins;
|
||||
volatile long RegisterLock;
|
||||
} HAL_IOAPIC;
|
||||
|
||||
static HAL_IOAPIC gIoapics[HAL_IOAPIC_MAX];
|
||||
static uint32_t gIoapicCount;
|
||||
static uint32_t gBspLapicId;
|
||||
static uint8_t gX2ApicSupported;
|
||||
static uint8_t gX2ApicEnabled;
|
||||
static uint32_t gIsaGsi[16];
|
||||
static uint16_t gIsaFlags[16];
|
||||
static uint16_t gSciIrq = UINT16_MAX;
|
||||
static bool gIsaOverridesInitialized = false;
|
||||
#define IOAPIC_IDX 0x00
|
||||
#define IOAPIC_DATA 0x10
|
||||
static bool gIsaOverridesInitialized;
|
||||
|
||||
// Implements the ioapic Read operation.
|
||||
static uint32_t IoapicRead(uint8_t reg) {
|
||||
*(volatile uint32_t*)((uint8_t*)gIoapic + IOAPIC_IDX) = reg;
|
||||
return *(volatile uint32_t*)((uint8_t*)gIoapic + IOAPIC_DATA);
|
||||
}
|
||||
// Implements the ioapic Write operation.
|
||||
static void IoapicWrite(uint8_t reg, uint32_t val) {
|
||||
*(volatile uint32_t*)((uint8_t*)gIoapic + IOAPIC_IDX) = reg;
|
||||
*(volatile uint32_t*)((uint8_t*)gIoapic + IOAPIC_DATA) = val;
|
||||
// I/O APIC register selectors are shared by every CPU accessing that APIC.
|
||||
static uint32_t IoapicRead(HAL_IOAPIC* apic, uint8_t reg) {
|
||||
uintptr_t interruptFlags = HalDisableInterrupts();
|
||||
while (_InterlockedCompareExchange(&apic->RegisterLock, 1, 0))
|
||||
_mm_pause();
|
||||
apic->Registers[IOAPIC_IDX / 4u] = reg;
|
||||
uint32_t value = apic->Registers[IOAPIC_DATA / 4u];
|
||||
_InterlockedExchange(&apic->RegisterLock, 0);
|
||||
HalRestoreInterrupts(interruptFlags);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void IoapicWrite(HAL_IOAPIC* apic, uint8_t reg, uint32_t value) {
|
||||
uintptr_t interruptFlags = HalDisableInterrupts();
|
||||
while (_InterlockedCompareExchange(&apic->RegisterLock, 1, 0))
|
||||
_mm_pause();
|
||||
apic->Registers[IOAPIC_IDX / 4u] = reg;
|
||||
apic->Registers[IOAPIC_DATA / 4u] = value;
|
||||
_InterlockedExchange(&apic->RegisterLock, 0);
|
||||
HalRestoreInterrupts(interruptFlags);
|
||||
}
|
||||
|
||||
static HAL_IOAPIC* HalApicFindGsi(uint32_t gsi, uint32_t* pinOut) {
|
||||
for (uint32_t i = 0; i < gIoapicCount; i++) {
|
||||
HAL_IOAPIC* apic = &gIoapics[i];
|
||||
if (gsi >= apic->GsiBase && gsi - apic->GsiBase < apic->Pins) {
|
||||
*pinOut = gsi - apic->GsiBase;
|
||||
return apic;
|
||||
}
|
||||
}
|
||||
return (HAL_IOAPIC*)0;
|
||||
}
|
||||
|
||||
// Implements the apic Detect Mode operation.
|
||||
static void HalApicDetectMode(void) {
|
||||
int regs[4] = {0, 0, 0, 0};
|
||||
__cpuid(regs, 1);
|
||||
@@ -70,7 +107,6 @@ static void HalApicStallUs(uint32_t us) {
|
||||
HalTimerStall(us);
|
||||
}
|
||||
|
||||
// Implements the apic Wait Icr Idle operation.
|
||||
static void HalApicWaitIcrIdle(void) {
|
||||
if (gX2ApicEnabled)
|
||||
return;
|
||||
@@ -82,7 +118,6 @@ static void HalApicWaitIcrIdle(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the apic Send Ipi operation.
|
||||
static void HalApicSendIpi(uint32_t lapicId, uint32_t low) {
|
||||
if (gX2ApicEnabled) {
|
||||
__writemsr(IA32_X2APIC_ICR, ((uint64_t)lapicId << 32) | low);
|
||||
@@ -98,8 +133,6 @@ static void HalApicSendIpi(uint32_t lapicId, uint32_t low) {
|
||||
// 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 -> vector 0x21, ...
|
||||
#define IRQ_VECTOR_BASE 0x20
|
||||
|
||||
// Returns the local interrupt-controller hardware ID of the boot processor.
|
||||
uint32_t HalApicGetBootProcessorId(void) {
|
||||
@@ -126,12 +159,46 @@ void HalApicInitializeCurrentProcessor(void) {
|
||||
apicBase |= IA32_APIC_BASE_X2APIC;
|
||||
__writemsr(IA32_APIC_BASE, apicBase);
|
||||
__writemsr(IA32_X2APIC_SVR, LAPIC_ENABLE | 0xFFu);
|
||||
HalApicSetTaskPriority(0);
|
||||
return;
|
||||
}
|
||||
|
||||
__writemsr(IA32_APIC_BASE, apicBase);
|
||||
if (gLapic)
|
||||
LAPIC_REG(LAPIC_SPURIOUS) = LAPIC_ENABLE | 0xFF;
|
||||
HalApicSetTaskPriority(0);
|
||||
}
|
||||
|
||||
// Controls the current CPU's interrupt priority without changing its interrupt-enable flag.
|
||||
void HalApicSetTaskPriority(uint8_t priority) {
|
||||
if (gX2ApicEnabled) {
|
||||
__writemsr(IA32_X2APIC_TPR, priority);
|
||||
} else if (gLapic) {
|
||||
LAPIC_REG(LAPIC_TPR) = priority;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t HalApicQueryTaskPriority(void) {
|
||||
if (gX2ApicEnabled)
|
||||
return (uint8_t)__readmsr(IA32_X2APIC_TPR);
|
||||
return gLapic ? (uint8_t)LAPIC_REG(LAPIC_TPR) : 0u;
|
||||
}
|
||||
|
||||
// Reads the current processor's local delivery state after a source is masked.
|
||||
bool HalApicVectorPending(uint8_t vector) {
|
||||
const uint32_t index = (uint32_t)vector >> 5u;
|
||||
const uint32_t mask = 1u << (vector & 31u);
|
||||
uint32_t irr, isr;
|
||||
if (gX2ApicEnabled) {
|
||||
irr = (uint32_t)__readmsr(IA32_X2APIC_IRR_BASE + index);
|
||||
isr = (uint32_t)__readmsr(IA32_X2APIC_ISR_BASE + index);
|
||||
} else if (gLapic) {
|
||||
irr = LAPIC_REG(LAPIC_IRR_BASE + 0x10u * index);
|
||||
isr = LAPIC_REG(LAPIC_ISR_BASE + 0x10u * index);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return ((irr | isr) & mask) != 0u;
|
||||
}
|
||||
|
||||
// Broadcasts an NMI to every processor except the caller.
|
||||
@@ -182,102 +249,85 @@ KSTATUS HalApicStartProcessor(uint32_t hardwareId, uintptr_t startPhysical) {
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Composes an MSI message targeting the boot processor without exposing APIC mode.
|
||||
KSTATUS HalApicComposeMsi(uint8_t vector, HAL_MSI_MESSAGE* messageOut) {
|
||||
if (!messageOut || vector < 0x20u)
|
||||
// MSI destination encoding without interrupt remapping supports an 8-bit APIC ID.
|
||||
KSTATUS HalApicComposeMsi(uint32_t hardwareId, uint8_t vector, HAL_MSI_MESSAGE* out) {
|
||||
if (!out || vector < KE_VECTOR_DEVICE_FIRST || vector > KE_VECTOR_DEVICE_LAST)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (gBspLapicId >= 256u)
|
||||
if (hardwareId > 255u)
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
|
||||
messageOut->Address = 0xFEE00000ull | ((uint64_t)(gBspLapicId & 0xFFu) << 12);
|
||||
messageOut->Data = vector;
|
||||
messageOut->Reserved = 0;
|
||||
out->Address = 0xFEE00000ull | ((uint64_t)hardwareId << 12);
|
||||
out->Data = vector;
|
||||
out->Reserved = 0;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Initializes the identity ISA map before processing MADT source overrides.
|
||||
static void HalApicInitializeIsaMap(void) {
|
||||
if (gIsaOverridesInitialized) return;
|
||||
for (uint32_t irq = 0; irq < 16; ++irq) {
|
||||
for (uint32_t irq = 0; irq < 16; irq++) {
|
||||
gIsaGsi[irq] = irq;
|
||||
gIsaFlags[irq] = 0;
|
||||
}
|
||||
gIsaOverridesInitialized = true;
|
||||
}
|
||||
|
||||
// Records the global-system-interrupt base of the currently supported IOAPIC.
|
||||
void HalApicSetGsiBase(uint32_t gsiBase) { gIoapicGsiBase = gsiBase; }
|
||||
void HalApicAddIoapic(uintptr_t physical, uint32_t gsiBase) {
|
||||
if (!physical || gIoapicCount >= HAL_IOAPIC_MAX)
|
||||
return;
|
||||
for (uint32_t i = 0; i < gIoapicCount; i++)
|
||||
if (gIoapics[i].Physical == physical)
|
||||
return;
|
||||
HAL_IOAPIC* apic = &gIoapics[gIoapicCount++];
|
||||
apic->Physical = physical;
|
||||
apic->GsiBase = gsiBase;
|
||||
}
|
||||
|
||||
// Preserves MADT interrupt-source overrides for legacy ISA devices.
|
||||
void HalApicSetIsaOverride(uint8_t irq, uint32_t gsi, uint16_t flags) {
|
||||
if (irq >= 16) return;
|
||||
if (irq >= 16u) return;
|
||||
HalApicInitializeIsaMap();
|
||||
gIsaGsi[irq] = gsi;
|
||||
gIsaFlags[irq] = flags;
|
||||
}
|
||||
|
||||
// Marks the FADT SCI as a low-active, level-triggered interrupt by default.
|
||||
void HalApicSetSciIrq(uint16_t irq) { gSciIrq = irq; }
|
||||
|
||||
// Resolves one logical IRQ to a physical pin on the selected IOAPIC.
|
||||
static bool HalApicResolveIrq(uint8_t irq, uint32_t* pinOut, uint32_t* flagsOut) {
|
||||
KSTATUS HalApicResolveIsa(uint8_t irq, uint32_t* gsiOut, uint16_t* flagsOut) {
|
||||
if (irq >= 16u || !gsiOut || !flagsOut)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
HalApicInitializeIsaMap();
|
||||
uint32_t gsi = irq < 16 ? gIsaGsi[irq] : irq;
|
||||
if (gsi < gIoapicGsiBase || gsi - gIoapicGsiBase >= gIoapicRedirectionCount)
|
||||
return false;
|
||||
uint32_t flags = 0;
|
||||
if (irq == gSciIrq) flags = (1u << 13) | (1u << 15);
|
||||
if (irq < 16) {
|
||||
uint16_t override = gIsaFlags[irq];
|
||||
// MADT 00 is bus-conformant; 11 selects active low or level triggered.
|
||||
if ((override & 3u) == 3u) flags |= (1u << 13);
|
||||
else if ((override & 3u) == 1u) flags &= ~(1u << 13);
|
||||
if (((override >> 2) & 3u) == 3u) flags |= (1u << 15);
|
||||
else if (((override >> 2) & 3u) == 1u) flags &= ~(1u << 15);
|
||||
}
|
||||
*pinOut = gsi - gIoapicGsiBase;
|
||||
*flagsOut = flags;
|
||||
return true;
|
||||
uint32_t pin;
|
||||
if (!HalApicFindGsi(gIsaGsi[irq], &pin))
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
*gsiOut = gIsaGsi[irq];
|
||||
*flagsOut = gIsaFlags[irq];
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Reports whether a platform IRQ can be routed by the current IOAPIC.
|
||||
bool HalApicCanRouteIrq(uint8_t irq) {
|
||||
uint32_t pin, flags;
|
||||
return irq < 24 && HalApicResolveIrq(irq, &pin, &flags);
|
||||
// ACPI polarity bits 1:0 and trigger bits 3:2 encode bus-defined defaults.
|
||||
KSTATUS HalApicRouteGsi(uint32_t gsi, uint8_t vector, uint32_t hardwareId,
|
||||
uint16_t flags, bool masked) {
|
||||
if (vector < KE_VECTOR_DEVICE_FIRST || vector > KE_VECTOR_DEVICE_LAST || hardwareId > 255u)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
uint32_t pin;
|
||||
HAL_IOAPIC* apic = HalApicFindGsi(gsi, &pin);
|
||||
if (!apic) return NTLSTATUS_NOT_SUPPORTED;
|
||||
uint32_t mode = 0;
|
||||
if ((flags & 3u) == 3u) mode |= (1u << 13);
|
||||
if (((flags >> 2) & 3u) == 3u) mode |= (1u << 15);
|
||||
IoapicWrite(apic, IOREDTBL_LO(pin), (1u << 16) | vector | mode);
|
||||
IoapicWrite(apic, IOREDTBL_HI(pin), (hardwareId & 255u) << 24);
|
||||
if (!masked) IoapicWrite(apic, IOREDTBL_LO(pin), vector | mode);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements the apic Route Irq operation.
|
||||
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 pin, flags;
|
||||
if (!HalApicResolveIrq(irq, &pin, &flags)) return;
|
||||
uint32_t vector = IRQ_VECTOR_BASE + irq;
|
||||
IoapicWrite(IOREDTBL_HI(pin), (gBspLapicId & 0xFFu) << 24);
|
||||
IoapicWrite(IOREDTBL_LO(pin), vector | flags);
|
||||
KSTATUS HalApicMaskGsi(uint32_t gsi, bool masked) {
|
||||
uint32_t pin;
|
||||
HAL_IOAPIC* apic = HalApicFindGsi(gsi, &pin);
|
||||
if (!apic) return NTLSTATUS_NOT_SUPPORTED;
|
||||
uint32_t lo = IoapicRead(apic, IOREDTBL_LO(pin));
|
||||
if (masked) lo |= 1u << 16;
|
||||
else lo &= ~(1u << 16);
|
||||
IoapicWrite(apic, IOREDTBL_LO(pin), lo);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements the apic Mask Irq operation.
|
||||
void HalApicMaskIrq(uint8_t irq) {
|
||||
uint32_t pin, flags;
|
||||
if (!HalApicResolveIrq(irq, &pin, &flags)) return;
|
||||
uint32_t lo = IoapicRead(IOREDTBL_LO(pin));
|
||||
lo |= (1 << 16);
|
||||
IoapicWrite(IOREDTBL_LO(pin), lo);
|
||||
}
|
||||
|
||||
// Implements the apic Unmask Irq operation.
|
||||
void HalApicUnmaskIrq(uint8_t irq) {
|
||||
uint32_t pin, flags;
|
||||
if (!HalApicResolveIrq(irq, &pin, &flags)) return;
|
||||
uint32_t lo = IoapicRead(IOREDTBL_LO(pin));
|
||||
lo = (lo & ~(0xFFu | (1u << 16) | (1u << 13) | (1u << 15))) |
|
||||
(IRQ_VECTOR_BASE + irq) | flags;
|
||||
IoapicWrite(IOREDTBL_HI(pin), (gBspLapicId & 0xFFu) << 24);
|
||||
IoapicWrite(IOREDTBL_LO(pin), lo);
|
||||
}
|
||||
|
||||
// Implements the apic Send Eoi operation.
|
||||
void HalApicSendEoi(void) {
|
||||
if (gX2ApicEnabled) {
|
||||
__writemsr(IA32_X2APIC_EOI, 0);
|
||||
@@ -286,27 +336,29 @@ void HalApicSendEoi(void) {
|
||||
LAPIC_REG(LAPIC_EOI) = 0;
|
||||
}
|
||||
|
||||
// Implements the apic Initialize operation.
|
||||
void HalApicInitialize(uintptr_t lapicPhys, uintptr_t ioapicPhys) {
|
||||
void HalApicInitialize(uintptr_t lapicPhys) {
|
||||
// The PIC remains masked: legacy input arrives through programmed I/O APICs.
|
||||
__outbyte(0x21, 0xFF);
|
||||
__outbyte(0xA1, 0xFF);
|
||||
HalApicDetectMode();
|
||||
|
||||
gLapic = (volatile uint32_t*)(HalPhysicalToVirtual(lapicPhys));
|
||||
gIoapic = (volatile uint32_t*)(HalPhysicalToVirtual(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.
|
||||
gLapic = (volatile uint32_t*)HalPhysicalToVirtual(lapicPhys);
|
||||
if (gX2ApicEnabled)
|
||||
gBspLapicId = (uint32_t)__readmsr(IA32_X2APIC_ID);
|
||||
else
|
||||
gBspLapicId = (LAPIC_REG(LAPIC_ID) >> 24) & 0xFF;
|
||||
|
||||
gBspLapicId = (LAPIC_REG(LAPIC_ID) >> 24) & 0xFFu;
|
||||
HalApicInitializeCurrentProcessor();
|
||||
if (gIoapicCount == 0)
|
||||
HalApicAddIoapic(0xFEC00000u, 0);
|
||||
|
||||
// Mask all IOAPIC lines initially.
|
||||
uint32_t maxRedir = (IoapicRead(1) >> 16) & 0xFF;
|
||||
gIoapicRedirectionCount = maxRedir + 1u;
|
||||
for (uint32_t i = 0; i <= maxRedir; i++) {
|
||||
IoapicWrite(IOREDTBL_LO(i), (1u << 16) | IRQ_VECTOR_BASE);
|
||||
IoapicWrite(IOREDTBL_HI(i), (gBspLapicId & 0xFFu) << 24);
|
||||
for (uint32_t index = 0; index < gIoapicCount; index++) {
|
||||
HAL_IOAPIC* apic = &gIoapics[index];
|
||||
apic->Registers = (volatile uint32_t*)HalPhysicalToVirtual(apic->Physical);
|
||||
uint32_t version = IoapicRead(apic, 1u);
|
||||
apic->Pins = ((version >> 16) & 0xFFu) + 1u;
|
||||
for (uint32_t pin = 0; pin < apic->Pins; pin++) {
|
||||
IoapicWrite(apic, IOREDTBL_LO(pin), (1u << 16) | KE_VECTOR_DEVICE_FIRST);
|
||||
IoapicWrite(apic, IOREDTBL_HI(pin), (gBspLapicId & 255u) << 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user