implement proper IRQL, DPCs, kernel and user APCs, alertable waits, async file I/O with cancellation, trap frames, selftests, a real driver/device model, native async FAT32, VFAT dotfile fixes, syscall ABI cleanup, async_apc and async_cancel tests, POSIX multi-volume paths, and pimp the readme.

This commit is contained in:
maksw committed 2026-05-19 20:56:15 +02:00
1 parent f5fd7bdd75
commit 529f816166
75 files changed
+9969 -5675

No files matched your search

+95 -42
View File
@@ -11,12 +11,14 @@
#include <ke_sched.h>
#include <ke_idt.h>
#include <ke_irq.h>
#include <ke_dpc.h>
#include <ke_syscall.h>
#include <ke_debug.h>
#include <ke_util.h>
#include <ldr_image.h>
#include <hal_api.h>
#include <io_file.h>
#include <ke_selftest.h>
#include <ini_parser.h>
typedef struct {
@@ -30,7 +32,49 @@ typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API *);
// threading a parameter through every call chain.
static const HAL_API* gKmainHal;
static int PageInBootloaderRegion(const BOOT_INFO* bootInfo, PHYSICAL_ADDRESS page) {
// Kernel-owned DPC wrappers for HAL input devices. The HAL keeps the tiny
// hardware-specific ISR fast and exposes a bottom-half entry point; the kernel
// owns the actual DPC objects and scheduling policy.
static KDPC gKeyboardDpc;
static KDPC gMouseDpc;
static void KeyboardDpcRoutine(KDPC* dpc, void* context, void* systemArgument1, void* systemArgument2) {
(void)dpc;
(void)context;
(void)systemArgument1;
(void)systemArgument2;
if (gKmainHal && gKmainHal->Keyboard.Dpc)
gKmainHal->Keyboard.Dpc();
}
static void KiMouseDpcRoutine(KDPC* dpc, void* context, void* systemArgument1, void* systemArgument2) {
(void)dpc;
(void)context;
(void)systemArgument1;
(void)systemArgument2;
if (gKmainHal && gKmainHal->Mouse.Dpc)
gKmainHal->Mouse.Dpc();
}
static void KeyboardIrqWrapper(void) {
if (gKmainHal && gKmainHal->Keyboard.Isr)
gKmainHal->Keyboard.Isr();
if (gKmainHal && gKmainHal->Keyboard.Dpc)
KeInsertQueueDpc(&gKeyboardDpc, (void*)0, (void*)0);
}
static void KiMouseIrqWrapper(void) {
if (gKmainHal && gKmainHal->Mouse.Isr)
gKmainHal->Mouse.Isr();
if (gKmainHal && gKmainHal->Mouse.Dpc)
KeInsertQueueDpc(&gMouseDpc, (void*)0, (void*)0);
}
static int KiPageInBootloaderRegion(const BOOT_INFO* bootInfo, PHYSICAL_ADDRESS page) {
for (uint32_t i = 0; i < bootInfo->MemoryMap.RegionCount; i++) {
const MEMORY_REGION* r = &bootInfo->MemoryMap.Regions[i];
if (r->Type != MemoryBootloader) continue;
@@ -44,7 +88,7 @@ static int PageInBootloaderRegion(const BOOT_INFO* bootInfo, PHYSICAL_ADDRESS pa
return 0;
}
static void ReclaimBootloaderMemory(const BOOT_INFO* bootInfo) {
static void KiReclaimBootloaderMemory(const BOOT_INFO* bootInfo) {
// Reclaim only the raw buffers backing boot-loaded .sys modules.
// The kernel/HAL images, page tables, and bootloader code remain live.
for (uint32_t i = 2; i < bootInfo->ModuleCount; i++) {
@@ -55,7 +99,7 @@ static void ReclaimBootloaderMemory(const BOOT_INFO* bootInfo) {
uintptr_t end = (uintptr_t)((mod->PhysBase + mod->ImageSize + PAGE_SIZE - 1) & PAGE_MASK);
for (uintptr_t page = base; page < end; page += PAGE_SIZE) {
if (!PageInBootloaderRegion(bootInfo, (PHYSICAL_ADDRESS)page)) continue;
if (!KiPageInBootloaderRegion(bootInfo, (PHYSICAL_ADDRESS)page)) continue;
MmFreeFrame((PHYSICAL_ADDRESS)page);
}
}
@@ -64,7 +108,7 @@ static void ReclaimBootloaderMemory(const BOOT_INFO* bootInfo) {
// ---------------------------------------------------------------------------
// Phase Helper: Resolve Imports for core modules
// ---------------------------------------------------------------------------
static void ResolveSystemImports(BOOT_INFO* bootInfo) {
static void KiResolveSystemImports(BOOT_INFO* bootInfo) {
// 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;
@@ -79,7 +123,7 @@ static void ResolveSystemImports(BOOT_INFO* bootInfo) {
// ---------------------------------------------------------------------------
// Phase Helper: Initialize dynamically loaded .sys drivers
// ---------------------------------------------------------------------------
static void DriversIniCb(const char* section, const char* key,
static void KiDriversIniCb(const char* section, const char* key,
const char* val, void* ud) {
(void)val;
if (!strcmp(section, "runtime")) {
@@ -93,8 +137,8 @@ static void DriversIniCb(const char* section, const char* key,
}
}
static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
DbgPrint("InitializeDrivers: Initializing drivers...\n");
static void KiInitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
DbgPrint("KiInitializeDrivers: Initializing drivers...\n");
// boot drivers (provided by the bootloader)
for (uint32_t i = 0; i < bootInfo->ModuleCount; i++) {
@@ -104,7 +148,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
// or have no physical data (invalid)
if (mod->VirtBase != 0 || mod->PhysBase == 0) continue;
DbgPrint("InitializeDrivers: Loading boot driver %s\n", mod->Name);
DbgPrint("KiInitializeDrivers: Loading boot driver %s\n", mod->Name);
// Calculate virtual address of the raw file in the physical window
void* rawPeBuffer = (void*)(bootInfo->PhysicalMapBase + mod->PhysBase);
@@ -145,7 +189,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
s = IoOpenFile("drivers\\drivers.ini", &f);
if (s != STATUS_SUCCESS) {
KePanic("InitializeDrivers: Failed to open drivers.ini (status %d)\n", s);
KePanic("KiInitializeDrivers: Failed to open drivers.ini (status %d)\n", s);
}
uint64_t size = IoGetFileSize(f) + 1;
@@ -153,14 +197,14 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
size_t got;
if (!KSUCCESS(IoReadFile(f, mem, size, &got))) {
IoCloseFile(f);
KePanic("InitializeDrivers: Failed to read drivers.ini\n");
KePanic("KiInitializeDrivers: Failed to read drivers.ini\n");
}
mem[got] = '\0';
IoCloseFile(f);
char** runtimeKeys = NULL;
IniParse(mem, DriversIniCb, &runtimeKeys);
IniParse(mem, KiDriversIniCb, &runtimeKeys);
for (uint32_t i = 0; i < arr_len(runtimeKeys); i++) {
DbgPrint("Found runtime driver: %s\n", runtimeKeys[i]);
@@ -179,7 +223,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
s = IoOpenFile(path, &f);
if (s != STATUS_SUCCESS) {
DbgPrint("InitializeDrivers: Failed to open runtime driver: %s (%s)\n", runtimeKeys[i], path);
DbgPrint("KiInitializeDrivers: Failed to open runtime driver: %s (%s)\n", runtimeKeys[i], path);
continue; // Skip this driver but keep going with others
}
@@ -188,7 +232,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
uint64_t drvSize = IoGetFileSize(f);
void* drvMem = MmAllocatePool(drvSize);
if (!KSUCCESS(IoReadFile(f, drvMem, drvSize, &got))) {
DbgPrint("InitializeDrivers: Failed to read runtime driver: %s\n", runtimeKeys[i]);
DbgPrint("KiInitializeDrivers: Failed to read runtime driver: %s\n", runtimeKeys[i]);
IoCloseFile(f);
continue;
}
@@ -196,14 +240,14 @@ 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]);
DbgPrint("KiInitializeDrivers: 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]);
DbgPrint("KiInitializeDrivers: Failed to resolve imports for runtime driver: %s\n", runtimeKeys[i]);
continue;
}
@@ -211,7 +255,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
KSTATUS ds = entry(hal);
if (!KSUCCESS(ds)) {
DbgPrint("InitializeDrivers: Driver %s failed to init!\n", runtimeKeys[i]);
DbgPrint("KiInitializeDrivers: Driver %s failed to init!\n", runtimeKeys[i]);
}
}
@@ -235,23 +279,23 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
// Returns the new PROCESS* with one reference owned by the caller.
// Returns NULL on failure.
// ---------------------------------------------------------------------------
static PROCESS* LaunchUserProcess(const char* filePath, const char* args) {
static PROCESS* KiLaunchUserProcess(const char* filePath, const char* args) {
KSTATUS s;
FILE_OBJECT* f;
// Read the executable file into a raw buffer.
s = IoOpenFile(filePath, &f);
DbgPrint("LaunchUserProcess: IoOpenFile: %d\n", s);
DbgPrint("KiLaunchUserProcess: IoOpenFile: %d\n", s);
if (s != STATUS_SUCCESS) {
DbgPrint("Failed to load file: \"%s\"!\n", filePath);
return 0;
}
uint64_t size = IoGetFileSize(f);
DbgPrint("LaunchUserProcess: IoGetFileSize: %llu\n", size);
DbgPrint("KiLaunchUserProcess: IoGetFileSize: %llu\n", size);
void* mem = MmAllocatePool(size);
DbgPrint("LaunchUserProcess: MmAllocatePool: 0x%llX\n", mem);
DbgPrint("KiLaunchUserProcess: MmAllocatePool: 0x%llX\n", mem);
if (!mem) {
IoCloseFile(f);
return 0;
@@ -259,7 +303,7 @@ static PROCESS* LaunchUserProcess(const char* filePath, const char* args) {
size_t got = 0;
s = IoReadFile(f, mem, size, &got);
DbgPrint("LaunchUserProcess: IoReadFile: %d\n", s);
DbgPrint("KiLaunchUserProcess: IoReadFile: %d\n", s);
IoCloseFile(f);
if (!KSUCCESS(s)) {
MmFreePool(mem);
@@ -280,7 +324,7 @@ static PROCESS* LaunchUserProcess(const char* filePath, const char* args) {
s = KeSetupUserProcessEnvironment(proc, filePath, args, proc->CurrentDirectory);
if (!KSUCCESS(s)) {
DbgPrint("LaunchUserProcess: Failed to build user process environment. Status: %d\n", s);
DbgPrint("KiLaunchUserProcess: Failed to build user process environment. Status: %d\n", s);
MmFreePool(mem);
ObDereferenceObject(&proc->Header);
return 0;
@@ -291,15 +335,15 @@ static PROCESS* LaunchUserProcess(const char* filePath, const char* args) {
s = LdrLoadImage(mem, size, &imageBase, true);
MmFreePool(mem);
if (!KSUCCESS(s)) {
DbgPrint("LaunchUserProcess: LdrLoadImage failed with status: %d\n", s);
DbgPrint("KiLaunchUserProcess: 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));
DbgPrint("KiLaunchUserProcess: Failed to resolve EXE imports for %s (status %d)\n", filePath, s);
MmFreeUserMemory((void*)imageBase);
ObDereferenceObject(&proc->Header);
return 0;
}
@@ -308,24 +352,24 @@ static PROCESS* LaunchUserProcess(const char* filePath, const char* args) {
proc->ImageSize = LdrGetImageSize(imageBase);
uintptr_t entryPoint = LdrGetEntryPoint(imageBase);
DbgPrint("LaunchUserProcess: PE Image mapped! Base 0x%llx, Entry 0x%llX\n", imageBase, entryPoint);
DbgPrint("KiLaunchUserProcess: PE Image mapped! Base 0x%llx, Entry 0x%llX\n", imageBase, entryPoint);
// Create the main thread last. KeCreateThread queues it before returning.
s = KeCreateThread(proc, (uintptr_t)entryPoint, 0, PriorityNormal, &thread);
if (!KSUCCESS(s)) {
DbgPrint("LaunchUserProcess: Failed to create thread. Status: %d\n", s);
DbgPrint("KiLaunchUserProcess: Failed to create thread. Status: %d\n", s);
proc->ImageBase = 0;
proc->ImageSize = 0;
MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase));
MmFreeUserMemory((void*)imageBase);
ObDereferenceObject(&proc->Header);
return 0;
}
DbgPrint("LaunchUserProcess: Thread created and queued!\n");
DbgPrint("KiLaunchUserProcess: Thread created and queued!\n");
// Caller owns the reference returned by KeCreateProcess.
return proc;
}
static void PrintProcessList() {
static void KiPrintProcessList() {
LIST_ENTRY* listHead = KeGetProcessList();
LIST_ENTRY* current;
@@ -349,10 +393,10 @@ void SystemInitThread(void* arg) {
DbgPrint("SystemInitThread: Thread started. Igniting the system...\n");
InitializeDrivers(args->bootInfo, args->hal);
KiInitializeDrivers(args->bootInfo, args->hal);
ResolveSystemImports(args->bootInfo);
ReclaimBootloaderMemory(args->bootInfo);
KiResolveSystemImports(args->bootInfo);
KiReclaimBootloaderMemory(args->bootInfo);
args->hal->Screen.Clear(0x000000);
@@ -362,16 +406,19 @@ void SystemInitThread(void* arg) {
DbgPrint(" -> Kernel Pool: %.2f MB\n", (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f));
DbgPrint(" -> User Heap: %.2f MB\n", (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f));
if (args->bootInfo->Debug & 2)
KiRunKernelSelfTests(args->hal);
// Launch User-Mode init.exe and restart it until it exits cleanly.
while (true) {
PROCESS* shellProc = LaunchUserProcess("system/init.exe", args->bootInfo->CommandLine);
PROCESS* shellProc = KiLaunchUserProcess("system/init.exe", args->bootInfo->CommandLine);
if (!shellProc) {
DbgPrint("SystemInitThread: Failed to start system/init.exe; retrying.\n");
KeYield();
continue;
}
KeWaitForEvent(shellProc->ExitEvent);
KeWaitForEvent(shellProc->ExitEvent, 0);
int exitCode = shellProc->ExitCode;
DbgPrint("SystemInitThread: init.exe exited with code %d.\n", exitCode);
ObDereferenceObject(&shellProc->Header);
@@ -421,7 +468,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
.FramebufferHeight = bootInfo->FramebufferHeight,
.FramebufferStride = bootInfo->FramebufferStride,
.RsdpPhysical = bootInfo->RsdpPhysical,
.DebugEnabled = bootInfo->DebugEnabled
.Debug = bootInfo->Debug
};
KSTATUS s = HalInitialize(&halParams);
@@ -432,13 +479,19 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
const HAL_API* hal = HalGetApi();
gKmainHal = hal;
KeInitDebug(hal->Screen.PrintChar, bootInfo->DebugEnabled); // Enable debug
KeInitDebug(hal->Screen.PrintChar, bootInfo->Debug & 1); // Enable debug
KeIrqInitialize(hal);
KeInitializeDpcSystem();
KeIrqRegister(hal->Timer.IrqNumber, hal->Timer.Isr);
KeIrqRegister(hal->Keyboard.IrqNumber, hal->Keyboard.Isr);
KeIrqRegister(hal->Mouse.IrqNumber, hal->Mouse.Isr);
KeInitializeDpc(&gKeyboardDpc, KeyboardDpcRoutine, (void*)0);
KeInitializeDpc(&gMouseDpc, KiMouseDpcRoutine, (void*)0);
KeIrqRegister(hal->Timer.IrqNumber, hal->Timer.Isr);
KeIrqRegister(hal->Keyboard.IrqNumber,
hal->Keyboard.Dpc ? KeyboardIrqWrapper : hal->Keyboard.Isr);
KeIrqRegister(hal->Mouse.IrqNumber,
hal->Mouse.Dpc ? KiMouseIrqWrapper : hal->Mouse.Isr);
HalRegisterScheduler(KeSchedulerTick);
@@ -447,8 +500,8 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
//
// Dynamic Linking & Driver Execution
//
ResolveSystemImports(bootInfo);
//InitializeDrivers(bootInfo, hal);
KiResolveSystemImports(bootInfo);
//KiInitializeDrivers(bootInfo, hal);
//
// Scheduler Prep & Status Update