Start the user-space driver track (VFS + IPC + heap). This lays the
process/syscall foundation the runtime heap will grow on.
- Rename usermode.zig -> process.zig; drop the retired hello/ping blob and
its `user` test (subsumed by the real /sbin/init exerciser). Keep the
isolation-proof pf blob and the user-pf test.
- Add danos.Syscall as the single source of truth for syscall numbers, shared
by the kernel dispatcher and (later) the user runtime lib. Dispatch on the
enum. New calls: 1=yield, 4=mmap, 5=munmap. Widen debug_write's bounds
check to the whole user low half so heap buffers are writable.
- mmap grants zeroed RW+NX pages from a per-process bump arena
(Task.heap_next, PML4[224] above image+stack); munmap frees the frames.
Add paging.translateIn / unmapInto (+ arch.translate / unmapUserPageInto)
as the primitives munmap and future cross-AS copies need.
- New `usermem` test: grant three pages into a fresh AS, translate them,
release via the munmap path, tear down, and assert no frames leak.
Suite 28/28 (user -> usermem).
init is now a real scheduled ring-3 process: it prints a heartbeat and
sleeps, forever. The kernel spawns it at boot via spawnProcess (its own
address space, preemption on) and the boot context drops to idle — the
system's steady state is "kernel idle, init alive in ring 3", beating
~1 Hz. Adds the sleep(ms) syscall. The init/process tests are reshaped
around the heartbeat (repeated syscalls, still-alive, two concurrent
processes on distinct address spaces). Pins init to LLD and folds the
.large code model's .ltext/.lrodata/.ldata into the linker script so its
code segment is R+X. Removes the now-dead borrowed-thread ELF loader
(runInitElf); spawnProcess is the one path. Docs updated. Suite 28/28.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-core MSR setup (EFER.SCE, STAR, LSTAR, SFMASK) enables syscall; the
GDT layout was already chosen so sysret lands on CS 0x23 / SS 0x1B. A new
syscall_entry stub swaps in the kernel GS, switches to the task's kernel
stack via the per-CPU block, builds a CpuState frame identical to the
interrupt path's, and reuses interruptDispatch (vector 128) — then
sysretq back. enter_user now also publishes kernel_rsp so the borrowed
path's syscalls land on a good stack. /sbin/init uses the `syscall`
instruction. int 0x80 stays for the test blobs. Suite 27/27.
(Noted in the stub: sysretq #GPs in ring 0 on a non-canonical return
RIP — a hardening item once untrusted user code exists.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ring 3 works: user GDT descriptors (sysret-ready layout), TSS.rsp0,
U/S-bit user mappings (W^X preserved), an int 0x80 syscall gate with a
mutable trap frame, and a setjmp-style enter/exit path. /sbin/init is a
real freestanding Zig binary built from sbin/, shipped on the ESP,
loaded by the bootloader (BootInfo.init_base/len), validated and mapped
by an in-kernel user-ELF loader, and run at CPL 3 — syscalls: exit,
ping, write. Tests: user, user-pf (U/S isolation proof, error code
0x5), init. Suite 27/27.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>