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.

This commit is contained in:
maksw committed 2026-05-13 09:24:16 +02:00
1 parent 0c7f461c6d
commit f80e66ecde
38 files changed
+1620 -462

No files matched your search

Binary file not shown.
+51 -24
View File
@@ -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...
+1 -1
View File
@@ -1,4 +1,4 @@
[kernel]
debug = 1
[init]
commandline = shell.exe
commandline = apps/shell_native.exe
+14 -32
View File
@@ -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");
+46 -11
View File
@@ -2,20 +2,52 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
// ---------------------------------------------------------------------------
// 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 <syscall.h>
#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);
}
+3 -4
View File
@@ -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;
+3 -1
View File
@@ -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 {
+123
View File
@@ -4,6 +4,9 @@
#include <string.h>
#include <hal_api.h>
#include <ke_spinlock.h>
#include <ke_process.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <printf.h>
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);
}
+18 -2
View File
@@ -4,8 +4,24 @@
#include <stdint.h>
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
+30
View File
@@ -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));
+27 -5
View File
@@ -6,10 +6,20 @@
#include <ke_list.h>
#include <ke_spinlock.h>
#include <ke_event.h>
#include <stddef.h>
#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). */
+1 -1
View File
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <stdbool.h>
#include <ke_sched.h>
#include <ke_process.h>
#include <ke_thread.h>
#include <ke_spinlock.h>
#include <ke_list.h>
@@ -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);
+51 -68
View File
@@ -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
+26 -3
View File
@@ -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.
+100 -76
View File
@@ -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
// ---------------------------------------------------------------------------
+252 -36
View File
@@ -3,6 +3,8 @@
#include <string.h>
#include <ldr_image.h>
#include <boot_info.h>
#include <ke_process.h>
#include <io_file.h>
#include <mm_virt.h>
#include <ke_debug.h>
@@ -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;
}
+12 -1
View File
@@ -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
+1 -1
View File
@@ -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;
+10
View File
@@ -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;
+1
View File
@@ -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
+6 -14
View File
@@ -1,17 +1,9 @@
// posix_dir.c - chdir, getcwd, opendir, readdir, closedir
#include <string.h>
#include <syscall.h>
#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));
+5 -12
View File
@@ -1,20 +1,13 @@
// posix_fd.c - file descriptor table
#include "posix.h"
#include "posix_fd.h"
// yeah
#ifdef errno
#undef errno
#endif
#include <syscall.h>
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 };
+4 -4
View File
@@ -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);
+27 -18
View File
@@ -1,23 +1,11 @@
// posix_io.c - open, read, write, close, lseek
#include <stddef.h>
#include <string.h>
#include <syscall.h>
#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; }
+2 -2
View File
@@ -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);
+8 -11
View File
@@ -1,17 +1,10 @@
// posix_proc.c - posix_spawn, waitpid, getpid
#include <stddef.h>
#include <string.h>
#include <syscall.h>
#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);
}
+9 -22
View File
@@ -1,21 +1,8 @@
// posix_thread.c - pthread_create, pthread_join, pthread_exit, pthread_mutex_*
#include <stddef.h>
#include <syscall.h>
#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;
}
+247
View File
@@ -0,0 +1,247 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <syscall.h>
#include <io_file.h>
// ---------------------------------------------------------------------------
// 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 <path> - Change directory\n"
" type <file> - Display file contents\n"
" del <file> - Delete a file\n"
" write <file> <tx> - 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 <filename> <text>\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;
}
+231
View File
@@ -0,0 +1,231 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#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 <path> - Change directory\n"
" type <file> - Display file contents\n"
" del <file> - Delete a file\n"
" write <file> <txt> - 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("<DIR> ");
} 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);
}
@@ -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("<DIR> ");
print("<DIR> ");
} 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;
}
+110
View File
@@ -0,0 +1,110 @@
#pragma once
// Syscall.h
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
// ---------------------------------------------------------------------------
// 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
+5 -1
View File
@@ -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);
+1 -8
View File
@@ -1,6 +1,7 @@
// gdi32.c
#include <stdint.h>
#include <stddef.h>
#include <syscall.h>
#if defined(__SSE2__) || defined(_M_X64) || defined(_M_IX86)
#include <emmintrin.h>
@@ -8,14 +9,6 @@
#include <arm_neon.h>
#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
// ---------------------------------------------------------------------------
+70 -77
View File
@@ -24,63 +24,7 @@
#include <stdbool.h>
#include <string.h>
#include <intrin.h>
// ---------------------------------------------------------------------------
// 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 <syscall.h>
// ---------------------------------------------------------------------------
// 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;
}
+1 -2
View File
@@ -2,6 +2,7 @@
// No COM infrastructure at this stage; all functions fail gracefully.
#include <stdint.h>
#include <stddef.h>
#include <syscall.h>
// ---------------------------------------------------------------------------
// Types
@@ -37,8 +38,6 @@ typedef struct {
};
} PROPVARIANT;
extern void SysFree(void* ptr, size_t size);
// ---------------------------------------------------------------------------
// COM initialisation
// ---------------------------------------------------------------------------
+1 -3
View File
@@ -1,9 +1,7 @@
// user32.c - Win32 User Interface
#include <stdint.h>
#include <stddef.h>
extern void SysYield(void);
extern void SysDebugPrint(const char* str);
#include <syscall.h>
typedef void* HWND;
typedef void* HDC;
+1 -4
View File
@@ -2,6 +2,7 @@
// Stubs only; no audio hardware access at this stage.
#include <stdint.h>
#include <stddef.h>
#include <syscall.h>
// ---------------------------------------------------------------------------
// 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();
}
+76 -12
View File
@@ -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 <path> - Change directory
type <file> - Display file contents
del <file> - Delete a file
write <file> <tx> - 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 <path> - Change directory
type <file> - Display file contents
del <file> - Delete a file
write <file> <txt> - 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.
```
</details>