From db175ab20af4a7f34c449b898e6ebf5d5d111a98 Mon Sep 17 00:00:00 2001 From: Maksymilian Wilczynski Date: Wed, 20 May 2026 22:42:52 +0200 Subject: [PATCH] first PID is 0, separate idle to system --- OVMF/OVMF_VARS_4M_d.fd | Bin 540672 -> 540672 bytes code/kernel/ke_process.c | 29 ++++++++++++++++++++++++++++- code/kernel/ke_process.h | 2 ++ code/kernel/ke_sched.c | 25 ++++++++++++++++++++++++- code/kernel/ke_thread.c | 12 ++++++++---- code/kernel/ke_thread.h | 2 +- code/kernel/kmain.c | 39 +++++++++++++++++++++------------------ 7 files changed, 84 insertions(+), 25 deletions(-) diff --git a/OVMF/OVMF_VARS_4M_d.fd b/OVMF/OVMF_VARS_4M_d.fd index 1001423ae96e8e18bf464cd928a5ba2c9e922f9d..592a7049bd9e3f1c7f367f725ae6d5bb83cdd64b 100644 GIT binary patch delta 73 zcmZo@P;3CA7RD`1r`ApO3v$}dv!3Y^*XDP*yI2|hHct%l6qtT$9g`EIKahQqtNq?i crtSB3GIN=>39z&Yu(k=XwF$5<6W}la08|MZW&i*H delta 59 zcmZo@P;3CA7RD`1r`AnQQ&pN=pr^2%XFby;uJ&)Yn6`hr#mr^8z2O0qgkqZjOPc^| On*dvz0Q)il4g&ze%oQg9 diff --git a/code/kernel/ke_process.c b/code/kernel/ke_process.c index e2418d2..f7a9021 100644 --- a/code/kernel/ke_process.c +++ b/code/kernel/ke_process.c @@ -14,7 +14,8 @@ // --------------------------------------------------------------------------- static LIST_ENTRY gProcessList; static SPINLOCK gProcessListLock; -static uint32_t gNextProcessId = 1; +static uint32_t gNextProcessId = 0; +static PROCESS* gSystemProcess = (PROCESS*)0; static void KiProcessInit(void) { static int inited = 0; @@ -38,6 +39,29 @@ PROCESS* KeGetCurrentProcess(void) { return NULL; } +PROCESS* KeGetSystemProcess(void) { + return gSystemProcess; +} + +KSTATUS KeCreateSystemProcess(PROCESS** out) { + if (!out) return STATUS_INVALID_PARAMETER; + if (gSystemProcess) { + *out = gSystemProcess; + return STATUS_SUCCESS; + } + + PROCESS* proc = (PROCESS*)0; + KSTATUS s = KeCreateProcess("system", &proc); + if (!KSUCCESS(s)) { + *out = (PROCESS*)0; + return s; + } + + gSystemProcess = proc; + *out = proc; + return STATUS_SUCCESS; +} + size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount) { KiProcessInit(); @@ -59,6 +83,9 @@ size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount) { static void KiProcessDestroy(OBJECT* obj) { PROCESS* proc = CONTAINING_RECORD(obj, PROCESS, Header); + if (proc == gSystemProcess) + gSystemProcess = (PROCESS*)0; + // Release all remaining handles. for (int i = 1; i < HANDLE_TABLE_SIZE; i++) { if (proc->Handles[i]) { diff --git a/code/kernel/ke_process.h b/code/kernel/ke_process.h index e0dab6d..6fd1b85 100644 --- a/code/kernel/ke_process.h +++ b/code/kernel/ke_process.h @@ -69,6 +69,7 @@ typedef struct PROCESS { } PROCESS; KSTATUS KeCreateProcess(const char* name, PROCESS **out); +KSTATUS KeCreateSystemProcess(PROCESS** out); KSTATUS KeSetupUserProcessEnvironment(PROCESS* process, const char* imagePath, const char* commandLine, const char* currentDirectory); void KeExitProcess(PROCESS* process, int exitCode); KSTATUS KeGetProcessExitCode(PROCESS* process, int* exitCodeOut); @@ -81,6 +82,7 @@ OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle); /* Return the global process list head (kernel-internal). */ LIST_ENTRY* KeGetProcessList(void); PROCESS* KeGetCurrentProcess(void); +PROCESS* KeGetSystemProcess(void); /* Copy a snapshot of process IDs into caller-provided storage. */ size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount); /* Find a live process by its ProcessId. Bumps refcount; caller must ObDereferenceObject. */ diff --git a/code/kernel/ke_sched.c b/code/kernel/ke_sched.c index 84740c2..c2c819b 100644 --- a/code/kernel/ke_sched.c +++ b/code/kernel/ke_sched.c @@ -33,7 +33,13 @@ void KeInitializeScheduler(void) { gSchedLock = (SPINLOCK)SPINLOCK_INIT; PROCESS* idleProc; - KeCreateProcess("idle", &idleProc); + KSTATUS s = KeCreateProcess("idle", &idleProc); + if (!KSUCCESS(s)) return; + + PROCESS* systemProc; + s = KeCreateSystemProcess(&systemProc); + if (!KSUCCESS(s)) return; + (void)systemProc; THREAD* idle = (THREAD *)ObAllocateObject(ObjectTypeThread, sizeof(THREAD)); idle->Header.Destroy = (void *)0; @@ -44,9 +50,17 @@ void KeInitializeScheduler(void) { idle->Owner = idleProc; idle->WaitObject = (OBJECT *)0; idle->WaitStatus = STATUS_SUCCESS; + idle->WaitListHead = (LIST_ENTRY*)0; + idle->AlertableWait = 0; idle->SchedLockFlags = 0x202ULL; // IF=1 + idle->UserStackBase = (void*)0; + idle->Teb = (void*)0; + idle->TebSize = 0; + idle->ExitEvent = (EVENT*)0; KiInitializeApcState(idle); idle->TrapFrame = (KTRAP_FRAME*)0; + LIST_INIT(&idle->ProcessLink); + LIST_INIT(&idle->SchedulerLink); void* kstack = MmAllocatePool(KSTACK_SIZE); idle->KernelStackBase = kstack; @@ -61,6 +75,15 @@ void KeInitializeScheduler(void) { idle->SavedContext = ctx; KeInitThreadFpuContext(idle); + // The hand-built CPU idle thread is not created through KeCreateThread(), + // so register it manually with the idle process. This keeps PID 0 visible + // as the real idle process while kernel worker threads live under PID 1. + ObReferenceObject(&idleProc->Header); + uintptr_t idleFlags = KeAcquireSpinlock(&idleProc->HandleLock); + ListInsertTail(&idleProc->ThreadList, &idle->ProcessLink); + idleProc->ThreadCount++; + KeReleaseSpinlock(&idleProc->HandleLock, idleFlags); + gIdleThread = idle; gCurrentThread = idle; } diff --git a/code/kernel/ke_thread.c b/code/kernel/ke_thread.c index 9340018..187abc4 100644 --- a/code/kernel/ke_thread.c +++ b/code/kernel/ke_thread.c @@ -211,10 +211,14 @@ extern void KeKernelThreadEntry(void); __declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg, THREAD_PRIORITY priority, THREAD** out) { - // Kernel threads are owned by the idle process. We need a PROCESS* for - // the owner field; grab it from the idle/init thread that already exists. - THREAD* idleThread = KeGetCurrentThread(); // safe to call before scheduler starts - PROCESS* owner = idleThread ? idleThread->Owner : (PROCESS*)0; + // Kernel worker threads are owned by the system process. The scheduler's + // hand-built CPU idle thread stays attached to PID 0 (idle), while driver, + // async I/O, and init worker threads are grouped under PID 1 (system). + PROCESS* owner = KeGetSystemProcess(); + if (!owner) { + THREAD* currentThread = KeGetCurrentThread(); + owner = currentThread ? currentThread->Owner : (PROCESS*)0; + } if (!owner) return STATUS_INVALID_PARAMETER; if (priority >= PriorityCount) return STATUS_INVALID_PARAMETER; diff --git a/code/kernel/ke_thread.h b/code/kernel/ke_thread.h index eea084b..ad1adcc 100644 --- a/code/kernel/ke_thread.h +++ b/code/kernel/ke_thread.h @@ -116,7 +116,7 @@ __declspec(dllexport) KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, ui // Create a kernel-mode-only thread. fn is called directly in ring 0 with // arg; when fn returns the thread exits automatically. No user stack or TEB -// is allocated. The thread is owned by the idle process and runs at the +// is allocated. The thread is owned by the system process and runs at the // given priority. __declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg, THREAD_PRIORITY priority, THREAD** out); diff --git a/code/kernel/kmain.c b/code/kernel/kmain.c index 9a728f5..1106d14 100644 --- a/code/kernel/kmain.c +++ b/code/kernel/kmain.c @@ -370,24 +370,6 @@ static PROCESS* KiLaunchUserProcess(const char* filePath, const char* args) { // Caller owns the reference returned by KeCreateProcess. return proc; } -static void KiPrintProcessList() { - LIST_ENTRY* listHead = KeGetProcessList(); - LIST_ENTRY* current; - - DbgPrint("\nPID | Name | Threads | ExitCode\n"); - DbgPrint("---------------------------------------------\n"); - - for (current = listHead->Fwd; current != listHead; current = current->Fwd) { - // Translate the list entry back to the PROCESS structure - PROCESS* proc = CONTAINING_RECORD(current, PROCESS, GlobalLink); - - DbgPrint("%-5u | %-16s | %-7u | %d\n", - proc->ProcessId, - proc->Name, - proc->ThreadCount, - proc->ExitCode); - } -} void SystemInitThread(void* arg) { SYSTEM_INIT_ARGS* args = (SYSTEM_INIT_ARGS*)arg; @@ -487,6 +469,27 @@ uint64_t KeCatchAllDebugBucket(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a return status; } + if (a0 == 2) { + LIST_ENTRY* listHead = KeGetProcessList(); + LIST_ENTRY* current; + + DbgPrint("\nPID | Name | Threads | ExitCode\n"); + DbgPrint("---------------------------------------------\n"); + + for (current = listHead->Fwd; current != listHead; current = current->Fwd) { + // Translate the list entry back to the PROCESS structure + PROCESS* proc = CONTAINING_RECORD(current, PROCESS, GlobalLink); + + DbgPrint("%-5u | %-16s | %-7u | %d\n", + proc->ProcessId, + proc->Name, + proc->ThreadCount, + proc->ExitCode); + } + + return STATUS_SUCCESS; + } + DbgPrint("DebugBucket: unknown command %llu\n", a0); return STATUS_INVALID_PARAMETER; }