From ddb074f0e086680df65f78dc75a214e6b18ddf0c Mon Sep 17 00:00:00 2001 From: Maksymilian Wilczynski Date: Wed, 13 May 2026 10:41:48 +0200 Subject: [PATCH] rewrite init to restart failed processes, add file renaming, directory creation, directory renaming, directory removal, add process killing, unify shells, readme changes. --- OVMF/OVMF_VARS_4M_d.fd | Bin 540672 -> 540672 bytes code/init/init.c | 44 +++-- code/kernel/io_file.c | 42 ++++ code/kernel/io_file.h | 11 ++ code/kernel/ke_process.c | 17 ++ code/kernel/ke_process.h | 2 + code/kernel/ke_syscall.c | 71 +++++++ code/kernel/kmain.c | 42 ++-- code/kernel/syscall_nr.h | 15 +- code/shell_native/shell_native.c | 207 ++++++-------------- code/shell_posix/shell_posix.c | 172 ++++------------- code/shell_win32/shell_win32.c | 321 ++++++------------------------- code/syscall/syscall.h | 13 +- code/syscall/syscall_nr.inc | 7 +- code/syscall/syscall_stubs.asm | 13 ++ readme.md | 140 ++++++++------ 16 files changed, 476 insertions(+), 641 deletions(-) diff --git a/OVMF/OVMF_VARS_4M_d.fd b/OVMF/OVMF_VARS_4M_d.fd index 0dcfc4afe65ec9874ccc45611956ec49e71931c5..7de2fece8e77552e9d5f9da0e8f331637215a718 100644 GIT binary patch delta 101 zcmZo@P;3CA7RD`1T1J!of}FPJ7%^Sq+Wane7c1k#%@c#V1sESesK*fM350qIq&x+t pYZ);)F+KybFLJfp*)nanvt_QzZxdi?6JTuDelete(fs, relPath); } +__declspec(dllexport) KSTATUS IoRenameFile(const char* oldPath, const char* newPath) { + if (!oldPath || !newPath) return STATUS_INVALID_PARAMETER; + + char oldRel[CWD_MAX]; + char newRel[CWD_MAX]; + uint8_t oldDrive = ResolvePath(oldPath, oldRel, sizeof(oldRel)); + uint8_t newDrive = ResolvePath(newPath, newRel, sizeof(newRel)); + if (oldDrive != newDrive) return STATUS_NOT_SUPPORTED; + + IO_FILESYSTEM* fs = gVolumes[oldDrive].Fs; + if (!fs) return STATUS_NOT_FOUND; + if (!fs->Rename) return STATUS_NOT_SUPPORTED; + + return fs->Rename(fs, oldRel, newRel); +} + +__declspec(dllexport) KSTATUS IoCreateDir(const char* path) { + if (!path) return STATUS_INVALID_PARAMETER; + + char relPath[CWD_MAX]; + uint8_t drive = ResolvePath(path, relPath, sizeof(relPath)); + + IO_FILESYSTEM* fs = gVolumes[drive].Fs; + if (!fs) return STATUS_NOT_FOUND; + if (!fs->CreateDir) return STATUS_NOT_SUPPORTED; + + return fs->CreateDir(fs, relPath); +} + +__declspec(dllexport) KSTATUS IoRemoveDir(const char* path) { + if (!path) return STATUS_INVALID_PARAMETER; + + char relPath[CWD_MAX]; + uint8_t drive = ResolvePath(path, relPath, sizeof(relPath)); + + IO_FILESYSTEM* fs = gVolumes[drive].Fs; + if (!fs) return STATUS_NOT_FOUND; + if (!fs->RemoveDir) return STATUS_NOT_SUPPORTED; + + return fs->RemoveDir(fs, relPath); +} + // --------------------------------------------------------------------------- // IoTruncateFile - resize the file; updates the cached Size on success // --------------------------------------------------------------------------- diff --git a/code/kernel/io_file.h b/code/kernel/io_file.h index 6707216..2a8f81c 100644 --- a/code/kernel/io_file.h +++ b/code/kernel/io_file.h @@ -45,6 +45,14 @@ typedef struct IO_FILESYSTEM { // Delete the file at 'path'. KSTATUS (*Delete)(struct IO_FILESYSTEM* fs, const char* path); + // Rename or move a file/directory within the same filesystem. + KSTATUS (*Rename)(struct IO_FILESYSTEM* fs, + const char* oldPath, const char* newPath); + + // Create or remove directories. + KSTATUS (*CreateDir)(struct IO_FILESYSTEM* fs, const char* path); + KSTATUS (*RemoveDir)(struct IO_FILESYSTEM* fs, const char* path); + // Truncate or extend the file to exactly 'newSize' bytes. KSTATUS (*Truncate)(struct IO_FILESYSTEM* fs, void* fileCtx, uint64_t newSize); @@ -119,6 +127,9 @@ __declspec(dllexport) KSTATUS IoWriteFile (FILE_OBJECT* file, const void* buf, size_t size, size_t* bytesWritten); __declspec(dllexport) KSTATUS IoCreateFile (const char* path, FILE_OBJECT** out); __declspec(dllexport) KSTATUS IoDeleteFile (const char* path); +__declspec(dllexport) KSTATUS IoRenameFile (const char* oldPath, const char* newPath); +__declspec(dllexport) KSTATUS IoCreateDir (const char* path); +__declspec(dllexport) KSTATUS IoRemoveDir (const char* path); __declspec(dllexport) KSTATUS IoTruncateFile(FILE_OBJECT* file, uint64_t newSize); __declspec(dllexport) KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset); __declspec(dllexport) uint64_t IoGetFileSize(FILE_OBJECT* file); diff --git a/code/kernel/ke_process.c b/code/kernel/ke_process.c index 08a0f7f..103f715 100644 --- a/code/kernel/ke_process.c +++ b/code/kernel/ke_process.c @@ -25,6 +25,7 @@ static void ProcessInit(void) { } LIST_ENTRY* KeGetProcessList(void) { + ProcessInit(); return &gProcessList; } @@ -36,6 +37,21 @@ PROCESS* KeGetCurrentProcess(void) { return NULL; } +size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount) { + ProcessInit(); + + 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; + count++; + } + KeReleaseSpinlock(&gProcessListLock, flags); + return count; +} + // --------------------------------------------------------------------------- // Destructor (called by ObDereferenceObject when RefCount hits zero) // --------------------------------------------------------------------------- @@ -206,6 +222,7 @@ OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle) { } PROCESS* KeGetProcessById(uint32_t pid) { + ProcessInit(); uintptr_t flags = KeAcquireSpinlock(&gProcessListLock); LIST_ENTRY* head = &gProcessList; LIST_ENTRY* node = head->Fwd; diff --git a/code/kernel/ke_process.h b/code/kernel/ke_process.h index 9a560c8..21ad23d 100644 --- a/code/kernel/ke_process.h +++ b/code/kernel/ke_process.h @@ -77,5 +77,7 @@ OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle); /* Return the global process list head (kernel-internal). */ LIST_ENTRY* KeGetProcessList(void); PROCESS* KeGetCurrentProcess(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. */ PROCESS* KeGetProcessById(uint32_t pid); diff --git a/code/kernel/ke_syscall.c b/code/kernel/ke_syscall.c index c6b2931..22204c3 100644 --- a/code/kernel/ke_syscall.c +++ b/code/kernel/ke_syscall.c @@ -1177,6 +1177,72 @@ static uint64_t SyscallNamedQueueOwnerPid(uint64_t a0, uint64_t a1, uint64_t a2, return STATUS_NOT_FOUND; } +static uint64_t SyscallKillProcess(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { + (void)a2; (void)a3; (void)a4; (void)a5; + PROCESS* proc = KeGetProcessById((uint32_t)a0); + if (!proc) return STATUS_NOT_FOUND; + THREAD* self = KeGetCurrentThread(); + int exitCode = (int)a1; + if (self && self->Owner == proc) { + KeExitProcess(proc, exitCode); + ObDereferenceObject(&proc->Header); + KeExitThread(self, exitCode); + while (true) ; + } + KeExitProcess(proc, exitCode); + ObDereferenceObject(&proc->Header); + return STATUS_SUCCESS; +} + +// --------------------------------------------------------------------------- +// SYS_GET_PROCESS_LIST (65) a0=*pidsOut 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) { + (void)a3; (void)a4; (void)a5; + uint32_t* pidsOut = (uint32_t*)(uintptr_t)a0; + size_t maxCount = (size_t)a1; + size_t* countOut = (size_t*)(uintptr_t)a2; + size_t count = KeCopyProcessIds(pidsOut, maxCount); + if (countOut) *countOut = count; + return STATUS_SUCCESS; +} + +// --------------------------------------------------------------------------- +// SYS_RENAME_FILE (66) a0=*oldPath a1=*newPath +// --------------------------------------------------------------------------- +static uint64_t SyscallRenameFile(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { + (void)a2; (void)a3; (void)a4; (void)a5; + const char* oldPath = (const char*)(uintptr_t)a0; + const char* newPath = (const char*)(uintptr_t)a1; + if (!oldPath || !newPath) return STATUS_INVALID_PARAMETER; + return IoRenameFile(oldPath, newPath); +} + +// --------------------------------------------------------------------------- +// SYS_CREATE_DIR (67) a0=*path +// --------------------------------------------------------------------------- +static uint64_t SyscallCreateDir(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { + (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; + const char* path = (const char*)(uintptr_t)a0; + if (!path) return STATUS_INVALID_PARAMETER; + return IoCreateDir(path); +} + +// --------------------------------------------------------------------------- +// SYS_REMOVE_DIR (68) a0=*path +// --------------------------------------------------------------------------- +static uint64_t SyscallRemoveDir(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { + (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; + const char* path = (const char*)(uintptr_t)a0; + if (!path) return STATUS_INVALID_PARAMETER; + return IoRemoveDir(path); +} + // =========================================================================== // Dispatch table - index must match SYS_* in syscall_nr.h exactly. // =========================================================================== @@ -1248,6 +1314,11 @@ static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = { /* 61 SYS_OPEN_NAMED_QUEUE */ SyscallOpenNamedQueue, /* 62 SYS_QUEUE_DUPLICATE */ SyscallQueueDuplicate, /* 63 SYS_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid, + /* 64 SYS_KILL_PROCESS */ SyscallKillProcess, + /* 65 SYS_GET_PROCESS_LIST */ SyscallGetProcessList, + /* 66 SYS_RENAME_FILE */ SyscallRenameFile, + /* 67 SYS_CREATE_DIR */ SyscallCreateDir, + /* 68 SYS_REMOVE_DIR */ SyscallRemoveDir, }; // --------------------------------------------------------------------------- diff --git a/code/kernel/kmain.c b/code/kernel/kmain.c index 59aa582..5b10f5f 100644 --- a/code/kernel/kmain.c +++ b/code/kernel/kmain.c @@ -303,21 +303,6 @@ static PROCESS* LaunchUserProcess(const char* filePath, const char* args) { // Caller owns the reference returned by KeCreateProcess. return proc; } -// --------------------------------------------------------------------------- -// Kernel thread: wait for a process to exit, then log a message and shut down. -// Takes ownership of the PROCESS* reference passed as arg; releases it on exit. -// --------------------------------------------------------------------------- -static void ProcessWatcherThread(void* arg) { - PROCESS* proc = (PROCESS*)arg; - KeWaitForEvent(proc->ExitEvent); - DbgPrint("ProcessWatcherThread: Process \"%s\" (PID %u) exited with code %d.\n", - proc->Name, proc->ProcessId, proc->ExitCode); - ObDereferenceObject(&proc->Header); - - DbgPrint("ProcessWatcherThread: Shutting down.\n"); - gKmainHal->Power.Shutdown(); // does not return -} - static void PrintProcessList() { LIST_ENTRY* listHead = KeGetProcessList(); LIST_ENTRY* current; @@ -354,20 +339,29 @@ void SystemInitThread(void* arg) { DbgPrint(" -> Kernel Pool: %.2f MB\n", (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f)); DbgPrint(" -> User Heap: %.2f MB\n", (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f)); - // Launch User-Mode Shell (this will trigger AHCI & FAT32 which CAN safely block now) - PROCESS* shellProc = LaunchUserProcess("system/init.exe", args->bootInfo->CommandLine); - - if (shellProc) { - KSTATUS ws = KeCreateKernelThread((uintptr_t)ProcessWatcherThread, - (uintptr_t)shellProc, - PriorityNormal, (THREAD**)0); - if (!KSUCCESS(ws)) { - DbgPrint("SystemInitThread: Failed to create watcher thread (%d) -- leaking proc ref.\n", ws); + // Launch User-Mode init.exe and restart it until it exits cleanly. + while (true) { + PROCESS* shellProc = LaunchUserProcess("system/init.exe", args->bootInfo->CommandLine); + if (!shellProc) { + DbgPrint("SystemInitThread: Failed to start system/init.exe; retrying.\n"); + KeYield(); + continue; } + + KeWaitForEvent(shellProc->ExitEvent); + int exitCode = shellProc->ExitCode; + DbgPrint("SystemInitThread: init.exe exited with code %d.\n", exitCode); + ObDereferenceObject(&shellProc->Header); + + if (exitCode == 0) break; + DbgPrint("SystemInitThread: Restarting init.exe.\n"); } + DbgPrint("SystemInitThread: init.exe completed successfully; shutting down.\n"); + gKmainHal->Power.Shutdown(); MmFreePool(args); } + // --------------------------------------------------------------------------- // Main Kernel Entry // --------------------------------------------------------------------------- diff --git a/code/kernel/syscall_nr.h b/code/kernel/syscall_nr.h index 02d8376..a8b678c 100644 --- a/code/kernel/syscall_nr.h +++ b/code/kernel/syscall_nr.h @@ -162,4 +162,17 @@ #define SYS_QUEUE_DUPLICATE 62 // (uint32_t handle, uint32_t targetPid, uint32_t* handleOut) -> KSTATUS #define SYS_NAMED_QUEUE_OWNER_PID 63 // (const char* name, uint32_t* pidOut) -> KSTATUS -#define SYS_MAX 64 +// --------------------------------------------------------------------------- +// Process utilities +// --------------------------------------------------------------------------- +#define SYS_KILL_PROCESS 64 // (uint32_t pid, int exitCode) -> KSTATUS +#define SYS_GET_PROCESS_LIST 65 // (uint32_t* pidsOut, size_t maxCount, size_t* countOut) -> KSTATUS + +// --------------------------------------------------------------------------- +// Filesystem mutations +// --------------------------------------------------------------------------- +#define SYS_RENAME_FILE 66 // (const char* oldPath, const char* newPath) -> KSTATUS +#define SYS_CREATE_DIR 67 // (const char* path) -> KSTATUS +#define SYS_REMOVE_DIR 68 // (const char* path) -> KSTATUS + +#define SYS_MAX 69 diff --git a/code/shell_native/shell_native.c b/code/shell_native/shell_native.c index f244374..e5efbab 100644 --- a/code/shell_native/shell_native.c +++ b/code/shell_native/shell_native.c @@ -5,67 +5,37 @@ #include #include +#define MAX_CMD 256 + // --------------------------------------------------------------------------- // Output helpers // --------------------------------------------------------------------------- -static void print(const char* s) { - SysWriteConsole(s, strlen(s)); -} +static void print(const char* s) { SysWriteConsole(s, strlen(s)); } static void printUInt(uint32_t n) { - char buf[12]; - int i = 0; + char buf[12]; int i = 0; if (n == 0) { print("0"); return; } while (n > 0) { buf[i++] = (char)('0' + n % 10); n /= 10; } - char rev[12]; - int j = 0; - while (i > 0) rev[j++] = buf[--i]; - rev[j] = '\0'; - print(rev); + while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); } } static void printInt(int32_t n) { - if (n < 0) { - print("-"); - printUInt((uint32_t)-(n + 1) + 1); - } else { - printUInt((uint32_t)n); - } + if (n < 0) { print("-"); printUInt((uint32_t)-(n + 1) + 1); } + else { printUInt((uint32_t)n); } } // --------------------------------------------------------------------------- // Line editor // --------------------------------------------------------------------------- -#define MAX_CMD 256 - static void readLine(char* buf, int len) { int pos = 0; while (true) { char c = SysKbReadChar(); - if (!c) { - SysYield(); - continue; - } - - if (c == '\r' || c == '\n') { - print("\n"); - break; - } - - if ((c == '\b' || c == 127) && pos > 0) { - pos--; - print("\b \b"); - continue; - } - - if (c < 0x20 || c == 127) - continue; - - if (pos < len - 1) { - buf[pos++] = c; - char echo[2] = { c, '\0' }; - print(echo); - } + if (!c) { SysYield(); continue; } + if (c == '\r' || c == '\n') { print("\n"); break; } + if ((c == '\b' || c == 127) && pos > 0) { pos--; print("\b \b"); continue; } + if (c < 0x20 || c == 127) continue; + if (pos < len - 1) { buf[pos++] = c; char echo[2] = {c, '\0'}; print(echo); } } buf[pos] = '\0'; } @@ -83,87 +53,74 @@ static char* trim(char* s) { // --------------------------------------------------------------------------- static void cmd_help() { print("Available commands:\n" - " help - Show this list\n" - " dir - List files\n" - " cd - Change directory\n" - " type - Display file contents\n" - " del - Delete a file\n" - " write - Create a file with text\n" - " exit - Close the shell\n"); + " help - Show this list\n" + " dir [path] - List directory contents\n" + " cd - Change directory\n" + " type - Display file contents\n" + " del - Delete a file\n" + " write - Create a file with text\n" + " clear - Clear the screen\n" + " exit - Close the shell\n"); } static void cmd_write(const char* args) { - char filename[MAX_CMD]; - int i = 0; + char filename[MAX_CMD]; int i = 0; while (args[i] != ' ' && args[i] != '\0' && i < MAX_CMD - 1) { - filename[i] = args[i]; - i++; + filename[i] = args[i]; i++; } filename[i] = '\0'; - - if (args[i] == '\0' || args[i+1] == '\0') { - print("write: usage: write \n"); - return; - } - + if (args[i] == '\0' || args[i+1] == '\0') { print("write: usage: write \n"); return; } uint32_t hFile; - if (SysCreateFile(filename, &hFile) != 0) { - print("write: could not create file\n"); - return; - } - - const char* text = args + i + 1; + if (SysCreateFile(filename, &hFile) != 0) { print("write: could not create file\n"); return; } size_t written; - SysWriteFile(hFile, text, strlen(text), &written); + SysWriteFile(hFile, args + i + 1, strlen(args + i + 1), &written); SysCloseHandle(hFile); print("File written successfully.\n"); } static void cmd_dir(const char* path) { uint32_t hDir; + const char* target = (path && *path != '\0') ? path : "."; - // Validate input - if (path == NULL || path[0] == '\0') { - path = "."; // Default to current directory if empty + if (SysOpenDir(target, &hDir) != 0) { + print("dir: failed to open directory\n"); + return; } - // SysOpenDir (Syscall 54) handles the const char* path directly - if (SysOpenDir(path, &hDir) != 0) { - SysDebugPrint("dir: failed to open directory\n"); - return; - } - - // Assuming KDIR_ENTRY is your structure for directory entries KDIR_ENTRY ke; - - // SysReadDir (Syscall 55) populates the buffer with entry data - // It typically returns 0 on success and non-zero (or error) when done while (SysReadDir(hDir, &ke) == 0) { - // We assume ke.Name is a null-terminated string within the struct + // Skip hidden/system markers if desired (e.g., those starting with .) + if (ke.Name[0] == '.') continue; + + // Corrected Attribute Check: 0x10 is the Directory bit in FAT + if (ke.Attr & 0x10) { + print(" "); + } else { + print(" "); + } + print(ke.Name); + + // Optional: print file size for non-directories + if (!(ke.Attr & 0x10)) { + print(" ("); + printUInt(ke.FileSize); + print(" bytes)"); + } + print("\n"); } - - // Always close the handle (Syscall 26) to prevent leaks SysCloseHandle(hDir); } static void cmd_type(const char* filename) { uint32_t hFile; - if (SysOpenFile(filename, &hFile) != 0) { - print("type: error opening file\n"); - return; - } - - char buffer[512]; - size_t bytesRead; + if (SysOpenFile(filename, &hFile) != 0) { print("type: cannot open file\n"); return; } + char buffer[512]; size_t bytesRead; while (SysReadFile(hFile, buffer, sizeof(buffer) - 1, &bytesRead) == 0 && bytesRead > 0) { - buffer[bytesRead] = '\0'; - print(buffer); + buffer[bytesRead] = '\0'; print(buffer); } - - SysCloseHandle(hFile); - print("\n"); + SysCloseHandle(hFile); print("\n"); } // --------------------------------------------------------------------------- @@ -171,76 +128,34 @@ static void cmd_type(const char* filename) { // --------------------------------------------------------------------------- static int runCommand(const char* cmd) { if (!cmd || *cmd == '\0') return 0; - if (strcmp(cmd, "exit") == 0) return 1; if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; } + if (strcmp(cmd, "clear") == 0) { SysScreenClear(0); return 0; } if (strcmp(cmd, "crash") == 0) { *(int*)0 = 42; return 0; } - if (strcmp(cmd, "dir") == 0) { - cmd_dir("."); - return 0; - } - if (strncmp(cmd, "dir ", 4) == 0) { - cmd_dir(cmd + 4); - return 0; - } - - if (strcmp(cmd, "clear") == 0) { - SysScreenClear(0x00000000); - return 0; - } + if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; } + if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; } + if (strncmp(cmd, "cd ", 3) == 0) { SysSetCwd(cmd + 3); return 0; } + if (strncmp(cmd, "del ", 4) == 0) { SysDeleteFile(cmd + 4); return 0; } + if (strncmp(cmd, "type ", 5) == 0) { cmd_type(cmd + 5); return 0; } + if (strncmp(cmd, "write ", 6) == 0) { cmd_write(cmd + 6); return 0; } - if (strncmp(cmd, "cd ", 3) == 0) { - SysSetCwd(cmd + 3); - return 0; - } - - if (strncmp(cmd, "del ", 4) == 0) { - SysDeleteFile(cmd + 4); - return 0; - } - - if (strncmp(cmd, "type ", 5) == 0) { - cmd_type(cmd + 5); - return 0; - } - - if (strncmp(cmd, "write ", 6) == 0) { - cmd_write(cmd + 6); - return 0; - } - - // --- External Process Execution --- uint32_t hProc; if (SysCreateProcess(cmd, &hProc, cmd) == 0) { SysWaitForProcess(hProc); - int exitCode = 0; - SysGetProcessExitCode(hProc, &exitCode); SysCloseHandle(hProc); - while (SysKbPoll()) { - (void)SysKbReadChar(); - } - } else { - print("shell: launch failed\n"); - } - + while (SysKbPoll()) (void)SysKbReadChar(); + } else { print("shell: launch failed\n"); } return 0; } -// --------------------------------------------------------------------------- -// Entry point -// --------------------------------------------------------------------------- int main(int argc, char** argv) { char lineBuf[MAX_CMD]; - print("shell: ready\n"); - while (true) { print("> "); readLine(lineBuf, MAX_CMD); - if (runCommand(trim(lineBuf))) - break; + if (runCommand(trim(lineBuf))) break; } - print("shell: goodbye\n"); SysExitProcess(0); return 0; diff --git a/code/shell_posix/shell_posix.c b/code/shell_posix/shell_posix.c index 1b1f2e1..15d31c8 100644 --- a/code/shell_posix/shell_posix.c +++ b/code/shell_posix/shell_posix.c @@ -3,18 +3,11 @@ #include #include +#define MAX_CMD 256 #define NAME_MAX 259 -typedef struct dirent { - char d_name[NAME_MAX + 1]; - unsigned char d_type; // DT_REG or DT_DIR -} dirent; - -typedef struct DIR { - uint32_t KHandle; // kernel DIR_OBJECT handle - dirent Current; - bool Valid; -} DIR; +typedef struct dirent { char d_name[NAME_MAX + 1]; unsigned char d_type; } dirent; +typedef struct DIR { uint32_t KHandle; dirent Current; bool Valid; } DIR; extern int read(int fd, void *buf, size_t count); extern int write(int fd, const void *buf, size_t count); @@ -25,36 +18,21 @@ extern DIR* opendir(const char* path); extern dirent* readdir(DIR* d); extern int closedir(DIR* d); extern int unlink(const char *pathname); -extern int posix_spawn(int *pid, const char *path, const void *file_act, const void *attr, char *const argv[], char *const envp[]); +extern int posix_spawn(int *pid, const char *path, const void *act, const void *attr, char *const argv[], char *const envp[]); extern int waitpid(int pid, int *status, int options); extern void exit(int status); - +extern int ClearConsoleScreenBuffer(void* h); extern void PosixFdInit(void); -extern int ClearConsoleScreenBuffer(void* hConsole); -// --------------------------------------------------------------------------- -// Global handles -// --------------------------------------------------------------------------- -static int hIn = 0; // stdin -static int hOut = 1; // stdout +static int hIn = 0; static int hOut = 1; -// --------------------------------------------------------------------------- -// Output helpers -// --------------------------------------------------------------------------- -static void print(const char* s) { - write(hOut, s, strlen(s)); -} +static void print(const char* s) { write(hOut, s, strlen(s)); } static void printUInt(uint32_t n) { - char buf[12]; - int i = 0; + char buf[12]; int i = 0; if (n == 0) { print("0"); return; } while (n > 0) { buf[i++] = (char)('0' + n % 10); n /= 10; } - char rev[12]; - int j = 0; - while (i > 0) rev[j++] = buf[--i]; - rev[j] = '\0'; - print(rev); + while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); } } static void printInt(int32_t n) { @@ -62,28 +40,14 @@ static void printInt(int32_t n) { printUInt((uint32_t)n); } -// --------------------------------------------------------------------------- -// Line editor -// --------------------------------------------------------------------------- -#define MAX_CMD 256 - static void readLine(char* buf, int len) { int pos = 0; while (true) { - char c; - if (read(hIn, &c, 1) <= 0) break; + char c; if (read(hIn, &c, 1) <= 0) break; if (c == '\r' || c == '\n') { print("\n"); break; } - if ((c == '\b' || c == 127) && pos > 0) { - pos--; - print("\b \b"); - continue; - } + if ((c == '\b' || c == 127) && pos > 0) { pos--; print("\b \b"); continue; } if (c < 0x20 || c == 127) continue; - if (pos < len - 1) { - buf[pos++] = c; - char echo[2] = { c, '\0' }; - print(echo); - } + if (pos < len - 1) { buf[pos++] = c; char echo[2] = {c, '\0'}; print(echo); } } buf[pos] = '\0'; } @@ -96,136 +60,82 @@ static char* trim(char* s) { return s; } -// --------------------------------------------------------------------------- -// Built-in commands -// --------------------------------------------------------------------------- static void cmd_help() { print("Available commands:\n" - " help - Show this list\n" - " dir [path] - List directory contents\n" - " cd - Change directory\n" - " type - Display file contents\n" - " del - Delete a file\n" - " write - Create a file with text\n" - " exit - Close the shell\n"); + " help - Show this list\n" + " dir [path] - List directory contents\n" + " cd - Change directory\n" + " type - Display file contents\n" + " del - Delete a file\n" + " write - Create a file with text\n" + " clear - Clear the screen\n" + " exit - Close the shell\n"); } static void cmd_write(const char* args) { - char filename[MAX_CMD]; - int i = 0; + char filename[MAX_CMD]; int i = 0; while (args[i] != ' ' && args[i] != '\0' && i < MAX_CMD - 1) { - filename[i] = args[i]; - i++; + filename[i] = args[i]; i++; } filename[i] = '\0'; - if (args[i] == '\0' || args[i+1] == '\0') return; - - // Open with O_WRONLY | O_CREAT | O_TRUNC (typical flags: 0x0001 | 0x0040 | 0x0200) - int fd = open(filename, 0x0241, 0644); - if (fd < 0) return; + if (args[i] == '\0' || args[i+1] == '\0') { print("write: usage: write \n"); return; } + int fd = open(filename, 0x0241, 0644); // O_WRONLY | O_CREAT | O_TRUNC + if (fd < 0) { print("write: could not create file\n"); return; } write(fd, args + i + 1, strlen(args + i + 1)); close(fd); + print("File written successfully.\n"); } static void cmd_dir(const char* path) { - // If no path is provided, default to current directory const char* target = (path && *path != '\0') ? path : "."; - DIR* d = opendir(target); - if (!d) { - print("dir: cannot access '"); - print(target); - print("'\n"); - return; - } - + if (!d) { print("dir: cannot access directory\n"); return; } dirent* entry; while ((entry = readdir(d)) != NULL) { - // Filter out the current and parent directory markers - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - continue; - } - - // Display type (Assuming 1=DIR, 2=REG based on common custom POSIX layouts) - if (entry->d_type == 1) { - print(" "); - } else { - print(" "); - } - - print(entry->d_name); - print("\n"); + if (entry->d_name[0] == '.') continue; + print(entry->d_type == 1 ? " " : " "); + print(entry->d_name); print("\n"); } - closedir(d); } static void cmd_type(const char* filename) { int fd = open(filename, 0); // O_RDONLY - if (fd < 0) return; - char buffer[512]; - int n; - while ((n = read(fd, buffer, 511)) > 0) { - buffer[n] = '\0'; - print(buffer); - } - close(fd); - print("\n"); + if (fd < 0) { print("type: cannot open file\n"); return; } + char buffer[512]; int n; + while ((n = read(fd, buffer, 511)) > 0) { buffer[n] = '\0'; print(buffer); } + close(fd); print("\n"); } -// --------------------------------------------------------------------------- -// Run one command. -// --------------------------------------------------------------------------- static int runCommand(const char* cmd) { if (!cmd || *cmd == '\0') return 0; - if (strcmp(cmd, "exit") == 0) return 1; if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; } + if (strcmp(cmd, "clear") == 0) { ClearConsoleScreenBuffer(0); return 0; } if (strcmp(cmd, "crash") == 0) { *(int*)0 = 42; return 0; } - - if (strcmp(cmd, "dir") == 0) { - cmd_dir("."); - return 0; - } - if (strncmp(cmd, "dir ", 4) == 0) { - cmd_dir(cmd + 4); - return 0; - } - - if (strcmp(cmd, "clear") == 0) { - ClearConsoleScreenBuffer(0); - return 0; - } - + if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; } + if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; } if (strncmp(cmd, "cd ", 3) == 0) { chdir(cmd + 3); return 0; } if (strncmp(cmd, "del ", 4) == 0) { unlink(cmd + 4); return 0; } if (strncmp(cmd, "type ", 5) == 0) { cmd_type(cmd + 5); return 0; } if (strncmp(cmd, "write ", 6) == 0) { cmd_write(cmd + 6); return 0; } - // --- External Process Execution (No Fork) --- - int pid; - char *argv[] = {(char*)cmd, NULL}; + int pid; char *argv[] = {(char*)cmd, NULL}; if (posix_spawn(&pid, cmd, NULL, NULL, argv, NULL) == 0) { - int status; - waitpid(pid, &status, 0); - } else { - print("shell: error launching\n"); - } + int status; waitpid(pid, &status, 0); + } else { print("shell: launch failed\n"); } return 0; } -int main(const char* args) { +int main() { PosixFdInit(); char lineBuf[MAX_CMD]; print("shell: ready\n"); - while (true) { print("> "); readLine(lineBuf, MAX_CMD); if (runCommand(trim(lineBuf))) break; } - print("shell: goodbye\n"); - exit(0); } diff --git a/code/shell_win32/shell_win32.c b/code/shell_win32/shell_win32.c index d084613..354f84e 100644 --- a/code/shell_win32/shell_win32.c +++ b/code/shell_win32/shell_win32.c @@ -4,85 +4,42 @@ #include #include -// !Made-up! clear console api. -BOOL ClearConsoleScreenBuffer(HANDLE hConsole); - -// --------------------------------------------------------------------------- -// Global handles -// --------------------------------------------------------------------------- +#define MAX_CMD 256 static HANDLE hIn = INVALID_HANDLE_VALUE; static HANDLE hOut = INVALID_HANDLE_VALUE; -// --------------------------------------------------------------------------- -// Output helpers -// --------------------------------------------------------------------------- +// External/Custom API +BOOL ClearConsoleScreenBuffer(HANDLE hConsole); + +// --- Output Helpers --- static void print(const char* s) { DWORD written; - // Write to the actual console window - if (hOut != INVALID_HANDLE_VALUE) { - WriteConsoleA(hOut, s, (DWORD)strlen(s), &written, 0); - } else { - OutputDebugStringA(s); - } + if (hOut != INVALID_HANDLE_VALUE) WriteConsoleA(hOut, s, (DWORD)strlen(s), &written, 0); + else OutputDebugStringA(s); } static void printUInt(uint32_t n) { - char buf[12]; - int i = 0; + char buf[12]; int i = 0; if (n == 0) { print("0"); return; } while (n > 0) { buf[i++] = (char)('0' + n % 10); n /= 10; } - char rev[12]; - int j = 0; - while (i > 0) rev[j++] = buf[--i]; - rev[j] = '\0'; - print(rev); + while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); } } static void printInt(int32_t n) { - char buf[12]; - int i = 0; - uint32_t val = (n < 0) ? (print("-"), (uint32_t)-(n + 1) + 1) : (uint32_t)n; - - if (val == 0) { print("0"); return; } - - while (val > 0) { - buf[i++] = (char)('0' + (val % 10)); - val /= 10; - } - - while (i > 0) { - char c[2] = { buf[--i], '\0' }; - print(c); // Assumes print() handles strings - } + if (n < 0) { print("-"); n = -n; } + printUInt((uint32_t)n); } -// --------------------------------------------------------------------------- -// Line editor -// --------------------------------------------------------------------------- -#define MAX_CMD 256 - +// --- Line Editor --- static void readLine(char* buf, int len) { int pos = 0; while (true) { - char c; - DWORD nRead; + char c; DWORD nRead; ReadConsoleA(hIn, &c, 1, &nRead, 0); if (!nRead) continue; - - if (c == '\r' || c == '\n') { - print("\n"); - break; - } - - if ((c == '\b' || c == 127) && pos > 0) { - pos--; - print("\b \b"); - continue; - } - - if (c < 0x20 || c == 127) - continue; - + if (c == '\r' || c == '\n') { print("\n"); break; } + if ((c == '\b' || c == 127) && pos > 0) { pos--; print("\b \b"); continue; } + if (c < 0x20 || c == 127) continue; if (pos < len - 1) { buf[pos++] = c; char echo[2] = { c, '\0' }; @@ -100,253 +57,101 @@ static char* trim(char* s) { return s; } -// --------------------------------------------------------------------------- -// Built-in commands -// --------------------------------------------------------------------------- +// --- Built-in Commands --- static void cmd_help() { print("Available commands:\n" - " help - Show this list\n" - " dir - List files in current directory\n" - " cd - Change directory\n" - " type - Display file contents\n" - " del - Delete a file\n" - " write - Create a file with text\n" - " exit - Close the shell\n"); + " help - Show this list\n" + " dir [path] - List directory contents\n" + " cd - Change directory\n" + " type - Display file contents\n" + " del - Delete a file\n" + " write - Create a file with text\n" + " clear - Clear the screen\n" + " exit - Close the shell\n"); } static void cmd_write(const char* args) { - char filename[MAX_PATH]; - int i = 0; - - // Parse filename (up to first space) + char filename[MAX_PATH]; int i = 0; while (args[i] != ' ' && args[i] != '\0' && i < MAX_PATH - 1) { - filename[i] = args[i]; - i++; + filename[i] = args[i]; i++; } filename[i] = '\0'; - if (args[i] == '\0' || args[i+1] == '\0') { print("write: usage: write \n"); return; } - - const char* text = args + i + 1; // Content starts after the space - HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); - if (hFile == INVALID_HANDLE_VALUE) { - print("write: could not create file\n"); - return; - } - + if (hFile == INVALID_HANDLE_VALUE) { print("write: could not create file\n"); return; } DWORD written; - if (!WriteFile(hFile, text, (DWORD)strlen(text), &written, 0)) { - print("write: error writing to file\n"); - } else { - print("File written successfully.\n"); - } - + WriteFile(hFile, args + i + 1, (DWORD)strlen(args + i + 1), &written, 0); CloseHandle(hFile); + print("File written successfully.\n"); } static void cmd_dir(const char* path) { WIN32_FIND_DATAA fd; char search_path[MAX_PATH]; + const char* target = (path && *path != '\0') ? path : "."; - size_t path_len = 0; - while (path[path_len] != '\0' && path_len < MAX_PATH) { - path_len++; - } - - // Ensure we have room for the path + "\*" + null terminator - if (path_len + 3 > MAX_PATH) { - print("dir: path too long\n"); - return; - } - - // Manual concatenation - memcpy(search_path, path, path_len); - - // Append the wildcard pattern - search_path[path_len] = '\\'; - search_path[path_len + 1] = '*'; - search_path[path_len + 2] = '\0'; + size_t len = strlen(target); + if (len + 3 > MAX_PATH) { print("dir: path too long\n"); return; } + strcpy(search_path, target); + strcat(search_path, "\\*"); HANDLE hFind = FindFirstFileA(search_path, &fd); - - if (hFind == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) { - return; - } - print("dir: failed to read directory\n"); - return; - } - + if (hFind == INVALID_HANDLE_VALUE) { print("dir: failed to read directory\n"); return; } do { - // Skip the "." and ".." entries to keep output clean - if (path_len > 0 && fd.cFileName[0] == '.') { - if (fd.cFileName[1] == '\0' || (fd.cFileName[1] == '.' && fd.cFileName[2] == '\0')) { - continue; - } - } - - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - print(" "); - } else { - print(" "); - } - print(fd.cFileName); - print("\n"); + if (fd.cFileName[0] == '.') continue; // Skip . and .. + print(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? " " : " "); + print(fd.cFileName); print("\n"); } while (FindNextFileA(hFind, &fd)); - FindClose(hFind); } static void cmd_type(const char* filename) { HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - if (hFile == INVALID_HANDLE_VALUE) { - print("type: could not open '"); - print(filename); - print("'\n"); - return; - } - - char buffer[512]; - DWORD bytesRead; + if (hFile == INVALID_HANDLE_VALUE) { print("type: cannot open file\n"); return; } + char buffer[512]; DWORD bytesRead; while (ReadFile(hFile, buffer, sizeof(buffer) - 1, &bytesRead, 0) && bytesRead > 0) { - buffer[bytesRead] = '\0'; - print(buffer); + buffer[bytesRead] = '\0'; print(buffer); } - - CloseHandle(hFile); - print("\n"); + CloseHandle(hFile); print("\n"); } -// --------------------------------------------------------------------------- -// Run one command. Returns 1 if the shell should exit. -// --------------------------------------------------------------------------- static int runCommand(const char* cmd) { - if (!cmd || *cmd == '\0') - return 0; + if (!cmd || *cmd == '\0') return 0; + if (strcmp(cmd, "exit") == 0) return 1; + if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; } + if (strcmp(cmd, "clear") == 0) { ClearConsoleScreenBuffer(hOut); return 0; } + if (strcmp(cmd, "crash") == 0) { *(int*)0 = 42; return 0; } + if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; } + if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; } + if (strncmp(cmd, "cd ", 3) == 0) { SetCurrentDirectoryA(cmd + 3); return 0; } + if (strncmp(cmd, "del ", 4) == 0) { DeleteFileA(cmd + 4); return 0; } + if (strncmp(cmd, "type ", 5) == 0) { cmd_type(cmd + 5); return 0; } + if (strncmp(cmd, "write ", 6) == 0) { cmd_write(cmd + 6); return 0; } - // --- Built-in commands --- - if (strcmp(cmd, "exit") == 0) { - return 1; + STARTUPINFOA si = { sizeof(si) }; PROCESS_INFORMATION pi; + char cmdBuf[MAX_CMD]; strncpy(cmdBuf, cmd, MAX_CMD-1); + if (CreateProcessA(NULL, cmdBuf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); CloseHandle(pi.hThread); + } else { + print("shell: launch failed\n"); } - - if (strcmp(cmd, "help") == 0) { - cmd_help(); - return 0; - } - - if (strcmp(cmd, "crash") == 0) { - *(int*)0 = 42; - return 0; - } - - if (strcmp(cmd, "clear") == 0) { - ClearConsoleScreenBuffer(hOut); - return 0; - } - - if (strcmp(cmd, "dir") == 0) { - cmd_dir("."); - return 0; - } - if (strncmp(cmd, "dir ", 4) == 0) { - cmd_dir(cmd + 4); - return 0; - } - - if (strncmp(cmd, "cd ", 3) == 0) { - const char* path = cmd + 3; - if (!SetCurrentDirectoryA(path)) { - print("cd: failed to change directory to '"); - print(path); - print("'\n"); - } - return 0; - } - - if (strncmp(cmd, "del ", 4) == 0) { - const char* file = cmd + 4; - if (!DeleteFileA(file)) { - print("del: failed to delete '"); - print(file); - print("'\n"); - } - return 0; - } - - if (strncmp(cmd, "type ", 5) == 0) { - cmd_type(cmd + 5); - return 0; - } - - if (strncmp(cmd, "write ", 6) == 0) { - cmd_write(cmd + 6); - return 0; - } - - // --- External Process Execution --- - STARTUPINFOA si; - PROCESS_INFORMATION pi; - unsigned char* p = (unsigned char*)&si; - for (size_t i = 0; i < sizeof(si); i++) p[i] = 0; - si.cb = (DWORD)sizeof(si); - - // CreateProcessA requires a mutable buffer for the command line argument - char cmdBuf[MAX_CMD]; - strncpy(cmdBuf, cmd, MAX_CMD - 1); - cmdBuf[MAX_CMD - 1] = '\0'; - - if (!CreateProcessA(0, cmdBuf, 0, 0, 0, 0, 0, 0, &si, &pi)) { - print("shell: could not launch '"); - print(cmd); - print("', error code: "); - printUInt(GetLastError()); - print("\n"); - return 0; - } - - WaitForSingleObject(pi.hProcess, INFINITE); - - FlushConsoleInputBuffer(hOut); - - DWORD exitCode = 0; - GetExitCodeProcess(pi.hProcess, &exitCode); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - if (exitCode != 0) { - print("shell: '"); - print(cmd); - print("' exited with code "); - printInt(exitCode); - print("\n"); - } - return 0; } -// --------------------------------------------------------------------------- -// Entry point -// --------------------------------------------------------------------------- -int main(const char* cmdline) { +int main() { hIn = GetStdHandle(STD_INPUT_HANDLE); hOut = GetStdHandle(STD_OUTPUT_HANDLE); char lineBuf[MAX_CMD]; - print("shell: ready\n"); - print(cmdline); - print("\n"); - while (true) { print("> "); readLine(lineBuf, MAX_CMD); - if (runCommand(trim(lineBuf))) - break; + if (runCommand(trim(lineBuf))) break; } - print("shell: goodbye\n"); ExitProcess(0); } diff --git a/code/syscall/syscall.h b/code/syscall/syscall.h index d964017..dc8c85b 100644 --- a/code/syscall/syscall.h +++ b/code/syscall/syscall.h @@ -82,7 +82,7 @@ uint64_t SysMouseRead(int* dx, int* dy, uint8_t* buttons); // 46 void SysMouseGetPos(int* x, int* y); // 47 // --------------------------------------------------------------------------- -// System Info & Process Management (48-53) +// System Info & Process Management (48-65) // --------------------------------------------------------------------------- uint64_t SysGetTick(void); // 48 uint32_t SysDebugPrint(const char* str); // 49 @@ -100,7 +100,7 @@ uint32_t SysSetCwd(const char* path); // 56 uint32_t SysGetCwd(char* buf, size_t size); // 57 // --------------------------------------------------------------------------- -// Process/Thread Helpers & Named Queues (58-63) +// Process/Thread Helpers & Named Queues (58-65) // --------------------------------------------------------------------------- uint32_t SysWaitThread(uint32_t tid); // 58 uint32_t SysGetProcessPid(uint32_t handle, uint32_t* pidOut); // 59 @@ -108,3 +108,12 @@ uint32_t SysPublishQueue(const char* name, uint32_t handle); // 60 uint32_t SysOpenNamedQueue(const char* name, uint32_t* handleOut); // 61 uint32_t SysQueueDuplicate(uint32_t handle, uint32_t targetPid, uint32_t* handleOut); // 62 uint32_t SysNamedQueueOwnerPid(const char* name, uint32_t* pidOut); // 63 +uint32_t SysKillProcess(uint32_t pid, int exitCode); // 64 +uint32_t SysGetProcessList(uint32_t* pidsOut, size_t maxCount, size_t* countOut); // 65 + +// --------------------------------------------------------------------------- +// Filesystem mutations (66-68) +// --------------------------------------------------------------------------- +uint32_t SysRenameFile(const char* oldPath, const char* newPath); // 66 +uint32_t SysCreateDir(const char* path); // 67 +uint32_t SysRemoveDir(const char* path); // 68 diff --git a/code/syscall/syscall_nr.inc b/code/syscall/syscall_nr.inc index d88e9e6..8c46a93 100644 --- a/code/syscall/syscall_nr.inc +++ b/code/syscall/syscall_nr.inc @@ -64,5 +64,10 @@ SYS_PUBLISH_QUEUE EQU 60 SYS_OPEN_NAMED_QUEUE EQU 61 SYS_QUEUE_DUPLICATE EQU 62 SYS_NAMED_QUEUE_OWNER_PID EQU 63 +SYS_KILL_PROCESS EQU 64 +SYS_GET_PROCESS_LIST EQU 65 +SYS_RENAME_FILE EQU 66 +SYS_CREATE_DIR EQU 67 +SYS_REMOVE_DIR EQU 68 -SYS_MAX EQU 64 +SYS_MAX EQU 69 diff --git a/code/syscall/syscall_stubs.asm b/code/syscall/syscall_stubs.asm index 16781cf..906c10e 100644 --- a/code/syscall/syscall_stubs.asm +++ b/code/syscall/syscall_stubs.asm @@ -199,4 +199,17 @@ SYSCALL_STUB2 OpenNamedQueue, SYS_OPEN_NAMED_QUEUE ; (const char* name, ui SYSCALL_STUB2 QueueDuplicate, SYS_QUEUE_DUPLICATE ; (uint32_t handle, uint32_t targetPid, uint32_t* handleOut) -> KSTATUS SYSCALL_STUB2 NamedQueueOwnerPid, SYS_NAMED_QUEUE_OWNER_PID ; (const char* name, uint32_t* pidOut) -> KSTATUS +; --------------------------------------------------------------------------- +; Process utilities +; --------------------------------------------------------------------------- +SYSCALL_STUB2 KillProcess, SYS_KILL_PROCESS ; (uint32_t pid, int exitCode) -> KSTATUS +SYSCALL_STUB2 GetProcessList, SYS_GET_PROCESS_LIST ; (uint32_t* pidsOut, size_t maxCount, size_t* countOut) -> KSTATUS + +; --------------------------------------------------------------------------- +; Filesystem mutations +; --------------------------------------------------------------------------- +SYSCALL_STUB2 RenameFile, SYS_RENAME_FILE ; (const char* oldPath, const char* newPath) -> KSTATUS +SYSCALL_STUB2 CreateDir, SYS_CREATE_DIR ; (const char* path) -> KSTATUS +SYSCALL_STUB2 RemoveDir, SYS_REMOVE_DIR ; (const char* path) -> KSTATUS + END diff --git a/readme.md b/readme.md index bc8ae69..5d11b60 100644 --- a/readme.md +++ b/readme.md @@ -4,88 +4,93 @@ Boots. Runs processes. Mimics Windows to some extent. ## what is it? -A 64-bit operating system kernel written from scratch. -UEFI bootloader, physical and virtual memory managers, preemptive scheduler, HAL, VFS, PE loader, partial Win32 layer. -It boots into a shell. -~20k lines of C and assembly. +NT-Lite is a 64-bit operating system kernel written from scratch. It includes a UEFI bootloader, physical and virtual memory managers, a preemptive scheduler, a HAL, a VFS, a PE loader, and partial Win32 and POSIX layers. It boots into a shell. + +The codebase is roughly 20k lines of C and assembly. ## features - UEFI bootloader - physical memory manager - virtual memory manager with kernel pool -- HAL (screen, keyboard, mouse, timer, disk, PCI, APIC) +- HAL for screen, keyboard, mouse, timer, disk, PCI, and APIC - preemptive scheduler with priority levels - processes and threads - VFS with IRPs -- drive-letter paths (`0:\apps\shell.exe`) +- drive-letter paths such as `0:\apps\shell.exe` - INI-based boot and driver configuration - PE import resolution and dynamic driver loading -- Win32 personality (partial) -- POSIX personality (partial) +- partial Win32 personality +- partial POSIX personality -## how 2 build +## architecture notes -* open vs x64 build tools as admin -* cd into this directory -* `mkimage.bat` -* `build.bat` -* `run.bat`(ide)/`rund.bat`(ide, debug)/`runa.bat`(ahci)/`runad.bat`(ahci, debug) -* enjoy +### memory layout -## how it looks when built +NT-Lite uses a single virtual address space per booted system rather than a fully separate kernel address space and user address space. The distinction between kernel and user mode comes from page permissions and CPU privilege checks, not from having a different page table for the kernel. -I have some strong opinions on OS design. +The kernel is mapped into the higher half of virtual memory and user processes only receive the regions they are explicitly granted. Kernel pages are marked supervisor-only, so user-mode code cannot read or write them directly. User pages are mapped with user permissions and are isolated from one another by the kernel’s allocator, VMM, and process creation path. -``` -efi/boot/ - bootx64.efi -boot.ini -hal.dll -colonel.exe -drivers/ - drivers.ini - ide.sys - ahci.sys - fat32.sys -syscall.dll -win32.dll -posix.dll -shell.exe -video.exe -``` +### boot chain -## driver model +The bootloader reads configuration, loads the core images, maps the higher-half layout, and hands control to `KernelMain`. After that, the kernel takes over interrupt setup, paging, scheduler bring-up, runtime driver loading, and user process launch. -drivers are PE32+ `.sys` files with an entry point preferably named DriverEntry accepting a constant pointer to HAL_API. +### drivers -drivers to be loaded have their path stored in `drivers.ini`, split into essential for boot (loaded by bootloader) and not required for boot (loaded by kernel). +Drivers are PE32+ `.sys` files with a conventional `DriverEntry` export that accepts a pointer to `HAL_API`. -a disk driver fills in a `DISK_DRIVER` vtable and calls `IoRegisterDisk(index, &driver)`. -a filesystem driver fills in an `IO_FILESYSTEM` vtable and calls `IoRegisterFilesystem(index, &fs, &vol)`. +Drivers are split into two groups: -currently shipping: AHCI (interrupts), IDE (PIO/DMA) and FAT32. +- essential boot drivers, which are loaded before the kernel starts doing real work +- runtime drivers, which are loaded later from disk once storage and the VFS are available + +The driver model is intentionally small. Disk drivers expose a `DISK_DRIVER` vtable and register with `IoRegisterDisk(index, &driver)`. Filesystem drivers expose an `IO_FILESYSTEM` vtable and register with `IoRegisterFilesystem(index, &fs, &vol)`. + +Currently shipping: AHCI (interrupts), IDE (PIO/DMA), and FAT32. + +### I/O and filesystems + +All file access flows through the VFS layer. That keeps disk access, filesystem parsing, and path translation separate instead of spreading storage logic across the rest of the kernel. + +Paths are not interpreted as Windows paths by default. A drive such as `0:\` is a mounted namespace, while the Win32 and POSIX personalities translate their own path styles into the same underlying VFS. + +### processes, threads, and syscalls + +User processes are launched from PE images, imports are resolved before the first thread is queued, and the syscall layer provides the boundary between user code and kernel services. `syscall.dll` is the shared entry point for the supported personalities. + +The scheduler is preemptive and priority-based, so threads do not depend on cooperative yielding to keep the system responsive. Process state is tracked separately from thread state, which allows a process to exit, be reaped, or be restarted by `init` without bringing down the rest of the system. + +### personalities + +The Win32 personality supports programs that expect drive letters, familiar process APIs, and a Windows-style runtime. The POSIX personality maps the same kernel primitives into a tree-shaped namespace and a different userspace contract. ## how it boots -1. UEFI loads `boot.ini`, reads `drivers.ini` -2. bootloader maps kernel, HAL, and boot drivers into the upper half -3. direct physical window at `0xFFFF880000000000` -4. jumps to `KernelMain` -5. PMM, VMM, GDT, IDT, HAL, IRQs, scheduler -6. loads runtime drivers from disk -7. launches `shell.exe` +1. UEFI loads `boot.ini` and reads `drivers.ini` +2. the bootloader maps the kernel, HAL, and boot drivers into the upper half +3. a direct physical window is mapped at `0xFFFF880000000000` +4. control passes to `KernelMain` +5. PMM, VMM, GDT, IDT, HAL, IRQs, and scheduler initialization run +6. runtime drivers are loaded from disk +7. `shell.exe` is launched -## paths (because they're different) +## how to build -``` -"apps\shell.exe" -> current working directory -"0:\apps\shell.exe" -> drive 0 -"2:\data\config.ini" -> drive 2 +- open the VS x64 build tools as administrator +- change into this directory +- run `mkimage.bat` +- run `build.bat` +- use one of `run.bat` (IDE), `rund.bat` (IDE, debug), `runa.bat` (AHCI), or `runad.bat` (AHCI, debug) + +## paths + +```text +"apps\shell.exe" -> current working directory +"0:\apps\shell.exe" -> drive 0 +"2:\data\config.ini" -> drive 2 ``` -Drives 0-7. A drive only works if a filesystem registered on it. -The Win32 personality translates drive letters to drive numbers, the POSIX personality maps drives onto a tree. +Drives 0-7 are available. A drive only works if a filesystem is registered on it. The Win32 personality translates drive letters to drive numbers, while the POSIX personality maps drives onto a tree. ## screenshots @@ -93,7 +98,7 @@ The Win32 personality translates drive letters to drive numbers, the POSIX perso
Boot logs -``` +```text BdsDxe: loading Boot0001 "UEFI QEMU HARDDISK QM00005 " from PciRoot(0x0)/Pci(0x4,0x0)/Sata(0x0,0xFFFF,0x0) BdsDxe: starting Boot0001 "UEFI QEMU HARDDISK QM00005 " from PciRoot(0x0)/Pci(0x4,0x0)/Sata(0x0,0xFFFF,0x0) 1 @@ -204,7 +209,7 @@ W_Init: Init WADfiles. Shareware! =========================================================================== M_Init: Init miscellaneous info. -R_Init: Init DOOM refresh daemon - [.. ] +R_Init: Init Doom refresh daemon - [.. ] InitTextures InitFlats........ InitSprites @@ -239,7 +244,7 @@ Available commands: type - Display file contents del - Delete a file write - Create a file with text - exit - Close the shell + exit - Close the shell > dir System Volume Information drivers @@ -289,14 +294,23 @@ A: `doom.exe` Q: Is the Win32 layer real? A: Real enough to load binaries that expect it. Not real enough to run Notepad. -Q: Is the scheduler preemptive? -A: As much as it will ever be. - -Q: Will it corrupt my data? -A: It shouldn't. +Q: Are processes isolated? +A: No. But IPC is free. Q: Is this finished? -A: Not in the slightest. +A: No. + +Will it corrupt my data? +A: It shouldn't. + +Q: Why is the path syntax so weird? +A: It makes sense to me. + +Q: Why are the logs so verbose? +A: How else do I debug it? + +Q: What should I read first? +A: This document. Q: Can I use this in production? A: Don't.