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

+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);
}