plan: bring the 1.0 register up to date, and file the SMP corruption in Gate 0

The register steers everything and it had drifted. The text-layer row said the
console still indexes font_data[256][16]; it has not for three commits. Half of
that row is closed -- the console draws real TrueType through font_ops -- and
the half that is not (deleting the cell grid) is now its own item rather than
hiding behind the finished one.

The font-from-disk row is restated rather than closed: the typeface is linked
into the kernel on purpose, because a panic during boot has to be readable, so
what is open is a *replaceable* font and not having one at all.

And Gate 0 gains the row it most needs. User processes are corrupted on SMP --
zero faults across three boots at -smp 1, one/three/one at -smp 2, and it takes
schinitd as well as shells. That is exactly the situation Gate 0 exists to
prevent carrying into the compositor: a desktop built on a kernel that randomly
corrupts processes fails indistinguishably from its own bugs. What has been
ruled out is recorded with it, so the next attempt does not repeat the search.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-09-21 21:53:08 +02:00
commit 374ed80096

View file

@ -84,8 +84,8 @@ The galling ones. The work exists, is tested, and nothing uses it.
| | Where it stopped |
|---|---|
| **The text layer** | `kernel/dev/text.c` and `kernel/dev/ttf.c` are 850 lines that rasterise TrueType and draw at any pixel position. The console still indexes `font_data[256][16]`. The only caller is a self-test. |
| **A font from disk** | Same layer, same reason. The console's 8×16 CP437 grid is compiled in. |
| ~~**The text layer**~~ | **Half closed, and the half that closed is the one that mattered.** The console draws real TrueType through `font_ops` now: cells hold a codepoint, the cell size comes from the font's measured advance, and `kernel/dev/ttf.c` has a caller that is not a self-test. What is still unused is `text.c`'s *proportional* path — the console remains a fixed grid. See Gate 0. |
| **A font from disk** | Still true, and now deliberate rather than pending: the console typeface is linked into the kernel image, because a panic during boot has to be readable before there is a filesystem. Loading a *second* font from disk is the open part. |
| **Socket activation** | `schinitd` parses `[Socket name]` and remembers the path. Nothing holds the socket. **This is the entire reason for copying launchd**, and it is the half that was not built. |
| **`display_ops.wait_vblank`** | In the vtable, implemented by the VBE driver, left null by virtio-gpu. A compositor that needs it cannot rely on it. |
@ -191,19 +191,47 @@ right then.
started reading the RTC; the comments outlived the condition. Two errors,
not one — `uptime()` counts 10 ms ticks and they were used as seconds, so
the clocks also ran 100× fast.
- [ ] **User processes are corrupted on SMP.** One to three per boot die with a
fault they could not have caused: `rip 0x0` — an instruction fetch at
zero, which a process does not branch to, it is handed and follows — or a
dereference of `0xffffffffffffffea`, which is `-EINVAL`. **Zero across
three boots at `-smp 1`; one, three and one at `-smp 2`.** It hits
`schinitd` as well as shells.
This is now the most important row in Gate 0, and it is the row Gate 0
was written for: a compositor built on a kernel that randomly corrupts
user processes will fail in ways indistinguishable from its own bugs.
Ruled out: kernel stack depth. That was the leading theory and it was
wrong — raising `KSTACKSIZE` to 8192 changed nothing. The search was
still worth it (the high-water mark really was 3736 of 4096 bytes, and
the AP scheduler stack really was being handed a page it did not own),
but neither was this. Not yet examined: TLB coherence when a page table
is changed on one CPU while the process runs on another, `kalloc`'s free
list under contention, and the buffer cache.
- [ ] **`getrusage` does not distinguish `RUSAGE_CHILDREN`** from `RUSAGE_SELF`.
- [ ] **`/proc/<pid>/exe` is a regular file, not a symlink**, so `readlink()`
fails and `ps -o comm` prints `[init]`. Needs symlink support in procfs.
fails and `ps -o comm` prints `[init]`. Symlinks themselves now work —
`open()` and `stat()` follow them, which they never did — so what is left
is procfs growing a symlink node type, not symlink support.
- [ ] **OVMF memory reporting**, if the region-list fix did not fully close it.
**Work already done and not connected:**
These are the galling ones — the replacement exists, is tested, and is unused.
- [ ] **Port the console onto the text layer and delete the cell grid.**
`text.c` and `ttf.c` both exist and work. The console still indexes
`font_data[256][16]`.
- [ ] **Load a font from disk** and point the console at it.
- [x] ~~**Point the console at a real typeface.**~~ It draws JetBrains Mono
through `font_ops` and `ttf.c`. The blocker was not the font: `vtcell.ch`
was **one byte** holding a CP437 index, so `Ą` (U+0104) could not be
*stored*, whatever was drawing it. The cell is a `uint32` codepoint now
and the cell size comes from the font's measured advance.
- [ ] **Delete the cell grid.** The other half of the original item, and still
open. The console is a fixed grid of codepoints; `text.c`'s proportional
path has no caller. Nothing needs this before the compositor, which is
why it is separated from the row above rather than left blocking it.
- [ ] **Load a font from disk** and point the console at it. The built-in one
is linked in on purpose — an early panic has to be readable — so this is
about a *replaceable* font, not about having one.
- [x] ~~**Interrupt-driven receive.**~~ The e1000's handler calls
`netdev_rx_signal()`, which ends the network thread's wait early; the frame
is still *pulled* by the thread, because an interrupt handler can neither