From f80e66ecdebad61491ebcabcbae3dd5ee68f4000 Mon Sep 17 00:00:00 2001 From: Maksymilian Wilczynski Date: Wed, 13 May 2026 09:24:16 +0200 Subject: [PATCH] build.bat can create the image if missing, split the shell into native, posix and win32, clean up the build by moving executables into directories, the bootloader is no longer responsible to resolve drivers, fix ResolvePath, every process gets a copy of a module (dll), the child always inherits the cwd, fix function exports in posix, add unlink and exit to posix, add path translator to win32, first bugcheck. --- OVMF/OVMF_VARS_4M_d.fd | Bin 540672 -> 540672 bytes build.bat | 75 +++-- code/boot.ini | 2 +- code/boot/main.c | 46 +-- code/init/init.c | 57 +++- code/kernel/boot_info.h | 7 +- code/kernel/io_file.c | 4 +- code/kernel/ke_debug.c | 123 ++++++++ code/kernel/ke_debug.h | 20 +- code/kernel/ke_process.c | 30 ++ code/kernel/ke_process.h | 32 +- code/kernel/ke_sched.c | 2 +- code/kernel/ke_syscall.asm | 119 ++++---- code/kernel/ke_syscall.c | 29 +- code/kernel/kmain.c | 176 ++++++----- code/kernel/ldr_image.c | 288 +++++++++++++++--- code/kernel/ldr_image.h | 13 +- code/kernel/ob_object.h | 2 +- code/libc.c | 10 + code/posix/posix.h | 1 + code/posix/posix_dir.c | 20 +- code/posix/posix_fd.c | 17 +- code/posix/posix_fd.h | 8 +- code/posix/posix_io.c | 45 +-- code/posix/posix_path.c | 4 +- code/posix/posix_proc.c | 19 +- code/posix/posix_thread.c | 31 +- code/shell_native/shell_native.c | 247 +++++++++++++++ code/shell_posix/shell_posix.c | 231 ++++++++++++++ .../shell.c => shell_win32/shell_win32.c} | 52 +++- code/syscall/syscall.h | 110 +++++++ code/video/video.c | 6 +- code/win32/gdi32.c | 9 +- code/win32/kernel32.c | 147 +++++---- code/win32/ole32.c | 3 +- code/win32/user32.c | 4 +- code/win32/winmm.c | 5 +- readme.md | 88 +++++- 38 files changed, 1620 insertions(+), 462 deletions(-) create mode 100644 code/shell_native/shell_native.c create mode 100644 code/shell_posix/shell_posix.c rename code/{shell/shell.c => shell_win32/shell_win32.c} (82%) create mode 100644 code/syscall/syscall.h diff --git a/OVMF/OVMF_VARS_4M_d.fd b/OVMF/OVMF_VARS_4M_d.fd index 4616f9687dea3f98577020f9924f2721f47a78f9..0dcfc4afe65ec9874ccc45611956ec49e71931c5 100644 GIT binary patch delta 284 zcmXBHISRr+06_~)h-_Sc+P$}rOyd!l-rW~1eWTq>#@(*Y- BbsGQx delta 143 zcmZo@P;6*W+%Q3pv3K)Cz2{7feVZo+bqg@|L#PQ5Y9fT11feEFs3{O?DukK_q&x+t zYZ);)F-`}vFLJfp*)nanvt>SXsr`Zz)AkEa%p5t}1Xva@ZT}#|BEUNxC>YSDz|y9` P+NQwProg^TfkOcRq--<+ diff --git a/build.bat b/build.bat index a77a28d..e0e0e4c 100644 --- a/build.bat +++ b/build.bat @@ -6,8 +6,7 @@ set SRC=%ROOT%\code set VHD=%~dp0disk.vhd if not exist "%VHD%" ( - echo ERROR: disk.vhd not found. Run mkimage.bat first. - exit /b 1 + call mkimage.bat ) if exist "obj" rd /s /q "obj" @@ -21,12 +20,14 @@ mkdir "obj\win32" 2>nul mkdir "obj\posix" 2>nul mkdir "obj\drivers" 2>nul mkdir "obj\init" 2>nul -mkdir "obj\shell" 2>nul +mkdir "obj\shell_win32" 2>nul +mkdir "obj\shell_posix" 2>nul +mkdir "obj\shell_native" 2>nul mkdir "obj\doom" 2>nul mkdir "obj\video" 2>nul mkdir "bin" 2>nul -set CFLAGS=/nologo /W3 /Od /GS- /Gs999999 /Gz /Gy /EHsc- /GR- /Oi /Zi /std:c17 /D_CRT_SECURE_NO_WARNINGS /I"%SRC%\kernel" /I"%SRC%\hal" +set CFLAGS=/nologo /W3 /WX /Od /GS- /Gs999999 /Gz /Gy /EHsc- /GR- /Oi /Zi /std:c17 /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /I"%SRC%\kernel" /I"%SRC%\hal" /I"%SRC%\syscall" set LFLAGS=/nologo /NODEFAULTLIB /DEBUG :: ---- Assemble ASM files ---- @@ -124,16 +125,38 @@ for %%f in (%SRC%\init\*.c) do ( link %LFLAGS% /SUBSYSTEM:NATIVE /ENTRY:_start ^ /OUT:"bin\init.exe" /PDB:"bin\init.pdb" bin\syscall.lib obj\libc.obj obj\init\init.obj || exit /b 1 -:: ---- Compile shell ---- -echo Compiling shell... -for %%f in (%SRC%\shell\*.c) do ( - cl %CFLAGS% /c /Fo"obj\shell\%%~nf.obj" "%%f" || exit /b 1 +:: ---- Compile shell_win32 ---- +echo Compiling shell_win32... +for %%f in (%SRC%\shell_win32\*.c) do ( + cl %CFLAGS% /c /Fo"obj\shell_win32\%%~nf.obj" "%%f" || exit /b 1 ) -:: ---- Link shell.exe ---- -echo Linking shell.exe... +:: ---- Compile shell_posix ---- +echo Compiling shell_posix... +for %%f in (%SRC%\shell_posix\*.c) do ( + cl %CFLAGS% /c /Fo"obj\shell_posix\%%~nf.obj" "%%f" || exit /b 1 +) + +:: ---- Compile shell_native ---- +echo Compiling shell_native... +for %%f in (%SRC%\shell_native\*.c) do ( + cl %CFLAGS% /c /Fo"obj\shell_native\%%~nf.obj" "%%f" || exit /b 1 +) + +:: ---- Link shell_win32.exe ---- +echo Linking shell_win32.exe... link %LFLAGS% /SUBSYSTEM:NATIVE /ENTRY:main ^ - /OUT:"bin\shell.exe" /PDB:"bin\shell.pdb" bin\win32.lib obj\libc.obj obj\shell\*.obj || exit /b 1 + /OUT:"bin\shell_win32.exe" /PDB:"bin\shell_win32.pdb" bin\win32.lib obj\libc.obj obj\shell_win32\*.obj || exit /b 1 + +:: ---- Link shell_posix.exe ---- +echo Linking shell_posix.exe... +link %LFLAGS% /SUBSYSTEM:NATIVE /ENTRY:main ^ + /OUT:"bin\shell_posix.exe" /PDB:"bin\shell_posix.pdb" bin\posix.lib obj\libc.obj obj\shell_posix\*.obj || exit /b 1 + +:: ---- Link shell_native.exe ---- +echo Linking shell_native.exe... +link %LFLAGS% /SUBSYSTEM:NATIVE /ENTRY:main ^ + /OUT:"bin\shell_native.exe" /PDB:"bin\shell_native.pdb" bin\syscall.lib obj\libc.obj obj\shell_native\*.obj || exit /b 1 :: ---- Compile doom ---- echo Compiling doom... @@ -179,27 +202,31 @@ set DEST=Z: :: ---- Copy to ESP layout ---- echo Assembling ESP... -mkdir "%DEST%\drivers" 2>nul +mkdir "%DEST%\apps" 2>nul +mkdir "%DEST%\system" 2>nul +mkdir "%DEST%\drivers" 2>nul mkdir "%DEST%\EFI\BOOT" 2>nul copy /y "bin\bootx64.efi" "%DEST%\EFI\BOOT\" -copy /y "bin\kernel.exe" "%DEST%\colonel.exe" -copy /y "bin\hal.dll" "%DEST%\" -copy /y "bin\syscall.dll" "%DEST%\" -copy /y "bin\win32.dll" "%DEST%\" -copy /y "bin\posix.dll" "%DEST%\" +copy /y "bin\kernel.exe" "%DEST%\system\colonel.exe" +copy /y "bin\hal.dll" "%DEST%\system\" +copy /y "bin\syscall.dll" "%DEST%\system\" +copy /y "bin\win32.dll" "%DEST%\system\" +copy /y "bin\posix.dll" "%DEST%\system\" copy /y "bin\ide.sys" "%DEST%\drivers\" copy /y "bin\ahci.sys" "%DEST%\drivers\" copy /y "bin\fat32.sys" "%DEST%\drivers\" copy /y "bin\usb.sys" "%DEST%\drivers\" -copy /y "bin\init.exe" "%DEST%\" -copy /y "bin\shell.exe" "%DEST%\" -copy /y "bin\doom.exe" "%DEST%\" -copy /y "bin\video.exe" "%DEST%\" +copy /y "bin\init.exe" "%DEST%\system\" +copy /y "bin\shell_win32.exe" "%DEST%\apps\" +copy /y "bin\shell_posix.exe" "%DEST%\apps\" +copy /y "bin\shell_native.exe" "%DEST%\apps\" +copy /y "bin\doom.exe" "%DEST%\apps\" +copy /y "bin\video.exe" "%DEST%\apps\" copy /y "%SRC%\boot.ini" "%DEST%\" copy /y "%SRC%\drivers\drivers.ini" "%DEST%\drivers\" -if exist "%SRC%\video\bink2w64.dll" copy /y "%SRC%\video\bink2w64.dll" "%DEST%\" -if exist "%SRC%\video\video.bk2" copy /y "%SRC%\video\video.bk2" "%DEST%\" -if exist "%SRC%\doom\doom1.wad" copy /y "%SRC%\doom\doom1.wad" "%DEST%\" +if exist "%SRC%\video\bink2w64.dll" copy /y "%SRC%\video\bink2w64.dll" "%DEST%\apps\" +if exist "%SRC%\video\video.bk2" copy /y "%SRC%\video\video.bk2" "%DEST%\apps\" +if exist "%SRC%\doom\doom1.wad" copy /y "%SRC%\doom\doom1.wad" "%DEST%\apps\" :: ---- Unmount disk image ---- echo Unmounting disk.vhd... diff --git a/code/boot.ini b/code/boot.ini index 7c91c2e..b6e55ca 100644 --- a/code/boot.ini +++ b/code/boot.ini @@ -1,4 +1,4 @@ [kernel] debug = 1 [init] -commandline = shell.exe +commandline = apps/shell_native.exe diff --git a/code/boot/main.c b/code/boot/main.c index 900b28c..c6a528b 100644 --- a/code/boot/main.c +++ b/code/boot/main.c @@ -558,8 +558,8 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable } MODULE_LOAD_INFO; MODULE_LOAD_INFO core[] = { - { L"colonel.exe", "kernel.exe", NULL, KERNEL_VIRT_BASE }, - { L"hal.dll", "hal.dll", NULL, 0 /* Calculated dynamically */ }, + { L"system\\colonel.exe", "kernel.exe", NULL, KERNEL_VIRT_BASE }, + { L"system\\hal.dll", "hal.dll", NULL, 0 /* Calculated dynamically */ }, }; for (int i = 0; i < 2; i++) { @@ -615,45 +615,27 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable Print(L"5\n"); - // Load driver .sys files. + // Load driver .sys files into raw buffers for (int i = 0; i < ps.driverCount; i++) { CHAR16 path[128]; UnicodeSPrint(path, sizeof(path), L"drivers\\%s", ps.drivers[i]); + UINTN imgSz; UINT8* buf = LoadFile(path, &imgSz); - if (!buf) { Print(L"Driver not found: %s\n", ps.drivers[i]); continue; } - - UINT32 stored = *(UINT32 *)(buf + *(UINT32 *)(buf + 0x3C) + 4 + 20 + 64); - UINT32 computed = ComputePeChecksum(buf, imgSz); - if (stored && computed != stored) { - Print(L"Checksum mismatch: %s\n", ps.drivers[i]); - FreePool(buf); continue; + if (!buf) { + Print(L"Driver not found: %s\n", ps.drivers[i]); + continue; } - UINT32 peOff = *(UINT32 *)(buf + 0x3C); - UINT32 imgLen = *(UINT32 *)(buf + peOff + 4 + 20 + 56); - imgLen = (imgLen + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - - EFI_PHYSICAL_ADDRESS phys; - EFI_STATUS status = LoadPeImage(buf, virtCursor, &phys); - if (EFI_ERROR(status)) { - Print(L"Driver PE load failed: %s\n", ps.drivers[i]); - FreePool(buf); - continue; - } - - UINT64 virt = virtCursor; - for (UINT64 off = 0; off < imgLen; off += PAGE_SIZE) - MapPage(virt + off, phys + off, 0x03); - + // Store file info for the kernel to process later char name[32]; UnicodeStrToAsciiStrS(ps.drivers[i], name, 32); - AsciiStrCpyS(bi->Modules[bi->ModuleCount].Name, 32, name); - bi->Modules[bi->ModuleCount].VirtBase = virt; - bi->Modules[bi->ModuleCount].ImageSize = imgLen; - bi->ModuleCount++; - virtCursor = (virtCursor + imgLen + 0xFFFFF) & ~0xFFFFF; - FreePool(buf); + + BOOT_MODULE* mod = &bi->Modules[bi->ModuleCount++]; + AsciiStrCpyS(mod->Name, 32, name); + mod->PhysBase = (uintptr_t)buf; // Raw physical buffer from LoadFile + mod->ImageSize = (size_t)imgSz; + mod->VirtBase = 0; // Kernel will map this later } Print(L"6\n"); diff --git a/code/init/init.c b/code/init/init.c index 8013ed0..a622c54 100644 --- a/code/init/init.c +++ b/code/init/init.c @@ -2,20 +2,52 @@ #include #include #include - -// --------------------------------------------------------------------------- -// Syscall stubs -// --------------------------------------------------------------------------- -extern uint32_t SysCreateProcess(const char* path, uint32_t* handleOut, - const char* cmdline); -extern uint32_t SysCloseHandle(uint32_t handle); -extern void SysDebugPrint(const char* str); -extern uint32_t SysWaitForProcess(uint32_t handle); -extern void SysExitProcess(int code); -extern void SysYield(void); +#include #define STATUS_SUCCESS 0u +void itoa(int num, char* str) { + int i = 0; + int is_negative = 0; + + // Handle 0 explicitly + if (num == 0) { + str[i++] = '0'; + str[i] = '\0'; + return; + } + + // Handle negative numbers + if (num < 0) { + is_negative = 1; + num = -num; + } + + // Process individual digits (result is in reverse) + while (num != 0) { + int rem = num % 10; + str[i++] = rem + '0'; + num = num / 10; + } + + if (is_negative) { + str[i++] = '-'; + } + + str[i] = '\0'; // Null terminate + + // Reverse the string + int start = 0; + int end = i - 1; + while (start < end) { + char temp = str[start]; + str[start] = str[end]; + str[end] = temp; + start++; + end--; + } +} + void _start(const char* args) { uint32_t h = 0; @@ -25,6 +57,9 @@ void _start(const char* args) s = SysCreateProcess(args, &h, NULL); if (s != STATUS_SUCCESS) { SysDebugPrint("[init] FATAL: failed to start!\n"); + char buffer[12]; + itoa(s, buffer); + SysDebugPrint(buffer); SysDebugPrint("\n"); SysExitProcess(1); } diff --git a/code/kernel/boot_info.h b/code/kernel/boot_info.h index 66f756e..c455ae7 100644 --- a/code/kernel/boot_info.h +++ b/code/kernel/boot_info.h @@ -9,8 +9,9 @@ typedef struct BOOT_MODULE { char Name[32]; /* e.g. "hal.dll", "ide.sys" */ - uintptr_t VirtBase; /* where it was mapped */ - size_t ImageSize; + uintptr_t VirtBase; /* Virtual address (mapped) */ + uintptr_t PhysBase; /* Raw physical address (file) */ + size_t ImageSize; /* File size / Image size */ } BOOT_MODULE; typedef struct BOOT_INFO { @@ -24,7 +25,6 @@ typedef struct BOOT_INFO { uint32_t FramebufferWidth; uint32_t FramebufferHeight; uint32_t FramebufferStride; /* pixels per row */ - uint32_t _pad0; /* Loaded modules. */ BOOT_MODULE Modules[MAX_BOOT_MODULES]; @@ -41,5 +41,4 @@ typedef struct BOOT_INFO { /* From boot.ini */ uint32_t DebugEnabled; - uint32_t _pad2; } BOOT_INFO; diff --git a/code/kernel/io_file.c b/code/kernel/io_file.c index d68a4cf..38a77b3 100644 --- a/code/kernel/io_file.c +++ b/code/kernel/io_file.c @@ -46,17 +46,19 @@ __declspec(dllexport) KSTATUS IoGetCwd(char* buf, size_t size) { static uint8_t ResolvePath(const char* path, char* resolved, size_t resolvedSize) { // Strip explicit drive prefix "N:\" uint8_t drive = 0; + bool fromDriveRoot = false; if (path[0] >= '0' && path[0] <= '7' && path[1] == ':' && (path[2] == '\\' || path[2] == '/')) { drive = (uint8_t)(path[0] - '0'); path = path + 3; + fromDriveRoot = true; } char work[CWD_MAX * 2]; work[0] = '\0'; // Initialize our working base - if (path[0] == '\\' || path[0] == '/') { + if (path[0] == '\\' || path[0] == '/' || fromDriveRoot) { // Absolute path: start from the root (empty work buffer) // The segment loop below will automatically skip the leading separators. } else { diff --git a/code/kernel/ke_debug.c b/code/kernel/ke_debug.c index 9736988..f42efd4 100644 --- a/code/kernel/ke_debug.c +++ b/code/kernel/ke_debug.c @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include int _fltused; // fuckass @@ -62,3 +65,123 @@ __declspec(dllexport) void KePrintConsole(const char* buf, size_t len) { for (size_t i = 0; i < len; i++) PrintChar(buf[i], 0xFFFFFF, 0x000000); } + +// --------------------------------------------------------------------------- +// KeBugCheckProcess - user-mode fault handler +// +// Resolves the faulting RIP to a module name, prints a yellow crash banner, +// kills the offending process, then exits the current thread so the scheduler +// can continue running everything else. +// --------------------------------------------------------------------------- + +// Return the short exception name for a vector number. +static const char* FaultVectorName(int vector) { + switch (vector) { + case 0: return "#DE Divide Error"; + case 13: return "#GP General Protection"; + case 14: return "#PF Page Fault"; + default: return "Unknown Exception"; + } +} + +// Walk the process module list to find which image owns rip. +// Returns the module name string, or "unknown" if rip is outside all regions. +static const char* ResolveModule(PROCESS* proc, uintptr_t rip) { + // Check the main executable image first. + if (proc->ImageBase && proc->ImageSize && + rip >= proc->ImageBase && rip < proc->ImageBase + proc->ImageSize) + return proc->Name; + + // Walk the per-process module table (DLLs / shared libraries). + for (uint32_t i = 0; i < proc->ModuleCount; i++) { + uintptr_t base = proc->Modules[i].Base; + size_t size = proc->Modules[i].Size; + if (base && size && rip >= base && rip < base + size) + return proc->Modules[i].Name; + } + + return "unknown"; +} + +static void PrintCrashChar(char c) { + PrintChar(c, 0xFFAA00, 0x000000); // amber - distinct from green debug / red panic +} + +_Noreturn void KeBugCheckProcess(int vector, uintptr_t rip, uintptr_t errCode, uintptr_t cr2) { + THREAD* thread = KeGetCurrentThread(); + PROCESS* proc = thread ? thread->Owner : (PROCESS*)0; + + // Snapshot everything we need before touching process state. + const char* faultName = FaultVectorName(vector); + const char* procName = proc ? proc->Name : "unknown"; + uint32_t pid = proc ? proc->ProcessId : 0; + const char* modName = proc ? ResolveModule(proc, rip) : "unknown"; + + // Amber crash banner. + static const char banner[] = "\n*** APPLICATION CRASH ***\n"; + for (const char* p = banner; *p; p++) + PrintCrashChar(*p); + + printf_set_putchar(PrintCrashChar); + + if (vector == 14) + printf("Process: %s (PID %u) | Fault: %s\n" + "Module: %s | RIP: %016llx | Code: %04llx | CR2: %016llx\n", + procName, pid, faultName, + modName, + (unsigned long long)rip, + (unsigned long long)errCode, + (unsigned long long)cr2); + else + printf("Process: %s (PID %u) | Fault: %s\n" + "Module: %s | RIP: %016llx | Code: %04llx\n", + procName, pid, faultName, + modName, + (unsigned long long)rip, + (unsigned long long)errCode); + + // Restore normal (green) output for subsequent kernel messages. + printf_set_putchar(kernel_putchar); + + // Kill the process and exit this thread. + // KeExitThread sets ThreadDead then calls KeYield; the scheduler will + // never return here, so the process crash cannot affect anything else. + if (proc) KeExitProcess(proc, -1); + if (thread) KeExitThread(thread, -1); + + // Unreachable - KeExitThread never returns for a dead thread. + while (1) __halt(); +} + +// --------------------------------------------------------------------------- +// KeFaultDispatch - single C entry point for all three IDT fault stubs. +// +// The asm stubs (ke_syscall.asm) collect the CPU exception frame values and +// call here. We check the CS RPL to decide: kernel fault → KePanic (halt), +// user fault → KeBugCheckProcess (kill process, resume scheduler). +// --------------------------------------------------------------------------- +__declspec(dllexport) _Noreturn void KeFaultDispatch(int vector, uintptr_t rip, + uintptr_t errCode, uintptr_t cr2, + uintptr_t cs) { + if ((cs & 3) == 0) { + // Kernel-mode fault: unrecoverable. + switch (vector) { + case 0: + KePanic("PANIC: #DE Divide Error | RIP: %016llx\n", + (unsigned long long)rip); + case 13: + KePanic("PANIC: #GP General Protection | RIP: %016llx | Code: %04llx\n", + (unsigned long long)rip, (unsigned long long)errCode); + case 14: + KePanic("PANIC: #PF Page Fault | RIP: %016llx | Code: %04llx | CR2: %016llx\n", + (unsigned long long)rip, (unsigned long long)errCode, + (unsigned long long)cr2); + default: + KePanic("PANIC: Exception #%d | RIP: %016llx\n", + vector, (unsigned long long)rip); + } + } + + // User-mode fault: recoverable - kill the process, resume the scheduler. + KeBugCheckProcess(vector, rip, errCode, cr2); +} diff --git a/code/kernel/ke_debug.h b/code/kernel/ke_debug.h index d7a6e2b..f85e2f2 100644 --- a/code/kernel/ke_debug.h +++ b/code/kernel/ke_debug.h @@ -4,8 +4,24 @@ #include void KeInitDebug(void (*PrintPtr)(char, uint32_t, uint32_t), int v); -__declspec(dllexport) void DbgPrint(const char* fmt, ...); +__declspec(dllexport) void DbgPrint(const char* fmt, ...); __declspec(dllexport) void KePrintConsole(const char* buf, size_t len); -__declspec(dllexport) void KePanic(const char *fmt, ...); +__declspec(dllexport) _Noreturn void KePanic(const char *fmt, ...); + +// --------------------------------------------------------------------------- +// Fault dispatch - called from the three IDT fault stubs (ke_syscall.asm). +// +// vector : CPU exception number (0=#DE, 13=#GP, 14=#PF) +// rip : faulting instruction pointer (from the CPU exception frame) +// errCode : CPU error code (0 for #DE) +// cr2 : value of CR2 at fault time (meaningful only for #PF) +// cs : CS from the exception frame; RPL bits determine ring +// +// Kernel-mode faults (cs & 3 == 0) call KePanic and halt. +// User-mode faults (cs & 3 == 3) kill the offending process and yield. +// --------------------------------------------------------------------------- +__declspec(dllexport) _Noreturn void KeFaultDispatch(int vector, uintptr_t rip, + uintptr_t errCode, uintptr_t cr2, + uintptr_t cs); #endif // KE_DEBUG_H diff --git a/code/kernel/ke_process.c b/code/kernel/ke_process.c index c2366fd..08a0f7f 100644 --- a/code/kernel/ke_process.c +++ b/code/kernel/ke_process.c @@ -50,6 +50,31 @@ static void ProcessDestroy(OBJECT* obj) { } } + // Release the main executable image. + if (proc->ImageBase && proc->ImageSize) { + MmFreeUserMemory((void *)proc->ImageBase, proc->ImageSize); + proc->ImageBase = 0; + proc->ImageSize = 0; + } + + // Release per-process modules. + for (uint32_t i = 0; i < proc->ModuleCount; i++) { + if (proc->Modules[i].Base && proc->Modules[i].Size) { + MmFreeUserMemory((void *)proc->Modules[i].Base, proc->Modules[i].Size); + } + proc->Modules[i].Base = 0; + proc->Modules[i].Size = 0; + proc->Modules[i].Name[0] = '\0'; + } + proc->ModuleCount = 0; + + // Release the user command line buffer. + if (proc->UserCmdlineBase && proc->UserCmdlineSize) { + MmFreeUserMemory((void *)proc->UserCmdlineBase, proc->UserCmdlineSize); + proc->UserCmdlineBase = 0; + proc->UserCmdlineSize = 0; + } + // Release the exit event. if (proc->ExitEvent) { ObDereferenceObject(&proc->ExitEvent->Header); @@ -86,6 +111,11 @@ KSTATUS KeCreateProcess(const char* name, PROCESS **out) { proc->ThreadCount = 0; proc->HandleLock = (SPINLOCK)SPINLOCK_INIT; proc->ExitCode = 0; + proc->ImageBase = 0; + proc->ImageSize = 0; + proc->UserCmdlineBase = 0; + proc->UserCmdlineSize = 0; + proc->ModuleCount = 0; // Slot 0 is the invalid handle - leave it NULL. memset(proc->Handles, 0, sizeof(proc->Handles)); diff --git a/code/kernel/ke_process.h b/code/kernel/ke_process.h index e662c22..9a560c8 100644 --- a/code/kernel/ke_process.h +++ b/code/kernel/ke_process.h @@ -6,10 +6,20 @@ #include #include #include +#include #define PROCESS_NAME_MAX 64 #define HANDLE_TABLE_SIZE 256 + +#define PROCESS_MODULE_MAX 16 + +typedef struct PROCESS_MODULE { + char Name[32]; + uintptr_t Base; + size_t Size; +} PROCESS_MODULE; + typedef struct PROCESS { OBJECT Header; /* must be first */ @@ -36,6 +46,18 @@ typedef struct PROCESS { int ExitCode; + /* Main executable image. Used for cleanup. */ + uintptr_t ImageBase; + size_t ImageSize; + + /* User command line buffer passed to the initial thread. */ + uintptr_t UserCmdlineBase; + size_t UserCmdlineSize; + + /* Per-process loaded modules (user processes only). */ + PROCESS_MODULE Modules[PROCESS_MODULE_MAX]; + uint32_t ModuleCount; + /* Signaled (manual-reset) when the process exits. Waiters block on this via KeWaitForEvent. */ EVENT* ExitEvent; @@ -43,13 +65,13 @@ typedef struct PROCESS { LIST_ENTRY GlobalLink; /* node in the global process list */ } PROCESS; -KSTATUS KeCreateProcess(const char* name, PROCESS **out); -void KeExitProcess(PROCESS* process, int exitCode); -KSTATUS KeGetProcessExitCode(PROCESS* process, int* exitCodeOut); +KSTATUS KeCreateProcess(const char* name, PROCESS **out); +void KeExitProcess(PROCESS* process, int exitCode); +KSTATUS KeGetProcessExitCode(PROCESS* process, int* exitCodeOut); /* Handle table operations. */ -KSTATUS KeAllocateHandle(PROCESS* process, OBJECT* object, uint32_t* handleOut); -void KeCloseHandle(PROCESS* process, uint32_t handle); +KSTATUS KeAllocateHandle(PROCESS* process, OBJECT* object, uint32_t* handleOut); +void KeCloseHandle(PROCESS* process, uint32_t handle); OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle); /* Return the global process list head (kernel-internal). */ diff --git a/code/kernel/ke_sched.c b/code/kernel/ke_sched.c index b246ad0..02924e7 100644 --- a/code/kernel/ke_sched.c +++ b/code/kernel/ke_sched.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,6 @@ void KeInitializeScheduler(void) { for (int i = 0; i < PriorityCount; i++) LIST_INIT(&gRunQueue[i]); gSchedLock = (SPINLOCK)SPINLOCK_INIT; - extern KSTATUS KeCreateProcess(const char *, PROCESS **); PROCESS* idleProc; KeCreateProcess("idle", &idleProc); diff --git a/code/kernel/ke_syscall.asm b/code/kernel/ke_syscall.asm index 7a9ccb5..6934ced 100644 --- a/code/kernel/ke_syscall.asm +++ b/code/kernel/ke_syscall.asm @@ -37,93 +37,76 @@ KeSyscallEntry PROC KeSyscallEntry ENDP ; --------------------------------------------------------------------------- -; Fault stubs - print a message and halt. +; Fault stubs - thin wrappers that collect the CPU exception frame and +; forward to KeFaultDispatch (C), which handles both kernel panics and +; user-process bugchecks. +; +; KeFaultDispatch signature (MS x64): +; void KeFaultDispatch(int vector, // rcx +; UINT64 rip, // rdx +; UINT64 errCode, // r8 +; UINT64 cr2, // r9 +; UINT64 cs) // [rsp+20h] (5th arg, on stack) ; --------------------------------------------------------------------------- -EXTERN KePanic:PROC +EXTERN KeFaultDispatch:PROC -.data -; We define separate strings to maximize the info we can print -StrKernel DB "Kernel Mode", 0 -StrUser DB "User Mode", 0 - -MsgFaultDE DB "PANIC: Divide Error (#0) | RIP: %016llx | Mode: %s", 0Ah, 0 -MsgFaultGP DB "PANIC: General Protection (#13) | RIP: %016llx | Code: %04x | Mode: %s", 0Ah, 0 -MsgFaultPF DB "PANIC: Page Fault (#14) | RIP: %016llx | Code: %04x | CR2: %016llx | %s", 0Ah, 0 - -.code +; Allocation for a 5-argument call (MS x64): +; 32 bytes shadow space (0x00..0x1F) +; 8 bytes for 5th arg (0x20..0x27) +; Total = 0x28 bytes. +; After "and rsp,-16" rsp%16==0; sub 0x28 (40) → rsp%16==8, +; so the subsequent "call" push makes rsp 16-byte aligned at callee entry. ✓ +FAULT_FRAME_SIZE EQU 28h ; --------------------------------------------------------- -; Divide Error (#0) - NO Error Code pushed by CPU -; Stack: [rsp] = RIP, [rsp+8] = CS, [rsp+16] = RFLAGS +; Divide Error (#0) - NO error code pushed by CPU +; Exception frame at entry: [rsp]=RIP [rsp+8]=CS [rsp+16]=RFLAGS ; --------------------------------------------------------- KeFaultDE PROC - mov rdx, [rsp] ; Arg 2: RIP + mov rdx, [rsp] ; Arg2: rip + xor r8, r8 ; Arg3: errCode = 0 (no error code for #DE) + xor r9, r9 ; Arg4: cr2 = 0 (not a page fault) + mov r10, [rsp+8] ; cs (save before we clobber rsp) + mov ecx, 0 ; Arg1: vector = 0 - ; Determine User/Kernel mode from CS - mov rax, [rsp + 8] ; Read CS - and rax, 3 ; Isolate the bottom 2 bits (RPL) - lea r8, StrKernel - lea r9, StrUser - test rax, rax ; If 0, it's Kernel. If >0, it's User. - cmovnz r8, r9 ; Arg 3: Mode String (moves r9 into r8 if Not Zero) - - lea rcx, MsgFaultDE ; Arg 1: Format string - - ; Safely align stack and allocate shadow space for the call - and rsp, -16 ; Force 16-byte ABI stack alignment - sub rsp, 20h ; Allocate 32 bytes of shadow space - call KePanic + and rsp, -16 + sub rsp, FAULT_FRAME_SIZE + mov [rsp+20h], r10 ; Arg5: cs + call KeFaultDispatch ; _Noreturn - never returns KeFaultDE ENDP ; --------------------------------------------------------- -; General Protection Fault (#13) - Error Code PUSHED -; Stack: [rsp] = ErrCode, [rsp+8] = RIP, [rsp+16] = CS +; General Protection Fault (#13) - error code pushed by CPU +; Exception frame at entry: [rsp]=ErrCode [rsp+8]=RIP [rsp+16]=CS ; --------------------------------------------------------- KeFaultGP PROC - mov r8, [rsp] ; Arg 3: Error Code - mov rdx, [rsp + 8] ; Arg 2: RIP + mov r8, [rsp] ; Arg3: errCode + mov rdx, [rsp+8] ; Arg2: rip + xor r9, r9 ; Arg4: cr2 = 0 (not a page fault) + mov r10, [rsp+16] ; cs + mov ecx, 13 ; Arg1: vector = 13 - ; Determine User/Kernel mode from CS - mov rax, [rsp + 16] ; Read CS - and rax, 3 - lea r9, StrKernel - lea r10, StrUser - test rax, rax - cmovnz r9, r10 ; Arg 4: Mode String - - lea rcx, MsgFaultGP ; Arg 1: Format string - - and rsp, -16 ; Align stack - sub rsp, 20h ; 32 bytes shadow space - call KePanic + and rsp, -16 + sub rsp, FAULT_FRAME_SIZE + mov [rsp+20h], r10 ; Arg5: cs + call KeFaultDispatch KeFaultGP ENDP ; --------------------------------------------------------- -; Page Fault (#14) - Error Code PUSHED -; Stack: [rsp] = ErrCode, [rsp+8] = RIP, [rsp+16] = CS +; Page Fault (#14) - error code pushed by CPU +; Exception frame at entry: [rsp]=ErrCode [rsp+8]=RIP [rsp+16]=CS ; --------------------------------------------------------- KeFaultPF PROC - mov r8, [rsp] ; Arg 3: Error Code - mov rdx, [rsp + 8] ; Arg 2: RIP - mov r9, cr2 ; Arg 4: CR2 (The faulting virtual address) + mov r8, [rsp] ; Arg3: errCode + mov rdx, [rsp+8] ; Arg2: rip + mov r9, cr2 ; Arg4: cr2 (faulting virtual address) + mov r10, [rsp+16] ; cs + mov ecx, 14 ; Arg1: vector = 14 - ; Determine User/Kernel mode from CS - mov rax, [rsp + 16] ; Read CS - and rax, 3 - lea r10, StrKernel - lea r11, StrUser - test rax, rax - cmovnz r10, r11 ; r10 now holds the Mode String - - lea rcx, MsgFaultPF ; Arg 1: Format string - - ; We have 5 arguments for PF! (rcx, rdx, r8, r9, and the stack) - ; x64 ABI dictates the 5th argument goes on the stack just above the shadow space. - and rsp, -16 ; Align stack - sub rsp, 30h ; 32 bytes shadow space + 16 bytes for 5th arg and padding - mov [rsp + 20h], r10 ; Arg 5: Mode String (placed exactly after shadow space) - - call KePanic + and rsp, -16 + sub rsp, FAULT_FRAME_SIZE + mov [rsp+20h], r10 ; Arg5: cs + call KeFaultDispatch KeFaultPF ENDP EXTERN KeIrqDispatch:PROC diff --git a/code/kernel/ke_syscall.c b/code/kernel/ke_syscall.c index e12d15a..c6b2931 100644 --- a/code/kernel/ke_syscall.c +++ b/code/kernel/ke_syscall.c @@ -769,6 +769,15 @@ static uint64_t SyscallCreateProcess(uint64_t a0, uint64_t a1, uint64_t a2, s = KeCreateProcess(path, &proc); if (!KSUCCESS(s)) { MmFreeUserMemory(mem, size); return s; } + // Inherit CWD from parent + PROCESS* parent = KeGetCurrentProcess(); + if (parent) { + uintptr_t flags = KeAcquireSpinlock(&parent->CwdLock); + strncpy(proc->CurrentDirectory, parent->CurrentDirectory, sizeof(proc->CurrentDirectory) - 1); + proc->CurrentDirectory[sizeof(proc->CurrentDirectory) - 1] = '\0'; + KeReleaseSpinlock(&parent->CwdLock, flags); + } + // Store the command line in the process so _start can pick it up. // If no cmdline was supplied default to just the image path. if (cmdline && cmdline[0]) @@ -781,8 +790,10 @@ static uint64_t SyscallCreateProcess(uint64_t a0, uint64_t a1, uint64_t a2, // Copy into user memory so the initial thread can access it directly. size_t cmdlineLen = strlen(proc->Cmdline) + 1; char* userCmdline = (char*)MmAllocateUserMemory(cmdlineLen); - if (!userCmdline) { ObDereferenceObject(&proc->Header); return STATUS_NO_MEMORY; } + if (!userCmdline) { MmFreeUserMemory(mem, size); ObDereferenceObject(&proc->Header); return STATUS_NO_MEMORY; } memcpy(userCmdline, proc->Cmdline, cmdlineLen); + proc->UserCmdlineBase = (uintptr_t)userCmdline; + proc->UserCmdlineSize = cmdlineLen; // Map the PE image into memory. uintptr_t imageBase = 0; @@ -790,13 +801,26 @@ static uint64_t SyscallCreateProcess(uint64_t a0, uint64_t a1, uint64_t a2, MmFreeUserMemory(mem, size); if (!KSUCCESS(s)) { ObDereferenceObject(&proc->Header); return s; } + s = LdrResolveImportsForProcess(proc, imageBase); + if (!KSUCCESS(s)) { + MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase)); + ObDereferenceObject(&proc->Header); + return s; + } + // Spin up the initial thread. Pass userCmdline as UserArg so _start // receives it directly in RCX without an extra syscall. THREAD* thread; uintptr_t entryPoint = LdrGetEntryPoint(imageBase); s = KeCreateThread(proc, entryPoint, (uintptr_t)userCmdline, PriorityNormal, &thread); - if (!KSUCCESS(s)) { ObDereferenceObject(&proc->Header); return s; } + if (!KSUCCESS(s)) { + MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase)); + ObDereferenceObject(&proc->Header); + return s; + } + proc->ImageBase = imageBase; + proc->ImageSize = LdrGetImageSize(imageBase); // Give the caller a handle to the new process so they can wait on it. PROCESS* caller = KeGetCurrentProcess(); @@ -809,7 +833,6 @@ static uint64_t SyscallCreateProcess(uint64_t a0, uint64_t a1, uint64_t a2, *handleOut = handle; return STATUS_SUCCESS; } - // --------------------------------------------------------------------------- // SYS_WAIT_FOR_PROCESS (51) a0=handle // Blocks until the target process signals its ExitEvent. diff --git a/code/kernel/kmain.c b/code/kernel/kmain.c index 7f0aeba..59aa582 100644 --- a/code/kernel/kmain.c +++ b/code/kernel/kmain.c @@ -31,13 +31,17 @@ typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API *); static const HAL_API* gKmainHal; // --------------------------------------------------------------------------- -// Phase Helper: Resolve Imports for all registered modules +// Phase Helper: Resolve Imports for core modules // --------------------------------------------------------------------------- static void ResolveSystemImports(BOOT_INFO* bootInfo) { - // Resolve imports for all loaded modules (drivers may import from hal.dll, win32.dll imports from syscall.dll, etc). - // Starting at 2 to skip the kernel and HAL base images. - for (uint32_t i = 2; i < bootInfo->ModuleCount; i++) { - LdrResolveImports(bootInfo->Modules[i].VirtBase); + // Only resolve imports for kernel.exe and hal.dll (typically indices 0 and 1). + // The bootloader maps these, but drivers are now passed as raw physical files. + uint32_t coreModuleCount = (bootInfo->ModuleCount > 2) ? 2 : bootInfo->ModuleCount; + + for (uint32_t i = 0; i < coreModuleCount; i++) { + if (bootInfo->Modules[i].VirtBase != 0) { + LdrResolveImports(bootInfo->Modules[i].VirtBase); + } } } @@ -63,19 +67,44 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) { // boot drivers (provided by the bootloader) for (uint32_t i = 0; i < bootInfo->ModuleCount; i++) { - const char* name = bootInfo->Modules[i].Name; + BOOT_MODULE* mod = &bootInfo->Modules[i]; - // Identify .sys files by extension - size_t len = strlen(name); - if (len < 4 || strcmp(name + len - 4, ".sys")) continue; + // Skip modules that are already mapped (Kernel/HAL) + // or have no physical data (invalid) + if (mod->VirtBase != 0 || mod->PhysBase == 0) continue; - DbgPrint("InitializeDrivers: Executing DriverEntry for %s\n", name); + DbgPrint("InitializeDrivers: Loading boot driver %s\n", mod->Name); - DRIVER_ENTRY_FN entry = (DRIVER_ENTRY_FN)(LdrGetEntryPoint(bootInfo->Modules[i].VirtBase)); + // Calculate virtual address of the raw file in the physical window + void* rawPeBuffer = (void*)(bootInfo->PhysicalMapBase + mod->PhysBase); - KSTATUS ds = entry(hal); - if (!KSUCCESS(ds)) { - DbgPrint("InitializeDrivers: Driver %s failed to init!\n", name); + // Map the PE image into kernel space + uintptr_t mappedBase = 0; + KSTATUS st = LdrLoadImage(rawPeBuffer, mod->ImageSize, &mappedBase, false); + if (!KSUCCESS(st)) { + DbgPrint("ERROR: Failed to map driver %s (0x%X)\n", mod->Name, st); + continue; + } + + // Update the struct so other modules can find it + mod->VirtBase = mappedBase; + + // Resolve imports (can now see Kernel, HAL, and previous drivers) + if (!KSUCCESS(LdrResolveImports(mappedBase))) { + DbgPrint("ERROR: Failed to resolve imports for %s\n", mod->Name); + continue; + } + + // Register with the global module list so subsequent drivers can import from this one + LdrRegisterModule(mod->Name, mod->VirtBase); + + // Execute Entry Point + DRIVER_ENTRY_FN entry = (DRIVER_ENTRY_FN)LdrGetEntryPoint(mappedBase); + if (entry) { + KSTATUS ds = entry(hal); + if (!KSUCCESS(ds)) { + DbgPrint("WARNING: Driver %s returned failure status 0x%X\n", mod->Name, ds); + } } } @@ -137,6 +166,13 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) { uintptr_t mappedBase = 0; if (!KSUCCESS(LdrLoadImage(drvMem, drvSize, &mappedBase, false))) { // Load into kernel space DbgPrint("InitializeDrivers: Failed to load runtime driver: %s\n", runtimeKeys[i]); + MmFreePool(drvMem); + continue; + } + MmFreePool(drvMem); + + if (!KSUCCESS(LdrResolveImports(mappedBase))) { + DbgPrint("InitializeDrivers: Failed to resolve imports for runtime driver: %s\n", runtimeKeys[i]); continue; } @@ -163,41 +199,6 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) { MmFreePool(mem); } -// --------------------------------------------------------------------------- -// Phase Helper: Load a DLL from disk and register it -// --------------------------------------------------------------------------- -static void LoadAndRegisterDll(const char* filename) { - KSTATUS s; - FILE_OBJECT* f; - - // Read the DLL from disk - s = IoOpenFile(filename, &f); - if (s != STATUS_SUCCESS) { - KePanic("LoadAndRegisterDll: Failed to open DLL: %s\n", filename); - } - - uint64_t size = IoGetFileSize(f); - void* mem = MmAllocatePool(size); // Temporary pool for the raw file - size_t got; - if (!KSUCCESS(IoReadFile(f, mem, size, &got))) { - KePanic("LoadAndRegisterDll: Failed to read %s\n", filename); - IoCloseFile(f); - } - IoCloseFile(f); - - // Map the DLL into memory - // Passing 'true' for user-mode - uintptr_t mappedBase = 0; - s = LdrLoadImage(mem, size, &mappedBase, true); - if (!KSUCCESS(s)) { - KePanic("LoadAndRegisterDll: Failed to map %s\n", filename); - } - - MmFreePool(mem); // Free the raw file buffer, we only need the mapped image now - - LdrRegisterModule(filename, mappedBase); // Register the module -} - // --------------------------------------------------------------------------- // Phase Helper: Load and launch a process from the filesystem. // Returns the new PROCESS* with one reference owned by the caller. @@ -206,69 +207,102 @@ static void LoadAndRegisterDll(const char* filename) { static PROCESS* LaunchUserProcess(const char* filePath, const char* args) { KSTATUS s; FILE_OBJECT* f; - - // Read the executable file into a raw buffer + + // Read the executable file into a raw buffer. s = IoOpenFile(filePath, &f); DbgPrint("LaunchUserProcess: IoOpenFile: %d\n", s); if (s != STATUS_SUCCESS) { DbgPrint("Failed to load file: \"%s\"!\n", filePath); - return (PROCESS*)0; + return 0; } - + uint64_t size = IoGetFileSize(f); DbgPrint("LaunchUserProcess: IoGetFileSize: %llu\n", size); void* mem = MmAllocateUserMemory(size); DbgPrint("LaunchUserProcess: MmAllocateUserMemory: 0x%llX\n", mem); + if (!mem) { + IoCloseFile(f); + return 0; + } - size_t got; + size_t got = 0; s = IoReadFile(f, mem, size, &got); DbgPrint("LaunchUserProcess: IoReadFile: %d\n", s); IoCloseFile(f); - DbgPrint("LaunchUserProcess: IoCloseFile\n"); + if (!KSUCCESS(s)) { + MmFreeUserMemory(mem, size); + return 0; + } - // Create the process object + // Create the process object. PROCESS* proc; THREAD* thread; s = KeCreateProcess(filePath, &proc); if (!KSUCCESS(s)) { DbgPrint("Failed to create process. System halted.\n"); - return (PROCESS*)0; + MmFreeUserMemory(mem, size); + return 0; } DbgPrint("Created process (PID %u) with command line: %s\n", proc->ProcessId, filePath); - strncpy(proc->Cmdline, args, sizeof(proc->Cmdline) - 1); + if (args && args[0]) + strncpy(proc->Cmdline, args, sizeof(proc->Cmdline) - 1); + else + strncpy(proc->Cmdline, filePath, sizeof(proc->Cmdline) - 1); + proc->Cmdline[sizeof(proc->Cmdline) - 1] = '\0'; // proc->Cmdline is kernel pool (ffffc000...) - not readable at CPL=3. // Copy into user memory before handing the pointer to the initial thread. - char* userCmdline = (char*)MmAllocateUserMemory(sizeof(proc->Cmdline)); + size_t cmdlineLen = strlen(proc->Cmdline) + 1; + char* userCmdline = (char*)MmAllocateUserMemory(cmdlineLen); if (!userCmdline) { DbgPrint("LaunchUserProcess: Failed to allocate user cmdline buffer.\n"); - return (PROCESS*)0; + MmFreeUserMemory(mem, size); + ObDereferenceObject(&proc->Header); + return 0; } - memcpy(userCmdline, proc->Cmdline, sizeof(proc->Cmdline)); + memcpy(userCmdline, proc->Cmdline, cmdlineLen); + proc->UserCmdlineBase = (uintptr_t)userCmdline; + proc->UserCmdlineSize = cmdlineLen; - // Parse the raw PE file and map it into executable memory + // Parse the raw PE file and map it into executable memory. uintptr_t imageBase = 0; s = LdrLoadImage(mem, size, &imageBase, true); + MmFreeUserMemory(mem, size); if (!KSUCCESS(s)) { DbgPrint("LaunchUserProcess: LdrLoadImage failed with status: %d\n", s); + ObDereferenceObject(&proc->Header); + return 0; } + + s = LdrResolveImportsForProcess(proc, imageBase); + if (!KSUCCESS(s)) { + DbgPrint("LaunchUserProcess: Failed to resolve EXE imports for %s (status %d)\n", filePath, s); + MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase)); + ObDereferenceObject(&proc->Header); + return 0; + } + uintptr_t entryPoint = LdrGetEntryPoint(imageBase); DbgPrint("LaunchUserProcess: PE Image mapped! Base 0x%llx, Entry 0x%llX\n", imageBase, entryPoint); - // Create the main thread, pointing it to the PE Entry Point + // Create the main thread, pointing it to the PE Entry Point. s = KeCreateThread(proc, (uintptr_t)entryPoint, (uintptr_t)userCmdline, PriorityNormal, &thread); if (!KSUCCESS(s)) { DbgPrint("LaunchUserProcess: Failed to create thread. Status: %d\n", s); + MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase)); + ObDereferenceObject(&proc->Header); + return 0; } + proc->ImageBase = imageBase; + proc->ImageSize = LdrGetImageSize(imageBase); DbgPrint("LaunchUserProcess: Thread created and queued!\n"); // 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. @@ -312,15 +346,6 @@ void SystemInitThread(void* arg) { ResolveSystemImports(args->bootInfo); - DbgPrint("SystemInitThread: Loading system DLLs...\n"); - LoadAndRegisterDll("syscall.dll"); - LoadAndRegisterDll("win32.dll"); - LoadAndRegisterDll("bink2w64.dll"); - - // Now that they are in memory and registered, we link them together - // (e.g., win32.dll resolving its imports against syscall.dll) - ResolveSystemImports(args->bootInfo); - args->hal->Screen.Clear(0x000000); // Print memory status now that the system is fully alive @@ -330,7 +355,7 @@ void SystemInitThread(void* arg) { 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("init.exe", args->bootInfo->CommandLine); + PROCESS* shellProc = LaunchUserProcess("system/init.exe", args->bootInfo->CommandLine); if (shellProc) { KSTATUS ws = KeCreateKernelThread((uintptr_t)ProcessWatcherThread, @@ -340,10 +365,9 @@ void SystemInitThread(void* arg) { DbgPrint("SystemInitThread: Failed to create watcher thread (%d) -- leaking proc ref.\n", ws); } } - + MmFreePool(args); } - // --------------------------------------------------------------------------- // Main Kernel Entry // --------------------------------------------------------------------------- diff --git a/code/kernel/ldr_image.c b/code/kernel/ldr_image.c index 4e43fda..3807481 100644 --- a/code/kernel/ldr_image.c +++ b/code/kernel/ldr_image.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -109,39 +111,72 @@ typedef struct { typedef struct { char Name[32]; uintptr_t Base; + size_t Size; } MODULE_ENTRY; static MODULE_ENTRY gModules[MAX_MODULES]; -static int gModuleCount = 0; +static uint32_t gModuleCount = 0; + +static uintptr_t FindModuleBaseInTable(const MODULE_ENTRY* modules, uint32_t count, const char* name) { + for (uint32_t i = 0; i < count; i++) { + if (_stricmp(modules[i].Name, name) == 0) return modules[i].Base; + } + return 0; +} + +static void RegisterModuleEntry(MODULE_ENTRY* entry, const char* name, uintptr_t base, size_t size) { + strncpy(entry->Name, name, 31); + entry->Name[31] = '\0'; + entry->Base = base; + entry->Size = size; +} void LdrRegisterModulesFromBootInfo(const BOOT_INFO* bootInfo) { - for (uint32_t i = 0; i < bootInfo->ModuleCount && i < MAX_MODULES; i++) { - strncpy(gModules[gModuleCount].Name, bootInfo->Modules[i].Name, 31); - gModules[gModuleCount].Base = bootInfo->Modules[i].VirtBase; - gModuleCount++; + for (uint32_t i = 0; i < bootInfo->ModuleCount && gModuleCount < MAX_MODULES; i++) { + // Only register modules that have a virtual base (Kernel, HAL) + if (bootInfo->Modules[i].VirtBase != 0) { + RegisterModuleEntry(&gModules[gModuleCount], + bootInfo->Modules[i].Name, + bootInfo->Modules[i].VirtBase, + bootInfo->Modules[i].ImageSize); + gModuleCount++; + } } } void LdrRegisterModule(const char* name, uintptr_t base) { if (gModuleCount < MAX_MODULES) { - strncpy(gModules[gModuleCount].Name, name, 31); - gModules[gModuleCount].Base = base; + RegisterModuleEntry(&gModules[gModuleCount], name, base, 0); gModuleCount++; } } -static uintptr_t FindModuleBase(const char* name) { - for (int i = 0; i < gModuleCount; i++) { - if (_stricmp(gModules[i].Name, name) == 0) return gModules[i].Base; +static uintptr_t FindGlobalModuleBase(const char* name) { + return FindModuleBaseInTable(gModules, gModuleCount, name); +} + +static uintptr_t FindProcessModuleBaseInTable( + const PROCESS_MODULE* modules, + uint32_t count, + const char* name +) { + for (uint32_t i = 0; i < count; i++) { + if (_stricmp(modules[i].Name, name) == 0) { + return modules[i].Base; + } } return 0; } -// --------------------------------------------------------------------------- -// Export lookup -// --------------------------------------------------------------------------- -void* LdrGetExport(const char* moduleName, const char* functionName) { - uintptr_t base = FindModuleBase(moduleName); +static uintptr_t FindProcessOrGlobalModuleBase(PROCESS* process, const char* name) { + if (process) { + uintptr_t base = FindProcessModuleBaseInTable(process->Modules, process->ModuleCount, name); + if (base) return base; + } + return FindGlobalModuleBase(name); +} + +static void* GetExportAtBase(uintptr_t base, const char* functionName) { if (!base) return (void *)0; uint32_t peOffset = *(uint32_t *)(base + 0x3C); @@ -169,6 +204,26 @@ void* LdrGetExport(const char* moduleName, const char* functionName) { return (void *)0; } +// --------------------------------------------------------------------------- +// Export lookup +// --------------------------------------------------------------------------- +void* LdrGetExport(const char* moduleName, const char* functionName) { + uintptr_t base = FindGlobalModuleBase(moduleName); + return GetExportAtBase(base, functionName); +} + +void* LdrGetExportForProcess(PROCESS* process, const char* moduleName, const char* functionName) { + uintptr_t base = FindProcessOrGlobalModuleBase(process, moduleName); + return GetExportAtBase(base, functionName); +} + +size_t LdrGetImageSize(uintptr_t base) { + uint32_t peOffset = *(uint32_t *)(base + 0x3C); + PE_HEADER* pe = (PE_HEADER *)(base + peOffset); + if (pe->Signature != PE_SIGNATURE) return 0; + return (size_t)pe->OptionalHeader.SizeOfImage; +} + // --------------------------------------------------------------------------- // Entry point lookup // --------------------------------------------------------------------------- @@ -216,43 +271,210 @@ static KSTATUS LdrApplyRelocations(uintptr_t base, uintptr_t delta) { // --------------------------------------------------------------------------- // Import resolution // --------------------------------------------------------------------------- -KSTATUS LdrResolveImports(uintptr_t imageBase) { +typedef void* (*EXPORT_LOOKUP_FN)(void* ctx, const char* moduleName, const char* functionName); + +static void* GlobalExportLookup(void* ctx, const char* moduleName, const char* functionName) { + (void)ctx; + return LdrGetExport(moduleName, functionName); +} + +static void* ProcessExportLookup(void* ctx, const char* moduleName, const char* functionName) { + return LdrGetExportForProcess((PROCESS*)ctx, moduleName, functionName); +} + +static KSTATUS LdrResolveImportsCommon( + PROCESS* process, + uintptr_t imageBase, + EXPORT_LOOKUP_FN lookup, + void* ctx +) { uint32_t peOffset = *(uint32_t *)(imageBase + 0x3C); PE_HEADER* pe = (PE_HEADER *)(imageBase + peOffset); OPT_HEADER64* opt = &pe->OptionalHeader; - if (opt->NumberOfRvaAndSizes < 2) return STATUS_SUCCESS; // no imports + if (opt->NumberOfRvaAndSizes < 2) + return STATUS_SUCCESS; + uint32_t impRva = opt->DataDirectory[1].VirtualAddress; - if (!impRva) return STATUS_SUCCESS; + if (!impRva) + return STATUS_SUCCESS; IMPORT_DESC* imp = (IMPORT_DESC *)(imageBase + impRva); + while (imp->Name) { const char* dllName = (const char *)(imageBase + imp->Name); - if (!_stricmp(dllName, "kernel32.dll") || !_stricmp(dllName, "user32.dll") - || !_stricmp(dllName, "ole32.dll") || !_stricmp(dllName, "winmm.dll")) + + // Win32 compatibility remap + if (!_stricmp(dllName, "kernel32.dll") || + !_stricmp(dllName, "user32.dll") || + !_stricmp(dllName, "ole32.dll") || + !_stricmp(dllName, "winmm.dll")) { dllName = "win32.dll"; - uint64_t* thunk = (uint64_t *)(imageBase + imp->FirstThunk); - uint64_t* origThunk = (uint64_t *)(imageBase + (imp->OriginalFirstThunk - ? imp->OriginalFirstThunk - : imp->FirstThunk)); + } + + // + // Ensure dependency is loaded into the process + // + if (process) { + uintptr_t modBase = + FindProcessOrGlobalModuleBase(process, dllName); + + if (!modBase) { + KSTATUS s = + LdrLoadModuleForProcess(process, dllName, &modBase); + + if (!KSUCCESS(s)) { + DbgPrint( + "LdrResolveImports: Failed to load dependency %s (%d)\n", + dllName, + s + ); + return s; + } + } + } + + uint64_t* thunk = + (uint64_t *)(imageBase + imp->FirstThunk); + + uint64_t* origThunk = + (uint64_t *)(imageBase + + (imp->OriginalFirstThunk + ? imp->OriginalFirstThunk + : imp->FirstThunk)); + while (*origThunk) { if (*origThunk & (1ULL << 63)) { - // Import by ordinal - not supported. - DbgPrint("LdrResolveImports: Ordinal imports not supported! (%s)\n", dllName); + DbgPrint( + "LdrResolveImports: Ordinal imports not supported! (%s)\n", + dllName + ); return STATUS_NOT_SUPPORTED; } - const char* funcName = (const char *)(imageBase + (*origThunk & 0xFFFFFFFF) + 2); - void* addr = LdrGetExport(dllName, funcName); + + const char* funcName = + (const char *)(imageBase + + (*origThunk & 0xFFFFFFFF) + 2); + + void* addr = lookup(ctx, dllName, funcName); + if (!addr) { - DbgPrint("LdrResolveImports: Function not found! (%s)\n", funcName); + DbgPrint( + "LdrResolveImports: Function not found! (%s!%s)\n", + dllName, + funcName + ); return STATUS_NOT_FOUND; } + *thunk = (uint64_t)addr; + thunk++; origThunk++; } + imp++; } + + return STATUS_SUCCESS; +} + +KSTATUS LdrResolveImports(uintptr_t imageBase) { + return LdrResolveImportsCommon( + (PROCESS*)0, + imageBase, + GlobalExportLookup, + (void*)0 + ); +} + +KSTATUS LdrResolveImportsForProcess(PROCESS* process, uintptr_t imageBase) { + return LdrResolveImportsCommon( + process, + imageBase, + ProcessExportLookup, + process + ); +} + +static KSTATUS LdrRegisterProcessModule(PROCESS* process, const char* name, uintptr_t base) { + if (!process || !name || !base) return STATUS_INVALID_PARAMETER; + + for (uint32_t i = 0; i < process->ModuleCount; i++) { + if (_stricmp(process->Modules[i].Name, name) == 0) { + return STATUS_SUCCESS; + } + } + + if (process->ModuleCount >= PROCESS_MODULE_MAX) return STATUS_NO_MEMORY; + + PROCESS_MODULE* mod = &process->Modules[process->ModuleCount++]; + strncpy(mod->Name, name, 31); + mod->Name[31] = '\0'; + mod->Base = base; + mod->Size = LdrGetImageSize(base); + return STATUS_SUCCESS; +} + +KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uintptr_t* baseOut) { + if (!process || !filename) return STATUS_INVALID_PARAMETER; + + for (uint32_t i = 0; i < process->ModuleCount; i++) { + if (_stricmp(process->Modules[i].Name, filename) == 0) { + if (baseOut) *baseOut = process->Modules[i].Base; + return STATUS_SUCCESS; + } + } + + FILE_OBJECT* f; + KSTATUS s = IoOpenFile(filename, &f); + if (!KSUCCESS(s)) { + char path[260]; + memcpy(path, "0:/system/", 10); + memcpy(path + 10, filename, strnlen(filename, 248) + 1); + path[259] = '\0'; + s = IoOpenFile(path, &f); + if (!KSUCCESS(s)) { + DbgPrint("LdrLoadModuleForProcess: Failed to open %s (%d)\n", filename, s); + return s; + } + } + + uint64_t fileSize = IoGetFileSize(f); + void* mem = MmAllocatePool((size_t)fileSize); + if (!mem) { + IoCloseFile(f); + return STATUS_NO_MEMORY; + } + + size_t got = 0; + s = IoReadFile(f, mem, (size_t)fileSize, &got); + IoCloseFile(f); + if (!KSUCCESS(s)) { + MmFreePool(mem); + return s; + } + + uintptr_t imageBase = 0; + s = LdrLoadImage(mem, (size_t)fileSize, &imageBase, true); + MmFreePool(mem); + if (!KSUCCESS(s)) { + return s; + } + + s = LdrResolveImportsForProcess(process, imageBase); + if (!KSUCCESS(s)) { + MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase)); + return s; + } + + s = LdrRegisterProcessModule(process, filename, imageBase); + if (!KSUCCESS(s)) { + MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase)); + return s; + } + + if (baseOut) *baseOut = imageBase; return STATUS_SUCCESS; } @@ -271,7 +493,6 @@ KSTATUS LdrLoadImage(const void* buffer, size_t size, uintptr_t* baseOut, bool u if (!mem) return STATUS_NO_MEMORY; memset(mem, 0, imageSize); - // Copy headers and sections memcpy(mem, buffer, opt->SizeOfHeaders); SECTION_HEADER* sec = (SECTION_HEADER *)((uint8_t *)&pe->OptionalHeader + pe->SizeOfOptionalHeader); for (int i = 0; i < pe->NumberOfSections; i++) { @@ -280,21 +501,16 @@ KSTATUS LdrLoadImage(const void* buffer, size_t size, uintptr_t* baseOut, bool u if (sec[i].SizeOfRawData) { memcpy(dst, src, sec[i].SizeOfRawData < sec[i].VirtualSize ? sec[i].SizeOfRawData : sec[i].VirtualSize); } - + uint64_t prot = PAGE_PRESENT | PAGE_WRITE | (user ? PAGE_USER : 0); MmSetPageProtect((uintptr_t)mem + sec[i].VirtualAddress, sec[i].VirtualSize, prot); } - // Apply Relocations uintptr_t delta = (uintptr_t)mem - opt->ImageBase; if (delta != 0) { LdrApplyRelocations((uintptr_t)mem, delta); } - // Resolve Imports - KSTATUS status = LdrResolveImports((uintptr_t)mem); - if (status != STATUS_SUCCESS) return status; - *baseOut = (uintptr_t)mem; return STATUS_SUCCESS; } diff --git a/code/kernel/ldr_image.h b/code/kernel/ldr_image.h index 3b93aa8..45ae5f7 100644 --- a/code/kernel/ldr_image.h +++ b/code/kernel/ldr_image.h @@ -10,6 +10,9 @@ // On success, *baseOut receives the virtual base address. KSTATUS LdrLoadImage(const void* buffer, size_t size, uintptr_t* baseOut, bool user); +// Return the SizeOfImage recorded in the PE header for an already-mapped image. +size_t LdrGetImageSize(uintptr_t base); + // Look up a named export in a loaded module. // 'moduleName' must match a name in BOOT_INFO.Modules (e.g., "hal.dll"). void* LdrGetExport(const char* moduleName, const char* functionName); @@ -17,9 +20,17 @@ void* LdrGetExport(const char* moduleName, const char* functionName); // Get the entry point address of a loaded image. uintptr_t LdrGetEntryPoint(uintptr_t base); -// Resolve the import table of an already-loaded image. +// Resolve the import table of an already-loaded image using the global registry. KSTATUS LdrResolveImports(uintptr_t imageBase); +// Resolve imports using a process-local module registry. +struct PROCESS; +KSTATUS LdrResolveImportsForProcess(struct PROCESS* process, uintptr_t imageBase); + +// Load a DLL for a specific process, resolve it against that process's +// loaded modules, and register it in the process-local registry. +KSTATUS LdrLoadModuleForProcess(struct PROCESS* process, const char* filename, uintptr_t* baseOut); + // Called by KernelMain to register all modules from BOOT_INFO so that // LdrGetExport can find them. struct BOOT_INFO; // forward declare for the compiler to shut the fuck up diff --git a/code/kernel/ob_object.h b/code/kernel/ob_object.h index 64f63ba..5a79a4c 100644 --- a/code/kernel/ob_object.h +++ b/code/kernel/ob_object.h @@ -19,7 +19,7 @@ typedef enum OBJECT_TYPE { typedef struct OBJECT { OBJECT_TYPE Type; - volatile long RefCount; // interlocked; long = 4 bytes on MSVC x64 + volatile long RefCount; // interlocked void (*Destroy)(struct OBJECT* self); } OBJECT; diff --git a/code/libc.c b/code/libc.c index 892ef72..de38fcd 100644 --- a/code/libc.c +++ b/code/libc.c @@ -73,6 +73,16 @@ size_t strlen(const char* s) { return n; } +size_t strnlen(const char *s, size_t maxlen) { + size_t len; + for (len = 0; len < maxlen; len++) { + if (s[len] == '\0') { + break; + } + } + return len; +} + char* strchr(const char* s, int c) { while (*s) { if (*s == (char)c) return (char *)s; diff --git a/code/posix/posix.h b/code/posix/posix.h index 6203acf..7ffebc1 100644 --- a/code/posix/posix.h +++ b/code/posix/posix.h @@ -32,6 +32,7 @@ extern int errno; // defined in posix_fd.c; single global in v1 #define ENODEV 19 #define ENOTDIR 20 #define EINVAL 22 +#define ESPIPE 29 #define EMFILE 24 #define ENOSPC 28 #define ERANGE 34 diff --git a/code/posix/posix_dir.c b/code/posix/posix_dir.c index 8f1a590..40b64b4 100644 --- a/code/posix/posix_dir.c +++ b/code/posix/posix_dir.c @@ -1,17 +1,9 @@ // posix_dir.c - chdir, getcwd, opendir, readdir, closedir #include +#include #include "posix.h" #include "posix_path.h" -extern uint32_t SysGetCurrentPid(void); -extern uint32_t SysSetCwd(const char* path); -extern uint32_t SysGetCwd(char* buf, size_t size); -extern uint32_t SysOpenDir(const char* path, uint32_t* handleOut); -extern uint32_t SysReadDir(uint32_t handle, void* entryOut); -extern void SysCloseHandle(uint32_t handle); -extern void* SysAlloc(size_t); -extern void SysFree(void*, size_t); - // KDIR_ENTRY layout mirrors io_file.h - duplicated here to avoid // pulling kernel headers into posix.dll #define KDIR_NAME_MAX 260 @@ -23,7 +15,7 @@ typedef struct { #define KATTR_DIR 0x10 -int chdir(const char* path) { +__declspec(dllexport) int chdir(const char* path) { char native[512]; PosixTranslatePath(path, native, sizeof(native)); uint32_t s = SysSetCwd(native); @@ -31,7 +23,7 @@ int chdir(const char* path) { return 0; } -char* getcwd(char* buf, size_t size) { +__declspec(dllexport) char* getcwd(char* buf, size_t size) { if (!buf || size == 0) { errno = EINVAL; return (char*)0; } char native[512]; uint32_t s = SysGetCwd(native, sizeof(native)); @@ -40,7 +32,7 @@ char* getcwd(char* buf, size_t size) { return buf; } -DIR* opendir(const char* path) { +__declspec(dllexport) DIR* opendir(const char* path) { char native[512]; PosixTranslatePath(path, native, sizeof(native)); uint32_t kh; @@ -55,7 +47,7 @@ DIR* opendir(const char* path) { return d; } -struct dirent* readdir(DIR* d) { +__declspec(dllexport) struct dirent* readdir(DIR* d) { if (!d) { errno = EBADF; return (struct dirent*)0; } KDIR_ENTRY ke; uint32_t s = SysReadDir(d->KHandle, &ke); @@ -70,7 +62,7 @@ struct dirent* readdir(DIR* d) { return &d->Current; } -int closedir(DIR* d) { +__declspec(dllexport) int closedir(DIR* d) { if (!d) { errno = EBADF; return -1; } SysCloseHandle(d->KHandle); SysFree(d, sizeof(DIR)); diff --git a/code/posix/posix_fd.c b/code/posix/posix_fd.c index 0059dc0..d10367e 100644 --- a/code/posix/posix_fd.c +++ b/code/posix/posix_fd.c @@ -1,20 +1,13 @@ // posix_fd.c - file descriptor table #include "posix.h" #include "posix_fd.h" - -// yeah -#ifdef errno -#undef errno -#endif +#include int errno = 0; static FD_ENTRY gFdTable[FD_TABLE_PIDS][FD_MAX]; -// Syscall stub declarations (from syscall.dll) -extern uint32_t SysGetCurrentPid(void); - -void PosixFdInit(void) { +__declspec(dllexport) void PosixFdInit(void) { uint32_t pid = SysGetCurrentPid(); uint32_t slot = pid % FD_TABLE_PIDS; @@ -28,7 +21,7 @@ void PosixFdInit(void) { gFdTable[slot][2] = (FD_ENTRY){ FD_CONSOLE_W, 0, true }; } -int FdAlloc(uint32_t pid, FD_TYPE type, uint32_t khandle) { +__declspec(dllexport) int FdAlloc(uint32_t pid, FD_TYPE type, uint32_t khandle) { uint32_t slot = pid % FD_TABLE_PIDS; for (int fd = 3; fd < FD_MAX; fd++) { if (!gFdTable[slot][fd].Used) { @@ -40,7 +33,7 @@ int FdAlloc(uint32_t pid, FD_TYPE type, uint32_t khandle) { return -1; } -FD_ENTRY* FdGet(uint32_t pid, int fd) { +__declspec(dllexport) FD_ENTRY* FdGet(uint32_t pid, int fd) { if (fd < 0 || fd >= FD_MAX) { errno = EBADF; return (FD_ENTRY*)0; } uint32_t slot = pid % FD_TABLE_PIDS; FD_ENTRY* e = &gFdTable[slot][fd]; @@ -48,7 +41,7 @@ FD_ENTRY* FdGet(uint32_t pid, int fd) { return e; } -void FdFree(uint32_t pid, int fd) { +__declspec(dllexport) void FdFree(uint32_t pid, int fd) { if (fd < 0 || fd >= FD_MAX) return; uint32_t slot = pid % FD_TABLE_PIDS; gFdTable[slot][fd] = (FD_ENTRY){ FD_FREE, 0, false }; diff --git a/code/posix/posix_fd.h b/code/posix/posix_fd.h index 0310089..fdb82f2 100644 --- a/code/posix/posix_fd.h +++ b/code/posix/posix_fd.h @@ -22,13 +22,13 @@ typedef struct { #define FD_TABLE_PIDS 32 // circular, indexed by pid % FD_TABLE_PIDS // Called from _start before main(); sets up fds 0/1/2 for this process. -void PosixFdInit(void); +__declspec(dllexport) void PosixFdInit(void); // Allocate the lowest free fd >= 3. Returns -1 and sets errno=EMFILE on failure. -int FdAlloc(uint32_t pid, FD_TYPE type, uint32_t khandle); +__declspec(dllexport) int FdAlloc(uint32_t pid, FD_TYPE type, uint32_t khandle); // Look up an fd. Returns NULL and sets errno=EBADF if invalid. -FD_ENTRY* FdGet(uint32_t pid, int fd); +__declspec(dllexport) FD_ENTRY* FdGet(uint32_t pid, int fd); // Release an fd slot (does NOT close the kernel handle). -void FdFree(uint32_t pid, int fd); +__declspec(dllexport) void FdFree(uint32_t pid, int fd); diff --git a/code/posix/posix_io.c b/code/posix/posix_io.c index 84bd5c4..a91049e 100644 --- a/code/posix/posix_io.c +++ b/code/posix/posix_io.c @@ -1,23 +1,11 @@ // posix_io.c - open, read, write, close, lseek #include #include +#include #include "posix.h" #include "posix_fd.h" #include "posix_path.h" -extern uint32_t SysGetCurrentPid(void); -extern uint32_t SysOpenFile (const char* path, uint32_t* handleOut); -extern uint32_t SysCreateFile (const char* path, uint32_t* handleOut); -extern uint32_t SysTruncateFile(uint32_t handle, uint64_t newSize); -extern uint32_t SysReadFile (uint32_t handle, void* buf, size_t size, size_t* bytesRead); -extern uint32_t SysWriteFile (uint32_t handle, const void* buf, size_t size, size_t* written); -extern uint32_t SysSeekFile (uint32_t handle, uint64_t offset); -extern uint64_t SysGetFilePos (uint32_t handle); -extern uint64_t SysGetFileSize(uint32_t handle); -extern void SysCloseHandle(uint32_t handle); -extern void SysWriteConsole(const char* buf, size_t len); -extern char SysKbReadChar(void); - // KSTATUS -> errno static int KsToErrno(uint32_t s) { switch (s) { @@ -34,7 +22,12 @@ static int KsToErrno(uint32_t s) { } } -int open(const char* path, int flags, ...) { +__declspec(dllexport) int ClearConsoleScreenBuffer(void* hConsole) { + SysScreenClear(0x00000000); + return 1; +} + +__declspec(dllexport) int open(const char* path, int flags, ...) { char native[512]; const char* p = PosixTranslatePath(path, native, sizeof(native)); @@ -72,7 +65,7 @@ int open(const char* path, int flags, ...) { return fd; } -ssize_t read(int fd, void* buf, size_t count) { +__declspec(dllexport) ssize_t read(int fd, void* buf, size_t count) { if (count == 0) return 0; uint32_t pid = SysGetCurrentPid(); FD_ENTRY* e = FdGet(pid, fd); @@ -105,7 +98,7 @@ ssize_t read(int fd, void* buf, size_t count) { } } -ssize_t write(int fd, const void* buf, size_t count) { +__declspec(dllexport) ssize_t write(int fd, const void* buf, size_t count) { if (count == 0) return 0; uint32_t pid = SysGetCurrentPid(); FD_ENTRY* e = FdGet(pid, fd); @@ -130,7 +123,7 @@ ssize_t write(int fd, const void* buf, size_t count) { } } -int close(int fd) { +__declspec(dllexport) int close(int fd) { uint32_t pid = SysGetCurrentPid(); FD_ENTRY* e = FdGet(pid, fd); if (!e) return -1; @@ -140,7 +133,23 @@ int close(int fd) { return 0; } -off_t lseek(int fd, off_t offset, int whence) { +__declspec(dllexport) int unlink(const char* path) { + if (!path) { errno = EINVAL; return -1; } + + char native[512]; + const char* p = PosixTranslatePath(path, native, sizeof(native)); + + if (strcmp(p, SYNTH_DEVNULL) == 0 || strcmp(p, SYNTH_DEVZERO) == 0) { + errno = EINVAL; + return -1; + } + + uint32_t s = SysDeleteFile(p); + if (s != 0) { errno = KsToErrno(s); return -1; } + return 0; +} + +__declspec(dllexport) off_t lseek(int fd, off_t offset, int whence) { uint32_t pid = SysGetCurrentPid(); FD_ENTRY* e = FdGet(pid, fd); if (!e || e->Type != FD_FILE) { errno = (e ? ESPIPE : EBADF); return -1; } diff --git a/code/posix/posix_path.c b/code/posix/posix_path.c index 79db61a..974deb1 100644 --- a/code/posix/posix_path.c +++ b/code/posix/posix_path.c @@ -5,7 +5,7 @@ // The drive letter used as the POSIX filesystem root. // A future SYS_GET_BOOT_DRIVE could populate this; hardcoded for v1. -static const char gRootDrive = 'C'; +static const char gRootDrive = '0'; static void FlipSlashes(char* s) { for (; *s; s++) if (*s == '/') *s = '\\'; @@ -27,7 +27,7 @@ const char* PosixTranslatePath(const char* in, char* out, size_t outSize) { // outSize must fit "C:\" + rest out[0] = gRootDrive; out[1] = ':'; - out[2] = '\\'; + out[2] = '/'; size_t rest = strlen(in + 1); if (rest + 4 > outSize) rest = outSize - 4; memcpy(out + 3, in + 1, rest); diff --git a/code/posix/posix_proc.c b/code/posix/posix_proc.c index bb84c80..c3df33d 100644 --- a/code/posix/posix_proc.c +++ b/code/posix/posix_proc.c @@ -1,17 +1,10 @@ // posix_proc.c - posix_spawn, waitpid, getpid #include #include +#include #include "posix.h" #include "posix_path.h" -extern uint32_t SysGetCurrentPid(void); -extern uint32_t SysCreateProcess(const char* path, uint32_t* handleOut, - const char* cmdline); -extern uint32_t SysWaitForProcess(uint32_t handle); -extern uint32_t SysGetProcessExitCode(uint32_t handle, int* exitCodeOut); -extern uint32_t SysGetProcessPid(uint32_t handle, uint32_t* pidOut); -extern void SysCloseHandle(uint32_t handle); - // pid -> proc handle table (user-mode side, for waitpid) #define PROC_TABLE_SIZE 32 typedef struct { @@ -69,11 +62,11 @@ static void BuildCmdline(char* const argv[], char* out, size_t outSize) { // POSIX API // --------------------------------------------------------------------------- -pid_t getpid(void) { +__declspec(dllexport) pid_t getpid(void) { return (pid_t)SysGetCurrentPid(); } -int posix_spawn(pid_t* pidOut, +__declspec(dllexport) int posix_spawn(pid_t* pidOut, const char* path, const posix_spawn_file_actions_t* file_actions, // ignored v1 const posix_spawnattr_t* attrp, // ignored v1 @@ -108,7 +101,7 @@ int posix_spawn(pid_t* pidOut, } // options: WNOHANG not supported in v1 (always blocks). -pid_t waitpid(pid_t pid, int* status, int options) { +__declspec(dllexport) pid_t waitpid(pid_t pid, int* status, int options) { (void)options; uint32_t handle = ProcTableFind(pid); @@ -124,3 +117,7 @@ pid_t waitpid(pid_t pid, int* status, int options) { ProcTableRemove(pid); return pid; } + +__declspec(dllexport) void exit(int status) { + SysExitProcess(status); +} diff --git a/code/posix/posix_thread.c b/code/posix/posix_thread.c index ae578ec..61a4b1a 100644 --- a/code/posix/posix_thread.c +++ b/code/posix/posix_thread.c @@ -1,21 +1,8 @@ // posix_thread.c - pthread_create, pthread_join, pthread_exit, pthread_mutex_* #include +#include #include "posix.h" -extern uint32_t SysGetCurrentPid(void); -extern uint32_t SysGetCurrentTid(void); -extern uint32_t SysCreateThread(uint64_t entry, uint64_t arg, - uint32_t priority, uint32_t* tidOut); -extern uint32_t SysWaitThread(uint32_t tid); -extern void SysExitThread(int code); -extern void* SysAlloc(size_t size); -extern void SysFree(void* ptr, size_t size); -extern uint32_t SysMutexCreate(uint32_t* handleOut); -extern uint32_t SysMutexAcquire(uint32_t handle); -extern uint32_t SysMutexTryAcquire(uint32_t handle); -extern uint32_t SysMutexRelease(uint32_t handle); -extern void SysCloseHandle(uint32_t handle); - // Thread return-value table (PID-keyed like the fd table) #define PTHREAD_TABLE_PIDS 32 #define PTHREAD_TABLE_SIZE 32 @@ -79,7 +66,7 @@ static void PthreadTrampoline(uintptr_t raw) { // pthread API // --------------------------------------------------------------------------- -int pthread_create(pthread_t* t, const pthread_attr_t* attr, +__declspec(dllexport) int pthread_create(pthread_t* t, const pthread_attr_t* attr, void* (*fn)(void*), void* arg) { (void)attr; @@ -108,7 +95,7 @@ int pthread_create(pthread_t* t, const pthread_attr_t* attr, return 0; } -int pthread_join(pthread_t t, void** retval) { +__declspec(dllexport) int pthread_join(pthread_t t, void** retval) { uint32_t pid = SysGetCurrentPid(); uint32_t s = SysWaitThread(t.Tid); // STATUS_NOT_FOUND (0x22) means already dead - treat as success @@ -120,7 +107,7 @@ int pthread_join(pthread_t t, void** retval) { return 0; } -void pthread_exit(void* retval) { +__declspec(dllexport) void pthread_exit(void* retval) { uint32_t pid = SysGetCurrentPid(); uint32_t tid = SysGetCurrentTid(); PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid); @@ -129,7 +116,7 @@ void pthread_exit(void* retval) { while (1); // unreachable } -int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr) { +__declspec(dllexport) int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr) { (void)attr; uint32_t h; uint32_t s = SysMutexCreate(&h); @@ -138,23 +125,23 @@ int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr) { return 0; } -int pthread_mutex_destroy(pthread_mutex_t* m) { +__declspec(dllexport) int pthread_mutex_destroy(pthread_mutex_t* m) { SysCloseHandle(m->Handle); m->Handle = 0; return 0; } -int pthread_mutex_lock(pthread_mutex_t* m) { +__declspec(dllexport) int pthread_mutex_lock(pthread_mutex_t* m) { uint32_t s = SysMutexAcquire(m->Handle); return s == 0 ? 0 : EINVAL; } -int pthread_mutex_trylock(pthread_mutex_t* m) { +__declspec(dllexport) int pthread_mutex_trylock(pthread_mutex_t* m) { uint32_t s = SysMutexTryAcquire(m->Handle); return s == 0 ? 0 : EAGAIN; } -int pthread_mutex_unlock(pthread_mutex_t* m) { +__declspec(dllexport) int pthread_mutex_unlock(pthread_mutex_t* m) { uint32_t s = SysMutexRelease(m->Handle); return s == 0 ? 0 : EINVAL; } diff --git a/code/shell_native/shell_native.c b/code/shell_native/shell_native.c new file mode 100644 index 0000000..f244374 --- /dev/null +++ b/code/shell_native/shell_native.c @@ -0,0 +1,247 @@ +#include +#include +#include +#include +#include +#include + +// --------------------------------------------------------------------------- +// Output helpers +// --------------------------------------------------------------------------- +static void print(const char* s) { + SysWriteConsole(s, strlen(s)); +} + +static void printUInt(uint32_t n) { + 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); +} + +static void printInt(int32_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); + } + } + buf[pos] = '\0'; +} + +static char* trim(char* s) { + while (*s == ' ') s++; + int len = (int)strlen(s); + while (len > 0 && s[len - 1] == ' ') len--; + s[len] = '\0'; + return s; +} + +// --------------------------------------------------------------------------- +// Built-in commands +// --------------------------------------------------------------------------- +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"); +} + +static void cmd_write(const char* args) { + char filename[MAX_CMD]; + int i = 0; + while (args[i] != ' ' && args[i] != '\0' && i < MAX_CMD - 1) { + filename[i] = args[i]; + i++; + } + filename[i] = '\0'; + + 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; + size_t written; + SysWriteFile(hFile, text, strlen(text), &written); + SysCloseHandle(hFile); + print("File written successfully.\n"); +} + +static void cmd_dir(const char* path) { + uint32_t hDir; + + // Validate input + if (path == NULL || path[0] == '\0') { + path = "."; // Default to current directory if empty + } + + // 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 + print(ke.Name); + 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; + while (SysReadFile(hFile, buffer, sizeof(buffer) - 1, &bytesRead) == 0 && bytesRead > 0) { + buffer[bytesRead] = '\0'; + print(buffer); + } + + SysCloseHandle(hFile); + 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, "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 (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"); + } + + 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; + } + + print("shell: goodbye\n"); + SysExitProcess(0); + return 0; +} diff --git a/code/shell_posix/shell_posix.c b/code/shell_posix/shell_posix.c new file mode 100644 index 0000000..1b1f2e1 --- /dev/null +++ b/code/shell_posix/shell_posix.c @@ -0,0 +1,231 @@ +#include +#include +#include +#include + +#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; + +extern int read(int fd, void *buf, size_t count); +extern int write(int fd, const void *buf, size_t count); +extern int open(const char *pathname, int flags, ...); +extern int close(int fd); +extern int chdir(const char *path); +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 waitpid(int pid, int *status, int options); +extern void exit(int status); + +extern void PosixFdInit(void); +extern int ClearConsoleScreenBuffer(void* hConsole); + +// --------------------------------------------------------------------------- +// Global handles +// --------------------------------------------------------------------------- +static int hIn = 0; // stdin +static int hOut = 1; // stdout + +// --------------------------------------------------------------------------- +// Output helpers +// --------------------------------------------------------------------------- +static void print(const char* s) { + write(hOut, s, strlen(s)); +} + +static void printUInt(uint32_t n) { + 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); +} + +static void printInt(int32_t n) { + if (n < 0) { print("-"); n = -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; + 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'; +} + +static char* trim(char* s) { + while (*s == ' ') s++; + int len = (int)strlen(s); + while (len > 0 && s[len - 1] == ' ') len--; + s[len] = '\0'; + 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"); +} + +static void cmd_write(const char* args) { + char filename[MAX_CMD]; + int i = 0; + while (args[i] != ' ' && args[i] != '\0' && i < MAX_CMD - 1) { + 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; + write(fd, args + i + 1, strlen(args + i + 1)); + close(fd); +} + +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; + } + + 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"); + } + + 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"); +} + +// --------------------------------------------------------------------------- +// 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, "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 (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}; + if (posix_spawn(&pid, cmd, NULL, NULL, argv, NULL) == 0) { + int status; + waitpid(pid, &status, 0); + } else { + print("shell: error launching\n"); + } + return 0; +} + +int main(const char* args) { + 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/shell.c b/code/shell_win32/shell_win32.c similarity index 82% rename from code/shell/shell.c rename to code/shell_win32/shell_win32.c index de958c2..d084613 100644 --- a/code/shell/shell.c +++ b/code/shell_win32/shell_win32.c @@ -148,20 +148,51 @@ static void cmd_write(const char* args) { CloseHandle(hFile); } -static void cmd_dir() { +static void cmd_dir(const char* path) { WIN32_FIND_DATAA fd; - HANDLE hFind = FindFirstFileA("*", &fd); + char search_path[MAX_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'; + + 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; } 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(" "); + print(" "); } else { - print(" "); + print(" "); } print(fd.cFileName); print("\n"); @@ -207,13 +238,22 @@ static int runCommand(const char* cmd) { 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(); + if (strcmp(cmd, "dir") == 0) { + cmd_dir("."); + return 0; + } + if (strncmp(cmd, "dir ", 4) == 0) { + cmd_dir(cmd + 4); return 0; } diff --git a/code/syscall/syscall.h b/code/syscall/syscall.h new file mode 100644 index 0000000..d964017 --- /dev/null +++ b/code/syscall/syscall.h @@ -0,0 +1,110 @@ +#pragma once +// Syscall.h + +#include +#include +#include + +// --------------------------------------------------------------------------- +// Thread & Process Management (0-7) +// --------------------------------------------------------------------------- +void SysExitProcess(int exitCode); // 00 +void SysExitThread(int exitCode); // 01 +uint32_t SysCreateThread(uintptr_t entry, uintptr_t arg, uint32_t priority, uint32_t* tidOut); // 02 +uint32_t SysGetCurrentTid(void); // 03 +uint32_t SysGetCurrentPid(void); // 04 +uint32_t SysYield(void); // 05 +uint32_t SysSleep(uint64_t ms); // 06 +uint32_t SysSetThreadPriority(uint32_t priority); // 07 + +// --------------------------------------------------------------------------- +// Memory Management (8-10) +// --------------------------------------------------------------------------- +void* SysAlloc(size_t size); // 08 +uint32_t SysFree(void* ptr, size_t size); // 09 +void* SysRealloc(void* ptr, size_t newSize); // 10 + +// --------------------------------------------------------------------------- +// Synchronization Primitives (11-22) +// --------------------------------------------------------------------------- +uint32_t SysMutexCreate(uint32_t* handleOut); // 11 +uint32_t SysMutexAcquire(uint32_t handle); // 12 +uint32_t SysMutexTryAcquire(uint32_t handle); // 13 +uint32_t SysMutexRelease(uint32_t handle); // 14 + +uint32_t SysSemCreate(int32_t initial, int32_t max, uint32_t* handleOut); // 15 +uint32_t SysSemWait(uint32_t handle); // 16 +uint32_t SysSemTryWait(uint32_t handle); // 17 +uint32_t SysSemSignal(uint32_t handle); // 18 + +uint32_t SysEventCreate(uint32_t type, uint32_t initialState, uint32_t* handleOut); // 19 +uint32_t SysEventSignal(uint32_t handle); // 20 +uint32_t SysEventClear(uint32_t handle); // 21 +uint32_t SysEventWait(uint32_t handle); // 22 + +// --------------------------------------------------------------------------- +// Anonymous Queues & Unified Handle Path (23-26) +// --------------------------------------------------------------------------- +uint32_t SysQueueCreate(uint32_t* handleOut); // 23 +uint32_t SysQueueSend(uint32_t handle, const void* msg, bool blocking); // 24 +uint32_t SysQueueRecv(uint32_t handle, void* msg, bool blocking); // 25 +uint32_t SysCloseHandle(uint32_t handle); // 26 + +// --------------------------------------------------------------------------- +// File System (27-35) +// --------------------------------------------------------------------------- +uint32_t SysOpenFile(const char* path, uint32_t* handleOut); // 27 +uint32_t SysReadFile(uint32_t handle, void* buf, size_t size, size_t* bytesRead); // 28 +uint32_t SysWriteFile(uint32_t handle, const void* buf, size_t size, size_t* written); // 29 +uint32_t SysCreateFile(const char* path, uint32_t* handleOut); // 30 +uint32_t SysDeleteFile(const char* path); // 31 +uint32_t SysTruncateFile(uint32_t handle, uint64_t newSize); // 32 +uint64_t SysGetFilePos(uint32_t handle); // 33 +uint32_t SysSeekFile(uint32_t handle, uint64_t offset); // 34 +uint64_t SysGetFileSize(uint32_t handle); // 35 + +// --------------------------------------------------------------------------- +// Graphics & Input (36-47) +// --------------------------------------------------------------------------- +uint32_t SysScreenBlit(int x, int y, int w, int h, const uint32_t* pixels); // 36 +uint32_t SysScreenClear(uint32_t color); // 37 +uint32_t SysScreenGetSize(int* widthOut, int* heightOut); // 38 +uint32_t SysScreenPutChar(char c, int x, int y, uint32_t fg, uint32_t bg); // 39 + +uint64_t SysKbPoll(void); // 40 +uint64_t SysKbIsKeyDown(uint8_t scancode, bool extended); // 41 +char SysKbReadChar(void); // 42 +uint8_t SysKbReadScancode(void); // 43 +uint32_t SysKbGetModifiers(void); // 44 + +uint64_t SysMousePoll(void); // 45 +uint64_t SysMouseRead(int* dx, int* dy, uint8_t* buttons); // 46 +void SysMouseGetPos(int* x, int* y); // 47 + +// --------------------------------------------------------------------------- +// System Info & Process Management (48-53) +// --------------------------------------------------------------------------- +uint64_t SysGetTick(void); // 48 +uint32_t SysDebugPrint(const char* str); // 49 +uint32_t SysCreateProcess(const char* path, uint32_t* handleOut, const char* cmdline); // 50 +uint32_t SysWaitForProcess(uint32_t handle); // 51 +uint32_t SysGetProcessExitCode(uint32_t handle, int* exitCodeOut); // 52 +uint32_t SysWriteConsole(const char* buf, size_t len); // 53 + +// --------------------------------------------------------------------------- +// Directories & Environment (54-57) +// --------------------------------------------------------------------------- +uint32_t SysOpenDir(const char* path, uint32_t* handleOut); // 54 +uint32_t SysReadDir(uint32_t handle, void* dirEntryBuffer); // 55 +uint32_t SysSetCwd(const char* path); // 56 +uint32_t SysGetCwd(char* buf, size_t size); // 57 + +// --------------------------------------------------------------------------- +// Process/Thread Helpers & Named Queues (58-63) +// --------------------------------------------------------------------------- +uint32_t SysWaitThread(uint32_t tid); // 58 +uint32_t SysGetProcessPid(uint32_t handle, uint32_t* pidOut); // 59 +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 diff --git a/code/video/video.c b/code/video/video.c index 365feee..d436d94 100644 --- a/code/video/video.c +++ b/code/video/video.c @@ -13,12 +13,16 @@ int main(const char* cmdline) { WriteConsoleA(h, "\n", 1, 0, 0); void* f = CreateFileA("video.bk2", 0, 0, 0, 3, 0, 0); - if (!f) { + if (!f || f == (void*)(unsigned long long)0xFFFFFFFF) { // fuckass WriteConsoleA(h, "video: failed to open video.bk2\n", 32, 0, 0); ExitProcess(1); } unsigned long s = GetFileSize(f, 0); + if (!s || s == 0xFFFFFFFF) { + WriteConsoleA(h, "video: GetFileSize failed!\n", 27, 0, 0); + ExitProcess(1); + } void* buf = HeapAlloc(0, 0, s); if (!buf) { WriteConsoleA(h, "video: HeapAlloc failed\n", 24, 0, 0); diff --git a/code/win32/gdi32.c b/code/win32/gdi32.c index 5c26415..2e0d17c 100644 --- a/code/win32/gdi32.c +++ b/code/win32/gdi32.c @@ -1,6 +1,7 @@ // gdi32.c #include #include +#include #if defined(__SSE2__) || defined(_M_X64) || defined(_M_IX86) #include @@ -8,14 +9,6 @@ #include #endif -// --------------------------------------------------------------------------- -// Syscall stubs (from syscall.dll) -// --------------------------------------------------------------------------- -extern void SysScreenBlit(int x, int y, int w, int h, const uint32_t* pixels); -extern void* SysAlloc(size_t size); -extern void SysFree(void* ptr, size_t size); - - // --------------------------------------------------------------------------- // Win32 Base Types // --------------------------------------------------------------------------- diff --git a/code/win32/kernel32.c b/code/win32/kernel32.c index 825223e..7d6ccb8 100644 --- a/code/win32/kernel32.c +++ b/code/win32/kernel32.c @@ -24,63 +24,7 @@ #include #include #include - -// --------------------------------------------------------------------------- -// Syscall stubs (from syscall.dll, assembled from syscall_stubs.asm) -// --------------------------------------------------------------------------- - -// Memory -extern void* SysAlloc(size_t size); -extern void SysFree(void* ptr, size_t size); -extern void* SysRealloc(void* ptr, size_t newSize); - -// Process & Thread -extern void SysExitProcess(int exitCode); -extern void SysExitThread(int exitCode); -extern uint32_t SysCreateProcess(const char* path, uint32_t* handleOut, const char* cmdline); -extern uint32_t SysCreateThread(uint64_t entry, uint64_t arg, uint32_t priority, uint32_t* tidOut); -extern uint32_t SysGetCurrentPid(void); -extern uint32_t SysGetCurrentTid(void); -extern uint32_t SysGetProcessExitCode(uint32_t handle, int* exitCodeOut); -extern uint32_t SysWaitForProcess(uint32_t handle); - -// File I/O -extern void SysCloseHandle(uint32_t handle); -extern uint32_t SysCreateFile(const char* path, uint32_t* handleOut); -extern uint32_t SysDeleteFile(const char* path); -extern uint64_t SysGetFilePos(uint32_t handle); -extern uint64_t SysGetFileSize(uint32_t handle); -extern uint32_t SysOpenFile(const char* path, uint32_t* handleOut); -extern uint32_t SysReadFile(uint32_t handle, void* buf, size_t size, size_t* bytesReadOut); -extern uint32_t SysSeekFile(uint32_t handle, uint64_t offset); -extern uint32_t SysTruncateFile(uint32_t handle, uint64_t newSize); -extern uint32_t SysWriteFile(uint32_t handle, const void* buf, size_t size, size_t* bytesWrittenOut); - -// Console & directory & CWD stubs -extern uint32_t SysGetCwd(char* buf, size_t size); -extern uint32_t SysOpenDir(const char* dirPath, uint32_t* handleOut); -extern uint32_t SysReadDir(uint32_t handle, void* entryOut); -extern void SysScreenClear(uint32_t color); -extern uint32_t SysSetCwd(const char* path); -extern void SysWriteConsole(const char* buf, size_t len); - -// Keyboard syscalls -extern uint32_t SysKbGetModifiers(void); -extern uint64_t SysKbIsKeyDown(uint8_t scancode, bool extended); -extern uint32_t SysKbPoll(void); -extern char SysKbReadChar(void); -extern unsigned char SysKbReadScancode(void); - -// Mouse syscalls -extern void SysMouseGetPos(int* x, int* y); -extern uint32_t SysMousePoll(void); -extern uint32_t SysMouseRead(int* dx, int* dy, unsigned char* buttons); - -// Misc -extern void SysDebugPrint(const char* str); -extern void SysYield(void); -extern void SysSleep(uint32_t ms); -extern uint64_t SysGetTick(void); +#include // --------------------------------------------------------------------------- // Types @@ -143,6 +87,36 @@ typedef struct _WIN32_FIND_DATAA { static inline HANDLE KH_TO_HANDLE(uint32_t kh) { return (HANDLE)(uintptr_t)kh; } static inline uint32_t HANDLE_TO_KH(HANDLE h) { return (uint32_t)(uintptr_t)h; } +// Path translator +static void TranslatePath(const char* input, char* output) { + if (input && input[0] != '\0' && input[1] == ':' && (input[2] == '\\' || input[2] == '/')) { + // Translate "C:\" -> "0:/" (assuming 'C' maps to '0', etc.) + // Map drive letter to index: 'C' or 'c' -> '0' + char drive = input[0]; + if (drive >= 'a') drive -= ('a' - 'A'); // To uppercase + + output[0] = (char)('0' + (drive - 'C')); + output[1] = ':'; + output[2] = '/'; + + // Copy the rest, swapping backslashes to forward slashes + const char* src = input + 3; + char* dst = output + 3; + while (*src) { + *dst = (*src == '\\') ? '/' : *src; + src++; dst++; + } + *dst = '\0'; + } else { + // Fallback for relative paths: just swap slashes + while (*input) { + *output = (*input == '\\') ? '/' : *input; + input++; output++; + } + *output = '\0'; + } +} + // --------------------------------------------------------------------------- // GetLastError / SetLastError (single-threaded stub) // --------------------------------------------------------------------------- @@ -342,24 +316,28 @@ __declspec(dllexport) DWORD GetOEMCP(void) { return 437; } // DOS Latin US // CreateFileA - opens or creates a file. // Supported modes: -// OPEN_EXISTING + GENERIC_READ -> open existing, read-only -// OPEN_EXISTING + GENERIC_WRITE -> open existing, read-write +// OPEN_EXISTING + GENERIC_READ -> open existing, read-only +// OPEN_EXISTING + GENERIC_WRITE -> open existing, read-write // OPEN_EXISTING + GENERIC_READ|GENERIC_WRITE -> open existing, read-write // CREATE_ALWAYS + GENERIC_WRITE -> create/truncate, write // OPEN_ALWAYS + GENERIC_WRITE -> create if absent, write // TRUNCATE_EXISTING + GENERIC_WRITE -> open & truncate to zero __declspec(dllexport) HANDLE CreateFileA(const char* name, - DWORD access, DWORD share, - void* sa, DWORD disposition, - DWORD flags, void* templ) { + DWORD access, DWORD share, + void* sa, DWORD disposition, + DWORD flags, void* templ) { (void)share; (void)sa; (void)flags; (void)templ; + // Translate the path from Windows format to custom 0:/ format + char translatedName[260]; + TranslatePath(name, translatedName); + int wantWrite = (access & GENERIC_WRITE) != 0; if (disposition == OPEN_EXISTING || disposition == TRUNCATE_EXISTING) { // Open the file via the read path (it must already exist). uint32_t kh = 0; - uint32_t s = SysOpenFile(name, &kh); + uint32_t s = SysOpenFile(translatedName, &kh); if (s != 0) { gLastError = 2; return INVALID_HANDLE_VALUE; } if (disposition == TRUNCATE_EXISTING && wantWrite) { @@ -378,10 +356,10 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name, // Create-or-replace: try to create; if the file already exists, // open it and truncate it to zero instead. uint32_t kh = 0; - uint32_t s = SysCreateFile(name, &kh); + uint32_t s = SysCreateFile(translatedName, &kh); if (s != 0) { // File may already exist - open and truncate. - s = SysOpenFile(name, &kh); + s = SysOpenFile(translatedName, &kh); if (s != 0) { gLastError = 5; return INVALID_HANDLE_VALUE; } SysTruncateFile(kh, 0); } @@ -391,8 +369,8 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name, if (disposition == OPEN_ALWAYS && wantWrite) { // Open if exists, create if not. uint32_t kh = 0; - if (SysOpenFile(name, &kh) != 0) { - if (SysCreateFile(name, &kh) != 0) { + if (SysOpenFile(translatedName, &kh) != 0) { + if (SysCreateFile(translatedName, &kh) != 0) { gLastError = 5; return INVALID_HANDLE_VALUE; } @@ -404,7 +382,7 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name, // Fail if the file already exists (we can't check atomically, // but SysCreateFile returns NAME_COLLISION for existing files). uint32_t kh = 0; - uint32_t s = SysCreateFile(name, &kh); + uint32_t s = SysCreateFile(translatedName, &kh); if (s != 0) { gLastError = 80; return INVALID_HANDLE_VALUE; } // ERROR_FILE_EXISTS return KH_TO_HANDLE(kh); } @@ -417,7 +395,7 @@ __declspec(dllexport) HANDLE CreateFileA(const char* name, // GetFileSize - fills optional high-DWORD pointer, returns low DWORD. // Returns 0xFFFFFFFF on error, matching Win32 behaviour. __declspec(dllexport) DWORD GetFileSize(HANDLE hFile, DWORD* fileSizeHigh) { - if (!hFile) { gLastError = 6; return 0xFFFFFFFFUL; } + if (!hFile || hFile == INVALID_HANDLE_VALUE) { gLastError = 6; return 0xFFFFFFFFUL; } uint64_t sz = SysGetFileSize(HANDLE_TO_KH(hFile)); if (fileSizeHigh) *fileSizeHigh = (DWORD)(sz >> 32); return (DWORD)(sz & 0xFFFFFFFFULL); @@ -427,7 +405,7 @@ __declspec(dllexport) DWORD GetFileSize(HANDLE hFile, DWORD* fileSizeHigh) { __declspec(dllexport) BOOL ReadFile(HANDLE hFile, void* buf, DWORD toRead, DWORD* bytesRead, void* overlapped) { (void)overlapped; - if (!hFile || !buf) { gLastError = 6; return FALSE; } + if (!hFile || hFile == INVALID_HANDLE_VALUE || !buf) { gLastError = 6; return FALSE; } size_t got = 0; uint32_t s = SysReadFile(HANDLE_TO_KH(hFile), buf, (size_t)toRead, &got); if (bytesRead) *bytesRead = (DWORD)got; @@ -452,7 +430,7 @@ __declspec(dllexport) BOOL WriteFile(HANDLE hFile, const void* buf, DWORD toWrit // Returns new position low DWORD, or 0xFFFFFFFF on error. __declspec(dllexport) DWORD SetFilePointer(HANDLE hFile, long dist, long* distHigh, DWORD method) { - if (!hFile) { gLastError = 6; return 0xFFFFFFFFUL; } + if (!hFile || hFile == INVALID_HANDLE_VALUE) { gLastError = 6; return 0xFFFFFFFFUL; } uint32_t kh = HANDLE_TO_KH(hFile); uint64_t offset = 0; @@ -481,7 +459,7 @@ __declspec(dllexport) DWORD SetFilePointer(HANDLE hFile, long dist, // SetEndOfFile - truncate or extend the file to the current seek position. __declspec(dllexport) BOOL SetEndOfFile(HANDLE hFile) { - if (!hFile) { gLastError = 6; return FALSE; } + if (!hFile || hFile == INVALID_HANDLE_VALUE) { gLastError = 6; return FALSE; } uint32_t kh = HANDLE_TO_KH(hFile); uint64_t pos = SysGetFilePos(kh); if (pos == (uint64_t)-1) { gLastError = 6; return FALSE; } @@ -493,8 +471,12 @@ __declspec(dllexport) BOOL SetEndOfFile(HANDLE hFile) { // DeleteFileA - delete a file by name; no open handle required. __declspec(dllexport) BOOL DeleteFileA(const char* lpFileName) { if (!lpFileName) { gLastError = 87; return FALSE; } - uint32_t s = SysDeleteFile(lpFileName); - if (s != 0) { gLastError = 2; return FALSE; } // ERROR_FILE_NOT_FOUND + + char translatedPath[MAX_PATH]; + TranslatePath(lpFileName, translatedPath); + + uint32_t s = SysDeleteFile(translatedPath); + if (s != 0) { gLastError = 2; return FALSE; } return TRUE; } @@ -712,9 +694,12 @@ __declspec(dllexport) BOOL CreateProcessA( // Build the cmdline: prefer lpCommandLine if given, otherwise fall back to path const char* cmdline = lpCommandLine ? lpCommandLine : targetPath; + char translatedPath[MAX_PATH]; + TranslatePath(targetPath, translatedPath); + uint32_t kh = 0; // Call the syscall.dll stub - uint32_t s = SysCreateProcess(targetPath, &kh, cmdline); + uint32_t s = SysCreateProcess(translatedPath, &kh, cmdline); if (s != 0 || kh == 0) { gLastError = 2; // ERROR_FILE_NOT_FOUND return FALSE; @@ -956,10 +941,14 @@ __declspec(dllexport) HANDLE FindFirstFileA(const char* lpFileName, return INVALID_HANDLE_VALUE; } + // Translate the path + char translatedInput[MAX_PATH]; + TranslatePath(lpFileName, translatedInput); + // Split path into directory and wildcard pattern char dir[MAX_PATH]; char pat[MAX_PATH]; - SplitFindPath(lpFileName, dir, sizeof(dir), pat, sizeof(pat)); + SplitFindPath(translatedInput, dir, sizeof(dir), pat, sizeof(pat)); // Open the kernel directory iterator uint32_t kh = 0; @@ -1040,7 +1029,11 @@ __declspec(dllexport) BOOL FindClose(HANDLE hFindFile) { __declspec(dllexport) BOOL SetCurrentDirectoryA(const char* lpPathName) { if (!lpPathName) { gLastError = 87; return FALSE; } - uint32_t s = SysSetCwd(lpPathName); + + char translatedPath[MAX_PATH]; + TranslatePath(lpPathName, translatedPath); + + uint32_t s = SysSetCwd(translatedPath); if (s != 0) { gLastError = 2; return FALSE; } return TRUE; } diff --git a/code/win32/ole32.c b/code/win32/ole32.c index c86d62a..c1be4ef 100644 --- a/code/win32/ole32.c +++ b/code/win32/ole32.c @@ -2,6 +2,7 @@ // No COM infrastructure at this stage; all functions fail gracefully. #include #include +#include // --------------------------------------------------------------------------- // Types @@ -37,8 +38,6 @@ typedef struct { }; } PROPVARIANT; -extern void SysFree(void* ptr, size_t size); - // --------------------------------------------------------------------------- // COM initialisation // --------------------------------------------------------------------------- diff --git a/code/win32/user32.c b/code/win32/user32.c index 8bf0c4b..af2d4fd 100644 --- a/code/win32/user32.c +++ b/code/win32/user32.c @@ -1,9 +1,7 @@ // user32.c - Win32 User Interface #include #include - -extern void SysYield(void); -extern void SysDebugPrint(const char* str); +#include typedef void* HWND; typedef void* HDC; diff --git a/code/win32/winmm.c b/code/win32/winmm.c index e21fc4e..0c9ae4b 100644 --- a/code/win32/winmm.c +++ b/code/win32/winmm.c @@ -2,6 +2,7 @@ // Stubs only; no audio hardware access at this stage. #include #include +#include // --------------------------------------------------------------------------- // Types @@ -51,10 +52,6 @@ typedef struct { // Timer // --------------------------------------------------------------------------- -// timeGetTime is the lightweight alternative to GetTickCount; both return -// milliseconds since system start. We forward to the kernel tick counter. -extern uint64_t SysGetTick(void); - __declspec(dllexport) unsigned long timeGetTime(void) { return (unsigned long)SysGetTick(); } diff --git a/readme.md b/readme.md index 34474c4..bc8ae69 100644 --- a/readme.md +++ b/readme.md @@ -114,7 +114,7 @@ HAL: _S5_ SLP_TYP_A=0x00 SLP_TYP_B=0x00 HAL: LAPIC=00000000fee00000 IOAPIC=00000000fec00000 HPET=00000000fed00000 HAL: lapicPhys=0xFEE00000, lapicVirt=0xFFFF8800FEE00000, hpetPhys=0xFED00000 HAL: Attempting to calibrate APIC timer via HPET... -HAL: APIC timer: 62990 ticks/ms +HAL: APIC timer: 62981 ticks/ms HAL: initialisation complete. KernelMain: Handing over to scheduler... SystemInitThread: Thread started. Igniting the system... @@ -146,25 +146,51 @@ Found runtime driver: usb.sys Test runtime driver SystemInitThread: Loading system DLLs... Memory Status: - -> Free (PMM): 151.80 MB + -> Free (PMM): 151.71 MB -> Kernel Pool: 4.00 MB - -> User Heap: 0.47 MB + -> User Heap: 0.55 MB LaunchUserProcess: IoOpenFile: 0 LaunchUserProcess: IoGetFileSize: 5120 -LaunchUserProcess: MmAllocateUserMemory: 0x7A020 +LaunchUserProcess: MmAllocateUserMemory: 0x8E020 LaunchUserProcess: IoReadFile: 0 LaunchUserProcess: IoCloseFile Created process (PID 2) with command line: init.exe -LaunchUserProcess: PE Image mapped! Base 0x7c020, Entry 0x7D600 +LaunchUserProcess: PE Image mapped! Base 0x90020, Entry 0x91600 LaunchUserProcess: Thread created and queued! [init] starting [init] waiting shell: ready -shell.exe -> clear -> -> -> +> help +Available commands: + help - Show this list + dir - List files + cd - Change directory + type - Display file contents + del - Delete a file + write - Create a file with text + exit - Close the shell +> dir +System Volume Information +drivers +efi +colonel.exe +hal.dll +syscall.dll +win32.dll +posix.dll +init.exe +shell_win32.exe +shell_posix.exe +shell_native.exe +doom.exe +video.exe +boot.ini +bink2w64.dll +video.bk2 +doom1.wad +> shell_win32.exe +shell: ready +shell_win32.exe > doom.exe doom: starting getenv: Unknown variable DOOMWADDIR @@ -203,13 +229,51 @@ HU_Init: Setting up heads up display. ST_Init: Init status bar. doom: entering game loop I_ShutdownSound: NOT finishing pending sounds -> clear +> shell_posix.exe +shell: ready +> help +Available commands: + help - Show this list + dir [path] - List directory contents + cd - Change directory + type - Display file contents + del - Delete a file + write - Create a file with text + exit - Close the shell +> dir + System Volume Information + drivers + efi + colonel.exe + hal.dll + syscall.dll + win32.dll + posix.dll + init.exe + shell_win32.exe + shell_posix.exe + shell_native.exe + doom.exe + video.exe + boot.ini + bink2w64.dll + video.bk2 + doom1.wad + .doo > video.exe video: starting video.exe video: video.bk2 loaded shell: goodbye -> +> exit +shell: goodbye +> exit +shell: goodbye +> exit +shell: goodbye +[init] done +ProcessWatcherThread: Process "init.exe" (PID 2) exited with code 0. +ProcessWatcherThread: Shutting down. ```