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
+98
-52
@@ -1,14 +1,14 @@
|
||||
#include <ntlite/atomic.h>
|
||||
// Kernel power coordinator and optional firmware-provider binding.
|
||||
|
||||
#include <ntlite/syscall.h>
|
||||
#include <ntlite/ddk/power.h>
|
||||
#include <kernel/ke_power.h>
|
||||
#include <kernel/ke_process.h>
|
||||
#include <kernel/ke_event.h>
|
||||
#include <kernel/ke_spinlock.h>
|
||||
#include <kernel/ke_irq.h>
|
||||
#include <kernel/ke_dpc.h>
|
||||
#include <kernel/ke_settings.h>
|
||||
#include <kernel/ke_debug.h>
|
||||
#include <kernel/hal/hal_api.h>
|
||||
#include <kernel/ob_object.h>
|
||||
#include <string.h>
|
||||
|
||||
static SPINLOCK gPowerLock = SPINLOCK_INIT;
|
||||
@@ -17,70 +17,116 @@ static EVENT* gPowerComplete;
|
||||
static PROCESS* gInit;
|
||||
static uint32_t gAction;
|
||||
static bool gCommitted;
|
||||
static const HAL_API* gButtonHal;
|
||||
static bool gPolicyReady;
|
||||
static bool gEarlyButtonPressed;
|
||||
static uint32_t gButtonAction;
|
||||
static KDPC gPowerButtonDpc;
|
||||
static NTL_FIRMWARE_POWER_PROVIDER gFirmwareProvider;
|
||||
static bool gFirmwarePrepared;
|
||||
static uint32_t gPreparedAction;
|
||||
|
||||
KSTATUS KePowerInitialize(void) {
|
||||
if (gPowerRequest) return NTLSTATUS_ALREADY_EXISTS;
|
||||
KSTATUS st = KeEventCreate(EventManualReset, false, &gPowerRequest);
|
||||
if (!KSUCCESS(st)) return st;
|
||||
st = KeEventCreate(EventManualReset, false, &gPowerComplete);
|
||||
return st;
|
||||
EVENT* request = NULL;
|
||||
EVENT* complete = NULL;
|
||||
KSTATUS status = KeEventCreate(EventManualReset, false, &request);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
status = KeEventCreate(EventManualReset, false, &complete);
|
||||
if (!KSUCCESS(status)) {
|
||||
ObDereferenceObject((OBJECT*)request);
|
||||
return status;
|
||||
}
|
||||
gPowerRequest = request;
|
||||
gPowerComplete = complete;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Delivers the physical action after interrupt-exit processing.
|
||||
static void KiPowerButtonDpc(KDPC* dpc, void* context, void* arg1, void* arg2) {
|
||||
(void)dpc;
|
||||
(void)context;
|
||||
(void)arg1;
|
||||
(void)arg2;
|
||||
(void)KePowerRequestHardware(gButtonAction);
|
||||
// The resident firmware owner may be ACPICA or another platform implementation.
|
||||
__declspec(dllexport) KSTATUS KeRegisterFirmwarePowerProvider(
|
||||
const NTL_FIRMWARE_POWER_PROVIDER* provider) {
|
||||
if (!provider || provider->Size != sizeof(*provider) ||
|
||||
!provider->Prepare || !provider->Enter)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPowerLock);
|
||||
KSTATUS status = gFirmwareProvider.Size ? NTLSTATUS_ALREADY_EXISTS : NTLSTATUS_SUCCESS;
|
||||
if (KSUCCESS(status)) gFirmwareProvider = *provider;
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
if (KSUCCESS(status)) DbgPrint("power: firmware provider registered\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
// The ACPI SCI handler only acknowledges the fixed event and queues normal work.
|
||||
static void KiPowerButtonIsr(void) {
|
||||
if (!gButtonHal || !gButtonHal->Power.ConsumeFixedButton ||
|
||||
!gButtonHal->Power.ConsumeFixedButton()) return;
|
||||
(void)KeInsertQueueDpc(&gPowerButtonDpc, NULL, NULL);
|
||||
// Events before system-root policy becomes available are retained once.
|
||||
__declspec(dllexport) KSTATUS KeNotifyPowerButton(void) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPowerLock);
|
||||
if (!gPowerRequest) {
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
}
|
||||
if (!gPolicyReady) {
|
||||
gEarlyButtonPressed = true;
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
uint32_t action = gButtonAction;
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
return action ? KePowerRequestHardware(action) : NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Reads immutable boot-time button policy and attaches it to the fixed ACPI SCI.
|
||||
void KePowerInitializeButton(const HAL_API* hal) {
|
||||
// System-root policy is loaded independently of the presence of a firmware driver.
|
||||
void KePowerInitializePolicy(void) {
|
||||
char mode[24];
|
||||
KSTATUS status = KeGetSettingString("power", "button", mode, sizeof(mode));
|
||||
if (!KSUCCESS(status))
|
||||
KePanic(KE_PANIC_CODE_INIT, "power: missing [power] button, status=0x%x\n", status);
|
||||
if (strcmp(mode, "ignore") == 0) {
|
||||
DbgPrint("power: ACPI power button ignored by policy\n");
|
||||
return;
|
||||
}
|
||||
if (strcmp(mode, "shutdown") == 0) gButtonAction = SYS_POWER_ACTION_SHUTDOWN;
|
||||
else if (strcmp(mode, "restart") == 0) gButtonAction = SYS_POWER_ACTION_RESTART;
|
||||
else KePanic(KE_PANIC_CODE_INIT, "power: invalid [power] button=%s\n", mode);
|
||||
uint32_t action = 0;
|
||||
if (strcmp(mode, "shutdown") == 0) action = SYS_POWER_ACTION_SHUTDOWN;
|
||||
else if (strcmp(mode, "restart") == 0) action = SYS_POWER_ACTION_RESTART;
|
||||
else if (strcmp(mode, "ignore") != 0)
|
||||
KePanic(KE_PANIC_CODE_INIT, "power: invalid [power] button=%s\n", mode);
|
||||
|
||||
if (!hal || !hal->Power.QueryFixedButtonIrq || !hal->Power.ArmFixedButton ||
|
||||
!hal->Power.ConsumeFixedButton) {
|
||||
DbgPrint("power: no ACPI fixed power button HAL support\n");
|
||||
return;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPowerLock);
|
||||
gButtonAction = action;
|
||||
gPolicyReady = true;
|
||||
bool pending = gEarlyButtonPressed;
|
||||
bool providerPresent = gFirmwareProvider.Size != 0;
|
||||
gEarlyButtonPressed = false;
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
DbgPrint("power: button policy=%s firmware provider=%s\n",
|
||||
mode, providerPresent ? "present" : "absent");
|
||||
if (pending && action) (void)KePowerRequestHardware(action);
|
||||
}
|
||||
|
||||
// A provider prepares firmware while threads, device resources and AML can run.
|
||||
KSTATUS KePowerPrepareFirmware(uint32_t action) {
|
||||
if (action != SYS_POWER_ACTION_SHUTDOWN && action != SYS_POWER_ACTION_RESTART)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
NTL_FIRMWARE_POWER_PROVIDER provider;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPowerLock);
|
||||
provider = gFirmwareProvider;
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
if (!provider.Size) return NTLSTATUS_NOT_SUPPORTED;
|
||||
flags = KeAcquireSpinlock(&gPowerLock);
|
||||
gFirmwarePrepared = false;
|
||||
gPreparedAction = 0;
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
KSTATUS status = provider.Prepare(provider.Context, action);
|
||||
if (KSUCCESS(status)) {
|
||||
flags = KeAcquireSpinlock(&gPowerLock);
|
||||
gFirmwarePrepared = true;
|
||||
gPreparedAction = action;
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
}
|
||||
uint8_t irq = 0;
|
||||
status = hal->Power.QueryFixedButtonIrq(&irq);
|
||||
if (!KSUCCESS(status)) {
|
||||
DbgPrint("power: ACPI fixed button unavailable (0x%x); AML button not yet supported\n", status);
|
||||
return;
|
||||
}
|
||||
// The IOAPIC is still masked for this IRQ. Arm the firmware source first,
|
||||
// then install the kernel handler and finally unmask via KeIrqRegister.
|
||||
status = hal->Power.ArmFixedButton();
|
||||
if (!KSUCCESS(status)) {
|
||||
DbgPrint("power: cannot arm fixed button IRQ %u, status=0x%x\n", irq, status);
|
||||
return;
|
||||
}
|
||||
KeInitializeDpc(&gPowerButtonDpc, KiPowerButtonDpc, NULL);
|
||||
gButtonHal = hal;
|
||||
KeIrqRegister(irq, KiPowerButtonIsr);
|
||||
DbgPrint("power: ACPI fixed button armed on IRQ %u, action=%s\n", irq, mode);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Any returned transition leaves the HAL as the supported final fallback.
|
||||
KSTATUS KePowerEnterFirmware(uint32_t action) {
|
||||
NTL_FIRMWARE_POWER_PROVIDER provider;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPowerLock);
|
||||
bool prepared = gFirmwarePrepared && gPreparedAction == action;
|
||||
provider = gFirmwareProvider;
|
||||
KeReleaseSpinlock(&gPowerLock, flags);
|
||||
if (!prepared || !provider.Size) return NTLSTATUS_NOT_SUPPORTED;
|
||||
return provider.Enter(provider.Context, action);
|
||||
}
|
||||
|
||||
void KePowerSetInitProcess(PROCESS* init) {
|
||||
|
||||
Reference in new issue
Block a user