replace ad hoc driver loading with a proper driver manager, new DDK, new PnP manager with device matching, asynchronous startup, resource ownership and removal, add shared PCI capability helpers, replace typed, rigid services with a proper service manager, implement proper system shutdown and restart, shutting down unloads drivers and shuts down services, add simple power button, remove heavyweight boot self-tests and SMP stress runs, add monotonic timestamps to kernel debug output, fruitless USB and PS/2 fixes, make test builds opt in.

This commit is contained in:
maksw committed 2026-10-26 10:08:03 +01:00
1 parent c0ad63c27f
commit d36f19509c
160 files changed
+6563 -7366

No files matched your search

-215
View File
@@ -863,218 +863,3 @@ KSTATUS KeAdmitApplicationProcessorsToScheduler(void) {
DbgPrint("SMP: scheduler admitted %u APs\n", admitted);
return NTLSTATUS_SUCCESS;
}
#define SMP_AP_WORKER_ROUNDS 64u
#define SMP_AP_WORKER_TIMEOUT_US 2000000ull
#define SMP_AP_TEST_MAGIC 0x524B575041504D53ULL // 'SMPAPWKR'
typedef struct SMP_AP_WORK_TEST SMP_AP_WORK_TEST;
typedef struct SMP_AP_WORKER_ARG {
uint64_t Magic;
uint32_t CpuIndex;
uint32_t WorkerIndex;
struct SMP_AP_WORK_TEST* Test;
EVENT* StepEvent;
volatile int32_t Ready;
volatile int32_t WaitArmed;
volatile int32_t Progress;
volatile int32_t Done;
volatile int32_t Failure;
uint32_t WrongCpu;
uint32_t WrongRunningCpu;
} SMP_AP_WORKER_ARG;
struct SMP_AP_WORK_TEST {
uint64_t Magic;
uint32_t WorkerCount;
volatile int32_t ReadyCount;
volatile int32_t DoneCount;
volatile int32_t FailureCount;
volatile int32_t CpuHits[KE_MAX_CPUS];
SMP_AP_WORKER_ARG Workers[KE_MAX_CPUS];
};
// Implements the smp Ap Controlled Worker operation.
static void KiSmpApControlledWorker(void* context) {
SMP_AP_WORKER_ARG* arg = (SMP_AP_WORKER_ARG*)context;
if (!arg || arg->Magic != SMP_AP_TEST_MAGIC || !arg->StepEvent) {
KePanic(KE_PANIC_CODE_SELFTEST, "SMP AP worker received bad context 0x%016llX\n", (uint64_t)arg);
}
NtlAtomicExchange32(&arg->Ready, 1);
NtlAtomicIncrement32(&arg->Test->ReadyCount);
for (uint32_t round = 0; round < SMP_AP_WORKER_ROUNDS; round++) {
NtlAtomicIncrement32(&arg->WaitArmed);
KSTATUS waitStatus = KeWaitForEvent(arg->StepEvent, 0);
if (!KSUCCESS(waitStatus)) {
NtlAtomicExchange32(&arg->Failure, 1);
break;
}
KCPU* cpu = KeGetCurrentCpu();
THREAD* self = KeGetCurrentThread();
if (!cpu || cpu->CpuIndex != arg->CpuIndex) {
arg->WrongCpu = cpu ? cpu->CpuIndex : KE_INVALID_CPU;
NtlAtomicExchange32(&arg->Failure, 1);
break;
}
if (!self || self->RunningCpu != cpu->CpuIndex) {
arg->WrongRunningCpu = self ? self->RunningCpu : KE_INVALID_CPU;
NtlAtomicExchange32(&arg->Failure, 1);
break;
}
if (self && (self->AffinityMask & (1ULL << cpu->CpuIndex)) == 0) {
arg->WrongCpu = cpu->CpuIndex;
NtlAtomicExchange32(&arg->Failure, 1);
break;
}
if (cpu->CpuIndex < KE_MAX_CPUS)
NtlAtomicIncrement32(&arg->Test->CpuHits[cpu->CpuIndex]);
NtlAtomicIncrement32(&arg->Progress);
if ((round & 3u) == 0)
KeYield();
}
if (NtlAtomicLoad32(&arg->Failure) != 0) {
NtlAtomicIncrement32(&arg->Test->FailureCount);
}
NtlAtomicExchange32(&arg->Done, 1);
NtlAtomicIncrement32(&arg->Test->DoneCount);
}
// Waits for for Worker Counter.
static bool KiWaitForWorkerCounter(volatile int32_t* counter, int32_t expected, const char* what) {
uint64_t deadline = KiSmpDeadlineAfter(SMP_AP_WORKER_TIMEOUT_US);
for (;;) {
if (NtlAtomicLoad32(counter) >= expected)
return true;
if (KiSmpQueryTicks() >= deadline)
break;
KeYield();
}
DbgPrint("SMP scheduler selftest timeout waiting for %s expected=%d got=%ld\n",
what ? what : "counter", expected, NtlAtomicLoad32(counter));
return false;
}
// Runs application Processor Scheduler Self Tests.
KSTATUS KeRunApplicationProcessorSchedulerSelfTests(void) {
if (gCpuCount <= 1) {
DbgPrint("SMP scheduler selftest: SKIP, no APs\n");
return NTLSTATUS_SUCCESS;
}
DbgPrint("SMP scheduler selftest: begin AP-affine workers\n");
SMP_AP_WORK_TEST* test = (SMP_AP_WORK_TEST*)MmAllocatePool(sizeof(SMP_AP_WORK_TEST));
if (!test) return NTLSTATUS_NO_MEMORY;
memset(test, 0, sizeof(*test));
test->Magic = SMP_AP_TEST_MAGIC;
uint32_t workerCount = 0;
for (uint32_t cpuIndex = 1; cpuIndex < gCpuCount; cpuIndex++) {
KCPU* cpu = &gCpus[cpuIndex];
if (cpu->State != KeCpuOnline)
continue;
if (cpuIndex >= 64)
continue;
SMP_AP_WORKER_ARG* arg = &test->Workers[workerCount];
arg->Magic = SMP_AP_TEST_MAGIC;
arg->CpuIndex = cpuIndex;
arg->WorkerIndex = workerCount;
arg->Test = test;
KSTATUS st = KeEventCreate(EventAutoReset, 0, &arg->StepEvent);
if (!KSUCCESS(st)) {
KePanic(KE_PANIC_CODE_SELFTEST,
"SMP scheduler selftest: AP%u step event create failed status=0x%x\n",
cpuIndex, st);
}
KE_THREAD_CREATE_PARAMETERS workerParameters =
KE_THREAD_CREATE_NAMED_NORMAL(PriorityNormal, "selftest.smp");
workerParameters.AffinityMask = 1ULL << cpuIndex;
st = KeCreateKernelThread((uintptr_t)KiSmpApControlledWorker,
(uintptr_t)arg,
&workerParameters,
(THREAD**)0);
if (!KSUCCESS(st)) {
KePanic(KE_PANIC_CODE_SELFTEST,
"SMP scheduler selftest: AP%u worker create failed status=0x%x\n",
cpuIndex, st);
}
workerCount++;
}
test->WorkerCount = workerCount;
if (workerCount == 0) {
MmFreePool(test);
DbgPrint("SMP scheduler selftest: SKIP, no online AP workers\n");
return NTLSTATUS_SUCCESS;
}
if (!KiWaitForWorkerCounter(&test->ReadyCount, (int32_t)workerCount, "AP worker ready")) {
KePanic(KE_PANIC_CODE_SELFTEST, "SMP scheduler selftest: workers failed to become ready ready=%ld workers=%u\n",
test->ReadyCount, workerCount);
}
for (uint32_t round = 0; round < SMP_AP_WORKER_ROUNDS; round++) {
for (uint32_t w = 0; w < workerCount; w++) {
SMP_AP_WORKER_ARG* arg = &test->Workers[w];
if (!KiWaitForWorkerCounter(&arg->WaitArmed, (int32_t)(round + 1), "AP worker wait-armed")) {
KePanic(KE_PANIC_CODE_SELFTEST,
"SMP scheduler selftest: AP%u did not arm wait for round %u armed=%ld progress=%ld\n",
arg->CpuIndex, round, arg->WaitArmed, arg->Progress);
}
KeSignalEvent(arg->StepEvent);
}
for (uint32_t w = 0; w < workerCount; w++) {
SMP_AP_WORKER_ARG* arg = &test->Workers[w];
if (!KiWaitForWorkerCounter(&arg->Progress, (int32_t)(round + 1), "AP worker progress")) {
KePanic(KE_PANIC_CODE_SELFTEST,
"SMP scheduler selftest: AP%u no progress round=%u progress=%ld failure=%ld wrongCpu=%u wrongRunningCpu=%u\n",
arg->CpuIndex, round, arg->Progress, arg->Failure,
arg->WrongCpu, arg->WrongRunningCpu);
}
if (NtlAtomicLoad32(&arg->Failure) != 0) {
KePanic(KE_PANIC_CODE_SELFTEST,
"SMP scheduler selftest: AP%u worker failed round=%u wrongCpu=%u wrongRunningCpu=%u progress=%ld\n",
arg->CpuIndex, round, arg->WrongCpu, arg->WrongRunningCpu, arg->Progress);
}
}
}
if (!KiWaitForWorkerCounter(&test->DoneCount, (int32_t)workerCount, "AP worker done")) {
KePanic(KE_PANIC_CODE_SELFTEST, "SMP scheduler selftest: workers did not finish done=%d workers=%u\n",
test->DoneCount, workerCount);
}
if (NtlAtomicLoad32(&test->FailureCount) != 0) {
KePanic(KE_PANIC_CODE_SELFTEST, "SMP scheduler selftest: failure count=%d\n",
test->FailureCount);
}
for (uint32_t w = 0; w < workerCount; w++) {
SMP_AP_WORKER_ARG* arg = &test->Workers[w];
int32_t hits = (arg->CpuIndex < KE_MAX_CPUS) ? test->CpuHits[arg->CpuIndex] : 0;
if (hits <= 0) {
KePanic(KE_PANIC_CODE_SELFTEST,
"SMP scheduler selftest: AP%u recorded no CPU hits\n", arg->CpuIndex);
}
if (arg->StepEvent)
ObDereferenceObject(&arg->StepEvent->Header);
}
DbgPrint("SMP scheduler selftest: PASS workers=%u rounds=%u\n",
workerCount, SMP_AP_WORKER_ROUNDS);
MmFreePool(test);
return NTLSTATUS_SUCCESS;
}