// HAL initialization entry point. This file discovers platform tables and publishes the HAL API to the kernel. #include #include #include #include #include #include #include #include #include #include #include #include void HalScreenInitialize(void* (*AllocatePool)(size_t size), uintptr_t fb, int32_t w, int32_t h, int32_t stride, HAL_SCREEN* out); void HalPciInitialize(HAL_PCI* out); void HalRtcInitialize(HAL_RTC* out); void HalRtcSetCenturyRegister(uint8_t centuryRegister); extern void HalSetDebugEnabled(int v); // Defined in mm_virt.c - HAL needs it for MMIO window access. static uint64_t gPhysBase = 0xFFFF880000000000ULL; static KSTATUS HalQueryProcessorTopology(HAL_PROCESSOR_TOPOLOGY* out); static HAL_API gApi = { .Size = sizeof(HAL_API), .Version = HAL_API_VERSION, .Processor = { .DisableInterrupts = HalDisableInterrupts, .RestoreInterrupts = HalRestoreInterrupts, .EnableInterrupts = HalEnableInterrupts, .WaitForInterrupt = HalWaitForInterrupt, .Halt = HalHalt, .Stop = HalStopProcessor, .QueryTopology = HalQueryProcessorTopology, .Start = HalApicStartProcessor, }, .InterruptController = { .RouteIrq = HalApicRouteIrq, .MaskIrq = HalApicMaskIrq, .UnmaskIrq = HalApicUnmaskIrq, .SendEoi = HalApicSendEoi, .InitializeCurrentProcessor = HalApicInitializeCurrentProcessor, .SendProcessorInterrupt = HalApicSendProcessorInterrupt, .SendProcessorNmi = HalApicSendProcessorNmi, .BroadcastNmi = HalApicBroadcastNmi, .ComposeMsi = HalApicComposeMsi, }, }; static int gInitialised = 0; // ACPI table walker - minimal, just enough to find APIC and HPET addresses. #define ACPI_SIG(a,b,c,d) ((uint32_t)(a)|((uint32_t)(b)<<8)|((uint32_t)(c)<<16)|((uint32_t)(d)<<24)) #pragma pack(push, 1) #pragma warning(disable : 4200) // ACPI RSDP (Root System Description Pointer). typedef struct { char Signature[8]; uint8_t Checksum; char OEMID[6]; uint8_t Revision; uint32_t RsdtAddress; uint32_t Length; uint64_t XsdtAddress; uint8_t ExtendedChecksum; uint8_t Padding[3]; } RSDP; // ACPI SDT Header. typedef struct { char Signature[4]; uint32_t Length; uint8_t Revision; uint8_t Checksum; char OEMID[6]; char OEMTableID[8]; uint32_t OEMRevision; uint32_t CreatorID; uint32_t CreatorRevision; } ACPISDTHeader; // RSDT (Root System Description Table). typedef struct { ACPISDTHeader Header; uint32_t PointerToOtherSDT[]; } RSDT; // XSDT (Extended System Description Table). typedef struct { ACPISDTHeader Header; uint64_t PointerToOtherSDT[]; } XSDT; // MADT (Multiple APIC Description Table). typedef struct { ACPISDTHeader Header; uint32_t LocalAPICAddress; uint32_t Flags; uint8_t Entries[]; } MADT; #pragma pack(pop) static uintptr_t gLapicPhys = 0xFEE00000; static uintptr_t gIoapicPhys = 0xFEC00000; static uintptr_t gHpetPhys = 0xFED00000; static HAL_PROCESSOR_TOPOLOGY gCpuTopology; // ACPI power-off state (filled in by ParseFadt / ScanDsdtForS5). // Do not guess SLP_TYP on real hardware: these values are firmware-specific. typedef struct ACPI_FIXED_REGISTER { uint8_t AddressSpaceId; uint8_t WidthBytes; uint16_t Reserved; uint64_t Address; } ACPI_FIXED_REGISTER; static ACPI_FIXED_REGISTER gPm1aCnt; static ACPI_FIXED_REGISTER gPm1bCnt; static ACPI_FIXED_REGISTER gPm1aStatus; static ACPI_FIXED_REGISTER gPm1bStatus; static ACPI_FIXED_REGISTER gPm1aEnable; static ACPI_FIXED_REGISTER gPm1bEnable; static uint16_t gSciIrq = 0; static bool gFixedPowerButtonArmed = false; static ACPI_FIXED_REGISTER gSleepControl; static uint32_t gLegacyPm1aPort = 0; static uint32_t gLegacyPm1bPort = 0; static uint32_t gFadtFlags = 0; static uint32_t gSmiCommandPort = 0; static uint8_t gAcpiEnableValue = 0; static uint8_t gSlpTypA = 0; static uint8_t gSlpTypB = 0; static int gS5Found = 0; static int gHwReducedAcpi = 0; static int gIntelPchPmBase = 0; int debugEnabled = 0; int _fltused; // MSVC floating-point helper anchor. // Writes a formatted early HAL diagnostic through the output router. void HalDbgPrint(const char* fmt, ...) { if (!debugEnabled || !fmt || !gApi.Output.Write) return; char line[1024]; va_list args; va_start(args, fmt); int count = vsnprintf_(line, sizeof(line), fmt, args); va_end(args); size_t length = 0; if (count > 0) { length = (size_t)count; if (length >= sizeof(line)) length = sizeof(line) - 1u; } HAL_OUTPUT_RECORD record; record.Stream = HAL_OUTPUT_STREAM_DEBUG; record.Flags = 0; record.Foreground = 0x00CCCCCCu; record.Background = 0x00012456u; record.Buffer = line; record.Length = length; gApi.Output.Write(&record); } void* HalPhysicalToVirtual(uint64_t phys) { return (void*)(phys + gPhysBase); } // FADT (Fixed ACPI Description Table) offsets used here. ACPI 2.0+ // systems may put the real DSDT and PM1 control registers in the extended // X_* fields, so do not rely only on the legacy 32-bit fields. #define FADT_SCI_INT_OFFSET 46u #define FADT_PM1A_EVT_BLK_OFFSET 56u #define FADT_PM1B_EVT_BLK_OFFSET 60u #define FADT_PM1_EVT_LEN_OFFSET 88u #define FADT_X_PM1A_EVT_BLK_OFFSET 148u #define FADT_X_PM1B_EVT_BLK_OFFSET 160u #define FADT_FLAG_POWER_BUTTON (1u << 4) #define ACPI_PM1_POWER_BUTTON_BIT (1u << 8) #define FADT_DSDT_OFFSET 40u #define FADT_SMI_CMD_OFFSET 48u #define FADT_ACPI_ENABLE_OFFSET 52u #define FADT_PM1A_CNT_BLK_OFFSET 64u #define FADT_PM1B_CNT_BLK_OFFSET 68u #define FADT_PM1_CNT_LEN_OFFSET 89u #define FADT_CENTURY_OFFSET 108u #define FADT_FLAGS_OFFSET 112u #define FADT_X_DSDT_OFFSET 140u #define FADT_X_PM1A_CNT_BLK_OFFSET 172u #define FADT_X_PM1B_CNT_BLK_OFFSET 184u #define FADT_SLEEP_CONTROL_OFFSET 244u #define FADT_RESET_REG_OFFSET 116u #define FADT_RESET_VALUE_OFFSET 128u #define FADT_FLAG_HW_REDUCED_ACPI (1u << 20) #define INTEL_PCH_SMI_EN_OFFSET 0x30u #define INTEL_PCH_SMI_ON_SLP_EN (1u << 4) #pragma pack(push, 1) typedef struct { uint8_t AddressSpaceId; uint8_t RegisterBitWidth; uint8_t RegisterBitOffset; uint8_t AccessSize; uint64_t Address; } ACPI_GAS; #pragma pack(pop) static ACPI_FIXED_REGISTER gResetRegister; static uint8_t gResetValue; // Implements the acpi Read U32 operation. static uint32_t AcpiReadU32(const void* table, uint32_t tableLen, uint32_t off) { uint32_t value = 0; if (off + sizeof(value) <= tableLen) memcpy(&value, (const uint8_t*)table + off, sizeof(value)); return value; } // Implements the acpi Read U64 operation. static uint64_t AcpiReadU64(const void* table, uint32_t tableLen, uint32_t off) { uint64_t value = 0; if (off + sizeof(value) <= tableLen) memcpy(&value, (const uint8_t*)table + off, sizeof(value)); return value; } // Decodes one ACPI Generic Address Structure used for fixed power registers. static bool AcpiReadGasRegister(const void* table, uint32_t tableLen, uint32_t off, ACPI_FIXED_REGISTER* out) { if (!out || off + sizeof(ACPI_GAS) > tableLen) return false; ACPI_GAS gas; memcpy(&gas, (const uint8_t*)table + off, sizeof(gas)); if (!gas.Address || gas.RegisterBitOffset != 0) return false; if (gas.AddressSpaceId != 0x00 && gas.AddressSpaceId != 0x01) return false; if (gas.AddressSpaceId == 0x01 && gas.Address > 0xFFFFu) return false; uint8_t widthBytes = 0; if (gas.AccessSize >= 1 && gas.AccessSize <= 3) widthBytes = (uint8_t)(1u << (gas.AccessSize - 1u)); else if (gas.RegisterBitWidth) widthBytes = (uint8_t)((gas.RegisterBitWidth + 7u) / 8u); if (widthBytes < 2u) widthBytes = 2u; if (widthBytes > 4u) widthBytes = 4u; out->AddressSpaceId = gas.AddressSpaceId; out->WidthBytes = widthBytes; out->Address = gas.Address; return true; } // Decodes one byte-wide ACPI GAS used by the HW-reduced Sleep Control register. static bool AcpiReadByteGasRegister(const void* table, uint32_t tableLen, uint32_t off, ACPI_FIXED_REGISTER* out) { if (!out || off + sizeof(ACPI_GAS) > tableLen) return false; ACPI_GAS gas; memcpy(&gas, (const uint8_t*)table + off, sizeof(gas)); if (!gas.Address || gas.RegisterBitOffset != 0 || gas.RegisterBitWidth != 8) return false; if (gas.AddressSpaceId != 0x00 && gas.AddressSpaceId != 0x01) return false; if (gas.AddressSpaceId == 0x01 && gas.Address > 0xFFFFu) return false; out->AddressSpaceId = gas.AddressSpaceId; out->WidthBytes = 1u; out->Address = gas.Address; return true; } // Reads one ACPI fixed register while preserving the address-space distinction. static uint32_t AcpiReadFixedRegister(const ACPI_FIXED_REGISTER* reg) { if (!reg || !reg->Address) return 0; if (reg->AddressSpaceId == 0x01) { uint16_t port = (uint16_t)reg->Address; if (reg->WidthBytes <= 1u) return __inbyte(port); if (reg->WidthBytes == 2u) return __inword(port); return __indword(port); } volatile void* address = HalPhysicalToVirtual(reg->Address); if (reg->WidthBytes <= 1u) return *(volatile uint8_t*)address; if (reg->WidthBytes == 2u) return *(volatile uint16_t*)address; return *(volatile uint32_t*)address; } // Writes one ACPI fixed register using the width advertised by firmware. static void AcpiWriteFixedRegister(const ACPI_FIXED_REGISTER* reg, uint32_t value) { if (!reg || !reg->Address) return; if (reg->AddressSpaceId == 0x01) { uint16_t port = (uint16_t)reg->Address; if (reg->WidthBytes <= 1u) __outbyte(port, (uint8_t)value); else if (reg->WidthBytes == 2u) __outword(port, (uint16_t)value); else __outdword(port, value); return; } volatile void* address = HalPhysicalToVirtual(reg->Address); if (reg->WidthBytes <= 1u) *(volatile uint8_t*)address = (uint8_t)value; else if (reg->WidthBytes == 2u) *(volatile uint16_t*)address = (uint16_t)value; else *(volatile uint32_t*)address = value; } // Selects a PM1 event block as two adjacent equal-width status and enable registers. static void AcpiConfigurePm1EventBlock(const void* fadt, uint32_t len, uint32_t legacyOffset, uint32_t gasOffset, uint8_t halfLength, ACPI_FIXED_REGISTER* status, ACPI_FIXED_REGISTER* enable) { ACPI_FIXED_REGISTER block = {0}; uint32_t legacy = AcpiReadU32(fadt, len, legacyOffset); if (legacy && legacy <= 0xFFFFu) { block.AddressSpaceId = 1; block.Address = legacy; } ACPI_FIXED_REGISTER extended = {0}; if (AcpiReadGasRegister(fadt, len, gasOffset, &extended)) block = extended; if (!block.Address || (block.AddressSpaceId == 1 && block.Address + halfLength * 2u - 1u > 0xFFFFu)) return; block.WidthBytes = halfLength; *status = block; block.Address += halfLength; *enable = block; } // Reports the fixed-feature power-button interrupt supported by this HAL. static KSTATUS AcpiQueryFixedButtonIrq(uint8_t* irqOut) { if (!irqOut) return NTLSTATUS_INVALID_PARAMETER; // A FADT control-method power button requires AML evaluation, not PM1 polling. if (gHwReducedAcpi || (gFadtFlags & FADT_FLAG_POWER_BUTTON) || !gSciIrq || gSciIrq >= 16u || !gPm1aStatus.Address || !gPm1aEnable.Address || !HalApicCanRouteIrq((uint8_t)gSciIrq)) return NTLSTATUS_NOT_SUPPORTED; *irqOut = (uint8_t)gSciIrq; return NTLSTATUS_SUCCESS; } // Discards any stale press then enables the PM1 fixed power-button SCI. static KSTATUS AcpiArmFixedButton(void) { uint8_t irq; KSTATUS status = AcpiQueryFixedButtonIrq(&irq); if (!KSUCCESS(status)) return status; // No SCI_EN means firmware still owns ACPI events. Never steal ownership // through SMI_CMD just to install a power-button handler during boot. if (!(AcpiReadFixedRegister(&gPm1aCnt) & 1u)) return NTLSTATUS_NOT_SUPPORTED; AcpiWriteFixedRegister(&gPm1aStatus, ACPI_PM1_POWER_BUTTON_BIT); if (gPm1bStatus.Address) AcpiWriteFixedRegister(&gPm1bStatus, ACPI_PM1_POWER_BUTTON_BIT); uint32_t enabled = AcpiReadFixedRegister(&gPm1aEnable); AcpiWriteFixedRegister(&gPm1aEnable, enabled | ACPI_PM1_POWER_BUTTON_BIT); if (gPm1bEnable.Address) { enabled = AcpiReadFixedRegister(&gPm1bEnable); AcpiWriteFixedRegister(&gPm1bEnable, enabled | ACPI_PM1_POWER_BUTTON_BIT); } gFixedPowerButtonArmed = true; return NTLSTATUS_SUCCESS; } // Acknowledges the fixed-button source only; the SCI may carry unrelated events. static bool AcpiConsumeFixedButton(void) { if (!gFixedPowerButtonArmed) return false; bool pressed = false; if (AcpiReadFixedRegister(&gPm1aStatus) & ACPI_PM1_POWER_BUTTON_BIT) { AcpiWriteFixedRegister(&gPm1aStatus, ACPI_PM1_POWER_BUTTON_BIT); pressed = true; } if (gPm1bStatus.Address && (AcpiReadFixedRegister(&gPm1bStatus) & ACPI_PM1_POWER_BUTTON_BIT)) { AcpiWriteFixedRegister(&gPm1bStatus, ACPI_PM1_POWER_BUTTON_BIT); pressed = true; } return pressed; } // Detects whether PM1 control is using the standard Intel PCH PMBASE layout. static void AcpiDetectIntelPchPmBase(void) { gIntelPchPmBase = 0; if (!gApi.Pci.Read32 || gPm1aCnt.AddressSpaceId != 0x01 || gPm1aCnt.Address > 0xFFFFu || (gPm1aCnt.Address & 0x7Fu) != 0x04u) { return; } uint32_t id = gApi.Pci.Read32(0, 0, 31, 0, 0x00u); uint32_t classRevision = gApi.Pci.Read32(0, 0, 31, 0, 0x08u); if ((id & 0xFFFFu) == 0x8086u && ((classRevision >> 16) & 0xFFFFu) == 0x0601u) gIntelPchPmBase = 1; } // Disables Intel PCH sleep trapping so SLP_EN reaches the hardware sleep transition. static void AcpiDisableIntelSleepSmiTrap(void) { if (!gIntelPchPmBase) return; uint64_t pmBase = gPm1aCnt.Address - 4u; if (pmBase > 0xFFFFu - INTEL_PCH_SMI_EN_OFFSET - 3u) return; uint16_t smiEnablePort = (uint16_t)(pmBase + INTEL_PCH_SMI_EN_OFFSET); uint32_t smiEnable = __indword(smiEnablePort); if (!(smiEnable & INTEL_PCH_SMI_ON_SLP_EN)) return; __outdword(smiEnablePort, smiEnable & ~INTEL_PCH_SMI_ON_SLP_EN); if (__indword(smiEnablePort) & INTEL_PCH_SMI_ON_SLP_EN) HalDbgPrint("HAL: Intel PCH refused to clear SMI_ON_SLP_EN.\n"); } // Requests ACPI mode when firmware left fixed power registers in legacy mode. static KSTATUS AcpiEnableModeForShutdown(void) { if (!gPm1aCnt.Address) return NTLSTATUS_NOT_SUPPORTED; if (AcpiReadFixedRegister(&gPm1aCnt) & 0x0001u) return NTLSTATUS_SUCCESS; if (!gSmiCommandPort || !gAcpiEnableValue || gSmiCommandPort > 0xFFFFu) return NTLSTATUS_NOT_SUPPORTED; __outbyte((uint16_t)gSmiCommandPort, gAcpiEnableValue); uint64_t startTick = gApi.Timer.QueryTicks ? gApi.Timer.QueryTicks() : 0; uint64_t deadline = startTick > UINT64_MAX - 3000000ull ? UINT64_MAX : startTick + 3000000ull; uint32_t fallbackWaits = 0; for (;;) { if (AcpiReadFixedRegister(&gPm1aCnt) & 0x0001u) return NTLSTATUS_SUCCESS; if (gApi.Timer.QueryTicks && gApi.Timer.QueryTicks() >= deadline) return NTLSTATUS_TIMEOUT; if (++fallbackWaits >= 3000u) return NTLSTATUS_TIMEOUT; if (gApi.Timer.Stall) gApi.Timer.Stall(1000u); else _mm_pause(); } } static bool AmlParsePkgLength(const uint8_t* p, const uint8_t* end, const uint8_t** body, const uint8_t** pkgEnd) { if (p >= end) return false; const uint8_t* start = p; uint8_t first = *p++; uint32_t follow = first >> 6; uint32_t length; if (follow == 0) { length = first & 0x3F; } else { length = first & 0x0F; for (uint32_t i = 0; i < follow; i++) { if (p >= end) return false; length |= ((uint32_t)*p++) << (4 + i * 8); } } if (start + length < p || start + length > end) return false; *body = p; *pkgEnd = start + length; return true; } static const uint8_t* AmlParseNameString(const uint8_t* p, const uint8_t* end, bool* lastSegmentIsS5) { uint32_t segments = 1; *lastSegmentIsS5 = false; // Optional root or parent prefixes: '\\', '^', '^^', ... while (p < end && (*p == 0x5C || *p == 0x5E)) p++; if (p >= end) return NULL; if (*p == 0x00) { // NullName return p + 1; } else if (*p == 0x2E) { // DualNamePrefix p++; segments = 2; } else if (*p == 0x2F) { // MultiNamePrefix p++; if (p >= end) return NULL; segments = *p++; } for (uint32_t s = 0; s < segments; s++) { if (p + 4 > end) return NULL; if (s == segments - 1 && memcmp(p, "_S5_", 4) == 0) *lastSegmentIsS5 = true; p += 4; } return p; } // Implements the aml Read Integer operation. static bool AmlReadInteger(const uint8_t** pp, const uint8_t* end, uint8_t* out) { const uint8_t* p = *pp; if (p >= end) return false; switch (*p++) { case 0x00: // ZeroOp *out = 0; break; case 0x01: // OneOp *out = 1; break; case 0x0A: // BytePrefix if (p >= end) return false; *out = *p++; break; case 0x0B: // WordPrefix if (p + 2 > end) return false; *out = p[0]; p += 2; break; case 0x0C: // DWordPrefix if (p + 4 > end) return false; *out = p[0]; p += 4; break; case 0x0E: // QWordPrefix if (p + 8 > end) return false; *out = p[0]; p += 8; break; default: return false; } *pp = p; return true; } // Scan DSDT AML for the _S5_ Name object and extract SLP_TYP values. Real // firmware commonly encodes the name as "\\_S5_" instead of just "_S5_", and // package integers may be ZeroOp/OneOp/Byte/Word/DWord/QWord constants. static bool ScanAmlForS5(const uint8_t* aml, uint32_t len, const char* source) { const uint8_t* end = aml + len; for (const uint8_t* cur = aml; cur < end; cur++) { if (*cur != 0x08) continue; // NameOp const uint8_t* p = cur + 1; bool isS5 = false; p = AmlParseNameString(p, end, &isS5); if (!p || !isS5 || p >= end || *p != 0x12) continue; // PackageOp const uint8_t* body; const uint8_t* pkgEnd; if (!AmlParsePkgLength(p + 1, end, &body, &pkgEnd)) continue; if (body >= pkgEnd) continue; uint8_t elements = *body++; if (elements < 2) continue; uint8_t typA, typB; if (!AmlReadInteger(&body, pkgEnd, &typA)) continue; if (!AmlReadInteger(&body, pkgEnd, &typB)) continue; gSlpTypA = typA & 0x07; gSlpTypB = typB & 0x07; gS5Found = 1; HalDbgPrint("HAL: _S5_ source=%s SLP_TYP_A=0x%02x SLP_TYP_B=0x%02x\n", source ? source : "AML", gSlpTypA, gSlpTypB); return true; } return false; } // Validates checksum. static bool validate_checksum(void* table, uint32_t length) { uint8_t sum = 0; uint8_t* bytes = (uint8_t*)table; for (uint32_t i = 0; i < length; i++) { sum += bytes[i]; } return sum == 0; } // Parses fadt. static void ParseFadt(const ACPISDTHeader* header) { const void* fadt = header; uint32_t len = header->Length; memset(&gPm1aCnt, 0, sizeof(gPm1aCnt)); memset(&gPm1bCnt, 0, sizeof(gPm1bCnt)); memset(&gPm1aStatus, 0, sizeof(gPm1aStatus)); memset(&gPm1bStatus, 0, sizeof(gPm1bStatus)); memset(&gPm1aEnable, 0, sizeof(gPm1aEnable)); memset(&gPm1bEnable, 0, sizeof(gPm1bEnable)); gSciIrq = 0; if (len >= FADT_SCI_INT_OFFSET + sizeof(gSciIrq)) memcpy(&gSciIrq, (const uint8_t*)fadt + FADT_SCI_INT_OFFSET, sizeof(gSciIrq)); memset(&gSleepControl, 0, sizeof(gSleepControl)); gLegacyPm1aPort = 0; gLegacyPm1bPort = 0; gFadtFlags = AcpiReadU32(fadt, len, FADT_FLAGS_OFFSET); if (AcpiReadByteGasRegister(fadt, len, FADT_RESET_REG_OFFSET, &gResetRegister) && FADT_RESET_VALUE_OFFSET < len) gResetValue = *((const uint8_t*)fadt + FADT_RESET_VALUE_OFFSET); gHwReducedAcpi = (gFadtFlags & FADT_FLAG_HW_REDUCED_ACPI) != 0; uint8_t pm1CntLength = FADT_PM1_CNT_LEN_OFFSET < len ? *((const uint8_t*)fadt + FADT_PM1_CNT_LEN_OFFSET) : 2u; if (pm1CntLength < 2u) pm1CntLength = 2u; if (pm1CntLength > 4u) pm1CntLength = 4u; uint32_t legacyPm1a = AcpiReadU32(fadt, len, FADT_PM1A_CNT_BLK_OFFSET); uint32_t legacyPm1b = AcpiReadU32(fadt, len, FADT_PM1B_CNT_BLK_OFFSET); gLegacyPm1aPort = legacyPm1a <= 0xFFFFu ? legacyPm1a : 0u; gLegacyPm1bPort = legacyPm1b <= 0xFFFFu ? legacyPm1b : 0u; if (legacyPm1a && legacyPm1a <= 0xFFFFu) { gPm1aCnt.AddressSpaceId = 0x01; gPm1aCnt.WidthBytes = pm1CntLength; gPm1aCnt.Address = legacyPm1a; } if (legacyPm1b && legacyPm1b <= 0xFFFFu) { gPm1bCnt.AddressSpaceId = 0x01; gPm1bCnt.WidthBytes = pm1CntLength; gPm1bCnt.Address = legacyPm1b; } // ACPI 2.0+ GAS fields supersede the legacy blocks when firmware supplies them. ACPI_FIXED_REGISTER extended; memset(&extended, 0, sizeof(extended)); if (AcpiReadGasRegister(fadt, len, FADT_X_PM1A_CNT_BLK_OFFSET, &extended)) gPm1aCnt = extended; memset(&extended, 0, sizeof(extended)); if (AcpiReadGasRegister(fadt, len, FADT_X_PM1B_CNT_BLK_OFFSET, &extended)) gPm1bCnt = extended; if (gHwReducedAcpi) (void)AcpiReadByteGasRegister(fadt, len, FADT_SLEEP_CONTROL_OFFSET, &gSleepControl); uint8_t eventLength = FADT_PM1_EVT_LEN_OFFSET < len ? *((const uint8_t*)fadt + FADT_PM1_EVT_LEN_OFFSET) : 0u; if (!gHwReducedAcpi && (eventLength == 4u || eventLength == 8u)) { uint8_t half = eventLength / 2u; AcpiConfigurePm1EventBlock(fadt, len, FADT_PM1A_EVT_BLK_OFFSET, FADT_X_PM1A_EVT_BLK_OFFSET, half, &gPm1aStatus, &gPm1aEnable); AcpiConfigurePm1EventBlock(fadt, len, FADT_PM1B_EVT_BLK_OFFSET, FADT_X_PM1B_EVT_BLK_OFFSET, half, &gPm1bStatus, &gPm1bEnable); } gSmiCommandPort = AcpiReadU32(fadt, len, FADT_SMI_CMD_OFFSET); gAcpiEnableValue = FADT_ACPI_ENABLE_OFFSET < len ? *((const uint8_t*)fadt + FADT_ACPI_ENABLE_OFFSET) : 0u; uint64_t dsdtPhys = AcpiReadU64(fadt, len, FADT_X_DSDT_OFFSET); if (!dsdtPhys) dsdtPhys = AcpiReadU32(fadt, len, FADT_DSDT_OFFSET); uint8_t centuryRegister = 0; if (FADT_CENTURY_OFFSET < len) centuryRegister = *((const uint8_t*)fadt + FADT_CENTURY_OFFSET); HalRtcSetCenturyRegister(centuryRegister); HalDbgPrint("HAL: FADT flags=0x%08x hw_reduced=%u PM1a_CNT=%u:0x%016llx legacy=0x%04x " "PM1b_CNT=%u:0x%016llx legacy=0x%04x SLEEP_CTL=%u:0x%016llx " "SMI=0x%08x DSDT=0x%016llx RTC_CENTURY=0x%02x\n", gFadtFlags, gHwReducedAcpi ? 1u : 0u, gPm1aCnt.AddressSpaceId, gPm1aCnt.Address, gLegacyPm1aPort, gPm1bCnt.AddressSpaceId, gPm1bCnt.Address, gLegacyPm1bPort, gSleepControl.AddressSpaceId, gSleepControl.Address, gSmiCommandPort, dsdtPhys, centuryRegister); if (dsdtPhys) { const ACPISDTHeader* dsdt = (const ACPISDTHeader*)(dsdtPhys + gPhysBase); if (memcmp(dsdt->Signature, "DSDT", 4) == 0 && // Validates checksum. validate_checksum((void*)dsdt, dsdt->Length)) { const uint8_t* aml = (const uint8_t*)(dsdt + 1); (void)ScanAmlForS5(aml, dsdt->Length - (uint32_t)sizeof(ACPISDTHeader), "DSDT"); } else { HalDbgPrint("HAL: DSDT invalid or checksum failed\n"); } } } // Implements the add Cpu Record operation. static void HalAddCpuRecord(uint32_t uid, uint32_t lapicId, uint32_t flags) { if (gCpuTopology.Count >= HAL_MAX_PROCESSORS) return; for (uint32_t i = 0; i < gCpuTopology.Count; i++) { if (gCpuTopology.Processors[i].HardwareId == lapicId) return; } HAL_PROCESSOR_INFO* cpu = &gCpuTopology.Processors[gCpuTopology.Count++]; memset(cpu, 0, sizeof(*cpu)); cpu->FirmwareId = uid; cpu->HardwareId = lapicId; cpu->Flags = flags; cpu->Enabled = (flags & 1u) ? 1u : 0u; } // Parses madt. 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 + 2 <= end) { uint8_t type = p[0], len = p[1]; 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); uint32_t base; memcpy(&base, p + 8, sizeof(base)); HalApicSetGsiBase(base); } else if (type == 2 && len >= 10 && p[2] == 0) { // ISA source override uint32_t gsi; uint16_t flags; memcpy(&gsi, p + 4, sizeof(gsi)); memcpy(&flags, p + 8, sizeof(flags)); HalApicSetIsaOverride(p[3], gsi, flags); } 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) HalAddCpuRecord(uid, lapicId, flags); } p += len; } } // Implements the walk Acpi operation. static void WalkAcpi(uintptr_t rsdpPhys) { if (!rsdpPhys) return; // Map RSDP into virtual memory. RSDP* rsdp = (RSDP*)(rsdpPhys + gPhysBase); if (memcmp(rsdp->Signature, "RSD PTR ", 8) != 0) { HalDbgPrint("HAL: Invalid RSDP signature!\n"); return; } ACPISDTHeader* sdtHeader = NULL; uint32_t count = 0; bool isXsdt = false; // Safely find and validate the XSDT (ACPI 2.0+). if (rsdp->Revision >= 2 && rsdp->XsdtAddress != 0) { XSDT* xsdt = (XSDT*)(rsdp->XsdtAddress + gPhysBase); if (validate_checksum(xsdt, xsdt->Header.Length) && // Implements the memcmp operation. memcmp(xsdt->Header.Signature, "XSDT", 4) == 0) { sdtHeader = &xsdt->Header; count = (xsdt->Header.Length - sizeof(ACPISDTHeader)) / 8; isXsdt = true; } } // Fallback to safely finding and validating the RSDT (ACPI 1.0). if (sdtHeader == NULL && rsdp->RsdtAddress != 0) { RSDT* rsdt = (RSDT*)((uintptr_t)rsdp->RsdtAddress + gPhysBase); if (validate_checksum(rsdt, rsdt->Header.Length) && // Implements the memcmp operation. memcmp(rsdt->Header.Signature, "RSDT", 4) == 0) { sdtHeader = &rsdt->Header; count = (rsdt->Header.Length - sizeof(ACPISDTHeader)) / 4; isXsdt = 0; } } if (sdtHeader == NULL) { HalDbgPrint("HAL: No valid XSDT or RSDT found!\n"); return; } // Walk the tables. for (uint32_t i = 0; i < count; i++) { uintptr_t tablePhys = 0; if (isXsdt) { tablePhys = ((XSDT*)sdtHeader)->PointerToOtherSDT[i]; } else { tablePhys = ((RSDT*)sdtHeader)->PointerToOtherSDT[i]; } // Paranoid alignment check to reject firmware garbage pointers. if (!tablePhys || (tablePhys & 3) != 0) continue; ACPISDTHeader* header = (ACPISDTHeader*)(tablePhys + gPhysBase); // Ensure the table isn't corrupt before parsing. if (!validate_checksum(header, header->Length)) continue; // Parse MADT. if (memcmp(header->Signature, "APIC", 4) == 0) { ParseMadt((MADT*)header); } // Parse FADT (signature "FACP") for PM1 control ports and DSDT pointer. else if (memcmp(header->Signature, "FACP", 4) == 0) { ParseFadt(header); } // Parse HPET. else if (memcmp(header->Signature, "HPET", 4) == 0) { // HPET base address block is located at offset 44 // (which is 8 bytes past the 36-byte ACPISDTHeader). gHpetPhys = *(uint64_t*)((uint8_t*)header + 44) & ~0xFFFULL; } else if (memcmp(header->Signature, "SSDT", 4) == 0 && !gS5Found && header->Length >= sizeof(ACPISDTHeader)) { const uint8_t* aml = (const uint8_t*)(header + 1); (void)ScanAmlForS5(aml, header->Length - (uint32_t)sizeof(ACPISDTHeader), "SSDT"); } } if (!gS5Found) HalDbgPrint("HAL: _S5_ not found in DSDT or SSDT AML; ACPI S5 unavailable\n"); } // HalShutdown - ACPI S5 soft power-off. Does not return. static void HalShutdown(void) { if (!gS5Found) { HalDbgPrint("HAL: shutdown unsupported: firmware _S5_ object was not resolved.\n"); HalStopProcessor(); } if (gHwReducedAcpi) { if (!gSleepControl.Address) { HalDbgPrint("HAL: shutdown unsupported: HW-reduced ACPI has no Sleep Control register.\n"); HalStopProcessor(); } uint32_t sleepValue = ((uint32_t)gSlpTypA << 2) | (1u << 5); (void)HalDisableInterrupts(); AcpiWriteFixedRegister(&gSleepControl, sleepValue); } else { if (!gPm1aCnt.Address) { HalDbgPrint("HAL: shutdown unsupported: PM1a control register is unavailable.\n"); HalStopProcessor(); } // Some Intel PCH firmware leaves SMI_ON_SLP_EN armed after boot. When set, // the chipset traps SLP_EN into SMM and explicitly suppresses the sleep transition. AcpiDisableIntelSleepSmiTrap(); // Try the fixed-register S5 request before changing ACPI ownership. A late // SMI_CMD transition can itself enter firmware SMM on machines that boot with SCI_EN clear. uint32_t valA = AcpiReadFixedRegister(&gPm1aCnt); valA &= ~(0x7u << 10); valA |= ((uint32_t)gSlpTypA << 10) | (1u << 13); uint32_t valB = 0u; if (gPm1bCnt.Address) { valB = AcpiReadFixedRegister(&gPm1bCnt); valB &= ~(0x7u << 10); valB |= ((uint32_t)gSlpTypB << 10) | (1u << 13); } uintptr_t interruptFlags = HalDisableInterrupts(); AcpiWriteFixedRegister(&gPm1aCnt, valA); if (gPm1bCnt.Address) AcpiWriteFixedRegister(&gPm1bCnt, valB); if (gApi.Timer.Stall) gApi.Timer.Stall(50000u); // If the direct request returned, fall back to the firmware ownership path. HalRestoreInterrupts(interruptFlags); (void)AcpiEnableModeForShutdown(); AcpiDisableIntelSleepSmiTrap(); valA = AcpiReadFixedRegister(&gPm1aCnt); valA &= ~(0x7u << 10); valA |= ((uint32_t)gSlpTypA << 10) | (1u << 13); if (gPm1bCnt.Address) { valB = AcpiReadFixedRegister(&gPm1bCnt); valB &= ~(0x7u << 10); valB |= ((uint32_t)gSlpTypB << 10) | (1u << 13); } (void)HalDisableInterrupts(); AcpiWriteFixedRegister(&gPm1aCnt, valA); if (gPm1bCnt.Address) AcpiWriteFixedRegister(&gPm1bCnt, valB); if (gApi.Timer.Stall) gApi.Timer.Stall(50000u); bool selectedPm1aIsLegacy = gPm1aCnt.AddressSpaceId == 0x01 && gPm1aCnt.Address == gLegacyPm1aPort; if (gLegacyPm1aPort && !selectedPm1aIsLegacy) { uint16_t legacyA = __inword((uint16_t)gLegacyPm1aPort); legacyA = (uint16_t)((legacyA & ~(0x7u << 10)) | ((uint16_t)gSlpTypA << 10) | (1u << 13)); uint16_t legacyB = 0u; if (gLegacyPm1bPort) { legacyB = __inword((uint16_t)gLegacyPm1bPort); legacyB = (uint16_t)((legacyB & ~(0x7u << 10)) | ((uint16_t)gSlpTypB << 10) | (1u << 13)); } AcpiDisableIntelSleepSmiTrap(); __outword((uint16_t)gLegacyPm1aPort, legacyA); if (gLegacyPm1bPort) __outword((uint16_t)gLegacyPm1bPort, legacyB); } } if (gApi.Timer.Stall) gApi.Timer.Stall(100000u); HalDbgPrint("HAL: shutdown failed: firmware returned from S5 request.\n"); HalStopProcessor(); } static void HalReset(void) { (void)HalDisableInterrupts(); if (gResetRegister.Address && gResetValue) AcpiWriteFixedRegister(&gResetRegister, gResetValue); if (gApi.Timer.Stall) gApi.Timer.Stall(100000u); __outbyte(0xCF9u, 0x06u); if (gApi.Timer.Stall) gApi.Timer.Stall(100000u); __outbyte(0x64u, 0xFEu); if (gApi.Timer.Stall) gApi.Timer.Stall(100000u); HalDbgPrint("HAL: reset failed\n"); HalStopProcessor(); } static KSTATUS HalQueryProcessorTopology(HAL_PROCESSOR_TOPOLOGY* out) { if (!out) return NTLSTATUS_INVALID_PARAMETER; memset(out, 0, sizeof(*out)); *out = gCpuTopology; if (!out->Count) { out->Count = 1; out->BootProcessorHardwareId = HalApicGetBootProcessorId(); out->Processors[0].HardwareId = out->BootProcessorHardwareId; out->Processors[0].FirmwareId = 0; out->Processors[0].Flags = 1; out->Processors[0].Enabled = 1; out->Processors[0].IsBootProcessor = 1; out->Processors[0].Startable = 1; return NTLSTATUS_SUCCESS; } uint32_t bsp = HalApicGetBootProcessorId(); out->BootProcessorHardwareId = bsp; int foundBsp = 0; for (uint32_t i = 0; i < out->Count; i++) { out->Processors[i].IsBootProcessor = (out->Processors[i].HardwareId == bsp) ? 1u : 0u; out->Processors[i].Startable = out->Processors[i].IsBootProcessor || HalApicCanAddressId(out->Processors[i].HardwareId); if (out->Processors[i].IsBootProcessor) foundBsp = 1; } if (!foundBsp && out->Count < HAL_MAX_PROCESSORS) { HAL_PROCESSOR_INFO* cpu = &out->Processors[out->Count++]; memset(cpu, 0, sizeof(*cpu)); cpu->HardwareId = bsp; cpu->FirmwareId = bsp; cpu->Flags = 1; cpu->Enabled = 1; cpu->IsBootProcessor = 1; cpu->Startable = 1; } return NTLSTATUS_SUCCESS; } HAL_ENTRY KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) { if (!initParams || initParams->Size != sizeof(HAL_INIT_PARAMS) || initParams->Flags != 0 || !initParams->PhysicalWindowBase || !initParams->AllocatePool) return NTLSTATUS_INVALID_PARAMETER; if (gInitialised) return NTLSTATUS_ALREADY_EXISTS; gPhysBase = initParams->PhysicalWindowBase; debugEnabled = initParams->Debug; HalOutputInitialize(&gApi.Output); HalSerialInitialize(&gApi.Output); // Screen follows serial so diagnostics still work without a framebuffer. HalScreenInitialize(initParams->AllocatePool, initParams->FramebufferBase + initParams->PhysicalWindowBase, (int)initParams->FramebufferWidth, (int)initParams->FramebufferHeight, (int)initParams->FramebufferStride, &gApi.Screen); HalScreenRegisterOutputEndpoint(&gApi.Output); HalDbgPrint("HAL: screen %dx%d\n", initParams->FramebufferWidth, initParams->FramebufferHeight); // Parse ACPI to find LAPIC / IOAPIC / HPET addresses. if (initParams->RsdpPhysical) WalkAcpi(initParams->RsdpPhysical); HalDbgPrint("HAL: LAPIC=%016llx IOAPIC=%016llx HPET=%016llx\n", gLapicPhys, gIoapicPhys, gHpetPhys); HalApicSetSciIrq(gSciIrq); HalApicInitialize(gLapicPhys, gIoapicPhys); HalDbgPrint("HAL: local APIC mode=%s BSP_ID=%u\n", HalApicUsingX2Apic() ? "x2APIC" : "xAPIC", HalApicGetBootProcessorId()); KSTATUS ts = HalTimerInitialize(gLapicPhys, gHpetPhys, &gApi.Timer); if (!KSUCCESS(ts)) HalDbgPrint("HAL: HPET unavailable, using fallback\n"); HalRtcInitialize(&gApi.Rtc); HalPciInitialize(&gApi.Pci); gApi.Power.Shutdown = HalShutdown; gApi.Power.Reset = HalReset; gApi.Power.QueryFixedButtonIrq = AcpiQueryFixedButtonIrq; gApi.Power.ArmFixedButton = AcpiArmFixedButton; gApi.Power.ConsumeFixedButton = AcpiConsumeFixedButton; AcpiDetectIntelPchPmBase(); gInitialised = 1; // 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 } gApi.Timer.Stall(1); // Micro-stalls } HalDbgPrint("HAL: initialisation complete.\n"); return NTLSTATUS_SUCCESS; } // Returns api. HAL_ENTRY const HAL_API* HalGetApi(void) { return &gApi; }