docs: full docs-vs-code audit — fix every stale claim across 40 docs

Every doc verified claim-by-claim against the code by parallel audit agents,
then fixed and adversarially re-verified. Two waves of staleness corrected:
the originally audited findings (higher-half boot handoff, kernel VFS
takeover, fault isolation + claim release + driver restart, AML/S5 moving to
ring 3, threading's shipped design, USB+FAT landing) and a second pass of
adjacent claims the verifiers caught (smp.md 'not built yet' intro,
system-requirements' PS/2-only and no-storage claims, halting.md's red-panic
and no-IDT text, testing.md's serial mirroring, router-era vfs-protocol
wording, capsule-first boot loading).

threading.md now documents the shared-fate gap explicitly: the design says a
process dies whole, the kernel today kills only the offending thread.

Also fixes three stale code comments (isr.s exceptionHandler, acpi.zig
sleepValue, build.zig boot-volume) — comments only, no behavior change.
This commit is contained in:
Daniel Samson
2026-07-22 09:09:53 +01:00
parent 52df2ba6f6
commit e854f65623
43 changed files with 821 additions and 546 deletions
+13 -8
View File
@@ -14,8 +14,12 @@ behind the [architecture](architecture.md) boundary in `system/kernel/architectu
x86_64 uses **4 levels**: PML4 → PDPT → PD → PT, each a 512-entry table, with 9
bits of the virtual address indexing each level and the low 12 bits the offset into
the final 4 KiB page. Each entry holds a physical address plus flag bits —
present, writable, and (bit 63) **no-execute**. danos maps everything with 4 KiB
pages: precise, and the extra table memory is negligible against available RAM.
present, writable, and (bit 63) **no-execute**. danos maps nearly everything with
4 KiB pages: precise, and the extra table memory is negligible against available
RAM. (The physmap has since become the one exception: 2 MiB-aligned RAM there is
mapped with **2 MiB huge pages** — a PS-bit leaf at the PD level — with 4 KiB
pages filling the unaligned edges, so the table footprint scales sanely with big
RAM. Kernel segments, heap, user space, and on-demand MMIO stay 4 KiB.)
## Higher half: the address-space layout
@@ -27,7 +31,7 @@ address to the low load address in its bootstrap tables and jumps in). The entir
alongside a **physmap** — a straight window onto all of physical memory at
`physmap_base + phys`. Wherever the kernel needs to touch a physical address (a
page-table frame, an ACPI table, a device register), it adds that constant:
`system.physToVirt(phys)`. The layout constants live in `system/boot-handoff.zig`:
`boot_handoff.physicalToVirtual(phys)`. The layout constants live in `system/boot-handoff.zig`:
| region | virtual base | PML4 slot |
|--------|--------------|-----------|
@@ -46,7 +50,7 @@ builds its own precise tables below and abandons them. Because both use the same
The address space is built in four passes (`init`):
1. **All RAM in the physmap, RW + NX.** Every non-MMIO region from the
[memory map](memory-map.md) is mapped at `physToVirt(phys)`, read-write and
[memory map](memory-map.md) is mapped at `physicalToVirtual(phys)`, read-write and
*non-executable*. There is **no low/identity mapping** — the low half is user
space. (Frames the kernel touches while still building these tables are reached
through the loader's bootstrap physmap, which covers the low 4 GiB; both the
@@ -72,7 +76,7 @@ Blanket RW+NX is fine for data but wrong for the kernel's own code, which must b
executable — and its code must *not* be writable (W^X: no page is both). We get the
right permissions per region straight from the kernel ELF: the **loader already
parses the program headers**, so `efi.zig` records each `PT_LOAD` segment's
address, size and R/W/X flags into `BootInfo`. Pass 3 re-maps those ranges with
address, size and R/W/X flags into `BootInformation`. Pass 3 re-maps those ranges with
flags derived from the ELF flags:
| segment | ELF flags | mapped as |
@@ -97,9 +101,10 @@ real memory — turning a whole class of silent bugs into an immediate, located
## Switching on, and the on-demand API
Loading the PML4's physical address into **CR3** switches address spaces and
flushes the TLB in one step. This works because the firmware's identity map is
still active *while we build*, so freshly allocated table frames are reachable by
physical address; afterwards they're covered by pass 1.
flushes the TLB in one step. This works because *while we build* the kernel is
still running on the loader's bootstrap tables, whose 4 GiB physmap makes freshly
allocated table frames reachable at the same `physmap_base + phys` addresses;
afterwards they're covered by pass 1.
`init` keeps the PML4 and the frame allocator around and exposes `map(virt, phys,
writable)` / `unmap(virt)` (with `invlpg` TLB invalidation) — the primitive the