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:
+26
-18
@@ -8,7 +8,7 @@ natural unit because that's the granularity the CPU's paging hardware maps — a
|
||||
it is the primitive everything above it stands on: page tables, the kernel heap,
|
||||
per-process memory all ultimately ask the frame allocator for pages.
|
||||
|
||||
It's **generic kernel code**: it operates on the neutral `system.MemoryRegion`
|
||||
It's **generic kernel code**: it operates on the neutral `boot_handoff.MemoryRegion`
|
||||
array, so there's no UEFI in it and nothing architecture-specific beyond the 4 KiB
|
||||
page. (Contrast [architecture.md](architecture.md), which is where CPU-specific code lives.)
|
||||
|
||||
@@ -38,16 +38,18 @@ and a `next_hint` marking where the next allocation scan should start.
|
||||
|
||||
### init(map) — building it from the memory map
|
||||
|
||||
1. **Size it.** Find the highest address across all `usable` regions;
|
||||
`total_frames = highest / page_size`. Reserved and MMIO spans above that
|
||||
(remember the ~12 GiB of MMIO from [memory-map.md](memory-map.md)) sit *outside*
|
||||
the bitmap and are simply never allocatable.
|
||||
1. **Size it.** Find the highest address across all RAM regions — every kind
|
||||
*except* `mmio` — so reserved and ACPI spans sit *inside* the bitmap, marked
|
||||
used but trackable (e.g. so the boot buffers can be freed later);
|
||||
`total_frames = highest / page_size`. Only MMIO (device address space —
|
||||
remember the ~12 GiB of it from [memory-map.md](memory-map.md)) sits outside
|
||||
the bitmap and is simply never allocatable.
|
||||
2. **Place it (the bootstrap).** The bitmap needs storage before an allocator
|
||||
exists — a chicken-and-egg. Solution: pick the first `usable` region big enough
|
||||
to hold the bitmap and put it there, addressing it directly as a pointer. That
|
||||
last part relies on the firmware's **identity mapping** still being in effect
|
||||
(physical address == virtual address), which holds until the kernel installs
|
||||
its own page tables.
|
||||
to hold the bitmap and put it there, addressing it through the **physmap**
|
||||
(`boot_handoff.physicalToVirtual`). The loader's bootstrap page tables already
|
||||
provide the physmap and the kernel's own tables keep it, so the pointer stays
|
||||
valid across the paging switch.
|
||||
3. **Mark, then free.** Set the whole bitmap to `used` (`0xff`), then walk the
|
||||
`usable` regions clearing their bits. Doing it in that direction means every
|
||||
gap, reserved span, and hole is unallocatable *by default* — we only ever hand
|
||||
@@ -73,10 +75,13 @@ free, or one out of range) are ignored rather than corrupting the used count.
|
||||
|
||||
- **Generic walk.** Because `MemoryRegion` is danos's own type, the map is a plain
|
||||
slice — none of the variable descriptor-stride from the raw UEFI map.
|
||||
- **Identity mapping assumption.** Placing the bitmap by physical address only
|
||||
works while the firmware's identity map is live. When danos sets up its own
|
||||
paging, the bitmap (and any other physical pointer) will need an explicit
|
||||
mapping. This is a deliberate, documented dependency of this stage.
|
||||
- **Physmap addressing.** The bitmap (and the region array) is reached through
|
||||
the physmap via `boot_handoff.physicalToVirtual`, which both the loader's
|
||||
bootstrap tables and the kernel's own tables provide — no remapping is needed
|
||||
when danos switches to its own paging. The one invariant: the bitmap must sit
|
||||
under the bootstrap physmap's reach (4 GiB), which holds because the placement
|
||||
scan (step 2 above) runs from the lowest usable region up and takes the first
|
||||
one big enough — on the supported configurations that lands well under 4 GiB.
|
||||
- **Frame 0 is reserved** so `0` stays a safe "none" sentinel — and the bitmap is
|
||||
never placed there. (An early bug did exactly that: a `usable` region at physical
|
||||
address 0 collided with a `0`-means-not-found sentinel and tripped a panic. The
|
||||
@@ -90,12 +95,15 @@ free, or one out of range) are ignored rather than corrupting the used count.
|
||||
`kmain` brings the allocator up and self-tests it. Booted in QEMU with 128 MiB:
|
||||
|
||||
```
|
||||
danos: frame allocator online
|
||||
free frames: 19751 (77 MiB) <- matches the map's 77 MiB usable
|
||||
alloc x3 : 0x2000 0x3000 0x4000 <- frame 0 reserved, bitmap at 0x1000, so allocs start at 0x2000
|
||||
after free : 19751 frames free <- three freed, count restored
|
||||
/system/kernel: frame allocator online
|
||||
free frames: 30520 (119 MiB) <- matches the map's 119 MiB usable
|
||||
alloc x3 : 0x3000 0x4000 0x5000 <- frame 0 reserved, bitmap at 0x1000, AP trampoline at 0x2000
|
||||
after free : 30520 frames free <- three freed, count restored
|
||||
```
|
||||
|
||||
(The AP-trampoline page is claimed with `allocBelow` right after `init`, before
|
||||
the demo allocations — hence they start at 0x3000.)
|
||||
|
||||
The `free frames` MiB agreeing with the memory map's `usable RAM`, the three
|
||||
distinct consecutive addresses, and the count returning to its start after freeing
|
||||
are the three signals that init, alloc and free are all correct.
|
||||
@@ -103,7 +111,7 @@ are the three signals that init, alloc and free are all correct.
|
||||
## Boot-services memory comes pre-reclaimed
|
||||
|
||||
The UEFI boot-services memory (~44 MiB) is defunct and free once
|
||||
`ExitBootServices` runs, taking usable RAM from ~76 MiB up to ~121 MiB. The frame
|
||||
`ExitBootServices` runs, taking usable RAM from ~76 MiB up to ~119 MiB. The frame
|
||||
allocator does **nothing special** to get it: the loader already classified it as
|
||||
`usable` (see [memory-map.md](memory-map.md)), so it's just part of the `usable`
|
||||
regions `init` frees. Keeping that boot-protocol knowledge on the loader side is
|
||||
|
||||
Reference in New Issue
Block a user