first PID is 0, separate idle to system

This commit is contained in:
maksw committed 2026-05-20 22:42:52 +02:00
1 parent 0d7f71b693
commit db175ab20a
7 files changed
+84 -25

No files matched your search

Binary file not shown.
+28 -1
View File
@@ -14,7 +14,8 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
static LIST_ENTRY gProcessList; static LIST_ENTRY gProcessList;
static SPINLOCK gProcessListLock; static SPINLOCK gProcessListLock;
static uint32_t gNextProcessId = 1; static uint32_t gNextProcessId = 0;
static PROCESS* gSystemProcess = (PROCESS*)0;
static void KiProcessInit(void) { static void KiProcessInit(void) {
static int inited = 0; static int inited = 0;
@@ -38,6 +39,29 @@ PROCESS* KeGetCurrentProcess(void) {
return NULL; 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) { size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount) {
KiProcessInit(); KiProcessInit();
@@ -59,6 +83,9 @@ size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount) {
static void KiProcessDestroy(OBJECT* obj) { static void KiProcessDestroy(OBJECT* obj) {
PROCESS* proc = CONTAINING_RECORD(obj, PROCESS, Header); PROCESS* proc = CONTAINING_RECORD(obj, PROCESS, Header);
if (proc == gSystemProcess)
gSystemProcess = (PROCESS*)0;
// Release all remaining handles. // Release all remaining handles.
for (int i = 1; i < HANDLE_TABLE_SIZE; i++) { for (int i = 1; i < HANDLE_TABLE_SIZE; i++) {
if (proc->Handles[i]) { if (proc->Handles[i]) {
+2
View File
@@ -69,6 +69,7 @@ typedef struct PROCESS {
} PROCESS; } PROCESS;
KSTATUS KeCreateProcess(const char* name, PROCESS **out); KSTATUS KeCreateProcess(const char* name, PROCESS **out);
KSTATUS KeCreateSystemProcess(PROCESS** out);
KSTATUS KeSetupUserProcessEnvironment(PROCESS* process, const char* imagePath, const char* commandLine, const char* currentDirectory); KSTATUS KeSetupUserProcessEnvironment(PROCESS* process, const char* imagePath, const char* commandLine, const char* currentDirectory);
void KeExitProcess(PROCESS* process, int exitCode); void KeExitProcess(PROCESS* process, int exitCode);
KSTATUS KeGetProcessExitCode(PROCESS* process, int* exitCodeOut); 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). */ /* Return the global process list head (kernel-internal). */
LIST_ENTRY* KeGetProcessList(void); LIST_ENTRY* KeGetProcessList(void);
PROCESS* KeGetCurrentProcess(void); PROCESS* KeGetCurrentProcess(void);
PROCESS* KeGetSystemProcess(void);
/* Copy a snapshot of process IDs into caller-provided storage. */ /* Copy a snapshot of process IDs into caller-provided storage. */
size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount); size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount);
/* Find a live process by its ProcessId. Bumps refcount; caller must ObDereferenceObject. */ /* Find a live process by its ProcessId. Bumps refcount; caller must ObDereferenceObject. */
+24 -1
View File
@@ -33,7 +33,13 @@ void KeInitializeScheduler(void) {
gSchedLock = (SPINLOCK)SPINLOCK_INIT; gSchedLock = (SPINLOCK)SPINLOCK_INIT;
PROCESS* idleProc; 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)); THREAD* idle = (THREAD *)ObAllocateObject(ObjectTypeThread, sizeof(THREAD));
idle->Header.Destroy = (void *)0; idle->Header.Destroy = (void *)0;
@@ -44,9 +50,17 @@ void KeInitializeScheduler(void) {
idle->Owner = idleProc; idle->Owner = idleProc;
idle->WaitObject = (OBJECT *)0; idle->WaitObject = (OBJECT *)0;
idle->WaitStatus = STATUS_SUCCESS; idle->WaitStatus = STATUS_SUCCESS;
idle->WaitListHead = (LIST_ENTRY*)0;
idle->AlertableWait = 0;
idle->SchedLockFlags = 0x202ULL; // IF=1 idle->SchedLockFlags = 0x202ULL; // IF=1
idle->UserStackBase = (void*)0;
idle->Teb = (void*)0;
idle->TebSize = 0;
idle->ExitEvent = (EVENT*)0;
KiInitializeApcState(idle); KiInitializeApcState(idle);
idle->TrapFrame = (KTRAP_FRAME*)0; idle->TrapFrame = (KTRAP_FRAME*)0;
LIST_INIT(&idle->ProcessLink);
LIST_INIT(&idle->SchedulerLink);
void* kstack = MmAllocatePool(KSTACK_SIZE); void* kstack = MmAllocatePool(KSTACK_SIZE);
idle->KernelStackBase = kstack; idle->KernelStackBase = kstack;
@@ -61,6 +75,15 @@ void KeInitializeScheduler(void) {
idle->SavedContext = ctx; idle->SavedContext = ctx;
KeInitThreadFpuContext(idle); 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; gIdleThread = idle;
gCurrentThread = idle; gCurrentThread = idle;
} }
+8 -4
View File
@@ -211,10 +211,14 @@ extern void KeKernelThreadEntry(void);
__declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg, __declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg,
THREAD_PRIORITY priority, THREAD** out) { THREAD_PRIORITY priority, THREAD** out) {
// Kernel threads are owned by the idle process. We need a PROCESS* for // Kernel worker threads are owned by the system process. The scheduler's
// the owner field; grab it from the idle/init thread that already exists. // hand-built CPU idle thread stays attached to PID 0 (idle), while driver,
THREAD* idleThread = KeGetCurrentThread(); // safe to call before scheduler starts // async I/O, and init worker threads are grouped under PID 1 (system).
PROCESS* owner = idleThread ? idleThread->Owner : (PROCESS*)0; PROCESS* owner = KeGetSystemProcess();
if (!owner) {
THREAD* currentThread = KeGetCurrentThread();
owner = currentThread ? currentThread->Owner : (PROCESS*)0;
}
if (!owner) return STATUS_INVALID_PARAMETER; if (!owner) return STATUS_INVALID_PARAMETER;
if (priority >= PriorityCount) return STATUS_INVALID_PARAMETER; if (priority >= PriorityCount) return STATUS_INVALID_PARAMETER;
+1 -1
View File
@@ -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 // 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 // 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. // given priority.
__declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg, __declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg,
THREAD_PRIORITY priority, THREAD** out); THREAD_PRIORITY priority, THREAD** out);
+21 -18
View File
@@ -370,24 +370,6 @@ static PROCESS* KiLaunchUserProcess(const char* filePath, const char* args) {
// Caller owns the reference returned by KeCreateProcess. // Caller owns the reference returned by KeCreateProcess.
return proc; 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) { void SystemInitThread(void* arg) {
SYSTEM_INIT_ARGS* args = (SYSTEM_INIT_ARGS*)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; 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); DbgPrint("DebugBucket: unknown command %llu\n", a0);
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }