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
+128
-114
@@ -12,8 +12,6 @@
|
||||
#include <kernel/mm_virt.h>
|
||||
#include <kernel/ke_debug.h>
|
||||
|
||||
#define PNP_MAX_DESCRIPTORS 64u
|
||||
#define PNP_MAX_DEVICES 128u
|
||||
#define PNP_WORKERS 2u
|
||||
|
||||
typedef enum PNP_BIND_STATE {
|
||||
@@ -29,12 +27,15 @@ typedef enum PNP_BIND_STATE {
|
||||
} PNP_BIND_STATE;
|
||||
|
||||
typedef struct PNP_DRIVER {
|
||||
struct PNP_DRIVER* Next;
|
||||
const NTL_DEVICE_DESC* Descriptor;
|
||||
DRIVER_OBJECT* IoDriver;
|
||||
struct NTL_MODULE* Module;
|
||||
bool Committed;
|
||||
} PNP_DRIVER;
|
||||
|
||||
typedef struct PNP_NODE {
|
||||
struct PNP_NODE* Next;
|
||||
DEVICE_OBJECT* Pdo;
|
||||
DEVICE_OBJECT* ParentPdo;
|
||||
NTL_DEVICE* Binding;
|
||||
@@ -63,10 +64,11 @@ struct NTL_DEVICE {
|
||||
};
|
||||
|
||||
static SPINLOCK gPnpLock = SPINLOCK_INIT;
|
||||
static PNP_DRIVER gPnpDrivers[PNP_MAX_DESCRIPTORS];
|
||||
static uint32_t gPnpDriverCount;
|
||||
static PNP_NODE* gPnpNodes[PNP_MAX_DEVICES];
|
||||
static uint32_t gPnpNodeCount;
|
||||
static PNP_DRIVER* gPnpDrivers;
|
||||
static PNP_DRIVER* gPnpDriversTail;
|
||||
static PNP_NODE* gPnpNodes;
|
||||
static PNP_NODE* gPnpNodesTail;
|
||||
static size_t gPnpNodeCount;
|
||||
static EVENT* gPnpReady;
|
||||
static EVENT* gPnpChanged;
|
||||
static bool gPnpStarted;
|
||||
@@ -113,18 +115,19 @@ static bool IoPnpMatchesIoDriver(const DRIVER_OBJECT* driver, const DEVICE_OBJEC
|
||||
}
|
||||
|
||||
static const PNP_DRIVER* IoPnpFindDriver(const DEVICE_OBJECT* pdo) {
|
||||
for (uint32_t i = 0; i < gPnpDriverCount; ++i) {
|
||||
if ((gPnpDrivers[i].Descriptor && IoPnpMatches(gPnpDrivers[i].Descriptor, pdo)) ||
|
||||
(gPnpDrivers[i].IoDriver && IoPnpMatchesIoDriver(gPnpDrivers[i].IoDriver, pdo)))
|
||||
return &gPnpDrivers[i];
|
||||
for (PNP_DRIVER* driver = gPnpDrivers; driver; driver = driver->Next) {
|
||||
if (!driver->Committed) continue;
|
||||
if ((driver->Descriptor && IoPnpMatches(driver->Descriptor, pdo)) ||
|
||||
(driver->IoDriver && IoPnpMatchesIoDriver(driver->IoDriver, pdo)))
|
||||
return driver;
|
||||
}
|
||||
return (const PNP_DRIVER*)0;
|
||||
}
|
||||
|
||||
static PNP_NODE* IoPnpFindNode(const DEVICE_OBJECT* pdo) {
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i)
|
||||
if (gPnpNodes[i]->Pdo == pdo)
|
||||
return gPnpNodes[i];
|
||||
for (PNP_NODE* node = gPnpNodes; node; node = node->Next)
|
||||
if (node->Pdo == pdo)
|
||||
return node;
|
||||
return (PNP_NODE*)0;
|
||||
}
|
||||
|
||||
@@ -139,9 +142,9 @@ static DEVICE_OBJECT* IoPnpParentPdo(const DEVICE_OBJECT* pdo) {
|
||||
}
|
||||
|
||||
static bool IoPnpHasChildren(const DEVICE_OBJECT* parent) {
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i) {
|
||||
const DEVICE_OBJECT* ancestor = gPnpNodes[i]->ParentPdo;
|
||||
for (uint32_t depth = 0; ancestor && depth < PNP_MAX_DEVICES; ++depth) {
|
||||
for (PNP_NODE* candidate = gPnpNodes; candidate; candidate = candidate->Next) {
|
||||
const DEVICE_OBJECT* ancestor = candidate->ParentPdo;
|
||||
for (size_t depth = 0; ancestor && depth < gPnpNodeCount; ++depth) {
|
||||
if (ancestor == parent) return true;
|
||||
const PNP_NODE* node = IoPnpFindNode(ancestor);
|
||||
ancestor = node ? node->ParentPdo : (const DEVICE_OBJECT*)0;
|
||||
@@ -180,12 +183,15 @@ static void IoPnpDispose(PNP_NODE* node) {
|
||||
}
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i) {
|
||||
if (gPnpNodes[i] == node) {
|
||||
gPnpNodes[i] = gPnpNodes[--gPnpNodeCount];
|
||||
gPnpNodes[gPnpNodeCount] = (PNP_NODE*)0;
|
||||
break;
|
||||
PNP_NODE** link = &gPnpNodes;
|
||||
while (*link && *link != node) link = &(*link)->Next;
|
||||
if (*link) {
|
||||
*link = node->Next;
|
||||
if (gPnpNodesTail == node) {
|
||||
gPnpNodesTail = (PNP_NODE*)0;
|
||||
for (PNP_NODE* it = gPnpNodes; it; it = it->Next) gPnpNodesTail = it;
|
||||
}
|
||||
--gPnpNodeCount;
|
||||
}
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
IoDereferenceDeviceObject(node->Pdo);
|
||||
@@ -247,8 +253,7 @@ static void IoPnpWorker(void* ignored) {
|
||||
bool cleanup = false;
|
||||
bool cancel = false;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i) {
|
||||
PNP_NODE* candidate = gPnpNodes[i];
|
||||
for (PNP_NODE* candidate = gPnpNodes; candidate; candidate = candidate->Next) {
|
||||
if (candidate->State == PnpPending && candidate->Removed &&
|
||||
!candidate->CancelIssued && (candidate->Driver->Descriptor && candidate->Driver->Descriptor->CancelStart)) {
|
||||
candidate->CancelIssued = true;
|
||||
@@ -338,82 +343,105 @@ KSTATUS IoPnpInitialize(void) {
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KSTATUS IoPnpPublishModule(struct NTL_MODULE* module,
|
||||
// Reserve declarative and DRIVER_OBJECT names in one namespace.
|
||||
KSTATUS IoPnpPrepareModule(struct NTL_MODULE* module,
|
||||
const NTL_DEVICE_DESC* descriptors, uint32_t count,
|
||||
DRIVER_OBJECT* const* ioDrivers, uint32_t ioCount) {
|
||||
if (!gPnpStarted || !module || (count && !descriptors) || (ioCount && !ioDrivers))
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (count > UINT32_MAX - ioCount) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
PNP_DRIVER* first = (PNP_DRIVER*)0;
|
||||
PNP_DRIVER* last = (PNP_DRIVER*)0;
|
||||
for (uint32_t i = 0; i < count + ioCount; ++i) {
|
||||
PNP_DRIVER* driver = (PNP_DRIVER*)MmAllocatePool(sizeof(*driver));
|
||||
if (!driver) {
|
||||
while (first) {
|
||||
PNP_DRIVER* next = first->Next;
|
||||
MmFreePool(first);
|
||||
first = next;
|
||||
}
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
}
|
||||
memset(driver, 0, sizeof(*driver));
|
||||
driver->Module = module;
|
||||
if (i < count) driver->Descriptor = &descriptors[i];
|
||||
else driver->IoDriver = ioDrivers[i - count];
|
||||
if (last) last->Next = driver;
|
||||
else first = driver;
|
||||
last = driver;
|
||||
}
|
||||
|
||||
KSTATUS status = NTLSTATUS_SUCCESS;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
if (gPnpShutdown) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
return NTLSTATUS_DEVICE_REMOVED;
|
||||
}
|
||||
if (count > PNP_MAX_DESCRIPTORS - gPnpDriverCount ||
|
||||
ioCount > PNP_MAX_DESCRIPTORS - gPnpDriverCount - count) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
}
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
for (uint32_t j = 0; j < gPnpDriverCount; ++j) {
|
||||
SYS_STRING_VIEW existing = gPnpDrivers[j].IoDriver ?
|
||||
gPnpDrivers[j].IoDriver->Name :
|
||||
SysSvFromParts(gPnpDrivers[j].Descriptor->Name,
|
||||
strlen(gPnpDrivers[j].Descriptor->Name));
|
||||
SYS_STRING_VIEW incoming = SysSvFromParts(descriptors[i].Name,
|
||||
strlen(descriptors[i].Name));
|
||||
if (SysSvEqual(existing, incoming)) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
if (gPnpShutdown) status = NTLSTATUS_DEVICE_REMOVED;
|
||||
for (PNP_DRIVER* proposed = first; KSUCCESS(status) && proposed;
|
||||
proposed = proposed->Next) {
|
||||
SYS_STRING_VIEW name = proposed->IoDriver ? proposed->IoDriver->Name :
|
||||
SysSvFromCstr(proposed->Descriptor->Name);
|
||||
for (PNP_DRIVER* existing = gPnpDrivers; existing; existing = existing->Next) {
|
||||
SYS_STRING_VIEW oldName = existing->IoDriver ? existing->IoDriver->Name :
|
||||
SysSvFromCstr(existing->Descriptor->Name);
|
||||
if (SysSvEqual(name, oldName)) {
|
||||
status = NTLSTATUS_ALREADY_EXISTS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (uint32_t j = i + 1; j < count; ++j) {
|
||||
if (!strcmp(descriptors[i].Name, descriptors[j].Name)) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
for (PNP_DRIVER* other = proposed->Next; KSUCCESS(status) && other;
|
||||
other = other->Next) {
|
||||
SYS_STRING_VIEW otherName = other->IoDriver ? other->IoDriver->Name :
|
||||
SysSvFromCstr(other->Descriptor->Name);
|
||||
if (SysSvEqual(name, otherName)) status = NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < ioCount; ++i) {
|
||||
DRIVER_OBJECT* driver = ioDrivers[i];
|
||||
for (uint32_t j = 0; j < gPnpDriverCount; ++j) {
|
||||
SYS_STRING_VIEW existing = gPnpDrivers[j].IoDriver ?
|
||||
gPnpDrivers[j].IoDriver->Name :
|
||||
SysSvFromParts(gPnpDrivers[j].Descriptor->Name,
|
||||
strlen(gPnpDrivers[j].Descriptor->Name));
|
||||
if (SysSvEqual(driver->Name, existing)) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
for (uint32_t j = i + 1; j < ioCount; ++j) {
|
||||
if (SysSvEqual(driver->Name, ioDrivers[j]->Name)) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
for (uint32_t j = 0; j < count; ++j) {
|
||||
if (SysSvEqual(driver->Name, SysSvFromParts(descriptors[j].Name,
|
||||
strlen(descriptors[j].Name)))) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
gPnpDrivers[gPnpDriverCount].Descriptor = &descriptors[i];
|
||||
gPnpDrivers[gPnpDriverCount].IoDriver = (DRIVER_OBJECT*)0;
|
||||
gPnpDrivers[gPnpDriverCount].Module = module;
|
||||
++gPnpDriverCount;
|
||||
}
|
||||
for (uint32_t i = 0; i < ioCount; ++i) {
|
||||
gPnpDrivers[gPnpDriverCount].Descriptor = (const NTL_DEVICE_DESC*)0;
|
||||
gPnpDrivers[gPnpDriverCount].IoDriver = ioDrivers[i];
|
||||
gPnpDrivers[gPnpDriverCount].Module = module;
|
||||
++gPnpDriverCount;
|
||||
if (KSUCCESS(status) && first) {
|
||||
if (gPnpDriversTail) gPnpDriversTail->Next = first;
|
||||
else gPnpDrivers = first;
|
||||
gPnpDriversTail = last;
|
||||
}
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
if (!KSUCCESS(status)) {
|
||||
while (first) {
|
||||
PNP_DRIVER* next = first->Next;
|
||||
MmFreePool(first);
|
||||
first = next;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Reserved registrations become eligible for binding without allocation.
|
||||
void IoPnpCommitModule(struct NTL_MODULE* module) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
for (PNP_DRIVER* driver = gPnpDrivers; driver; driver = driver->Next)
|
||||
if (driver->Module == module) driver->Committed = true;
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
IoPnpWake();
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Abort releases reservations before any binding can reference them.
|
||||
void IoPnpAbortModule(struct NTL_MODULE* module) {
|
||||
PNP_DRIVER* removed = (PNP_DRIVER*)0;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
PNP_DRIVER** link = &gPnpDrivers;
|
||||
while (*link) {
|
||||
PNP_DRIVER* driver = *link;
|
||||
if (driver->Module != module || driver->Committed) {
|
||||
link = &driver->Next;
|
||||
continue;
|
||||
}
|
||||
*link = driver->Next;
|
||||
driver->Next = removed;
|
||||
removed = driver;
|
||||
}
|
||||
gPnpDriversTail = (PNP_DRIVER*)0;
|
||||
for (PNP_DRIVER* it = gPnpDrivers; it; it = it->Next) gPnpDriversTail = it;
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
while (removed) {
|
||||
PNP_DRIVER* next = removed->Next;
|
||||
MmFreePool(removed);
|
||||
removed = next;
|
||||
}
|
||||
}
|
||||
|
||||
KSTATUS IoPnpPhysicalDeviceArrived(DEVICE_OBJECT* pdo) {
|
||||
@@ -432,21 +460,16 @@ KSTATUS IoPnpPhysicalDeviceArrived(DEVICE_OBJECT* pdo) {
|
||||
MmFreePool(node);
|
||||
return NTLSTATUS_DEVICE_REMOVED;
|
||||
}
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i) {
|
||||
if (gPnpNodes[i]->Pdo == pdo) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
IoDereferenceDeviceObject(pdo);
|
||||
MmFreePool(node);
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
if (gPnpNodeCount == PNP_MAX_DEVICES) {
|
||||
if (IoPnpFindNode(pdo)) {
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
IoDereferenceDeviceObject(pdo);
|
||||
MmFreePool(node);
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
return NTLSTATUS_ALREADY_EXISTS;
|
||||
}
|
||||
gPnpNodes[gPnpNodeCount++] = node;
|
||||
if (gPnpNodesTail) gPnpNodesTail->Next = node;
|
||||
else gPnpNodes = node;
|
||||
gPnpNodesTail = node;
|
||||
++gPnpNodeCount;
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
@@ -454,12 +477,8 @@ KSTATUS IoPnpPhysicalDeviceArrived(DEVICE_OBJECT* pdo) {
|
||||
void IoPnpPhysicalDevicePublished(DEVICE_OBJECT* pdo) {
|
||||
if (!pdo || !gPnpStarted) return;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i) {
|
||||
if (gPnpNodes[i]->Pdo == pdo) {
|
||||
gPnpNodes[i]->Published = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PNP_NODE* node = IoPnpFindNode(pdo);
|
||||
if (node) node->Published = true;
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
IoPnpWake();
|
||||
}
|
||||
@@ -467,12 +486,8 @@ void IoPnpPhysicalDevicePublished(DEVICE_OBJECT* pdo) {
|
||||
void IoPnpPhysicalDeviceRemoved(DEVICE_OBJECT* pdo) {
|
||||
if (!pdo || !gPnpStarted) return;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i) {
|
||||
if (gPnpNodes[i]->Pdo == pdo) {
|
||||
gPnpNodes[i]->Removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PNP_NODE* node = IoPnpFindNode(pdo);
|
||||
if (node) node->Removed = true;
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
IoPnpWake();
|
||||
}
|
||||
@@ -483,8 +498,7 @@ KSTATUS IoPnpWaitForIdle(uint64_t timeoutMs) {
|
||||
for (;;) {
|
||||
bool idle = true;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i) {
|
||||
PNP_NODE* node = gPnpNodes[i];
|
||||
for (PNP_NODE* node = gPnpNodes; node; node = node->Next) {
|
||||
if (node->State == PnpReserved || node->State == PnpStarting ||
|
||||
node->State == PnpPending || node->State == PnpCancelling ||
|
||||
node->State == PnpCleaning ||
|
||||
@@ -512,8 +526,8 @@ KSTATUS IoPnpShutdown(uint64_t timeoutMs) {
|
||||
if (!gPnpStarted) return NTLSTATUS_INVALID_PARAMETER;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gPnpLock);
|
||||
gPnpShutdown = true;
|
||||
for (uint32_t i = 0; i < gPnpNodeCount; ++i)
|
||||
gPnpNodes[i]->Removed = true;
|
||||
for (PNP_NODE* node = gPnpNodes; node; node = node->Next)
|
||||
node->Removed = true;
|
||||
KeReleaseSpinlock(&gPnpLock, flags);
|
||||
IoPnpWake();
|
||||
return IoPnpWaitForIdle(timeoutMs);
|
||||
|
||||
Reference in new issue
Block a user