# Requests to the kernel side (Rustbelt) The kernel is Edward's lane; Foundry OS never edits `/workspace/rust-kernel`. These are requests. The full list (K0-K11) with background is in [proposal.md](proposal.md), section 8. ## How M1 works without any kernel change The kernel's `build.rs` always builds *all* programs in its `user/` and its own `target/disk.img`. That does **not** stop us: the disk image is not inside the kernel's boot image. It is just a `-drive` argument to QEMU. So `make test`/`make run` boot the kernel's unchanged boot image with **our** `out/foundry.img` as the first virtio disk. The kernel's own `disk.img` (built into our `out/kernel-target`) is only used as the reference for `make compare` and `make test-reference`. No workaround in the kernel build was needed. The only costs today: - the kernel build still compiles the moved programs (wasted seconds), and - the kernel's own `cargo run`/`cargo test` use the kernel's `disk.img`, not Foundry OS's. `Cargo.toml`'s `run-args`/`test-args` say `file=target/disk.img`, a relative path that also assumes the default target dir. ## K1: `RUSTBELT_DISK0` (small, optional for M1, wanted before the kernel deletes the moved programs) > **Status: landed in Rustbelt 0.21.0 (50476f4).** Edward took this patch > and went further: `CARGO_TARGET_DIR` is honored everywhere (his scripts > and `Cargo.toml` paths, via the new `scripts/qemu.sh` runner), and the 19 > moved programs aren't even built when `RUSTBELT_DISK0` is set. > `make k1-check` builds the pinned kernel that way in its own target dir > (`out/kernel-k1-target`) and checks both: the kernel's `disk.img` is > byte-identical to `out/foundry.img`, and no moved program was built. > We still build the reference kernel *without* the variable, because > `make test-reference` and `make compare` need the kernel's own disk.img. **Request:** in `build.rs`, if the environment variable `RUSTBELT_DISK0` is set to an image file, copy that file to `$CARGO_TARGET_DIR/disk.img` (or `target/disk.img`) instead of building the FAT32 disk. Nothing changes when it is unset. ```sh RUSTBELT_DISK0=/workspace/foundry/out/foundry.img cargo test # kernel tests on the Foundry OS image ``` The exact change, 16 added lines in `build.rs` only. Tested in a scratch clone at a55b41d (`/workspace/foundry-scratch/rk`, branch `k1-experiment`, own target dir): `cargo build` with the variable set produced a `disk.img` byte-identical to `out/foundry.img`. ```diff diff --git a/build.rs b/build.rs index cc5505b..1f432dc 100644 --- a/build.rs +++ b/build.rs @@ -130,6 +130,9 @@ fn main() { println!("cargo:rerun-if-changed=vdso"); build_vdso(&manifest, &out_dir); + // K1: an OS image from outside (Foundry OS's `make image`) as disk 0. + println!("cargo:rerun-if-env-changed=RUSTBELT_DISK0"); + let external_disk0 = env::var_os("RUSTBELT_DISK0").map(PathBuf::from); for program in PROGRAMS { build_program(&user_dir, &out_dir, program); } @@ -139,7 +142,10 @@ fn main() { for &(program, kind) in MUSL_PROGRAMS { build_musl_program(&user_dir, &out_dir, program, kind); } - build_disk(&manifest, &out_dir); + match &external_disk0 { + Some(img) => use_external_disk(&manifest, img), + None => build_disk(&manifest, &out_dir), + } build_ext2_disks(&manifest, &out_dir); build_exfat_disks(&manifest, &out_dir); build_btrfs_disks(&manifest, &out_dir); @@ -263,6 +269,16 @@ fn run(cmd: &mut Command, stdin: Option<&str>) { assert!(status.success(), "{cmd:?} failed"); } +/// K1: copy an OS image built elsewhere to target/disk.img (instead of +/// building one), so `cargo run`/`cargo test` boot it as disk 0. +fn use_external_disk(manifest: &Path, img: &Path) { + println!("cargo:rerun-if-changed={}", img.display()); + let target_dir = env::var("CARGO_TARGET_DIR").map(PathBuf::from).unwrap_or_else(|_| manifest.join("target")); + fs::create_dir_all(&target_dir).unwrap(); + fs::copy(img, target_dir.join("disk.img")) + .unwrap_or_else(|e| panic!("RUSTBELT_DISK0={}: {e}", img.display())); +} + fn build_disk(manifest: &Path, out_dir: &Path) { let target_dir = env::var("CARGO_TARGET_DIR").map(PathBuf::from).unwrap_or_else(|_| manifest.join("target")); fs::create_dir_all(&target_dir).unwrap(); ``` Follow-ups, in order (each optional): 1. When `RUSTBELT_DISK0` is set, also skip `build_program` for the moved programs (`sh ls cat wc grep mkdir rm touch cp sleep ifconfig ping host fetch httpd getty tile random sysinfo`). Their binaries only go into the disk the kernel no longer builds. 2. Proposal step 9: once both repos have been green for a while, delete the moved programs from `user/`. The kernel keeps its fixtures and a frozen `ulib.rs`. `tests/shell.rs` includes `user/shparse.rs`; it would either keep a copy or test only through the booted shell. 3. K5 (contract v2: ext2 root, `/sbin/init` as pid 1). That is what makes Foundry OS the owner of what runs at boot. ## What Foundry OS still takes from the kernel repo | What | How | Goes away when | |---|---|---| | the kernel itself | `git archive $(KERNEL_REV)` (now 50476f4) → `out/kernel-src`, built in `out/kernel-target` | never (that's the point), but bumps are deliberate | | the 25 ABI fixtures in `/bin` | compiled from `out/kernel-src/user` | the self-test stops running them (they move to the kernel's own tests) or contract v2 | | the C:/D:/E: test disks | `ext2.img`, `exfat.img`, `btrfs.img` from the kernel build | stays: they are kernel-owned fixtures | | the expected self-test lines | copied into `scripts/run-headless.sh` (same 76 + 12 checks) | — (ours now; kernel-version lines must be updated on a bump) | | `scripts/http-reply.sh`, `scripts/hvc0-session.txt` | copied at a55b41d | — (ours now) | | Debian's `musl-gcc` | builds the 5 musl fixtures, as the kernel does | the fixtures leave the image |