diff --git a/issues/boot-media/a-memory-overwrite-request-ubuntu-left-set-stays-set-under-toyos.md b/issues/boot-media/a-memory-overwrite-request-ubuntu-left-set-stays-set-under-toyos.md new file mode 100644 index 00000000000..198f227bf65 --- /dev/null +++ b/issues/boot-media/a-memory-overwrite-request-ubuntu-left-set-stays-set-under-toyos.md @@ -0,0 +1,39 @@ +--- +status: open +kind: defect +opened: 2026-10-04 +--- + +# A memory-overwrite request Ubuntu left set stays set under ToyOS + +The owner's ruling "Keep crash records" (2026-10-03, +`issues/diagnostics/toyos-explains-itself.md`) has ToyOS not ask the firmware +to wipe memory at reset. On the T14 the request is already made: under its +Ubuntu (`6.8.0-142-generic`), whose EFI stub sets it on every boot +(`issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md`), + +``` +ls /sys/firmware/efi/efivars/ | grep -i -E "MemoryOverwrite|MOR" +for f in /sys/firmware/efi/efivars/MemoryOverwriteRequestControl*; do [ -e "$f" ] && { echo "$f"; od -An -tx1 "$f"; }; done +``` + +read `07 00 00 00 01` for `MemoryOverwriteRequestControl` and `07 00 00 00 00` +for `MemoryOverwriteRequestControlLock`: efivarfs's four attribute bytes +(non-volatile, boot-service and runtime access), then the value: the request +0x01, set, and its lock 0x00, unlocked. The variable is +non-volatile, so it stays set into every ToyOS boot that follows Ubuntu, and +`bootloader/src` neither reads nor writes it. Whether this firmware honours it +on the reset paths ToyOS takes is unmeasured: a black-box record has survived +two hours of Ubuntu, which does not say what an unclean reset does. Every +UEFI call ToyOS makes is the loader's, so the write belongs with +`issues/boot-media/the-loader-does-only-what-must-precede-the-handover.md`. + +**Exit**: where the firmware defines `MemoryOverwriteRequestControl` and it +reads non-zero, the loader writes 0 before `ExitBootServices` and logs the +value it found; where the firmware defines none, it makes no `SetVariable` +call under that GUID. A guest test on a fresh OVMF variable store planted with +1 reads 0 after the loader's pass, and one planted with nothing finds no +variable under the GUID; deleting the write reds the first, and an +unconditional write reds the second. On the T14, a boot that finds it set +logs the 1 it found, and a black-box record sealed by a forced reset of that +boot is read by the next. diff --git a/issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md b/issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md index 8520f027d76..b7e313b5516 100644 --- a/issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md +++ b/issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md @@ -1,6 +1,6 @@ --- -status: open -kind: defect +status: none +kind: rejected opened: 2026-09-29 --- @@ -13,26 +13,17 @@ At `Ubuntu-6.8.0-142.142`, the x86 EFI stub runs `MemoryOverwriteRequestControl`=1 under vendor `e20939be-32d4-41be-a150-897f85d49829` (`drivers/firmware/efi/libstub/tpm.c:20-21`) so firmware wipes RAM -on the next boot after an unclean reset. That function first reads the -existing variable and returns without writing when the firmware has none -defined (`tpm.c:36-40`), and it never inspects -the status of the `set_efi_var` call it does make (`tpm.c:42-45`). -`bootloader/src` writes no variable under this GUID at all. +on the next boot after an unclean reset, where the firmware already defines +the variable (`tpm.c:36-40`). `bootloader/src` writes no variable under this +GUID. -Root `CLAUDE.md`'s firmware rule puts every UEFI call ToyOS makes in the -loader, before `ExitBootServices`: the write is a `SetVariable` there, and -belongs with -`issues/boot-media/the-loader-does-only-what-must-precede-the-handover.md`. +**Declined** (owner, 2026-10-03): **"Keep crash records"**. ToyOS does not ask +the firmware to wipe memory at reset; crash records survive a reset in RAM +(`issues/diagnostics/toyos-explains-itself.md`). So ToyOS stays below Linux on +this one line of +`issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md`: +whoever resets a ToyOS machine into a boot medium of their own can read what +the last boot left in RAM. -**Exit**: on firmware that already defines `MemoryOverwriteRequestControl`, -the loader sets it to 1 before `ExitBootServices` and does not act on whether -the write succeeded; on firmware that does not define it, the loader performs -no `SetVariable` call under that GUID. The guest test `mor_is_set_where_defined` -has two boots, each on a fresh OVMF `VARS`. The first plants -`MemoryOverwriteRequestControl`=0 under that GUID with `vars::plant` -(`tests/common/update.rs`), boots, and asserts `vars::live` reads it as 1; -both helpers take only the anti-rollback floor's vendor today, so they gain -the vendor as an argument. The second plants nothing and asserts no variable -exists under that GUID afterward. Deleting the loader's `SetVariable` leaves -the planted 0 and reds the first boot; dropping its read of the variable -first makes the write unconditional and reds the second. +A request already set by another system is a different matter: +`issues/boot-media/a-memory-overwrite-request-ubuntu-left-set-stays-set-under-toyos.md`. diff --git a/issues/build/a-metal-judge-takes-a-names-lowest-pid-for-the-job.md b/issues/build/a-metal-judge-takes-a-names-lowest-pid-for-the-job.md index dd9cf30e3a0..261a81fe34b 100644 --- a/issues/build/a-metal-judge-takes-a-names-lowest-pid-for-the-job.md +++ b/issues/build/a-metal-judge-takes-a-names-lowest-pid-for-the-job.md @@ -13,7 +13,7 @@ job before the job spawned anything. The kernel does not issue pids in landing order. A spawn refused after its admission gives its pid back, and the next admission takes it -(`toyos_proclife::pids`). A spawn admitted before a job and refused after the +(`kernel::proclife::pids`). A spawn admitted before a job and refused after the job landed hands a pid below the job's to the next spawn, and if that is the job's child of the same name the judge reads the child's exit as the job's. diff --git a/issues/build/a-settled-thread-join-taking-the-table-lock-again-is-gated-by-nothing.md b/issues/build/a-settled-thread-join-taking-the-table-lock-again-is-gated-by-nothing.md index e61c9f7c81b..9bb8a169122 100644 --- a/issues/build/a-settled-thread-join-taking-the-table-lock-again-is-gated-by-nothing.md +++ b/issues/build/a-settled-thread-join-taking-the-table-lock-again-is-gated-by-nothing.md @@ -6,7 +6,7 @@ opened: 2026-09-28 # A settled thread join taking the table lock again is gated by nothing -`toyos_proclife::join::Join::ask` calls its `collect` only while the join is +`kernel::proclife::join::Join::ask` calls its `collect` only while the join is unsettled, and `a_settled_join_does_not_take_the_table_again` holds that. Whether `collect` is where the kernel takes `PROCESS_TABLE` is `kernel/src/process.rs`'s `ask_join`, in no crate a host test compiles. PR diff --git a/issues/build/clippy-stage-two-is-lints-one-at-a-time.md b/issues/build/clippy-stage-two-is-lints-one-at-a-time.md index cc889c0c357..806aca4bb7f 100644 --- a/issues/build/clippy-stage-two-is-lints-one-at-a-time.md +++ b/issues/build/clippy-stage-two-is-lints-one-at-a-time.md @@ -48,7 +48,7 @@ the group). | lint | count | why | |---|---:|---| | `checked_conversions` | 1 | `4a98107f^:kernel/src/arch/syscall.rs`'s device-register-write syscall bounded a `u64` against `u32::MAX` with a manual `as` comparison, then cast twice more in the body. Restructured through `u32::try_from` — one conversion, no repeated casts, at a trust-boundary site that is exactly what this bar is for. | -| `manual_midpoint` | 3 | `(a + b) / 2` can overflow near the integer's max; `T::midpoint` can't. Two in a `toyos-desktop` test, one in `toyos-sched/sim`'s binary-search shrinker — no realistic overflow today, but the fix is free and closes the class everywhere, forever. | +| `manual_midpoint` | 3 | `(a + b) / 2` can overflow near the integer's max; `T::midpoint` can't. Two in a `toyos-desktop` test, one in `kernel/sim`'s binary-search shrinker — no realistic overflow today, but the fix is free and closes the class everywhere, forever. | | `redundant_clone` | 6 | Real, not the false-positive-prone lint its `nursery` placement suggested — every instance checked was a clone of a binding never used again after (verified by hand, not by trusting the lint): `4a98107f^:kernel/src/arch/syscall.rs`, a `kernel-loom` test, `toyos-cc`'s parser (a double clone — the match scrutinee was already an owned value), and three in `tests/toyos.rs`. | | `unchecked_time_subtraction` | 1 | `tests/toyos.rs`: a bare `Duration - Duration` that panics identically today either way — `.checked_sub().expect(msg)` says why it can't underflow instead of hiding the same panic behind an operator. No behavior change; an honesty win at zero cost. | | `unnecessary_semicolon` | 2 | Two dead `;` after `if` statements in `kernel/src/process.rs` and `kernel/src/main.rs`. Nothing to weigh. | diff --git a/issues/build/parallel-tests-red-under-other-suites.md b/issues/build/parallel-tests-red-under-other-suites.md index bdb5567824f..386f8380d6f 100644 --- a/issues/build/parallel-tests-red-under-other-suites.md +++ b/issues/build/parallel-tests-red-under-other-suites.md @@ -163,7 +163,7 @@ changes. of its own — five sightings, each carrying the *guest's own panic text* — and that class has since been diagnosed and fixed: a CPU could hand a thief the task whose context it was still standing on, so two CPUs ran one kernel stack - (`SchedPass::answer_steal_requests`, `toyos-sched/src/cpu.rs`). This sighting + (`SchedPass::answer_steal_requests`, `kernel/pure/sched/cpu.rs`). This sighting carried no console at all — `TestResult::error` held the verdict, a failing test's guest console is not printed, and by the time the re-runs were green the capture was gone — so it can be neither confirmed as that class nor ruled diff --git a/issues/build/the-two-watch-poll-model-counts-a-dropped-watchs-answer-as-its-completion.md b/issues/build/the-two-watch-poll-model-counts-a-dropped-watchs-answer-as-its-completion.md index 899c9c18517..4e131baa43e 100644 --- a/issues/build/the-two-watch-poll-model-counts-a-dropped-watchs-answer-as-its-completion.md +++ b/issues/build/the-two-watch-poll-model-counts-a-dropped-watchs-answer-as-its-completion.md @@ -6,7 +6,7 @@ opened: 2026-09-30 # The two-watch poll model counts a dropped watch's answer as its completion -`toyos-sched/loom/tests/loom_watch.rs`'s +`kernel/loom/tests/loom_watch.rs`'s `a_poll_on_two_watches_racing_both_posts_completes_exactly_once` moves both worlds into their producer threads, so both watches drop before its assertion, and a watch's drop fires every live entry as `Fire::Gone`, which the model's diff --git a/issues/build/the-update-rig-the-guest-cut-deleted-is-still-cited.md b/issues/build/the-update-rig-the-guest-cut-deleted-is-still-cited.md index 52745ef69bb..218017c7ecc 100644 --- a/issues/build/the-update-rig-the-guest-cut-deleted-is-still-cited.md +++ b/issues/build/the-update-rig-the-guest-cut-deleted-is-still-cited.md @@ -9,7 +9,7 @@ opened: 2026-10-03 #660 (`06788146b`) deleted `tests/common/update.rs` with its `Rig`, `tests/common/fwvars.rs` and `tests/updatecase/system.toml`. `git grep -n 'fwvars\|updatecase\|common/update\.rs\|Rig::\|vars::plant\|vars::live'` finds -nine lines in three files, each planning or describing a test on them: +seven lines in two files, each planning or describing a test on them: - `issues/boot-media/the-loader-does-only-what-must-precede-the-handover.md`, six lines. Stage 3's exit takes `fwvars::live` as @@ -17,9 +17,6 @@ nine lines in three files, each planning or describing a test on them: `tests/updatecase/system.toml` grants `slots` and that two tests run `updatecase`; one of its negative controls signs with `Rig::update` and reads the floor with `fwvars::live`, which its oracles name too. -- `issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md`, - two lines: its exit's `mor_is_set_where_defined` plants and reads the vars - store with `vars::plant` and `vars::live`. - `issues/build/the-kernel-console-split-does-not-re-arm-across-a-guest-reset.md`, one line: the reset in place it describes is `Rig::boot`'s. diff --git a/issues/design-debt/redesign-the-log-subsystem.md b/issues/design-debt/redesign-the-log-subsystem.md index c3d4a99a434..e49abb550e2 100644 --- a/issues/design-debt/redesign-the-log-subsystem.md +++ b/issues/design-debt/redesign-the-log-subsystem.md @@ -17,6 +17,11 @@ names nothing that will land. The directory re-shape is a scheduling matter exactly as priced below: one clean pass in a window with few worktrees in flight, and never interleaved with a code change. +The log is a pillar of `issues/diagnostics/toyos-explains-itself.md`, and +its ring is +`issues/kernel/logging-records-from-every-producer-and-a-kernel-that-waits-on-nobody.md`'s; +this file holds the sinks and the layout. + The target shape stands as reviewed: a log core (ring + context stamping, once) with serial, file and screen as independent sinks carrying explicit backpressure — a slow sink drops-and-counts, never blocks, does no unbounded diff --git a/issues/design-debt/what-is-owed-on-file-size.md b/issues/design-debt/what-is-owed-on-file-size.md index c4dfc1547be..28256e6b61d 100644 --- a/issues/design-debt/what-is-owed-on-file-size.md +++ b/issues/design-debt/what-is-owed-on-file-size.md @@ -46,7 +46,7 @@ what survives it is a different question. no function body changed. The split made two facts visible and filed: 58 refusal `return`s exit past the epilogue, and a refused syscall is counted but not timed. -- `process.rs` — the lifecycle state machine is `toyos-proclife/` (pure, +- `process.rs` — the lifecycle state machine is `kernel/pure/proclife/` (pure, `forbid(unsafe_code)`, every interleaving of a scripted pair of paths enumerated; #142's mechanism class now has a host reproduction). Three subjects are still decided inside the file and reachable only by a booted diff --git a/issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md b/issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md index 9522e85abcd..0a346c25365 100644 --- a/issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md +++ b/issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md @@ -8,13 +8,16 @@ opened: 2026-07-30 `kernel/src/trace.rs` is a per-CPU ring of `RING_CAPACITY` 24-byte `repr(C)` records, enabled from `main.rs` at boot and written by the timer, the -scheduler, `irq_ring` and every `toyos_sched::hw::TraceEvent` the core emits. +scheduler, `irq_ring` and every `kernel::sched::hw::TraceEvent` the core emits. Its one reader is LLDB: `p &TRACE_RINGS` and then `memory read`, which is why the discriminants are fixed by hand and held there by const assertions. A booted machine can ask itself nothing: no syscall, no tool, no gate. -**Ruled** (owner, 2026-10-03): the ring is finished in three steps, and the -work then stops and is judged before anything more is built on it. +Part of `issues/diagnostics/toyos-explains-itself.md`. + +**Proposal accepted** (owner, 2026-10-03, "Build it as proposed"): the ring +is finished in three steps, and the work then stops and is judged before +anything more is built on it. 1. **The ring is readable**: the log's slot protocol, raw counter stamps, `SYS_TRACE_READ` in the shape of the log's read, the `trace` right it @@ -27,9 +30,14 @@ work then stops and is judged before anything more is built on it. pick events, with no tracer in the kernel. **Exit**, on the T14: the 50 ms for which `hold_once` keeps both windows open once a boot (`kernel/src/windows.rs`) reads back as at least that much lateness. -3. **Windows over a threshold, and shootdown records.** **Exit**: `SYS_DEBUG`'s +3. **Windows over a threshold, shootdown records, and slow system calls.** + A system call over the threshold is recorded with its number and its + program, in the shipped kernel: **"Always on"** (owner, 2026-10-03). + **Exit**: `SYS_DEBUG`'s shootdown-acknowledgement delay names the delayed CPU and its time in the - trace. A window's record names its opener by address, which + trace. A system call held past the threshold in a shipped-configuration + kernel reads back from the trace with its number and its program. A + window's record names its opener by address, which `issues/kernel/the-cpu-that-spawns-a-toybox-applet-reads-1-4-ms-of-interrupts-and-preemption-off-on-the-t14.md` and `issues/kernel/the-supervisors-claim-of-a-pci-function-the-t14-lacks-holds-interrupts-off-for-3-8-ms.md` @@ -39,13 +47,16 @@ Behind that judgement, and not before it: interrupt enter and exit records with a noise reader, the profiling sample, and the censuses moved onto the ring. -The lines he drew: +The proposal's other lines, accepted with it: - The ring stays always written in the shipping kernel. - Reading it needs a new `trace` right. -- The reader tool is not in the shipped image. - The LLDB reading path and its pinned numbers go. - A T14 judge may read a binary trace file, the decoder printing the lines a pull request quotes. - The profiling sample shares the ring. - 2 MiB of rings at eight CPUs is accepted. + +The reader ships with ToyOS, in the owner's words (2026-10-03): "its obvious +that we want to be able to understand kernel metrics from within toyos ... +thats an important and productive tool that should be shipped with toyos." diff --git a/issues/diagnostics/the-kernel-keeps-nothing-it-enumerates.md b/issues/diagnostics/the-kernel-keeps-nothing-it-enumerates.md index 4a34a411442..0d4e7bbf256 100644 --- a/issues/diagnostics/the-kernel-keeps-nothing-it-enumerates.md +++ b/issues/diagnostics/the-kernel-keeps-nothing-it-enumerates.md @@ -11,6 +11,10 @@ goes for NVMe Identify strings, USB INQUIRY strings, the GPT table and mount metadata. There is no `hw` and no `disk`, because there is nothing for them to read. Retention is the bulk of this work and it is blocked on nothing. +`inspect` is a pillar of `issues/diagnostics/toyos-explains-itself.md`. The +orchestrator's plan, not ruled: a `kernel.*` root rendered from the counters +and a `supervisor.*` root from the program table. + On top of retention, in dependency order: 1. **Retention plus one query syscall and a topic decoder**, with `hw` and diff --git a/issues/diagnostics/toyos-explains-itself.md b/issues/diagnostics/toyos-explains-itself.md new file mode 100644 index 00000000000..a1f9badb6f1 --- /dev/null +++ b/issues/diagnostics/toyos-explains-itself.md @@ -0,0 +1,83 @@ +--- +status: open +kind: track +opened: 2026-10-04 +--- + +# ToyOS explains itself: log, diary, counters, accounting, inspect, sizes and post-mortem + +ToyOS answers what it is doing, what it did and what it is made of from +inside itself, with programs it ships. Today the answers are scattered: the +log carries numbers in prose (`irq:`, `tlb:`, `PMM:`, `sched:`, `syscalls:`), +the trace ring has LLDB as its only reader, nothing reads APERF, MPERF, +`MSR_SMI_COUNT`, RAPL or C-state residency, a process's memory is a byte sum +that reads 0 under contention, and a user symbol is resolved by the kernel. +Each pillar's own track carries its steps and its exits; this track holds the +counters and sizes pillars, which no other track does. + +## The owner's rulings (2026-10-03) + +- On the diary's reader: "its obvious that we want to be able to understand + kernel metrics from within toyos ... thats an important and productive tool + that should be shipped with toyos." +- **"Keep crash records"**: ToyOS does not ask the firmware to wipe memory at + reset, and crash records survive a reset in RAM + (`issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md`). +- **"Only with permission"**, the option he chose: "A program needs a + permission to read counters; the revealing ones (power, per-device + interrupts) need the strict diary permission. Admin tools get them; ordinary + programs and the toolbox don't until each program can be granted rights on + its own." +- **"General counters"**: the firmware-interrupt (`MSR_SMI_COUNT`) reading of + stage 1 of + `issues/kernel/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md` + is built as the first piece of the general counters, not as a one-off check. +- **"Always on"**: the shipped kernel records a system call that runs over the + threshold in the diary, with its number and its program. +- **Symbols, "adopt"**: the kernel names only itself; a killed program is + reported as file and offset, and one userland naming service shares the + kernel's lookup and demangling code. He asked that it never panic or fail. + +## Decided by the orchestrator, not ruled (2026-10-03) + +From the orchestrator's strategy and the roast of it that the orchestrator +adopted. A line marked *told* was told to the owner with his veto open; the +rest were not put to him. + +- *Told*: counters are read on demand. The roast's bound: the requester serves + its own CPU and parks on a Watch under a bound, and a CPU silent at the + bound reads as stale. +- *Told*: one sampler per CPU, the hard-lockup detector's PMU NMI, at one + fixed rate held by a profile handle. +- The kick leaves the timer's vector for one cross-CPU request vector, which + counter requests share. + +| Pillar | Its track | +|---|---| +| Log | `issues/kernel/logging-records-from-every-producer-and-a-kernel-that-waits-on-nobody.md`; the sinks half of `issues/design-debt/redesign-the-log-subsystem.md` | +| Diary | `issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md` | +| Counters, sizes | this file | +| Profile | behind the diary's judgement; `issues/hardware/a-frozen-toyos-waits-for-a-hand-on-the-power-button.md` | +| Accounting | `issues/kernel/nothing-charges-kernel-memory-to-a-process.md`, `issues/kernel/a-processs-memory-is-a-byte-total-that-reads-zero-under-contention.md`, `issues/diagnostics/blocked-time-is-invisible-while-the-park-lasts.md` | +| Inspect | `issues/diagnostics/the-kernel-keeps-nothing-it-enumerates.md` | +| Post-mortem | step 1 of `issues/kernel/logging-records-from-every-producer-and-a-kernel-that-waits-on-nobody.md` | +| Symbols | `issues/kernel/the-kernel-still-parses-what-userland-writes.md` Move 3 | + +## What is to be built, in order (the orchestrator's) + +Lane A, what `issues/kernel/toyos-beats-linuxs-latency-on-the-t14.md` needs: +the diary's tid 0 and +`issues/kernel/the-nmi-entry-can-hand-the-lockup-sample-cs-for-rflags-and-no-test-reds.md`; +then the counters with their rights and the request vector, whose T14 exit is +that in legacy mode the SMI count rises alike on every CPU; then interrupts on +in syscalls; then the diary's three steps. Lane B, behind the diary's +judgement: the profile and call chains. Lane C: RAPL, C-state residency and +thermal counters, the log's steps, accounting, `inspect` and `size`. + +**Exit**: every pillar track above is closed; at a ToyOS shell on the T14 +`inspect kernel.*`, `trace` and `size` answer, each under the right its +manifest row names; a program without the counters right is refused a +counter read, and one that holds it but not `trace` is refused the power and +per-device interrupt counters; and a T14 row holds each counter ToyOS reads +there against Linux's reading of it +(`issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-lack-reads-owed-before-the-t14s-wipe.md`). diff --git a/issues/filesystem/where-everything-lives.md b/issues/filesystem/where-everything-lives.md index 9fa3b2de22f..01bf18711c7 100644 --- a/issues/filesystem/where-everything-lives.md +++ b/issues/filesystem/where-everything-lives.md @@ -24,7 +24,7 @@ may reach it. Every line below is the owner's ruling. /home/ Desktop Documents Downloads Music Pictures Videos Fonts Apps// /boot bootloader, kernel, kernel arguments; the updater's alone /log /media logs; foreign volumes, one /media/