refactor syscall ABI and FAT32 driver to use request structs and string views natively, enforce handle access rights on object lookup, add scheduler statistics tracking, fix KiSchedule to prevent 50% idle throttling on CPU-bound threads, better document x64 initial user stack alignment, fix process teardown to properly signal exit events and manage thread counts, optimize doom file I/O with a custom handle struct to internally track position and size, add SubsystemData to TEB for generic thread-local state, apply PAGE_NX to non-executable PE sections in the loader, update native apps, tests, and shells to match new APIs, update kernel32 directory retrieval.

This commit is contained in:
maksw committed 2026-05-26 14:46:49 +02:00
1 parent 603fbdfab1
commit e1248f4afe
43 files changed
+2892 -1857

No files matched your search

+21 -10
View File
@@ -18,11 +18,13 @@ The codebase is still small enough to understand, but large enough to hurt your
- higher-half x86-64 kernel
- physical memory manager
- virtual memory manager with kernel pool and user heap
- W^X-style user page protections
- single address-space design with user/supervisor page permissions
- HAL for screen, keyboard, mouse, timer, PCI, APIC, HPET, AHCI, and IDE
- preemptive priority scheduler
- preemptive priority scheduler accounting for ticks, context switches, idle selections, demotions, and aging promotions
- processes and threads
- object handles
- process termination state tracking and exit signaling
- object handles with per-handle rights metadata
- events, semaphores, mutexes, queues, and alertable waits
- IRQL model: `PASSIVE_LEVEL`, `APC_LEVEL`, `DISPATCH_LEVEL`, and device IRQLs
- interrupt-exit scheduling instead of context-switching inside hard IRQ handlers
@@ -42,14 +44,14 @@ The codebase is still small enough to understand, but large enough to hurt your
- lwIP network stack as a runtime driver (`lwip.sys`)
- RTL8139 and RTL816x ethernet drivers
- native BSD-style socket syscalls: `SysSocket`, `SysBind`, `SysConnect`, `SysSend`, `SysRecv`, `SysPoll`, `SysResolveHost`, and friends
- `SysGetMemoryStatus` syscall for querying physical/pool/heap usage
- length-tracked string-view syscall ABI with request structs for path/name/text arguments
- printf/debug formatting support for bounded string views via `%v`
- INI-based configuration
- PE import resolution and dynamic `.sys` driver loading
- partial Win32 personality
- partial (stub/microsoft-level) POSIX personality
- self-tests for APCs, async disk I/O, async file I/O, trap frames, and cancellation
- fully GDPR-compliant
- Doom, because priorities matter
## architecture notes
@@ -59,8 +61,7 @@ Single address space for the whole system. No separate kernel/user page tables.
Kernel lives in the higher half. User processes only see what they are explicitly given. Kernel pages are supervisor-only so user-mode code cannot touch them. User pages are isolated from each other through the allocator and process creation path, not by hardware address-space separation. One rogue pointer can't crash the kernel but it might corrupt other processes. But what are the chances?
Is this how a serious modern OS should isolate processes? No.
Is it very convenient while building? Absolutely.
User heap and stack mappings are non-executable, and the PE loader applies final section protections after loading. Writable sections are left writable and non-executable; executable sections are mapped executable without write access where possible.
### execution model
@@ -135,7 +136,11 @@ lwIP TCP/IP network stack
PE images get loaded, imports resolved, then the first thread is queued. `syscall.dll` is the shared syscall entry point, and both personalities go through it.
Scheduler is preemptive and priority-based. Process state and thread state are tracked separately, so a process can die or get reaped without taking the whole system down. `init` can restart things if needed.
String and buffer-heavy syscalls use request structs. Text arguments are passed as bounded `SYS_STRING_VIEW` values, then copied and validated by the kernel before use.
Scheduler is preemptive and priority-based. Process state and thread state are tracked separately, so a process can die or get reaped without taking the whole system down. `init` can restart things if needed. Process objects track termination and exit state separately from individual thread lifetime.
Handles carry rights metadata. Syscalls check both object type and required access for operations such as read, write, wait, signal, query, duplicate, and terminate.
Syscalls build real trap frames. That matters because user APC delivery needs to safely redirect the return path back into user mode and then restore the interrupted context with `SysApcReturn`.
@@ -203,6 +208,8 @@ Port forwarding is enabled by default in `runa.bat` — host port 8080 maps to g
Volumes `0`-`7` are available. A volume only works if a filesystem is registered on it (duh).
The Win32 personality translates drive letters to volume numbers, while the POSIX personality maps volumes onto a tree.
Path parsing is length-aware internally. Embedded NUL bytes are rejected for text paths and names.
## how to build
- open the VS x64 build tools as administrator
@@ -260,11 +267,14 @@ todo
## faq
Q: Why?
A: Learning. Fun. Spite.
A: Reasons.
Q: Does it run Doom?
A: `doom.exe`
Q: If I write a program now, will it run in the future?
A: Not a chance. WE DO in fact BREAK USERSPACE.
Q: Can you read and write files?
A: As far as I'm aware.
@@ -278,10 +288,11 @@ Q: Is the Win32 layer real?
A: Depends how you frame it. Some apps will run, most will not.
Q: Are processes isolated?
A: No. But IPC is free.
A: No. But IPC is free. Is this how a serious modern OS should isolate processes? No.
Is it very convenient while building? Absolutely.
Q: How often does it crash?
A: Less often than before.
A: Like Windows 11.
Q: Can it recover from a crash?
A: Yes. Unless the kernel faulted.