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
6 changes: 3 additions & 3 deletions .claude/agents/implementer.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ guess. Then build, then test on root `CLAUDE.md`'s tiers before anyone reviews:
- A result is the command's own exit code: `<cmd> > <file> 2>&1; echo EXIT=$?`. A grepped
`test result` line is not one, and a gate you did not run is a gate you do not claim.
- Long commands run in the background with output to a file under the scratchpad the brief names.
Stay inside one turn while anything runs: block in the foreground on `until <it is done>; do sleep
2; done` under an explicit `timeout`, print a line, repeat; a long `sleep` is refused. Ten minutes
of silence kills you, and ending a turn to announce a wait strands the work.
Stay inside one turn while anything runs: block in the foreground on `n=0; until <it is done> ||
[ $((n+=1)) -gt 50 ]; do sleep 2; done`, print a line, repeat; a long `sleep` is refused. Ten
minutes of silence kills you, and ending a turn to announce a wait strands the work.
- Nothing a pull request's evidence rests on, mutation patches and run logs included, lives only in
a temporary directory: `/tmp` is wiped when the CLI restarts. Post mutation patches to the pull
request as a comment.
Expand Down
3 changes: 3 additions & 0 deletions .claude/agents/reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ if it meets the bar above; otherwise it is a NOTE.
`arch::aarch64` in no generic kernel code; and none of them in a crate whose manifest
`description` says pure.
A `4096` in the kernel that means a page is a private copy of `mm::PAGE_SIZE`.
Nothing ships for tests alone, and a diff that ships something for a test alone is a BLOCKER.
- **Hosts.** A BLOCKER: a change that makes an app build on fewer of Linux under Wayland, macOS
and Windows, or answers a host build failure by making the app ToyOS-only — by a split, a `cfg`
that compiles what it does out of a host, or an `exempt` in its manifest — instead of fixing it
Expand Down Expand Up @@ -127,6 +128,8 @@ if it meets the bar above; otherwise it is a NOTE.
- **Forks.** A broken rule of `implementer.md`'s "A fork" is a BLOCKER, and so is a lockfile or
gitlink left naming a fork branch whose consumed commit the pull request changes. A search for
callers that skipped the fork clones and `~/.cargo/git/checkouts/` searched part of the tree.
LLVM and Rust are never changed to suit a ToyOS tool; a tool that cannot build them unchanged is
the one that goes, and a diff that changes either for one is a BLOCKER.

## Prose

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ There are no spec documents. A rule a reader can check lives in an agent's promp

## Dependencies

**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run (Python, Perl, CMake, make), each declared where `reviewer.md`'s Arrivals says. No binary for one host OS alone: a macOS binary is a hard no, and "only for tests" does not soften it. ToyOS's own code is Rust; it writes no Python, Perl or shell of its own. Only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull request is sent for now. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: ToyOS rebuilds itself on ToyOS and reproduces the host's bytes, and nothing — build, test, or verification — rests on a host binary; a bootstrap from source with no binary seed is out of scope. Ask of anything new: could this ever run inside ToyOS?
**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run (Python, Perl, CMake, make), each declared where `reviewer.md`'s Arrivals says. No binary for one host OS alone: a macOS binary is a hard no, and "only for tests" does not soften it. ToyOS's own code is Rust; it writes no Python, Perl or shell of its own. Only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull request is sent for now. Third-party source is used unmodified, pinned by hash, wherever only its packaging has to change; a fork is for source changes only. The north star is **self-hosting**: ToyOS rebuilds itself on ToyOS and reproduces the host's bytes, and nothing — build, test, or verification — rests on a host binary; a bootstrap from source with no binary seed is out of scope. Ask of anything new: could this ever run inside ToyOS?

Vendor firmware a device or CPU verifies by its maker's signature may be shipped: pinned by version and hash, redistributable unmodified, recorded in `NOTICE`. A device's is loaded only by its own driver through its IOMMU domain and never executes on the CPU; CPU microcode is loaded by the kernel. `NOTICE` names every committed third-party file with its hash, upstream and licence.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
status: open
kind: defect
opened: 2026-09-30
---

# The shipped image carries three test programs

"Nothing ships for tests alone" (`.claude/agents/reviewer.md`, Fit) is untrue
of the shipped `system.toml` in three rows:

- `proctest = {}`: `userland/proctest/README.md` calls it a test harness, and
nothing in the tree runs `/system/bin/proctest` but `proctest` itself.
- `input-test = {}`: a test utility by its README, and nothing runs
`/system/bin/input-test`; `toyos-symbols/tests/real.rs` reads a frozen copy
under `toyos-symbols/tests/fixtures/`, not the shipped binary.
- `"bin/spin" = "/system/bin/toybox"`: `userland/toybox/src/spin.rs` loops
forever, and nothing in the tree runs it; its one named use is a test, the
metal `sshd_exec` row
`issues/build/the-guest-suite-runs-only-what-no-cheaper-tier-reaches.md` owes.

Found by `git grep -n -w -e proctest -e input-test` and
`git grep -n -w -e spin -- system.toml tests userland issues/build`.

**Exit condition**: the shipped `system.toml` names none of the three, and a
test that needs one carries it in its own image alone.

This file was deleted.

7 changes: 2 additions & 5 deletions tests/toyos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ fn judge_virt_job(mut qemu: QemuInstance, job: &str, said: &str) -> Result<Strin
Ok(serial)
}

/// What toybox's `unmap_touch` says once every read of a page just unmapped,
/// What `unmap_touch` says once every read of a page just unmapped,
/// on the unmapping thread and on another, ended its process.
const UNMAP_TOUCH_SAID: &str =
"unmap_touch: 4 reads of a page just unmapped on the unmapping thread, and 4 on another";
Expand Down Expand Up @@ -1731,10 +1731,7 @@ fn run_screen_test(name: &str, profile: qemu::Profile, test_config: &Path) -> Re
}
Ok(())
}
"virt_timer_preempts" => {
// Spelled in `userland/toybox/src/preempt.rs`.
virt_job(profile, "preempt", "preempt: the counting thread was preempted twice")
}
"virt_timer_preempts" => virt_job(profile, "preempt", "preempt: the counting thread was preempted twice"),
"virt_fp_isolation" => virt_job(profile, "fp_isolation", "fp_isolation: v0-v31, FPCR and FPSR survived"),
"virt_first_entry" => virt_job(profile, "first_entry", "first_entry: x1-x30 were zero"),
"virt_unmap_touch" => virt_job(profile, "unmap_touch", UNMAP_TOUCH_SAID),
Expand Down
14 changes: 7 additions & 7 deletions tests/virtjobcase/system.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# One CPU and the AArch64 guest's jobs, each a toybox applet or, last because
# One CPU and the AArch64 guest's jobs, each a kernelprobe applet or, last because
# a kernel it fails on rewrites the clock page every reader asserts on, the
# suite's `test_rs_abuse_readonly_copyout`, which the harness puts on ROOT;
# each job's line comes only if the kernel kept what that job asks about.
Expand All @@ -15,11 +15,11 @@ receives = ["power"]
# CPU, and a job past the bound reboots the guest with the job named.
args = ["--bound-ms=240000", "preempt", "fp_isolation", "first_entry", "unmap_touch", "debug_refused", "test_rs_abuse_readonly_copyout"]

[programs.toybox]
[programs.kernelprobe]

[symlinks]
"bin/preempt" = "/system/bin/toybox"
"bin/fp_isolation" = "/system/bin/toybox"
"bin/first_entry" = "/system/bin/toybox"
"bin/unmap_touch" = "/system/bin/toybox"
"bin/debug_refused" = "/system/bin/toybox"
"bin/preempt" = "/system/bin/kernelprobe"
"bin/fp_isolation" = "/system/bin/kernelprobe"
"bin/first_entry" = "/system/bin/kernelprobe"
"bin/unmap_touch" = "/system/bin/kernelprobe"
"bin/debug_refused" = "/system/bin/kernelprobe"
4 changes: 2 additions & 2 deletions tests/virtsmpcase/system.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ receives = ["power"]
# the bound reboots the guest with the job named.
args = ["--bound-ms=240000", "unmap_touch"]

[programs.toybox]
[programs.kernelprobe]

[symlinks]
"bin/unmap_touch" = "/system/bin/toybox"
"bin/unmap_touch" = "/system/bin/kernelprobe"
7 changes: 7 additions & 0 deletions userland/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions userland/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ members = [
"init",
"input-test",
"inspect",
"kernelprobe",
"logd",
"metalprobe",
"netd",
Expand Down
9 changes: 9 additions & 0 deletions userland/kernelprobe/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "kernelprobe"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Test-only multi-call binary: the kernel probes the AArch64 guest's virt jobs run, one per name it is invoked by."

[dependencies]
toyos-abi = { path = "../../toyos-abi" }
9 changes: 9 additions & 0 deletions userland/kernelprobe/src/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! What the probes must say in assembly.

#[cfg(target_arch = "aarch64")]
mod aarch64;
#[cfg(target_arch = "aarch64")]
pub use aarch64::*;

#[cfg(not(target_arch = "aarch64"))]
compile_error!("kernelprobe is built for AArch64 alone: its probes are the AArch64 guest's");
20 changes: 20 additions & 0 deletions userland/kernelprobe/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
mod arch;
mod debug_refused;
mod preempt;
mod unmap_touch;

use arch::{first_entry, fp_isolation};

fn main() {
let mut args = std::env::args();
let invoked_as = args.next().expect("argv[0] names the probe");
let args: Vec<String> = args.collect();
match std::path::Path::new(&invoked_as).file_name().and_then(|n| n.to_str()) {
Some("debug_refused") => debug_refused::main(args),
Some("first_entry") => first_entry::main(args),
Some("fp_isolation") => fp_isolation::main(args),
Some("preempt") => preempt::main(args),
Some("unmap_touch") => unmap_touch::main(args),
other => panic!("kernelprobe: no probe is called {other:?}"),
}
}
File renamed without changes.
11 changes: 0 additions & 11 deletions userland/toybox/src/arch/mod.rs

This file was deleted.

51 changes: 0 additions & 51 deletions userland/toybox/src/arch/x86_64.rs

This file was deleted.

8 changes: 1 addition & 7 deletions userland/toybox/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
mod arch;
mod cat;
mod cp;
mod debug_refused;
mod echo;
mod free;
mod grep;
Expand All @@ -11,7 +9,6 @@ mod ls;
mod mkdir;
mod mv;
mod net;
mod preempt;
mod ps;
mod pwd;
mod reboot;
Expand All @@ -21,7 +18,6 @@ mod shutdown;
mod spin;
mod stats;
mod tone;
mod unmap_touch;

macro_rules! commands {
($($name:ident),*) => {
Expand All @@ -34,9 +30,7 @@ macro_rules! commands {
};
}

use arch::{first_entry, fp_isolation};

commands!(cat, cp, debug_refused, echo, first_entry, fp_isolation, free, grep, hexdump, locale, ls, mkdir, mv, net, preempt, ps, pwd, reboot, rm, screen, shutdown, spin, stats, tone, unmap_touch);
commands!(cat, cp, echo, free, grep, hexdump, locale, ls, mkdir, mv, net, ps, pwd, reboot, rm, screen, shutdown, spin, stats, tone);

fn main() {
let args: Vec<String> = std::env::args().collect();
Expand Down
Loading