diff --git a/CLAUDE.md b/CLAUDE.md index 5e480bcea0b..63d9bae5a99 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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. 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? +**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, used as published — one that does *our* job we write ourselves, and a driver crate never — and a fork carries a change written to upstream quality and goes when upstream has it. Where security or another important reason asks, above all on a trust boundary or in the kernel, we write our own crate, with a clear boundary and well tested; the kernel takes as few community crates as it can justify and depends on no libc. 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. diff --git a/issues/build/the-kernels-libc-test-reads-the-host-compilers-cfg-not-the-forks.md b/issues/build/the-kernels-libc-test-reads-the-host-compilers-cfg-not-the-forks.md new file mode 100644 index 00000000000..a27d6ef932a --- /dev/null +++ b/issues/build/the-kernels-libc-test-reads-the-host-compilers-cfg-not-the-forks.md @@ -0,0 +1,33 @@ +--- +status: open +kind: tooling +opened: 2026-10-03 +--- + +# The kernel's libc test reads the host compiler's `cfg`, not the fork's that builds the kernel + +`build::tests::the_kernel_resolves_no_libc_for_either_target` (`src/build.rs`) +runs `cargo tree --target ` for each kernel target with whatever `cargo` +and `rustc` the host gate runs: the host's default, stable on CI, whose host +job installs no ToyOS toolchain (`src/ci.rs`'s `host`). Cargo decides each +target-gated edge against that compiler's `rustc --print cfg`. The kernel +builds with the fork, whose `cfg` for the kernel targets only +`assert_kernel_is_softfloat` (`src/build.rs`) asks. + +The two answers differ. `rustc --print cfg --target `, stable `1.98.1` +against the fork's `1.99.0-dev`, every run exiting 0: on both +`x86_64-unknown-none` and `aarch64-unknown-none-softfloat` the fork prints +every line stable prints, and adds `overflow_checks`, `ub_checks`, +`fmt_debug`, `relocation_model`, `target_has_threads`, +`target_object_format`, and the unstable `target_has_atomic*` and +`target_has_reliable_*` names; on x86_64 it adds `target_feature="x87"` too. +Both print the same `target_os` and `target_arch` and no `unix`, the names +`dlmalloc` 0.2.13 gates its `libc` and `windows-sys` edges on, so the test's +verdict is the fork's today. An edge gated on a name only the fork +prints resolves one way in the kernel's build and the other in the test. + +Owner: the orchestrator. + +**Exit**: the test resolves the kernel's dependencies against the `cfg` of +the compiler that builds the kernel, or it is deleted, as +`issues/kernel/toyos-has-its-own-allocator.md`'s exit deletes it. diff --git a/issues/kernel/toyos-has-its-own-allocator.md b/issues/kernel/toyos-has-its-own-allocator.md new file mode 100644 index 00000000000..ca62befbde8 --- /dev/null +++ b/issues/kernel/toyos-has-its-own-allocator.md @@ -0,0 +1,32 @@ +--- +status: open +kind: track +opened: 2026-10-03 +--- + +# ToyOS has its own allocator + +Ruled (owner, 2026-10-03): ToyOS writes its own allocator crate, one core +with two fronts. The kernel's front comes first: built host-first, and +swapped in for the kernel's `dlmalloc` (`kernel/src/mm/alloc.rs`) after the +three steps of `issues/kernel/toyos-beats-linuxs-latency-on-the-t14.md`. +std's front, for programs, comes later, after it is measured against the +`dlmalloc` ToyOS's std allocates with (`library/std/src/sys/alloc/toyos.rs` +in the `rust/` fork). The 2 MiB heap-growth stall is fixed now, on +`dlmalloc`, and waits for neither front. + +The stall: when the kernel heap grows, `dlmalloc` calls +`KernelPageSource::alloc` (`kernel/src/mm/alloc.rs`) inside +`ALLOCATOR.dlmalloc.lock()`, and `pmm::alloc_page` (`kernel/src/mm/pmm.rs`) +scans the page bitmap and zeroes the whole 2 MiB page before it returns, so +every CPU that allocates from the heap meanwhile spins on its lock. How long +that takes on the T14 is unmeasured. + +Owner: the orchestrator. + +**Exit**: no heap growth allocates or zeroes a 2 MiB page inside the kernel +heap's lock; the kernel allocates through ToyOS's allocator, and `dlmalloc`, +`libc`, `windows-sys` and `windows-link` are gone from `kernel/Cargo.toml` and +`kernel/Cargo.lock`, with `build::tests::the_kernel_resolves_no_libc_for_either_target` +(`src/build.rs`) deleted in the same pull request; and ToyOS's std allocates +through the std front, measured against `dlmalloc` before it is swapped in. diff --git a/src/build.rs b/src/build.rs index bae3cc48b6c..65c9c8f7db5 100644 --- a/src/build.rs +++ b/src/build.rs @@ -2742,6 +2742,36 @@ mod tests { ); } + /// The kernel depends on no libc (root `CLAUDE.md`, Dependencies), and its + /// `Cargo.lock` cannot show it: a lock records every platform's edges and + /// none of their `cfg`s. + #[test] + fn the_kernel_resolves_no_libc_for_either_target() { + let root = Path::new(env!("CARGO_MANIFEST_DIR")); + for arch in Arch::ALL { + let out = Command::new("cargo") + .args(["tree", "--locked", "--all-features", "-e", "normal,no-proc-macro"]) + .args(["--prefix", "none", "--format", "{p}", "--target", arch.kernel()]) + .arg("--manifest-path") + .arg(root.join("kernel/Cargo.toml")) + .output() + .expect("cargo tree failed to launch"); + let tree = String::from_utf8_lossy(&out.stdout); + assert!( + out.status.success() && tree.starts_with("kernel "), + "cargo tree --target {} exited {} and printed no kernel: {}", + arch.kernel(), + out.status, + String::from_utf8_lossy(&out.stderr) + ); + assert!( + !tree.lines().any(|package| package.starts_with("libc ")), + "the {} kernel resolves libc:\n{tree}", + arch.kernel() + ); + } + } + /// Every negative control the tree declares: every feature of the kernel's /// manifest but its builds and [`KERNEL_CARRIES`], and every feature of every /// host workspace member's but [`NOT_A_CONTROL`].