Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
status: open
kind: defect
status: none
kind: rejected
opened: 2026-09-29
---

Expand All @@ -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`.
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion issues/build/clippy-stage-two-is-lints-one-at-a-time.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. |
Expand Down
2 changes: 1 addition & 1 deletion issues/build/parallel-tests-red-under-other-suites.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,14 @@ 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
`update_floor_is_the_images_own`'s oracle. Stage 5 says
`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.

Expand Down
5 changes: 5 additions & 0 deletions issues/design-debt/redesign-the-log-subsystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion issues/design-debt/what-is-owed-on-file-size.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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`
Expand All @@ -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."
4 changes: 4 additions & 0 deletions issues/diagnostics/the-kernel-keeps-nothing-it-enumerates.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
83 changes: 83 additions & 0 deletions issues/diagnostics/toyos-explains-itself.md
Original file line number Diff line number Diff line change
@@ -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`).
Loading
Loading