From c1a291c4c993e1b49670ecd644f8ecc417c07a84 Mon Sep 17 00:00:00 2001 From: Maksymilian Wilczynski Date: Tue, 9 Jun 2026 18:37:35 +0200 Subject: [PATCH] better ps --- OVMF/OVMF_VARS_4M_d.fd | Bin 540672 -> 540672 bytes code/kernel/include/kernel/ke_process.h | 6 +- code/kernel/include/kernel/mm_virt.h | 1 + code/kernel/ke_process.c | 76 +++++++++++++++- code/kernel/ke_syscall.c | 12 +-- code/kernel/mm_virt.c | 22 +++++ code/public/ntlite/syscall.h | 41 ++++++++- code/user/apps/shell_native/shell_native.c | 96 +++++++++++++++++---- 8 files changed, 228 insertions(+), 26 deletions(-) diff --git a/OVMF/OVMF_VARS_4M_d.fd b/OVMF/OVMF_VARS_4M_d.fd index 4a76af1f601746b08b7ae188ff4859b24219cc48..e155cd812a598322e33d7f10c06cc9618cb204da 100644 GIT binary patch delta 80 zcmZo@P;6*W+z?kXS=6JTo-U|%M{VE_Q7KpRm2 delta 56 zcmZo@P;6*W+z?kXnQxiX<^?5}xSEwVwkvI91Y)M`N*kH)#ckfOZG&N(085(yYnuRD Ln*jSV0S*HIn`;#v diff --git a/code/kernel/include/kernel/ke_process.h b/code/kernel/include/kernel/ke_process.h index 5b492c6..7711f8f 100644 --- a/code/kernel/include/kernel/ke_process.h +++ b/code/kernel/include/kernel/ke_process.h @@ -115,7 +115,9 @@ uint32_t KeGetHandleRights(PROCESS* process, uint32_t handle); 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); +struct SYS_PROCESS_INFO; + +/* Copy a snapshot of rich process information into caller-provided storage. */ +size_t KeCopyProcessInfo(struct SYS_PROCESS_INFO* infoOut, size_t maxCount); /* Find a live process by its ProcessId. Bumps refcount; caller must ObDereferenceObject. */ PROCESS* KeGetProcessById(uint32_t pid); diff --git a/code/kernel/include/kernel/mm_virt.h b/code/kernel/include/kernel/mm_virt.h index cb34d9c..8f311cc 100644 --- a/code/kernel/include/kernel/mm_virt.h +++ b/code/kernel/include/kernel/mm_virt.h @@ -126,6 +126,7 @@ KSTATUS MmProtectUserRegion(PROCESS* process, void* base, size_t size, uint64_t KSTATUS MmDestroyUserRegion(PROCESS* process, void* base); void MmDestroyAllUserRegions(PROCESS* process); KSTATUS MmQueryUserRegion(PROCESS* process, const void* address, void** baseOut, size_t* sizeOut, uint64_t* pageFlagsOut, USER_REGION_TYPE* typeOut, uint32_t* regionFlagsOut); +void MmQueryProcessUserMemory(PROCESS* process, size_t* regionCountOut, size_t* reservedBytesOut, size_t* committedBytesOut); size_t MmGetUserRegionSize(PROCESS* process, const void* base); size_t MmGetUserRegionSizeByBase(const void* base); diff --git a/code/kernel/ke_process.c b/code/kernel/ke_process.c index 09460b2..d861e48 100644 --- a/code/kernel/ke_process.c +++ b/code/kernel/ke_process.c @@ -10,6 +10,7 @@ #include #include #include +#include // --------------------------------------------------------------------------- // Global process list @@ -64,15 +65,86 @@ KSTATUS KeCreateSystemProcess(PROCESS** out) { return STATUS_SUCCESS; } -size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount) { +static uint32_t KiCountProcessHandlesLocked(PROCESS* process) { + uint32_t count = 0; + if (!process) return 0; + + for (uint32_t i = 1; i < HANDLE_TABLE_SIZE; i++) { + if (process->Handles[i].Object) count++; + } + return count; +} + +static void KiCopyTruncatedString(char* dst, size_t dstSize, const char* src, size_t srcLen) { + if (!dst || dstSize == 0) return; + size_t n = 0; + if (src) { + while (n + 1 < dstSize && n < srcLen && src[n]) { + dst[n] = src[n]; + n++; + } + } + dst[n] = '\0'; +} + +size_t KeCopyProcessInfo(struct SYS_PROCESS_INFO* infoOut, size_t maxCount) { KiProcessInit(); + PROCESS* current = KeGetCurrentProcess(); + PROCESS* system = KeGetSystemProcess(); + uintptr_t flags = KeAcquireSpinlock(&gProcessListLock); size_t count = 0; LIST_ENTRY* head = &gProcessList; for (LIST_ENTRY* node = head->Fwd; node != head; node = node->Fwd) { PROCESS* p = CONTAINING_RECORD(node, PROCESS, GlobalLink); - if (pidsOut && count < maxCount) pidsOut[count] = p->ProcessId; + if (infoOut && count < maxCount) { + SYS_PROCESS_INFO* info = &infoOut[count]; + memset(info, 0, sizeof(*info)); + info->Size = sizeof(*info); + info->ProcessId = p->ProcessId; + info->ImageBase = p->ImageBase; + info->ImageSize = p->ImageSize; + info->PebBase = p->UserPebBase; + info->ModuleCount = p->ModuleCount; + + uintptr_t handleFlags = KeAcquireSpinlock(&p->HandleLock); + uint32_t threadCount = p->ThreadCount; + uint32_t handleCount = KiCountProcessHandlesLocked(p); + int exitCode = p->ExitCode; + long terminating = p->Terminating; + long exited = p->Exited; + KeReleaseSpinlock(&p->HandleLock, handleFlags); + + info->ThreadCount = threadCount; + info->HandleCount = handleCount; + info->ExitCode = exitCode; + + if (exited) { + info->State = SYS_PROCESS_STATE_EXITED; + info->Flags |= SYS_PROCESS_FLAG_EXITED; + } else if (terminating) { + info->State = SYS_PROCESS_STATE_TERMINATING; + info->Flags |= SYS_PROCESS_FLAG_TERMINATING; + } else { + info->State = SYS_PROCESS_STATE_RUNNING; + } + + if (p == system) info->Flags |= SYS_PROCESS_FLAG_SYSTEM; + if (p == current) info->Flags |= SYS_PROCESS_FLAG_CURRENT; + + MmQueryProcessUserMemory(p, &info->UserRegionCount, + &info->UserReservedBytes, + &info->UserCommittedBytes); + + KiCopyTruncatedString(info->Name, sizeof(info->Name), p->Name, sizeof(p->Name)); + + uintptr_t cwdFlags = KeAcquireSpinlock(&p->CwdLock); + info->CurrentDrive = p->CurrentDrive; + KiCopyTruncatedString(info->CurrentDirectory, sizeof(info->CurrentDirectory), + p->CurrentDirectory, p->CurrentDirectoryLength); + KeReleaseSpinlock(&p->CwdLock, cwdFlags); + } count++; } KeReleaseSpinlock(&gProcessListLock, flags); diff --git a/code/kernel/ke_syscall.c b/code/kernel/ke_syscall.c index a511bbc..5460ac4 100644 --- a/code/kernel/ke_syscall.c +++ b/code/kernel/ke_syscall.c @@ -2012,7 +2012,7 @@ static uint64_t SyscallKillProcess(uint64_t a0, uint64_t a1, uint64_t a2, } // --------------------------------------------------------------------------- -// SYS_GET_PROCESS_LIST (65) a0=*pidsOut a1=maxCount a2=*countOut +// SYS_GET_PROCESS_LIST (6) a0=*SYS_PROCESS_INFO[] a1=maxCount a2=*countOut // --------------------------------------------------------------------------- static uint64_t SyscallGetProcessList(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5) { @@ -2025,20 +2025,20 @@ static uint64_t SyscallGetProcessList(uint64_t a0, uint64_t a1, uint64_t a2, if (!KSUCCESS(s)) return s; } - size_t total = KeCopyProcessIds(NULL, 0); + size_t total = KeCopyProcessInfo(NULL, 0); size_t toCopy = total < maxCount ? total : maxCount; if (toCopy) { size_t bytes = 0; - if (!KiMulSize(toCopy, sizeof(uint32_t), &bytes)) return STATUS_INVALID_PARAMETER; + if (!KiMulSize(toCopy, sizeof(SYS_PROCESS_INFO), &bytes)) return STATUS_INVALID_PARAMETER; - uint32_t* tmp = (uint32_t*)MmAllocatePool(bytes); + SYS_PROCESS_INFO* tmp = (SYS_PROCESS_INFO*)MmAllocatePool(bytes); if (!tmp) return STATUS_NO_MEMORY; - size_t copied = KeCopyProcessIds(tmp, toCopy); + size_t copied = KeCopyProcessInfo(tmp, toCopy); if (copied < toCopy) toCopy = copied; - KSTATUS s = CopyToUser((void*)(uintptr_t)a0, tmp, toCopy * sizeof(uint32_t)); + KSTATUS s = CopyToUser((void*)(uintptr_t)a0, tmp, toCopy * sizeof(SYS_PROCESS_INFO)); MmFreePool(tmp); if (!KSUCCESS(s)) return s; } diff --git a/code/kernel/mm_virt.c b/code/kernel/mm_virt.c index 3d1b0ae..965ab2e 100644 --- a/code/kernel/mm_virt.c +++ b/code/kernel/mm_virt.c @@ -1204,6 +1204,28 @@ KSTATUS MmQueryUserRegion(PROCESS* process, const void* address, void** baseOut, return STATUS_NOT_FOUND; } + +void MmQueryProcessUserMemory(PROCESS* process, size_t* regionCountOut, size_t* reservedBytesOut, size_t* committedBytesOut) { + size_t regions = 0; + size_t reserved = 0; + size_t committed = 0; + + if (process) { + uintptr_t flags = KeAcquireSpinlock(&process->UserRegionLock); + for (LIST_ENTRY* node = process->UserRegions.Fwd; node != &process->UserRegions; node = node->Fwd) { + USER_VA_REGION* r = CONTAINING_RECORD(node, USER_VA_REGION, ProcessLink); + regions++; + reserved += r->ReservationSize; + committed += r->CommittedSize; + } + KeReleaseSpinlock(&process->UserRegionLock, flags); + } + + if (regionCountOut) *regionCountOut = regions; + if (reservedBytesOut) *reservedBytesOut = reserved; + if (committedBytesOut) *committedBytesOut = committed; +} + size_t MmGetUserRegionSize(PROCESS* process, const void* base) { if (!process || !base) return 0; uintptr_t procFlags = KeAcquireSpinlock(&process->UserRegionLock); diff --git a/code/public/ntlite/syscall.h b/code/public/ntlite/syscall.h index e02b773..a1dbb79 100644 --- a/code/public/ntlite/syscall.h +++ b/code/public/ntlite/syscall.h @@ -193,7 +193,46 @@ uint32_t SysCreateProcess(const SYS_CREATE_PROCESS_REQUEST* request); uint32_t SysWaitForProcess(uint32_t handle); uint32_t SysGetProcessExitCode(uint32_t handle, int* exitCodeOut); uint32_t SysKillProcess(uint32_t pid, int exitCode); -uint32_t SysGetProcessList(uint32_t* pidsOut, size_t maxCount, size_t* countOut); + +#define SYS_PROCESS_NAME_MAX 64u +#define SYS_PROCESS_CWD_MAX 128u + +#define SYS_PROCESS_STATE_RUNNING 0u +#define SYS_PROCESS_STATE_TERMINATING 1u +#define SYS_PROCESS_STATE_EXITED 2u + +#define SYS_PROCESS_FLAG_SYSTEM 0x00000001u +#define SYS_PROCESS_FLAG_CURRENT 0x00000002u +#define SYS_PROCESS_FLAG_TERMINATING 0x00000004u +#define SYS_PROCESS_FLAG_EXITED 0x00000008u + +typedef struct SYS_PROCESS_INFO { + uint32_t Size; + uint32_t ProcessId; + uint32_t State; + uint32_t Flags; + + uint32_t ThreadCount; + uint32_t HandleCount; + uint32_t ModuleCount; + uint32_t CurrentDrive; + + int32_t ExitCode; + uint32_t Reserved0; + + uintptr_t ImageBase; + size_t ImageSize; + uintptr_t PebBase; + + size_t UserRegionCount; + size_t UserReservedBytes; + size_t UserCommittedBytes; + + char Name[SYS_PROCESS_NAME_MAX]; + char CurrentDirectory[SYS_PROCESS_CWD_MAX]; +} SYS_PROCESS_INFO; + +uint32_t SysGetProcessList(SYS_PROCESS_INFO* processesOut, size_t maxCount, size_t* countOut); uint32_t SysGetProcessPid(uint32_t handle, uint32_t* pidOut); uint32_t SysCreateThread(uintptr_t entry, uintptr_t arg, uint32_t priority, uint32_t* tidOut); diff --git a/code/user/apps/shell_native/shell_native.c b/code/user/apps/shell_native/shell_native.c index d2f46f7..a34ab55 100644 --- a/code/user/apps/shell_native/shell_native.c +++ b/code/user/apps/shell_native/shell_native.c @@ -5,10 +5,7 @@ #include #define MAX_CMD 256 -#define MAX_PIDS 64 // Maximum number of PIDs we will fetch at once - -// External Syscall Prototypes -uint32_t SysGetProcessList(uint32_t* pidsOut, size_t maxCount, size_t* countOut); +#define MAX_PROCS 64 // Maximum number of processes we will fetch at once // --------------------------------------------------------------------------- // Output helpers @@ -64,6 +61,34 @@ static void printUInt64(uint64_t n) { while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); } } +static uint32_t u64Digits(uint64_t n) { + uint32_t digits = 1; + while (n >= 10u) { n /= 10u; digits++; } + return digits; +} + +static void printSpaces(size_t count) { + while (count--) print(" "); +} + +static void printUIntWidth(uint32_t n, size_t width) { + uint32_t digits = u64Digits(n); + if (width > digits) printSpaces(width - digits); + printUInt(n); +} + +static void printUInt64Width(uint64_t n, size_t width) { + uint32_t digits = u64Digits(n); + if (width > digits) printSpaces(width - digits); + printUInt64(n); +} + +static void printStringWidth(const char* s, size_t width) { + size_t len = s ? strlen(s) : 0; + if (s) print(s); + if (width > len) printSpaces(width - len); +} + // --------------------------------------------------------------------------- // Line editor // --------------------------------------------------------------------------- @@ -96,7 +121,7 @@ static void cmd_help() { " help - Show this list\n" " mem - Show memory usage\n" " stats - Show scheduler/CPU/PMM telemetry\n" - " ps - List running process IDs\n" + " ps - List processes\n" " dir [path] - List directory contents\n" " cd - Change directory\n" " type - Display file contents\n" @@ -218,30 +243,71 @@ static void cmd_mem(void) { print("\n"); } +static const char* processStateName(uint32_t state) { + switch (state) { + case SYS_PROCESS_STATE_RUNNING: return "run"; + case SYS_PROCESS_STATE_TERMINATING: return "term"; + case SYS_PROCESS_STATE_EXITED: return "exit"; + default: return "?"; + } +} + static void cmd_ps(void) { - uint32_t pids[MAX_PIDS]; + SYS_PROCESS_INFO procs[MAX_PROCS]; size_t count = 0; - - uint32_t status = SysGetProcessList(pids, MAX_PIDS, &count); + + uint32_t status = SysGetProcessList(procs, MAX_PROCS, &count); if (status != 0) { print("ps: failed to retrieve process list\n"); return; } - print("Running Processes (Count: "); + print("Processes (Count: "); printUInt((uint32_t)count); print("):\n"); - - size_t displayCount = count < MAX_PIDS ? count : MAX_PIDS; + print(" PID State Thr Hnd Mod UserKiB ImageKiB Flags Name\n"); + + size_t displayCount = count < MAX_PROCS ? count : MAX_PROCS; for (size_t i = 0; i < displayCount; i++) { - print(" PID: "); - printUInt(pids[i]); + SYS_PROCESS_INFO* p = &procs[i]; + char flags[5]; + size_t flagLen = 0; + + if (p->Flags & SYS_PROCESS_FLAG_SYSTEM) flags[flagLen++] = 'S'; + if (p->Flags & SYS_PROCESS_FLAG_CURRENT) flags[flagLen++] = '*'; + if (p->Flags & SYS_PROCESS_FLAG_TERMINATING) flags[flagLen++] = 'T'; + if (p->Flags & SYS_PROCESS_FLAG_EXITED) flags[flagLen++] = 'X'; + if (flagLen == 0) flags[flagLen++] = '-'; + flags[flagLen] = '\0'; + + print(" "); + printUIntWidth(p->ProcessId, 3); + print(" "); + printStringWidth(processStateName(p->State), 5); + print(" "); + printUIntWidth(p->ThreadCount, 3); + print(" "); + printUIntWidth(p->HandleCount, 3); + print(" "); + printUIntWidth(p->ModuleCount, 3); + print(" "); + printUInt64Width((uint64_t)p->UserCommittedBytes / 1024u, 7); + print(" "); + printUInt64Width((uint64_t)p->ImageSize / 1024u, 8); + print(" "); + printStringWidth(flags, 5); + print(" "); + print(p->Name); + if (p->CurrentDirectory[0]) { + print(" cwd="); + print(p->CurrentDirectory); + } print("\n"); } - if (count > MAX_PIDS) { + if (count > MAX_PROCS) { print(" ... and "); - printUInt((uint32_t)(count - MAX_PIDS)); + printUInt((uint32_t)(count - MAX_PROCS)); print(" more processes.\n"); } }