SchOS/.claude/memory
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Nexoniarz 3185685997 syscall: three globals on the entry path, shared by every CPU
One to four processes died per boot with a fault they could not have caused:
`rip 0x0` -- an instruction fetch at zero, which a process does not branch to
-- or a dereference of `0xffffffffffffffea`, which is `-EINVAL`. It hit shells
and schinitd alike and had been carried for a long time as "zsh sometimes jumps
into .data".

`syscall_entry` has to swap FS_BASE from the user's TLS to the kernel's before
it can touch any `%fs:` data, and `wrmsr` destroys rax, rcx and rdx. Those have
to be parked somewhere first -- not on the user stack, which is untrusted and
has not been switched away from yet. They were parked in three globals:

    // Single-CPU scratch for syscall_entry FS swap
    // (safe while IF cleared by SYSCALL/SFMASK)
    uint64 _sc_rax, _sc_rcx, _sc_rdx;

IF being clear answers for an interrupt arriving on *this* CPU. It says nothing
whatever about a second CPU executing the same three stores at the same
instant, and with more than one processor entering syscalls that is not a rare
interleaving -- it is the ordinary one.

**%rcx is the user return address.** SYSCALL puts the user's rip there and
SYSRET takes it back from there. So the CPU that lost the race returned its
process into *another process's* instruction stream, with %rax -- the syscall
number on the way in, the return value on the way out -- swapped alongside it.
Both symptoms fall straight out of that: a zero handed over and followed, and
an errno used as a pointer.

Per-CPU words at %gs:32..48 now. %gs is usable there, before the FS swap, for
exactly the reason RESTORE_KERNEL_FS can already read %gs:0: GS base is per-CPU
in hardware, seginit() sets it once, and userspace cannot change it --
sys_arch_prctl() implements ARCH_SET_FS and ARCH_GET_FS and rejects the rest.

Measured rather than argued. Both variants built once, `build/esp` saved for
each, the same pristine schfs.img restored before every boot, -smp 4:

    three globals     10 boots    10 faults, in five of the ten
    three per-CPU     18 boots     0 faults

A _Static_assert pins all seven per-CPU offsets, because trapasm.S spells them
as literals and cannot include a header -- a slot that moves would leave a
register quietly holding somebody else's value, which is the hardest possible
thing to find.

**This is the second bug of this exact shape in this file.** The first was
`kernel_fs_base`, a single global every CPU wrote during its own seginit(), so
the last writer won and every CPU restored one CPU's per-CPU block;
RESTORE_KERNEL_FS reads %gs:0 for that reason. The lesson generalises and is
now written down in both places: **on the entry path, a global is a bug.**

Closes the row added to Gate 0 four commits ago. It was the right row to put
first -- a compositor built on this would have failed in ways indistinguishable
from its own bugs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 22:56:45 +02:00
..
MEMORY.md memory: the SMP crash is SMP-only, and what the font work cost 2026-09-21 21:05:52 +02:00
nexoniarz-sharing-preference.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schcom-v0.md memory: Schcom v0, and the order change that put it before the installer 2026-08-09 23:12:56 +02:00
schfs-btree-phase1.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schfs-next-and-platform-roadmap.md memory: the SchFS and platform roadmap, and the 614 MB ceiling 2026-08-10 18:53:32 +02:00
schfs-phase2-mount.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schfs-phase3-writes.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schfs-v2-and-ramdisk.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schos-boot-split.md memory: schinit and the BIOS/UEFI split 2026-08-09 16:36:54 +02:00
schos-bootcheck-trust.md Rebuild when RAMROOT is toggled, and add an opt-in KVM target 2026-08-09 22:46:00 +02:00
schos-cross-platform-build.md Rewrite run.ps1; it was five kinds of stale 2026-08-09 14:49:47 +02:00
schos-fedora-move-bugs.md Fix two bugs the Fedora move exposed 2026-08-09 19:29:21 +02:00
schos-linux-machine.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schos-memory-sync.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schos-performance-and-init.md memory: performance, init signal safety, and trusting the harness 2026-08-09 15:55:11 +02:00
schos-rename-and-git.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schos-schinit.md memory: schinit and the BIOS/UEFI split 2026-08-09 16:36:54 +02:00
schos-smp-userspace-corruption.md syscall: three globals on the entry path, shared by every CPU 2026-09-21 22:56:45 +02:00
schos-uefi-loader.md Rebuild when RAMROOT is toggled, and add an opt-in KVM target 2026-08-09 22:46:00 +02:00
schunix-boot-splash-logo.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-build-environment.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-build-speed.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-console-tty.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-crash-screen.md branding: one mark, and PSOGM draws it 2026-09-21 21:35:58 +02:00
schunix-devfs-procfs.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-device-model.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-dirsiz-14.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-doom-acceptance-test.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-driver-infrastructure.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-e1000-and-driver-layout.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-framebuffer-device.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-ioremap-and-bars.md memory: UEFI reaches userspace, and the ISO grows a hierarchy 2026-08-09 22:04:12 +02:00
schunix-iso-boot.md memory: the installer is scoped, and the live CD is off the list 2026-08-09 22:20:20 +02:00
schunix-layout-migration.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-licensing.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-linux-abi-decision.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-linux-open-flags.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-network-stack-choice.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-pci-drivers.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-qr-encoder.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-ramdisk-root-sizing.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-rewrite-priorities.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-roadmap-and-projects.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-schapi-direction.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-shm-and-mmap.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-smp-and-memory-bugs.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-sockets-and-evdev.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-syscall-single-table.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-text-rendering.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-ttf-rasteriser.md memory: the SMP crash is SMP-only, and what the font work cost 2026-09-21 21:05:52 +02:00
schunix-tty-fg-pgrp-coupling.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-usb-ids.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-usb-xhci.md docs: four directories, and a rule for when a thing leaves the roadmap 2026-09-12 17:13:35 +02:00
schunix-verify-by-driving-shell.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-virtio-gpu.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00
schunix-wall-clock.md Carry project memory in the repo, with tools/memory-sync.sh 2026-08-09 14:27:22 +02:00