fix the return value of LdrLoadImage, make use of __declspec(dllexport), speed up blitting, add dummy TEB, redesign the syscall interface, fix stack alignent so movaps doesn't crash, implement a shitload of win32, implement a simple shell, add bink as video.exe 😎, minor kmain.c cleanup, HAL now supports power-off events, implemented \b in hal_screen.c, fix many deadlocks, add wait for exit event for processes, completely new error codes, small readme changes.

This commit is contained in:
maksw committed 2026-05-03 13:43:29 +02:00
1 parent c13dd99150
commit 7f4052f41c
33 files changed
+6396 -735

No files matched your search

+64 -32
View File
@@ -74,6 +74,10 @@ typedef struct {
typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API *);
// HAL pointer cached at boot so kernel threads can reach it without
// threading a parameter through every call chain.
static const HAL_API* gKmainHal;
// ---------------------------------------------------------------------------
// Phase Helper: Resolve Imports for all registered modules
// ---------------------------------------------------------------------------
@@ -210,7 +214,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
}
// ---------------------------------------------------------------------------
// Phase Helper: Load a DLL from disk and register it as a system module
// Phase Helper: Load a DLL from disk and register it
// ---------------------------------------------------------------------------
static void LoadAndRegisterDll(const char* filename) {
KSTATUS s;
@@ -219,8 +223,8 @@ static void LoadAndRegisterDll(const char* filename) {
// Read the DLL from disk
s = IoOpenFile(filename, &f);
if (s != STATUS_SUCCESS) {
DbgPrint("KernelMain: Failed to open critical system DLL: %s\n", filename);
_disable(); while(1) __halt();
DbgPrint("KernelMain: Failed to open DLL: %s\n", filename);
return;
}
uint64_t size = IoGetFileSize(f);
@@ -229,7 +233,7 @@ static void LoadAndRegisterDll(const char* filename) {
if (!KSUCCESS(IoReadFile(f, mem, size, &got))) {
DbgPrint("KernelMain: Failed to read %s\n", filename);
IoCloseFile(f);
_disable(); while(1) __halt();
return;
}
IoCloseFile(f);
@@ -239,7 +243,7 @@ static void LoadAndRegisterDll(const char* filename) {
s = LdrLoadImage(mem, size, &mappedBase, true);
if (!KSUCCESS(s)) {
DbgPrint("KernelMain: Failed to map %s\n", filename);
_disable(); while(1) __halt();
return;
}
MmFreePool(mem); // Free the raw file buffer, we only need the mapped image now
@@ -248,18 +252,20 @@ static void LoadAndRegisterDll(const char* filename) {
}
// ---------------------------------------------------------------------------
// Phase Helper: Load and launch the init process from the filesystem
// Phase Helper: Load and launch a process from the filesystem.
// Returns the new PROCESS* with one reference owned by the caller.
// Returns NULL on failure.
// ---------------------------------------------------------------------------
static void LaunchInitProcess(BOOT_INFO* bootInfo) {
static PROCESS* LaunchUserProcess(const char* filePath) {
KSTATUS s;
FILE_OBJECT* f;
// Read the executable file into a raw buffer
s = IoOpenFile(bootInfo->CommandLine, &f);
s = IoOpenFile(filePath, &f);
DbgPrint("KernelMain: IoOpenFile: %d\n", s);
if (s != STATUS_SUCCESS) {
DbgPrint("Failed to load file: \"%s\"!\n", bootInfo->CommandLine);
_disable(); while(1) __halt();
DbgPrint("Failed to load file: \"%s\"!\n", filePath);
return (PROCESS*)0;
}
uint64_t size = IoGetFileSize(f);
@@ -278,29 +284,46 @@ static void LaunchInitProcess(BOOT_INFO* bootInfo) {
PROCESS* proc;
THREAD* thread;
s = KeCreateProcess("init", &proc);
s = KeCreateProcess(filePath, &proc);
if (!KSUCCESS(s)) {
DbgPrint("Failed to create init process. System halted.\n");
_disable(); while(1) __halt();
DbgPrint("Failed to create process. System halted.\n");
return (PROCESS*)0;
}
DbgPrint("Created init process (PID %u) with command line: %s\n", proc->ProcessId, bootInfo->CommandLine);
DbgPrint("Created process (PID %u) with command line: %s\n", proc->ProcessId, filePath);
// Parse the raw PE file and map it into executable memory
uintptr_t entryPoint = 0;
s = LdrLoadImage(mem, size, &entryPoint, true);
uintptr_t imageBase = 0;
s = LdrLoadImage(mem, size, &imageBase, true);
if (!KSUCCESS(s)) {
DbgPrint("KernelMain: LdrLoadImage failed with status: %d\n", s);
_disable(); while(1) __halt();
}
DbgPrint("KernelMain: PE Image mapped! Entry point at 0x%llX\n", (void*)entryPoint);
uintptr_t entryPoint = LdrGetEntryPoint(imageBase);
DbgPrint("KernelMain: PE Image mapped! Base 0x%llx, Entry 0x%llX\n", imageBase, entryPoint);
// Create the main thread, pointing it to the PE Entry Point
s = KeCreateThread(proc, (uintptr_t)entryPoint, 0, PriorityNormal, &thread);
if (!KSUCCESS(s)) {
DbgPrint("KernelMain: Failed to create init thread. Status: %d\n", s);
_disable(); while(1) __halt();
DbgPrint("KernelMain: Failed to create thread. Status: %d\n", s);
}
DbgPrint("KernelMain: 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.
// ---------------------------------------------------------------------------
static void ProcessWatcherThread(void* arg) {
PROCESS* proc = (PROCESS*)arg;
KeWaitForEvent(proc->ExitEvent);
DbgPrint("KernelMain: Process \"%s\" (PID %u) exited with code %d.\n",
proc->Name, proc->ProcessId, proc->ExitCode);
ObDereferenceObject(&proc->Header);
DbgPrint("KernelMain: Shutting down.\n");
gKmainHal->Power.Shutdown(); // does not return
}
static void PrintProcessList() {
@@ -360,6 +383,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
KSTATUS s = HalInitialize(&halParams);
if (!KSUCCESS(s)) for (;;) __halt(); // there's nothing we can do.
const HAL_API* hal = HalGetApi();
gKmainHal = hal;
KeInitDebug(hal->Screen.PrintChar, bootInfo->DebugEnabled); // Enable debug
@@ -382,11 +406,12 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
// Scheduler Prep & Status Update
//
KeInitializeScheduler();
// hal->Screen.Clear(0x000000);
hal->Screen.Clear(0x000000);
DbgPrint("KernelMain: 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)
@@ -395,7 +420,20 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
//
// User-Mode Launch
//
LaunchInitProcess(bootInfo);
PROCESS* shellProc = LaunchUserProcess(bootInfo->CommandLine);
// Spawn a kernel thread that blocks on the process exit event and prints
// when it fires. The watcher takes ownership of the LaunchUserProcess
// reference so we do not hold a dangling pointer in KernelMain.
if (shellProc) {
KSTATUS ws = KeCreateKernelThread((uintptr_t)ProcessWatcherThread,
(uintptr_t)shellProc,
PriorityNormal, (THREAD**)0);
if (!KSUCCESS(ws)) {
DbgPrint("KernelMain: Failed to create watcher thread (%d) -- leaking proc ref.\n", ws);
}
// Ownership of shellProc transferred to watcher; do not use it below.
}
//
// Ignite the System
@@ -403,18 +441,12 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
DbgPrint("KernelMain: Starting scheduler... Handing over control.\n");
_enable();
float freeMB = (float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f);
float kernelMB = (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f);
float userMB = (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f);
DbgPrint("Memory Status:\n");
DbgPrint(" -> Free (PMM): %.2f MB\n", freeMB);
DbgPrint(" -> Kernel Pool: %.2f MB\n", kernelMB);
DbgPrint(" -> User Heap: %.2f MB\n", userMB);
DbgPrint(" -> Free (PMM): %.2f MB\n", (float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f));
DbgPrint(" -> Kernel Pool: %.2f MB\n", (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f));
DbgPrint(" -> User Heap: %.2f MB\n", (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f));
while (1) {
//DbgPrint("KernelMain: Idle loop. Free memory: %.2f MB.\n",
//(float)(MmFreeFrameCount() * PAGE_SIZE) / (1024.0f * 1024.0f));
__halt(); // nothing to do
KeYield(); // nothing to do
}
}