isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.

This commit is contained in:
maksw committed 2026-09-16 10:33:20 +02:00
1 parent 3dacbd32c8
commit 73abd6f90d
441 files changed
+187073 -6549

No files matched your search

+304 -46
View File
@@ -8,6 +8,7 @@
#include <kernel/hal/hal_timer.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <intrin.h>
#include <common/printf.h>
@@ -112,11 +113,26 @@ 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.
static uint16_t gPm1aCntBlk = 0;
static uint16_t gPm1bCntBlk = 0;
static uint8_t gSlpTypA = 0;
static uint8_t gSlpTypB = 0;
static int gS5Found = 0;
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 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.
@@ -156,13 +172,21 @@ void* HalPhysicalToVirtual(uint64_t phys) {
// 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_DSDT_OFFSET 40u
#define FADT_PM1A_CNT_BLK_OFFSET 64u
#define FADT_PM1B_CNT_BLK_OFFSET 68u
#define FADT_X_DSDT_OFFSET 140u
#define FADT_X_PM1A_CNT_BLK_OFFSET 172u
#define FADT_X_PM1B_CNT_BLK_OFFSET 184u
#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_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 {
@@ -190,19 +214,131 @@ static uint64_t AcpiReadU64(const void* table, uint32_t tableLen, uint32_t off)
return value;
}
// Implements the acpi Read Gas Io Port operation.
static uint16_t AcpiReadGasIoPort(const void* table, uint32_t tableLen, uint32_t off) {
// Decodes one ACPI Generic Address Structure used for fixed power registers.
static int AcpiReadGasRegister(const void* table, uint32_t tableLen, uint32_t off,
ACPI_FIXED_REGISTER* out) {
if (!out || off + sizeof(ACPI_GAS) > tableLen) return 0;
ACPI_GAS gas;
if (off + sizeof(gas) > tableLen) return 0;
memcpy(&gas, (const uint8_t*)table + off, sizeof(gas));
if (!gas.Address || gas.RegisterBitOffset != 0) return 0;
if (gas.AddressSpaceId != 0x00 && gas.AddressSpaceId != 0x01) return 0;
if (gas.AddressSpaceId == 0x01 && gas.Address > 0xFFFFu) return 0;
// 0x01 == System I/O. HalShutdown currently writes PM1_CNT with outw(),
// so ignore MMIO GAS entries until the HAL grows MMIO register access here.
if (gas.AddressSpaceId != 0x01 || gas.Address == 0 || gas.Address > 0xFFFF)
return 0;
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;
return (uint16_t)gas.Address;
out->AddressSpaceId = gas.AddressSpaceId;
out->WidthBytes = widthBytes;
out->Address = gas.Address;
return 1;
}
// Decodes one byte-wide ACPI GAS used by the HW-reduced Sleep Control register.
static int AcpiReadByteGasRegister(const void* table, uint32_t tableLen, uint32_t off,
ACPI_FIXED_REGISTER* out) {
if (!out || off + sizeof(ACPI_GAS) > tableLen) return 0;
ACPI_GAS gas;
memcpy(&gas, (const uint8_t*)table + off, sizeof(gas));
if (!gas.Address || gas.RegisterBitOffset != 0 || gas.RegisterBitWidth != 8) return 0;
if (gas.AddressSpaceId != 0x00 && gas.AddressSpaceId != 0x01) return 0;
if (gas.AddressSpaceId == 0x01 && gas.Address > 0xFFFFu) return 0;
out->AddressSpaceId = gas.AddressSpaceId;
out->WidthBytes = 1u;
out->Address = gas.Address;
return 1;
}
// 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;
}
// 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 int AmlParsePkgLength(const uint8_t* p, const uint8_t* end,
@@ -302,7 +438,7 @@ static int AmlReadInteger(const uint8_t** pp, const uint8_t* end, uint8_t* out)
// 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 void ScanDsdtForS5(const uint8_t* aml, uint32_t len) {
static int 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++) {
@@ -329,12 +465,12 @@ static void ScanDsdtForS5(const uint8_t* aml, uint32_t len) {
gSlpTypB = typB & 0x07;
gS5Found = 1;
HalDbgPrint("HAL: _S5_ SLP_TYP_A=0x%02x SLP_TYP_B=0x%02x\n",
gSlpTypA, gSlpTypB);
return;
HalDbgPrint("HAL: _S5_ source=%s SLP_TYP_A=0x%02x SLP_TYP_B=0x%02x\n",
source ? source : "AML", gSlpTypA, gSlpTypB);
return 1;
}
HalDbgPrint("HAL: _S5_ not found in DSDT; ACPI shutdown disabled\n");
return 0;
}
// Validates checksum.
@@ -352,13 +488,50 @@ static void ParseFadt(const ACPISDTHeader* header) {
const void* fadt = header;
uint32_t len = header->Length;
gPm1aCntBlk = (uint16_t)AcpiReadU32(fadt, len, FADT_PM1A_CNT_BLK_OFFSET);
gPm1bCntBlk = (uint16_t)AcpiReadU32(fadt, len, FADT_PM1B_CNT_BLK_OFFSET);
memset(&gPm1aCnt, 0, sizeof(gPm1aCnt));
memset(&gPm1bCnt, 0, sizeof(gPm1bCnt));
memset(&gSleepControl, 0, sizeof(gSleepControl));
gLegacyPm1aPort = 0;
gLegacyPm1bPort = 0;
gFadtFlags = AcpiReadU32(fadt, len, FADT_FLAGS_OFFSET);
gHwReducedAcpi = (gFadtFlags & FADT_FLAG_HW_REDUCED_ACPI) != 0;
if (!gPm1aCntBlk)
gPm1aCntBlk = AcpiReadGasIoPort(fadt, len, FADT_X_PM1A_CNT_BLK_OFFSET);
if (!gPm1bCntBlk)
gPm1bCntBlk = AcpiReadGasIoPort(fadt, len, FADT_X_PM1B_CNT_BLK_OFFSET);
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);
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)
@@ -369,8 +542,14 @@ static void ParseFadt(const ACPISDTHeader* header) {
centuryRegister = *((const uint8_t*)fadt + FADT_CENTURY_OFFSET);
HalRtcSetCenturyRegister(centuryRegister);
HalDbgPrint("HAL: FADT PM1a_CNT=0x%04x PM1b_CNT=0x%04x DSDT=0x%016llx RTC_CENTURY=0x%02x\n",
gPm1aCntBlk, gPm1bCntBlk, dsdtPhys, 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);
@@ -378,7 +557,7 @@ static void ParseFadt(const ACPISDTHeader* header) {
// Validates checksum.
validate_checksum((void*)dsdt, dsdt->Length)) {
const uint8_t* aml = (const uint8_t*)(dsdt + 1);
ScanDsdtForS5(aml, dsdt->Length - (uint32_t)sizeof(ACPISDTHeader));
(void)ScanAmlForS5(aml, dsdt->Length - (uint32_t)sizeof(ACPISDTHeader), "DSDT");
} else {
HalDbgPrint("HAL: DSDT invalid or checksum failed\n");
}
@@ -514,28 +693,106 @@ static void WalkAcpi(uintptr_t rsdpPhys) {
// 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) {
// Refuse further maskable interrupts before entering firmware power state.
(void)HalDisableInterrupts();
if (!gS5Found || !gPm1aCntBlk) {
// Refuse to guess. Guessing SLP_TYP is exactly how real hardware gets
// put into S3/S4 sleep instead of S5 soft-off.
if (!gS5Found) {
HalDbgPrint("HAL: shutdown unsupported: firmware _S5_ object was not resolved.\n");
HalStopProcessor();
}
// SLP_EN (bit 13) | SLP_TYPx (bits 12:10).
uint16_t valA = (uint16_t)(((uint16_t)gSlpTypA << 10) | (1 << 13));
uint16_t valB = (uint16_t)(((uint16_t)gSlpTypB << 10) | (1 << 13));
if (gHwReducedAcpi) {
if (!gSleepControl.Address) {
HalDbgPrint("HAL: shutdown unsupported: HW-reduced ACPI has no Sleep Control register.\n");
HalStopProcessor();
}
__outword(gPm1aCntBlk, valA);
if (gPm1bCntBlk) __outword(gPm1bCntBlk, valB);
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();
}
@@ -616,8 +873,9 @@ HAL_ENTRY KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
HalRtcInitialize(&gApi.Rtc);
HalPciInitialize(&gApi.Pci);
gApi.Power.Shutdown = HalShutdown;
gApi.Power.Shutdown = HalShutdown;
AcpiDetectIntelPchPmBase();
gInitialised = 1;
// The 8042 can leave output bytes pending while the keyboard/mouse drivers