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:
maksw committed 2026-10-28 15:18:43 +01:00
1 parent d36f19509c
commit 36eef8f58d
696 files changed
+147281 -7530

No files matched your search

+17 -4
View File
@@ -12,6 +12,7 @@
#include <stddef.h>
#include <ntlite/status.h>
#include <ntlite/ddi/io_driver.h>
#include <ntlite/ddk/interrupt.h>
#ifndef PCI_API
# ifdef PCI_SYS_BUILD
@@ -115,8 +116,20 @@ PCI_API KSTATUS PciEnableDevice(DEVICE_OBJECT* pdo,
PCI_API KSTATUS PciGetInterrupt(DEVICE_OBJECT* pdo,
uint8_t* outIrq);
PCI_API KSTATUS PciEnableMsi(DEVICE_OBJECT* pdo,
uint8_t irqSlot);
typedef struct PCI_INTERRUPT_REQUEST {
KE_INTERRUPT_ROUTINE Routine;
void* Context;
uint64_t Affinity;
KE_INTERRUPT* Interrupt;
// Owned and cleared by pci.sys while the interrupt is connected.
void* BusContext;
} PCI_INTERRUPT_REQUEST;
PCI_API KSTATUS PciEnableMsiAuto(DEVICE_OBJECT* pdo,
uint8_t* outIrqSlot);
// Allocates and programs one or more MSI-X/MSI routes, or a shared INTx route.
PCI_API KSTATUS PciConnectInterrupts(DEVICE_OBJECT* pdo,
PCI_INTERRUPT_REQUEST* requests,
uint32_t count, bool* usingMessages);
// Disable the PCI source before releasing the interrupt objects.
PCI_API void PciDisconnectInterrupts(DEVICE_OBJECT* pdo,
PCI_INTERRUPT_REQUEST* requests,
uint32_t count);
+1
View File
@@ -20,6 +20,7 @@
#include <ntlite/ddk/mutex.h>
#include <ntlite/ddk/object.h>
#include <ntlite/ddk/platform.h>
#include <ntlite/ddk/power.h>
#include <ntlite/ddk/scheduler.h>
#include <ntlite/ddk/semaphore.h>
#include <ntlite/ddk/settings.h>
+2 -1
View File
@@ -15,11 +15,12 @@
#define KE_DEBUG_POOL_CALLERS 0x00000040u // Track pool allocation/free callers.
#define KE_DEBUG_DISPLAY_ASSERTS 0x00000080u // Enable display-path consistency assertions.
#define KE_DEBUG_LIST_CHECKS 0x00000100u // Validate intrusive-list links on mutation.
#define KE_DEBUG_ACPI_INFO 0x00000200u // Include ACPICA informational output.
#define KE_DEBUG_VALID_MASK (KE_DEBUG_CONSOLE | KE_DEBUG_SELFTEST | KE_DEBUG_FILE_LOG | \
KE_DEBUG_POOL_CANARY | KE_DEBUG_POOL_POISON | \
KE_DEBUG_POOL_QUARANTINE | KE_DEBUG_POOL_CALLERS | \
KE_DEBUG_DISPLAY_ASSERTS | KE_DEBUG_LIST_CHECKS)
KE_DEBUG_DISPLAY_ASSERTS | KE_DEBUG_LIST_CHECKS | KE_DEBUG_ACPI_INFO)
+44 -9
View File
@@ -1,22 +1,57 @@
// Public nt-lite DDK interrupt declarations.
// Kernel interrupt objects and platform source registration.
#pragma once
#include <stdint.h>
#include <ntlite/status.h>
typedef struct KE_INTERRUPT KE_INTERRUPT;
typedef void (*KE_INTERRUPT_ROUTINE)(void* context);
typedef struct KE_INTERRUPT_INFO {
uint32_t CpuIndex;
uint32_t HardwareId;
uint32_t Gsi;
uint16_t Flags;
uint8_t Vector;
uint8_t IsMessage;
uint64_t Delivered;
} KE_INTERRUPT_INFO;
typedef enum KE_INTERRUPT_MESSAGE_OPERATION {
KeInterruptMessageQuiesce = 1,
KeInterruptMessageProgram,
KeInterruptMessageResume
} KE_INTERRUPT_MESSAGE_OPERATION;
typedef struct NTL_DDK_MSI_MESSAGE {
uint64_t Address;
uint32_t Data;
uint32_t Reserved;
} NTL_DDK_MSI_MESSAGE;
// Only the bus owner programs a device's message source. The interrupt manager
// selects CPUs/vectors and coordinates quiescence with this device callback.
typedef KSTATUS (*KE_INTERRUPT_MESSAGE_PROGRAM)(void* context,
KE_INTERRUPT_MESSAGE_OPERATION operation, const NTL_DDK_MSI_MESSAGE* message);
// The platform owns GSI routing and ISA overrides; drivers own only their handler.
__declspec(dllexport) KSTATUS KeInterruptConnectGsi(uint32_t gsi, uint16_t flags,
uint64_t affinity, KE_INTERRUPT_ROUTINE routine, void* context, KE_INTERRUPT** out);
__declspec(dllexport) KSTATUS KeInterruptConnectIsa(uint8_t isaIrq, uint16_t sourceFlags, uint64_t affinity,
KE_INTERRUPT_ROUTINE routine, void* context, KE_INTERRUPT** out);
// Allocates one kernel IRQ slot for MSI delivery.
__declspec(dllexport) KSTATUS KeIrqAllocateMsiVector(uint8_t* outIrq);
// Registers a legacy interrupt handler for an IRQ slot.
__declspec(dllexport) void KeIrqRegister(uint8_t irq, void (*handler)(void));
__declspec(dllexport) KSTATUS KeIrqComposeMsiMessage(uint8_t irq, NTL_DDK_MSI_MESSAGE* messageOut);
// PCI enables the device's MSI/MSI-X source after reserving the CPU/vector route.
__declspec(dllexport) KSTATUS KeInterruptReserveMessage(uint64_t affinity,
KE_INTERRUPT_ROUTINE routine, void* context, KE_INTERRUPT** out);
__declspec(dllexport) KSTATUS KeInterruptComposeMessage(const KE_INTERRUPT* interrupt,
NTL_DDK_MSI_MESSAGE* out);
__declspec(dllexport) KSTATUS KeInterruptQuery(const KE_INTERRUPT* interrupt, KE_INTERRUPT_INFO* out);
__declspec(dllexport) KSTATUS KeInterruptBindMessageSource(KE_INTERRUPT* interrupt,
KE_INTERRUPT_MESSAGE_PROGRAM program, void* context);
__declspec(dllexport) KSTATUS KeInterruptActivateMessage(KE_INTERRUPT* interrupt);
__declspec(dllexport) KSTATUS KeInterruptSetAffinity(KE_INTERRUPT* interrupt,
uint64_t permittedCpuMask);
// Bus drivers close a route before disabling its source, serializing migration.
__declspec(dllexport) void KeInterruptBeginDisconnect(KE_INTERRUPT* interrupt);
// Disconnect waits for active handlers and requires PASSIVE_LEVEL.
__declspec(dllexport) void KeInterruptDisconnect(KE_INTERRUPT* interrupt);
+5
View File
@@ -83,3 +83,8 @@ __declspec(dllexport) void* MmReallocatePool(void* ptr, size_t newSize);
__declspec(dllexport) void* MmDdkPhysToVirt(uint64_t physicalAddress);
__declspec(dllexport) KSTATUS MmDdkMapPage(uintptr_t virtualAddress, uint64_t physicalAddress, uint64_t flags, NTL_DDK_MAP_MODE mode);
// UC device mapping with a private kernel VA and an exact matching unmap.
// Use in thread context. Returned mappings must be released with their length.
__declspec(dllexport) KSTATUS MmDdkMapIoMemory(uint64_t physicalAddress, size_t length, void** outVirtual);
__declspec(dllexport) KSTATUS MmDdkUnmapIoMemory(void* virtualAddress, size_t length);
+37 -17
View File
@@ -6,10 +6,12 @@
#define NTL_DDK_MODULE_EXPORT_NAME "NtlDriverModule"
#define NTL_DDK_MODULE_SIGNATURE 0x324D444Eu // "NDM2" in little-endian memory.
#define NTL_DDK_MODULE_ABI_VERSION 5u
#define NTL_DDK_MODULE_ABI_VERSION 6u
typedef struct NTL_MODULE NTL_MODULE;
typedef KSTATUS (*NTL_MODULE_INITIALIZE)(NTL_MODULE* module);
typedef KSTATUS (*NTL_MODULE_PREPARE_START)(NTL_MODULE* module);
typedef void (*NTL_MODULE_COMMIT_START)(NTL_MODULE* module);
typedef void (*NTL_MODULE_ABORT_START)(NTL_MODULE* module);
typedef KSTATUS (*NTL_MODULE_PREPARE_SHUTDOWN)(NTL_MODULE* module);
typedef void (*NTL_MODULE_COMMIT_SHUTDOWN)(NTL_MODULE* module);
@@ -20,7 +22,7 @@ typedef struct NTL_MODULE_EXPORT {
uint32_t Version;
uint32_t Size;
uint32_t Flags;
NTL_MODULE_INITIALIZE Initialize;
NTL_MODULE_PREPARE_START PrepareStart;
const NTL_DEVICE_DESC* Devices;
uint32_t DeviceCount;
uint32_t Reserved;
@@ -29,49 +31,67 @@ typedef struct NTL_MODULE_EXPORT {
uint32_t Reserved2;
NTL_MODULE_PREPARE_SHUTDOWN PrepareShutdown;
NTL_MODULE_COMMIT_SHUTDOWN CommitShutdown;
NTL_MODULE_COMMIT_START CommitStart;
NTL_MODULE_ABORT_START AbortStart;
} NTL_MODULE_EXPORT;
#ifdef __cplusplus
static_assert(sizeof(NTL_MODULE_EXPORT) == 72u, "DDK module export ABI changed");
static_assert(sizeof(NTL_MODULE_EXPORT) == 88u, "DDK module export ABI changed");
#define NTL_DDK_C_EXPORT extern "C"
#else
_Static_assert(sizeof(NTL_MODULE_EXPORT) == 72u, "DDK module export ABI changed");
_Static_assert(sizeof(NTL_MODULE_EXPORT) == 88u, "DDK module export ABI changed");
#define NTL_DDK_C_EXPORT
#endif
#define NTL_DECLARE_MODULE(initialize_fn) \
#define NTL_DECLARE_MODULE(prepareFn) \
NTL_DDK_C_EXPORT __declspec(dllexport) const NTL_MODULE_EXPORT NtlDriverModule = { \
NTL_DDK_MODULE_SIGNATURE, NTL_DDK_MODULE_ABI_VERSION, \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (initialize_fn), 0, 0u, 0u, 0, 0u, 0u, 0, 0 \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (prepareFn), 0, 0u, 0u, 0, 0u, 0u, 0, 0, 0, 0 \
}
#define NTL_DECLARE_DEVICE_MODULE(deviceArray) \
NTL_DDK_C_EXPORT __declspec(dllexport) const NTL_MODULE_EXPORT NtlDriverModule = { \
NTL_DDK_MODULE_SIGNATURE, NTL_DDK_MODULE_ABI_VERSION, \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, 0, (deviceArray), \
(uint32_t)(sizeof(deviceArray) / sizeof((deviceArray)[0])), 0u, 0, 0u, 0u, 0, 0 \
(uint32_t)(sizeof(deviceArray) / sizeof((deviceArray)[0])), 0u, 0, 0u, 0u, 0, 0, 0, 0 \
}
#define NTL_DECLARE_IO_MODULE(initialize_fn, driverArray) \
#define NTL_DECLARE_IO_MODULE(prepareFn, driverArray) \
NTL_DDK_C_EXPORT __declspec(dllexport) const NTL_MODULE_EXPORT NtlDriverModule = { \
NTL_DDK_MODULE_SIGNATURE, NTL_DDK_MODULE_ABI_VERSION, \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (initialize_fn), 0, 0u, 0u, \
(driverArray), (uint32_t)(sizeof(driverArray) / sizeof((driverArray)[0])), 0u, 0, 0 \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (prepareFn), 0, 0u, 0u, \
(driverArray), (uint32_t)(sizeof(driverArray) / sizeof((driverArray)[0])), 0u, 0, 0, 0, 0 \
}
#define NTL_DECLARE_MODULE_WITH_SHUTDOWN(initialize_fn, prepareFn, commitFn) \
#define NTL_DECLARE_MODULE_WITH_SHUTDOWN(startPrepareFn, shutdownPrepareFn, commitFn) \
NTL_DDK_C_EXPORT __declspec(dllexport) const NTL_MODULE_EXPORT NtlDriverModule = { \
NTL_DDK_MODULE_SIGNATURE, NTL_DDK_MODULE_ABI_VERSION, \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (initialize_fn), 0, 0u, 0u, \
0, 0u, 0u, (prepareFn), (commitFn) \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (startPrepareFn), 0, 0u, 0u, \
0, 0u, 0u, (shutdownPrepareFn), (commitFn), 0, 0 \
}
#define NTL_DECLARE_IO_MODULE_WITH_SHUTDOWN(initialize_fn, driverArray, prepareFn, commitFn) \
#define NTL_DECLARE_IO_MODULE_WITH_SHUTDOWN(startPrepareFn, driverArray, shutdownPrepareFn, commitFn) \
NTL_DDK_C_EXPORT __declspec(dllexport) const NTL_MODULE_EXPORT NtlDriverModule = { \
NTL_DDK_MODULE_SIGNATURE, NTL_DDK_MODULE_ABI_VERSION, \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (initialize_fn), 0, 0u, 0u, \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (startPrepareFn), 0, 0u, 0u, \
(driverArray), (uint32_t)(sizeof(driverArray) / sizeof((driverArray)[0])), 0u, \
(prepareFn), (commitFn) \
(shutdownPrepareFn), (commitFn), 0, 0 \
}
// Prepare may fail. Commit publishes fully prepared state and returns void.
#define NTL_DECLARE_STAGED_MODULE(prepareFn, commitFn, abortFn) \
NTL_DDK_C_EXPORT __declspec(dllexport) const NTL_MODULE_EXPORT NtlDriverModule = { \
NTL_DDK_MODULE_SIGNATURE, NTL_DDK_MODULE_ABI_VERSION, \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (prepareFn), 0, 0u, 0u, \
0, 0u, 0u, 0, 0, (commitFn), (abortFn) \
}
#define NTL_DECLARE_STAGED_IO_MODULE(prepareFn, driverArray, commitFn, abortFn) \
NTL_DDK_C_EXPORT __declspec(dllexport) const NTL_MODULE_EXPORT NtlDriverModule = { \
NTL_DDK_MODULE_SIGNATURE, NTL_DDK_MODULE_ABI_VERSION, \
(uint32_t)sizeof(NTL_MODULE_EXPORT), 0u, (prepareFn), 0, 0u, 0u, \
(driverArray), (uint32_t)(sizeof(driverArray) / sizeof((driverArray)[0])), \
0u, 0, 0, (commitFn), (abortFn) \
}
// Query the configured module identity; the returned string is borrowed.
+5
View File
@@ -3,6 +3,11 @@
#pragma once
#include <stdint.h>
#include <ntlite/status.h>
__declspec(dllexport) uint32_t KePciReadConfig32(uint16_t segment, uint8_t bus, uint8_t device, uint8_t function, uint16_t offset);
__declspec(dllexport) void KePciWriteConfig32(uint16_t segment, uint8_t bus, uint8_t device, uint8_t function, uint16_t offset, uint32_t value);
// Returns a checksum-validated ACPI RSDP root, independent of its consumer.
// A firmware driver maps the physical tables using the DDK memory interface.
__declspec(dllexport) KSTATUS KeFirmwareQueryAcpiRsdp(uint64_t* physicalAddressOut);
+36
View File
@@ -0,0 +1,36 @@
// Firmware power provider interface for resident platform drivers.
#pragma once
#include <stdint.h>
#include <ntlite/status.h>
// A registered provider remains resident through the final hardware transition.
// Callbacks run in thread context; Enter returns an error if the transition fails.
typedef struct NTL_FIRMWARE_POWER_PROVIDER {
uint32_t Size;
void* Context;
KSTATUS (*Prepare)(void* context, uint32_t action);
KSTATUS (*Enter)(void* context, uint32_t action);
} NTL_FIRMWARE_POWER_PROVIDER;
#ifdef NTL_KERNEL_BUILD
#define NTL_DDK_POWER_API __declspec(dllexport)
#else
#define NTL_DDK_POWER_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Installs one firmware power provider for the lifetime of the boot.
NTL_DDK_POWER_API KSTATUS KeRegisterFirmwarePowerProvider(
const NTL_FIRMWARE_POWER_PROVIDER* provider);
// Reports a physical button press from a firmware driver's worker context.
NTL_DDK_POWER_API KSTATUS KeNotifyPowerButton(void);
#ifdef __cplusplus
}
#endif
+3
View File
@@ -72,3 +72,6 @@ __declspec(dllexport) KSTATUS KeResumeThread(THREAD* thread,
// Yields the current processor to another runnable thread.
__declspec(dllexport) void KeYield(void);
// Returns the stable opaque identity of the calling kernel thread.
__declspec(dllexport) uintptr_t KeCurrentThreadIdentity(void);
+10
View File
@@ -0,0 +1,10 @@
// Native user-mode allocation functions provided by the process runtime.
#pragma once
#include <stddef.h>
void* malloc(size_t size);
void* calloc(size_t count, size_t size);
void* realloc(void* pointer, size_t size);
void free(void* pointer);
-13
View File
@@ -23,7 +23,6 @@ typedef struct SYS_STRING_VIEW {
#define SYS_SV_LITERAL(s) ((SYS_STRING_VIEW){ (s), sizeof(s) - 1 })
#define SYS_SV_NULL ((SYS_STRING_VIEW){ (const char*)0, 0 })
// Implements the sv From Parts operation.
static inline SYS_STRING_VIEW SysSvFromParts(const char* data, size_t length) {
SYS_STRING_VIEW v;
v.Data = data;
@@ -31,7 +30,6 @@ static inline SYS_STRING_VIEW SysSvFromParts(const char* data, size_t length) {
return v;
}
// Implements the sv From Cstr operation.
static inline SYS_STRING_VIEW SysSvFromCstr(const char* s) {
SYS_STRING_VIEW v;
v.Data = s;
@@ -39,12 +37,10 @@ static inline SYS_STRING_VIEW SysSvFromCstr(const char* s) {
return v;
}
// Implements the sv Is Empty operation.
static inline bool SysSvIsEmpty(SYS_STRING_VIEW s) {
return s.Length == 0;
}
// Implements the sv Is Valid operation.
static inline bool SysSvIsValid(SYS_STRING_VIEW s) {
return s.Data != (const char*)0 || s.Length == 0;
}
@@ -143,7 +139,6 @@ static inline size_t SysSvCopyUtf8WithReplacement(SYS_STRING_VIEW source,
return written;
}
// Implements the sv Equal operation.
static inline bool SysSvEqual(SYS_STRING_VIEW a, SYS_STRING_VIEW b) {
if (a.Length != b.Length) return false;
if (a.Length == 0) return true;
@@ -151,12 +146,10 @@ static inline bool SysSvEqual(SYS_STRING_VIEW a, SYS_STRING_VIEW b) {
return memcmp(a.Data, b.Data, a.Length) == 0;
}
// Implements the ascii Lower operation.
static inline char SysAsciiLower(char c) {
return (c >= 'A' && c <= 'Z') ? (char)(c + ('a' - 'A')) : c;
}
// Implements the sv Equal Ascii I operation.
static inline bool SysSvEqualAsciiI(SYS_STRING_VIEW a, SYS_STRING_VIEW b) {
if (a.Length != b.Length) return false;
if (a.Length == 0) return true;
@@ -167,17 +160,14 @@ static inline bool SysSvEqualAsciiI(SYS_STRING_VIEW a, SYS_STRING_VIEW b) {
return true;
}
// Implements the sv Equal Lit operation.
static inline bool SysSvEqualLit(SYS_STRING_VIEW a, const char* lit) {
return SysSvEqual(a, SysSvFromCstr(lit));
}
// Implements the sv Equal Lit Ascii I operation.
static inline bool SysSvEqualLitAsciiI(SYS_STRING_VIEW a, const char* lit) {
return SysSvEqualAsciiI(a, SysSvFromCstr(lit));
}
// Implements the sv Contains Byte operation.
static inline bool SysSvContainsByte(SYS_STRING_VIEW s, char ch) {
if (!s.Data && s.Length) return false;
for (size_t i = 0; i < s.Length; i++) {
@@ -186,14 +176,12 @@ static inline bool SysSvContainsByte(SYS_STRING_VIEW s, char ch) {
return false;
}
// Implements the sv Slice operation.
static inline SYS_STRING_VIEW SysSvSlice(SYS_STRING_VIEW s, size_t off, size_t len) {
if (off > s.Length) off = s.Length;
if (len > s.Length - off) len = s.Length - off;
return SysSvFromParts(s.Data ? s.Data + off : (const char*)0, len);
}
// Implements the sv Trim Ascii operation.
static inline SYS_STRING_VIEW SysSvTrimAscii(SYS_STRING_VIEW s) {
if (!SysSvIsValid(s)) return SYS_SV_NULL;
size_t begin = 0;
@@ -211,7 +199,6 @@ static inline SYS_STRING_VIEW SysSvTrimAscii(SYS_STRING_VIEW s) {
return SysSvSlice(s, begin, end - begin);
}
// Implements the sv Copy Z operation.
static inline bool SysSvCopyZ(char* dst, size_t dstSize, SYS_STRING_VIEW src) {
if (!dst || dstSize == 0) return false;
if (src.Length && !src.Data) return false;
+1 -1
View File
@@ -645,7 +645,7 @@ typedef struct SYS_QUEUE_RECV_REQUEST {
// SysWaitMany copies handles through a fixed kernel stack buffer. This public
// ABI/resource limit is intentionally small to keep wait setup bounded.
#define SYS_WAIT_MANY_MAX_HANDLES 32u
#define SYS_WAIT_MANY_MAX_HANDLES 64u
typedef struct SYS_WAIT_MANY_REQUEST {
uint32_t Size;