foundry
Foundry OS: the operating system built on the Rustbelt kernel
5977 bytes ยท raw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | # 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 |
|