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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ There are no spec documents. A rule a reader can check lives in an agent's promp

**Userspace servers** — `system.toml` names them. Each claims a device or capability from the kernel and serves its function; crash one and the kernel is fine.

**The log is a userland file.** `/system/bin/logd` reads records on a cursor and owns `/log`; the kernel keeps the record ring, the console and the panel, and writes no file. `SYS_FSYNC` reaches the device's cache flush because logd's durability claim rests on it.
**The log is a userland file.** `/system/bin/logkeeper` reads records on a cursor and owns `/log`; the kernel keeps the record ring, the console and the panel, and writes no file. `SYS_FSYNC` reaches the device's cache flush because logkeeper's durability claim rests on it.

**Syscall ABI** — `toyos-abi/`: struct layouts, syscall numbers, typed wrappers; completely unstable. The cleanest, most sustainable ABI beats convenience; a removed number is free. `toyos/` builds on it with typed handles, IPC framing, ports, namespaces and `surface` — userland uses `toyos`, the kernel uses `toyos-abi` only.

**Capabilities** — a process holds exactly what its parent moved into it, and among kernel objects there is nothing it can name to get more. No registry, no connect-by-name, no pid-as-authority: `/system/bin/init` builds every program's namespace and device claims from `system.toml` before spawning it, and a handle a process does not hold is a bug in that process — the kernel ends it rather than answering a word it can ignore. **Isolation is non-negotiable, and the filesystem is inside it**: a process names only the paths in the view its parent built for it, the unit of isolation is the program, and a user is the part of the tree a session was handed. Not yet true of files: the kernel still resolves every path against one machine-wide tree until the storage track's per-program views land.
**Capabilities** — a process holds exactly what its parent moved into it, and among kernel objects there is nothing it can name to get more. No registry, no connect-by-name, no pid-as-authority: `/system/bin/supervisor` builds every program's namespace and device claims from `system.toml` before spawning it, and a handle a process does not hold is a bug in that process — the kernel ends it rather than answering a word it can ignore. **Isolation is non-negotiable, and the filesystem is inside it**: a process names only the paths in the view its parent built for it, the unit of isolation is the program, and a user is the part of the tree a session was handed. Not yet true of files: the kernel still resolves every path against one machine-wide tree until the storage track's per-program views land.

**CPU state** — a CPU's control registers come from one declaration, applied by the BSP and by every AP and asserted on each; no read-modify-write decides what either holds.

Expand Down
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,16 @@ toyos-fat32 = { path = "toyos-fat32" }
toyos-fat32-check = { path = "toyos-fat32/check" }
toyos-gpt = { path = "toyos-gpt" }
toyos-keymap = { path = "toyos-keymap" }
# The form a program's line takes in a boot's log and the port `logd` serves it
# on, so the judges reading the log and `logd` writing it read one declaration.
# The form a program's line takes in a boot's log and the port `logkeeper` serves it
# on, so the judges reading the log and `logkeeper` writing it read one declaration.
toyos-logstream = { path = "toyos-logstream" }
toyos-manifest = { path = "toyos-manifest" }
# The shutdown's stop record: the kernel renders it and this crate reads it back
# off a stick, so one declaration is what both sides spell it with.
toyos-quiesce = { path = "toyos-quiesce" }
# The swap port's name and the one program the image may give it to, so the
# gate on every manifest and the host that asks for a swap read what init and
# sshd read.
# gate on every manifest and the host that asks for a swap read what the supervisor and
# sshserver read.
toyos-swap = { path = "toyos-swap" }
# The watchdog's parameter name, so the gate over `kernel/src/params.rs` reads
# the same constant the kernel and the bootloader do.
Expand All @@ -159,8 +159,8 @@ toyos-blackbox = { path = "toyos-blackbox" }
toyos-update = { path = "toyos-update", features = ["sign"] }
# A throwaway key's seed, from the operating system. Already resolved here.
getrandom = "0.3"
# `classify`, so the host reading a log volume and `logd` writing it cannot
# disagree about which files on it are `logd`'s.
# `classify`, so the host reading a log volume and `logkeeper` writing it cannot
# disagree about which files on it are `logkeeper`'s.
toyos-wallclock = { path = "toyos-wallclock" }
image = { version = "0.25", default-features = false, features = ["jpeg"] }
# The digest behind `NOTICE`'s record of every committed binary file
Expand All @@ -181,7 +181,7 @@ ureq = { version = "3", default-features = false, features = ["rustls"] }
# checks every user pointer against and not against a second copy of it.
toyos-userbound = { path = "toyos-userbound" }
# The I219 driver's own words and its PHY probe's exit-code table, so the
# harness judging netd's `exit:` record off the T14 and netd writing it read one
# harness judging netstack's `exit:` record off the T14 and netstack writing it read one
# declaration. Pure and `no_std`, so it compiles for the host as it does for
# the guest.
toyos-i219 = { path = "toyos-i219" }
Expand Down
2 changes: 1 addition & 1 deletion bcachefs/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ fn a_filesystems_name_round_trips_through_its_superblock() {
}

let mut fs = Formatted::format(VecBlockIO::new(128)).expect("format");
fs.create("bin/init", b"init-binary", 0).expect("create");
fs.create("bin/supervisor", b"supervisor-binary", 0).expect("create");
fs.set_uuid(named);
let raw = fs.into_io().expect("finish").into_vec();
let mounted =
Expand Down
2 changes: 1 addition & 1 deletion bootloader/src/attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::loaderlog;

/// The file, at the root of the log partition beside `loader.log`.
///
/// Not one of `logd`'s names and not the loader's log: a reader of the volume
/// Not one of `logkeeper`'s names and not the loader's log: a reader of the volume
/// that walks it for either finds this and passes over it
/// (`toyos_build::bootlog::split_listing`).
const NAME: &CStr16 = cstr16!("attempts");
Expand Down
2 changes: 1 addition & 1 deletion bootloader/src/loaderlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//!
//! The file is `loader.log` at the root of the partition
//! `KernelArgs::log_partition_guid` names, truncated at each boot. One file
//! under a fixed name and never one of `logd`'s timestamped ones, so a reader
//! under a fixed name and never one of `logkeeper`'s timestamped ones, so a reader
//! looking for the kernel's log on this volume never picks this up.
//!
//! A partition this cannot open or write is refused by name on the console and
Expand Down
16 changes: 8 additions & 8 deletions console/system.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# boot checkpoint stays on the glass — which is the only thing that works on a
# machine that wedges before userland, and is the answer to exactly one
# question. This image answers the rest by being asked them: `/system/bin/console`
# claims the screen, shows this boot's log as `logd` serves it — the kernel's
# claims the screen, shows this boot's log as `logkeeper` serves it — the kernel's
# records and every program's output — so nothing is lost with the checkpoint,
# and puts a prompt underneath.
#
Expand All @@ -16,17 +16,17 @@
assets = ["assets"]

[boot]
start = ["logd", "blockd", "fsd", "console"]
start = ["logkeeper", "diskserver", "fileserver", "console"]

# `/system/bin/console` owns the screen and provides the surface its shell and the
# shell's children inherit. No compositor here, so nothing receives one.
# **Every image that carries a `TOYOS-LOG` partition runs this**, and every
# image does. The kernel keeps the record ring and the console and writes no
# file at all, so a boot config without `logd` is a boot whose `/log` is empty —
# `every_boot_config_runs_logd` is what refuses one. It claims no device; it
# file at all, so a boot config without `logkeeper` is a boot whose `/log` is empty —
# `every_boot_config_runs_logkeeper` is what refuses one. It claims no device; it
# reads the kernel's records with `logread`, which is `Rights::LOG |
# Rights::WAIT` on a `SysCap` duplicate, and serves `log` to the console.
[programs.logd]
[programs.logkeeper]
service = true
syscap = ["logread"]
serves = ["log"]
Expand All @@ -41,7 +41,7 @@ receives = ["surface", "launcher"]

# `power` because `bin/shutdown` below is this binary, and on the machine this
# image exists for — no serial port, a prompt on the panel — there is no other
# way to turn it off: it asks init, which has `logd` make the log whole first.
# way to turn it off: it asks the supervisor, which has `logkeeper` make the log whole first.
# `roster` because `bin/ps` is the same binary and this image exists to be
# asked what the machine is doing.
[programs.toybox]
Expand All @@ -68,7 +68,7 @@ syscap = ["roster"]
# The block service: the NVMe controller this machine's DATA is on, driven
# from userland through its claim. Started again when it ends; the claim goes
# back with the process and is minted again for the next.
[programs.blockd]
[programs.diskserver]
service = true
restart = true
serves = ["block"]
Expand All @@ -77,7 +77,7 @@ devices = ["pci:1b36:0010"]
# The file servers: DATA, the log and the running slot's volume, one process
# each, serving every program the directories of its role. Started again when
# one ends, on the same ports.
[programs.fsd]
[programs.fileserver]
restart = true
roles = ["data", "log", "boot"]
receives = ["block"]
32 changes: 9 additions & 23 deletions diag/system.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,20 @@
# kernel logged — including the one `i8042:` line that says why the integrated
# keyboard is dead — was on screen for about a tenth of a second and then gone.
#
# `/system/bin/init` is in every image and holds the one `SysCap`, so the guarantee is
# no longer "nothing here *can* claim the framebuffer" but "this config declares
# no `devices`" — which `no_diag_program_claims_the_screen` checks before the
# image is written, and which nothing checked before. The reachable set is the
# same; a bug in init could reach a device where previously no code in the image
# could, and that is the trade.
#
# **Two programs now, and the guarantee is restated rather than assumed.** It
# used to be "nothing here can claim the framebuffer, because the compositor is
# not built into this image at all". `logd` is in this image because the kernel
# writes no file, and an unchanged config here would flash a T14 that logs to a
# panel and nowhere else. The argument survives verbatim: `logd` declares no
# `devices` at all — its whole row is `syscap = ["logread"]` — so the reachable
# set is unchanged and `no_diag_program_claims_the_screen` still checks it
# before the image is written.
#
# The other program it starts prints the cwd and exits.
# `/system/bin/supervisor` is in every image and holds the one `SysCap`, so the
# guarantee is that this config declares no `devices`, which
# `no_diag_program_claims_the_screen` checks.
[boot]
start = ["logd", "fsd", "toybox"]
start = ["logkeeper", "fileserver", "toybox"]

# **Every image that carries a `TOYOS-LOG` partition runs this**, and every
# image does. The kernel keeps the record ring and the console and writes no
# file at all, so a boot config without `logd` is a boot whose `/log` is empty —
# `every_boot_config_runs_logd` is what refuses one. It claims no device and
# file at all, so a boot config without `logkeeper` is a boot whose `/log` is empty —
# `every_boot_config_runs_logkeeper` is what refuses one. It claims no device and
# serves no port: its row's authority is `logread`, which is
# `Rights::LOG | Rights::WAIT` on a `SysCap` duplicate, and init hands it every
# `Rights::LOG | Rights::WAIT` on a `SysCap` duplicate, and the supervisor hands it every
# program's output beside that.
[programs.logd]
[programs.logkeeper]
service = true
syscap = ["logread"]

Expand All @@ -45,6 +31,6 @@ args = ["pwd"]
# `/log`'s file server, and only it: the log partition is the kernel's
# partition claim on the boot stick, so this row declares no `devices`, and
# DATA's block service would be one.
[programs.fsd]
[programs.fileserver]
restart = true
roles = ["log"]
2 changes: 1 addition & 1 deletion issues/audio/cpal-backend-hardcodes-the-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ and the cpal backend's `pause()` is a purely local futex store soundd is never
told about. No change confined to soundd can separate the two, and landing the
soundd and SDK halves alone would kill every paused cpal client. The
**protocol**, not the implementation, is what needs to change;
`issues/audio/a-client-cannot-tell-soundd-it-paused.md` is that change.
`issues/audio/a-client-cannot-tell-soundserver-it-paused.md` is that change.

The assignment was reclaimed 2026-08-23: nobody holds it, and the block above is
what it is waiting on.
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ Each stage lands on its own, in this order.
`issues/hardware/the-t14-redial-re-asks-mdns-after-every-refusal.md`,
`issues/diagnostics/a-first-dial-turned-away-before-a-line-is-waited-on-to-its-callers-bound.md`
and
`issues/diagnostics/a-netd-that-dies-while-serving-leaves-the-hosts-stream-silent.md`.
`issues/diagnostics/a-netstack-that-dies-while-serving-leaves-the-hosts-stream-silent.md`.
- #539's issues `a-loader-change-reaches-a-machine-only-by-writing-its-stick`,
`the-bench-reads-no-quiescent-log-volume`,
`the-bench-runs-with-no-bound-on-its-own-boot`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
status: open
kind: defect
opened: 2026-10-03
---

# The std fork's ToyOS files carry lines rustfmt would rewrap

Under `rust/rustfmt.toml`, the rustfmt `rust/src/stage0` pins (`1.9.0-nightly
77cf889bc1`, which applies the config's `group_imports` and
`imports_granularity`) rewrites seven places in four of the `rust` fork's
ToyOS files under `library/std` at `a0d44493347`, each file checked on its own
text (`rustfmt --check --config-path rustfmt.toml --edition 2024`). Stable
1.9.0, which skips those two options, rewrites the same seven:

| file | places |
|---|---|
| `src/os/toyos/fs.rs` | 1 |
| `src/sys/fs/toyos.rs` | 2 |
| `src/sys/pal/toyos/mod.rs` | 2 |
| `src/sys/process/toyos.rs` | 2: the three `setup_slot` calls and the `Outcome::Gone` arm |

A fork change is written as upstream would take it, and upstream formats
`library/std` with that configuration.

**Owner**: the `rust` fork.

**Exit**: the rustfmt `rust/src/stage0` pins, under `rust/rustfmt.toml` with
its two import options, changes no ToyOS file under `library/std`.
2 changes: 1 addition & 1 deletion issues/design-debt/toyos-has-its-own-network-stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ netd runs smoltcp. Its replacement is ToyOS's own stack, built clean-room: reade
- Stage 5: netd on one shard, pipe ABI unchanged; smoltcp leaves netd, `Cargo.toml` and `userland/Cargo.lock` in the same PR.
- Then multi-core, netring (blocked on the owner's ABI ruling), TCP and IP hardening, IPv6, offloads, soak.

The listener defects are this track's: `issues/hardware/a-handshake-nobody-finishes-holds-a-listeners-port-shut.md` and `issues/hardware/a-connect-between-two-accepts-is-reset.md`, on smoltcp until stage 5, and `issues/hardware/an-accept-that-never-reaches-netd-strands-its-listener.md`, in std's accept.
The listener defects are this track's: `issues/hardware/a-handshake-nobody-finishes-holds-a-listeners-port-shut.md` and `issues/hardware/a-connect-between-two-accepts-is-reset.md`, on smoltcp until stage 5, and `issues/hardware/an-accept-that-never-reaches-netstack-strands-its-listener.md`, in std's accept.

Owed from the stage 3 specifications: US-57 by stage 5, whose netd maps UDP's refusals onto the pipe ABI; `dhcp.renew-unroutable` by stage 5, whose netd counts it where `toyos-net-udp` refuses the renewal `udp.no-route`; FRA-01–20 and PMTU-01–06 by IP hardening.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ work then stops and is judged before anything more is built on it.
trace. 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/inits-claim-of-a-pci-function-the-t14-lacks-holds-interrupts-off-for-3-8-ms.md`
`issues/kernel/the-supervisors-claim-of-a-pci-function-the-t14-lacks-holds-interrupts-off-for-3-8-ms.md`
need.

Behind that judgement, and not before it: interrupt enter and exit records
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ public carries them unless whoever pastes it masks them by hand:

- the USB stick's serial number: `kernel/src/drivers/xhci/wait/msc.rs:1407`,
on every bind, and `:1415`, when a disk comes back;
- the network card's MAC: `userland/netd/src/main.rs:1608`, and
- the network card's MAC: `userland/netstack/src/main.rs:1605`, and
`src/metal.rs:2281`, where the host loop writes the one it read before the
flash into the readback's `boot.txt`;
- the resolvers the lease named, which on the bench are the provider's public
ones: `userland/netd/src/dhcp.rs:149`.
ones: `userland/netstack/src/dhcp.rs:149`.

`src/sourcegate.rs` reads tracked files only. A pull request's body, a comment
and a commit message are read by nothing before they are public.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
status: open
kind: defect
opened: 2026-10-03
---

# A renamed service's state stays under its old name, unread

The supervisor starts a service with `HOME` at `/state/<its name>`
(`toyos-manifest`'s `home`), so a service's state is keyed by its program's
name and a rename orphans it with nothing said. Stage 1 of
`issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md` renamed
five services, and a DATA volume that outlives that change:

- keeps `/state/logd`, `/state/soundd`, `/state/netd`, `/state/sshd` and
`/state/blockd`, which nothing reads or deletes;
- answers ssh with a host key `sshserver` mints afresh under
`/state/sshserver`, which a client that pinned the old key refuses;
- no longer authorizes a key that lived only in `/state/sshd/authorized_keys`:
`userland/sshserver/src/main.rs`'s `authorized_keys` reads
`/state/sshserver/authorized_keys` and `/system/etc/ssh_authorized_keys`, so
a machine updated over ssh whose owner's key was only there refuses its owner
afterwards.

A package under `/apps` built before the rename asks `toyos::endow::service`
for `soundd` and `netd`, which no row endows, so it finds no sound or network
server until it is reinstalled.

A DATA outlives an image only where one was made to: the boot image carries
none (`src/image.rs`'s `create_boot_image`), and the build stamps the
designation the kernel formats only into a scratch file it has just created
(`src/build.rs`'s `create_sparse`). Every checkout's `target/nvme.img`, which
`cargo run` keeps across runs, is one; a machine holds one only where a stamped
TOYOS-DATA partition was put by hand, and whether any of the owner's does is
not known here.

**Owner**: the orchestrator, which holds the supervisor track above.

**Exit**: the supervisor names at boot every `/state` directory that no service
of the running manifest owns, and a test stages one and reads the line.
2 changes: 1 addition & 1 deletion issues/filesystem/where-everything-lives.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,4 @@ until that lands nothing verifies it.
`--exit-with-lease` bench report the metal loop reads off the stick's FAT log
volume, as it reads `/log/metal-*.bin`, and the DATA volume is not readable
there. It goes with
`issues/diagnostics/netds-lease-probe-answers-a-question-its-lines-already-answer.md`.
`issues/diagnostics/netstacks-lease-probe-answers-a-question-its-lines-already-answer.md`.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ metal rows.
wedge, a reset) or judges a boot (the loader, an update, a file read back
after a reboot). Its registration says which.
- **One exec channel**, to `test-runner`'s stdin loop, since `sshd` aliases a
second channel's input (`issues/isolation/sshd-holds-one-channel-and-does-not-say-so.md`).
second channel's input (`issues/isolation/sshserver-holds-one-channel-and-does-not-say-so.md`).
`tests/ssh-client-host`'s `pipe` relays it once it writes output as it
arrives (`tests/ssh-client-host/src/main.rs:251-263`).
- **A test's window** is what crosses between its markers: the job's output,
Expand Down
Loading
Loading