RustForge

foundry

Foundry OS: the operating system built on the Rustbelt kernel

authorGrok Bot <grokbot@localhost>2026-10-31 19:55:48 -0700
commit5a331c407d44af349001b8164b0379d033a7eacb
parentc8f1cf11021adb985d3d928c170b40a5595d20cd
treebrowse files at this commit
Docs: boot contract v2 (layout, init, drive letters and the share for beginners), M3 done, K12 (FAT dirty bit: no unmount on pid 1 exit)
MREADME.md+29 -17
Mdocs/boot-contract.md+124 -17
Mdocs/glossary.md+7 -2
Mdocs/kernel-requests.md+33 -5
Mdocs/plan.md+14 -10
Mdocs/porting.md+1 -1

6 files changed, 208 insertions, 52 deletions

@@ -6,14 +6,17 @@ kernel, the way Ubuntu runs on Linux. The kernel (in its own repo, else: the shell `rbsh`, the tools (`ls`, `cat`, `grep`...), the network and system programs, and the disk image they live on. -This repo builds **one file**, `out/foundry.img`, a virtual hard disk. The-kernel boots and runs the shell from it.+This repo builds **one file**, `out/foundry.img`, a virtual hard disk with+three parts (partitions): the system (drive `A:`, mounted at `/`), a data+disk (`B:`) and a share for swapping files with other computers (`C:`).+The kernel boots, mounts them, and runs our `/sbin/init`, which starts the+shell.  ## Quick start  ```sh make            # build out/foundry.img (the same as `make image`)-make test       # boot it headless in QEMU and run the shell self-test+make test       # boot it headless in QEMU: init runs the self-test make run        # boot it in a QEMU window and play make help       # every target ```@@ -27,16 +30,20 @@ the packages the kernel needs plus `make` (all already on the box):  | Target | What it does | |---|---|-| `make image` | builds the Rust programs, our C programs and ports, the kernel's test fixtures, assembles `out/staging/`, and writes `out/foundry.img` |-| `make rust` | `cargo build --release` in `rust/` |+| `make image` | builds the Rust programs, our C programs and ports, the kernel's test fixtures, assembles `out/staging-v2/`, and writes `out/foundry.img` (boot contract v2: ext2 root A:, FAT32 data B:, exFAT share C:; see [docs/boot-contract.md](docs/boot-contract.md)) |+| `make image-v1` | the old one-partition FAT32 image, `out/foundry-v1.img` (contract v1) |+| `make rust` | `cargo build --release` in `rust/` (rbsh, init, the tools) | | `make fixtures` | builds the kernel's ABI test programs from the pinned kernel source |-| `make cprogs` | builds our C programs (`c/`: hello-musl, fprobe) as static-PIEs with `toolchain/foundry-cc` |+| `make cprogs` | builds our C programs (`c/`: hello-musl, fprobe, orphan) as static-PIEs with `toolchain/foundry-cc` | | `make ports` | downloads (SHA256-checked, into `cache/`) and builds the ports (dash) the same way | | `make kernel` | builds the pinned Rustbelt kernel into `out/kernel-target` |-| `make run` | boots the image in a QEMU window (`NOGRAPHIC=1` for serial only) |-| `make test` | headless boot, self-test, ~100 expected-output checks (the kernel's, plus ours from `scripts/expect-foundry.txt`); exit 0 = pass |-| `make test-reference` | the same test on the kernel's *own* disk image (the baseline) |-| `make compare` | compares our image with the kernel's, file by file |+| `make run` | boots the image in a QEMU window (`NOGRAPHIC=1` for serial only; `KEEP=1` keeps what you write to the disk) |+| `make test` | headless boot: our `/sbin/init` runs the self-test (expected lines in `scripts/expect-v2.txt`), then the host fscks all three file systems and reads the share back; exit 0 = pass |+| `make test-v1` | the contract-v1 test: the kernel runs the shell self-test on `out/foundry-v1.img` (~100 checks) |+| `make test-reference` | the v1 test on the kernel's *own* disk image (the baseline) |+| `make compare` | compares our v1 image with the kernel's, file by file |+| `make rbsh-test` | host unit tests for rbsh's parser and drive letters (no QEMU) |+| `make k1-check` | builds the kernel with `RUSTBELT_DISK0=out/foundry.img` and checks it uses our image | | `make musl` | downloads (into `cache/`) and builds musl into `out/sysroot`; `make cprogs`/`make ports` run it when needed | | `make clean` | `rm -rf out` (`make distclean` also empties `cache/`) | @@ -46,18 +53,20 @@ the packages the kernel needs plus `make` (all already on the box): foundry/ ├── Makefile, config.mk   the build; config.mk pins the kernel commit ├── rust/                 the Rust programs (a Cargo workspace)-│   ├── rbsh/             the shell (installed as /bin/sh for now)+│   ├── init/             /sbin/init: the first program; starts shells, reaps orphans+│   ├── rbsh/             the shell, /bin/rbsh (drive letters A: B: C:) │   ├── coreutils-rs/     ls cat wc grep mkdir rm touch cp sleep │   ├── net/              ifconfig ping host fetch httpd │   ├── sys/              getty tile random sysinfo │   ├── rbrt/             the runtime every program includes (ulib.rs) + shared build.rs │   └── link.ld           puts programs at address 0x80_0040_0000-├── rootfs/               files copied onto the disk as they are (readme, notes, the self-test)-│   └── etc/              passwd, hosts... for the later ext2 root (not in the image yet)+├── root/                 the root file system, A: = / (etc/, the v2 self-test in scripts/)+├── rootfs/               the FAT32 data disk, B: = /mnt/disk0 (readme, notes; v1 self-test)+├── share/                the exFAT share, C: = /mnt/share (README.TXT) ├── toolchain/           foundry-cc (gcc + musl, static-PIE); musl/ pinned by SHA256, downloaded into cache/-├── c/                    our own C programs: hello-musl, fprobe (the libc self-check)+├── c/                    our own C programs: hello-musl, fprobe (the libc self-check), orphan ├── ports/                other people's C programs, one directory each (dash: /bin/dash)-├── scripts/              mkimage, build-kernel, run-qemu, run-headless, compare-image...+├── scripts/              mkimage(-v2), exfat.py, build-kernel, run-qemu, run-headless, check-v2-image... ├── docs/                 how it all fits together (start with docs/glossary.md) ├── out/                  everything built (git-ignored) └── cache/                downloads (git-ignored)@@ -67,8 +76,11 @@ foundry/  The kernel repo and this repo meet in exactly one place: the **disk image**. [docs/boot-contract.md](docs/boot-contract.md) says what the image must-contain. QEMU gets our image as its first virtio disk, the kernel mounts it at-`/mnt/disk0` (the shell calls it drive `B:`) and runs `/mnt/disk0/bin/sh`.+contain. QEMU gets our image as its first virtio disk; the kernel (0.21.0+)+mounts the ext2 root partition at `/`, the FAT32 partition at `/mnt/disk0`+and the exFAT share at `/mnt/share`, and runs `/sbin/init` as process 1+(contract v2). `make test-v1` still checks the old layout (contract v1:+one FAT32 partition at `/mnt/disk0`, the kernel runs `/mnt/disk0/bin/sh`).  We build against **one exact kernel commit** (`KERNEL_REV` in `config.mk`, now `50476f4` = Rustbelt 0.21.0). The build exports that commit from the
@@ -4,9 +4,131 @@ The Rustbelt kernel and Foundry OS live in different repos. This page is the whole agreement between them. The kernel never needs to know *how* the image was built, only that it follows the contract. -## Contract v1: "today, written down" (in use now)+## Contract v2: a real root file system (in use since M3) -Pinned kernel: Rustbelt 0.21.0, commit 50476f4 (was 0.20.0, 5291332). No kernel change needed.+Pinned kernel: Rustbelt 0.21.0, commit 50476f4 (stage 21, which added+v2; it was kernel request K5). `make image` builds out/foundry.img with+scripts/mkimage-v2.sh; `make test` checks it.++### What the kernel does (Rustbelt 0.21.0)++1. **Root.** It mounts the **first GPT partition of type "Linux root+   (x86-64)"** (`4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709`, the freedesktop+   *Discoverable Partitions* type) that holds **ext2** at **`/`**. Only+   ext2, and there is no `root=` option to pick another one.+2. **Share.** It mounts the first **"Microsoft basic data"** partition+   holding **exFAT** at **`/mnt/share`**, read-write. Limits: no rename,+   no timestamps, no volume-dirty flag. A TexFAT volume (two FATs) is+   mounted read-only, so our share has one FAT (mkfs.exfat's default).+3. **Other disks/partitions** get `/mnt/disk0`, `/mnt/disk1`, ... in device+   order (the root and the share don't use a number). It also provides a+   ramfs at `/tmp`, devfs at `/dev`, proc at `/proc`.+4. **pid 1.** It runs the first of `/sbin/init`, `/bin/init`, `/bin/sh`+   that starts, with the console as its terminal:+   - argv `["init"]` (`["sh"]` for the sh fallback); environment+     `PATH=/sbin:/bin:/usr/bin:/mnt/disk0/bin HOME=/ TERM=linux`.+   - Headless kernel build: argv `["init", "selftest"]` (sh:+     `["sh", "/scripts/selftest.sh"]`) plus `RUSTBELT_HEADLESS=1`.+   - `RUSTBELT_INIT_ARGS` / `RUSTBELT_INIT_ENV` at kernel *build* time add+     arguments and variables. There are no run-time boot options.+   - Orphaned processes are handed to pid 1 **only if it is named+     `init`**. pid 1 is never restarted: when it exits with code n+     (0-111), QEMU exits with **33 + 2n** (33 = pass); anything else gives 35.+5. **No root partition** → the kernel behaves exactly as under v1.++### What Foundry OS puts on the disk++One disk, GPT, three partitions (sizes in config.mk):++| # | GPT type             | file system | size   | mounted at   | rbsh drive | from      |+|---|----------------------|-------------|--------|--------------|------------|-----------|+| 1 | Linux root (x86-64)  | ext2 (1 KiB blocks), label `foundry-root` | 32 MiB | `/`          | **A:** | `root/`   |+| 2 | Microsoft basic data | FAT32, label `FOUNDRY` | 40 MiB | `/mnt/disk0` | **B:** | `rootfs/` |+| 3 | Microsoft basic data | exFAT (1 FAT), label `SHARE` | 16 MiB | `/mnt/share` | **C:** | `share/`  |++**Why one disk and not three?** A real computer installs an OS on one+disk with several partitions, and the kernel looks for the root and the+share by partition type, so one image file is enough: one file to copy,+one `-drive` for QEMU, and the letters can't get mixed up by the order of+disks. (Several disks would also work; nothing in the kernel needs one.)+`make test` attaches *only* this disk. The kernel's own ext2/exFAT/btrfs+test disks are checked by `make test-v1` and `make test-reference`.++**A: (root, ext2)** holds the system:++- `/sbin/init`: Foundry OS init (rust/init). It is named `init`, so the+  kernel hands it orphans. It starts **rbsh** as the login shell on the+  console and on `/dev/hvc0` (when QEMU has a virtio console), starts a+  new one when a shell exits (it gives up on a terminal when the shell+  dies within a second of starting 5 times in a row, or can't be started+  at all), and reaps every orphan it is given.+  Headless (`init selftest` or `RUSTBELT_HEADLESS=1`) it runs+  `rbsh /scripts/selftest.sh` on the console, waits up to 5 s for all+  leftover processes, prints `[init] memory: N frames in use before the+  self-test, M after ...` (the kernel does not print a frame report under+  v2), and exits with the shell's status.+- `/bin`: **rbsh** (`/bin/rbsh`), **dash** (`/bin/dash`, and `/bin/sh`, a+  symlink to it), the Rust tools (`ls`, `cat`, `cp`, ...: first on PATH),+  our C programs (`hello-musl`, `fprobe`, `orphan`).+- `/etc` (passwd, group, hosts, resolv.conf, motd), `/scripts` (the+  self-test), and empty `/usr/bin`, `/tmp`, `/root`, `/home/tyler`,+  `/mnt/disk0`, `/mnt/share`.++**B: (data, FAT32)** holds `readme.txt`, `notes/` and, in `/bin`, the+kernel's **ABI test programs** (`forktest`, `rawabi`, `piehello`, ... 28+of them, built from the pinned kernel by `make fixtures`). They are last+on PATH (`/mnt/disk0/bin`), so the self-test runs them by name and they+never hide one of our tools.++**C: (share, exFAT)** holds `README.TXT`. scripts/exfat.py writes it+there, because mkfs.exfat can only create an empty volume.++### Drive letters and the share, for beginners++Linux has one tree of folders starting at `/`. Each disk (or partition)+is *mounted* on a folder in that tree: its files appear under that+folder. rbsh adds DOS-style **drive letters** on top, as shortcuts:++- **A:** is `/`, the root: the whole system. `A:/bin/ls` is `/bin/ls`.+- **B:** is `/mnt/disk0`, the data disk (FAT32, the format of old USB sticks).+- **C:** is `/mnt/share`, the share.+- More disks would be D:, E:, ... (`drives` lists them).++`cd C:` takes you to the share; `ls B:/bin` lists the test programs.+Other programs (dash, C programs) don't know the letters and use the+real paths.++**The share** is a place for files that go between Foundry OS and other+computers. It uses **exFAT**, the format of SD cards and USB sticks,+which Windows, macOS and Linux all read and write, so the partition can+be copied out of the image and opened elsewhere. In Foundry OS you can+create, write and delete files there (not rename them yet). `make test`+writes `from-foundry.txt` to it and then reads it back *on the host*,+without the kernel, to prove another system can see it.++### How `make test` checks this contract++- the banner; the kernel's mount lines (`mounted at / (root partition)`,+  `mounted at /mnt/share`); init's start line and its mount list;+- `drives` shows `A:  /  ext2`, `B:  /mnt/disk0  fat32`, `C:  /mnt/share  exfat`;+- rbsh writes to A: and C:; dash (root/scripts/v2-test.sh) checks the+  environment, PATH order, `/bin/sh` → dash, and writes, reads back and+  deletes files on A:, B: and C:;+- the kernel's stages (processes, threads, network, virtio...) as under v1;+- `orphan` (c/orphan.c): a grandchild left behind is adopted by pid 1+  and reaped; init reports how many orphans it reaped (must be ≥ 1);+- frames flat: init's memory line shows the same number before and after;+- QEMU exit 33 (init exited 0);+- afterwards, on the host (scripts/check-v2-image.sh): `e2fsck -fn` on A:,+  `fsck.fat -n` on B:, `fsck.exfat -n` on C:, a single-FAT check, and+  scripts/exfat.py reads `from-foundry.txt` back and checks deleted files+  are gone.++## Contract v1: the old layout (still supported: `make test-v1`)++Used until M3; Rustbelt 0.21.0 still falls back to it when a disk has no+root partition. `make image-v1` builds it (out/foundry-v1.img) and+`make test-v1` / `make compare` check it.  1. **Where.** The OS image is the **first virtio-blk disk** QEMU is given.    The kernel mounts it at `/mnt/disk0` (drive `B:` in rbsh).@@ -37,18 +159,3 @@ Under v1 the image must also carry the kernel's ABI test programs (`forktest`, `rawabi`, ...), because the self-test runs them. They are built from the pinned kernel source (`make fixtures`); see [kernel-requests.md](kernel-requests.md) for how that dependency goes away.--## Contract v2: a real root file system (planned, needs kernel request K5)--1. The OS image is GPT with a partition of type **Linux root (x86-64)**,-   `4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709` (the freedesktop *Discoverable-   Partitions* rule), formatted **ext2**. The kernel mounts it at **`/`**,-   so `A:` = `/` is the OS disk.-2. The kernel keeps a ramfs at `/tmp`, devfs at `/dev`, and mounts the other-   disks at `/mnt/diskN`.-3. The kernel runs the first that exists of `/sbin/init`, `/bin/init`,-   `/bin/sh` as **pid 1**, does not respawn it, and hands orphans to it.-   Headless: `["init", "selftest"]`; pid 1's exit status ends QEMU.-4. Fallback: no root partition → behave as v1.--See [plan.md](plan.md) for the disk layout we chose for v2.
@@ -6,8 +6,13 @@ | **userland** | Everything that is not the kernel: the shell, `ls`, the C library. It runs in the CPU's unprivileged mode ("ring 3"). Foundry OS *is* a userland. | | **syscall** | A request a program makes to the kernel ("open this file", "start this program"). Rustbelt uses Linux's syscall numbers, plus a few of its own (500-505). | | **disk image** | A plain file holding every byte of a virtual hard disk. QEMU uses it as a disk. Ours is `out/foundry.img`. |-| **GPT** | The partition table at the start of the disk: it says where each partition starts and what it is for. Ours has one partition, at sector 2048 (1 MiB). |-| **FAT32 / ext2 / exFAT** | File system formats. FAT32 is what the image uses today (simple, no permissions or symlinks). ext2 is the Unix-style format we will move the OS to. exFAT is for sharing files with Windows/macOS. |+| **GPT** | The partition table at the start of the disk: it says where each partition starts and what it is for. Ours has three (contract v2): the ext2 root, the FAT32 data disk and the exFAT share. The old v1 image has one. |+| **FAT32 / ext2 / exFAT** | File system formats. ext2 is the Unix-style format of our root (A:: permissions, symlinks). FAT32 is the data disk (B:; simple, no permissions or symlinks). exFAT is the share (C:), the format of USB sticks and SD cards that Windows, macOS and Linux all read and write. |+| **partition** | One slice of a disk, used as if it were a disk of its own, with its own file system. The GPT says where each one is and its *type* (e.g. "Linux root"), which is how the kernel finds the root. |+| **mount** | Making a file system appear under a folder. The root partition is mounted at `/`, the share at `/mnt/share`. Drive letters (`A:`, `B:`, `C:`) are rbsh's shortcuts for these folders. |+| **root file system** | The file system mounted at `/`, holding the system itself (`/bin`, `/sbin`, `/etc`). Ours is ext2, drive `A:`. |+| **init / pid 1** | The first program the kernel starts (process number 1): ours is `/sbin/init` (rust/init). It starts the shells, starts a new one when one exits, and *reaps orphans*. |+| **orphan, reaping** | When a process exits, its parent must collect ("reap") its exit status with `wait`, or it lingers as a *zombie*. If the parent died first, the child is an *orphan*; the kernel hands it to init, which reaps it. | | **mtools** | Programs (`mcopy`, `mmd`) that write files *into* a FAT image file directly, so building the image needs no root and no mounting. | | **QEMU** | A program that pretends to be a whole PC, so we can boot Rustbelt + Foundry OS without real hardware. "Headless" means no window: output goes to the terminal and a log. | | **boot contract** | The short agreement between kernel and OS about what the disk image must contain: [boot-contract.md](boot-contract.md). |
@@ -2,7 +2,7 @@  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.+[proposal.md](proposal.md), section 8. K12 (below) is new since M3.  ## How M1 works without any kernel change @@ -104,16 +104,44 @@ Follow-ups, in order (each optional):    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+3. K5 (contract v2: ext2 root, `/sbin/init` as pid 1). **Landed in+   0.21.0** and used since M3 (docs/boot-contract.md). That is what makes    Foundry OS the owner of what runs at boot. +## K12: clean shutdown when pid 1 exits (small, new in M3)++Found by `make test` (v2), which boots a writable copy of our image and+checks it with `fsck` afterwards. ext2 (A:) and exFAT (C:) come back+clean. The FAT32 data disk (B:) comes back with its **dirty bit set**:++```+$ fsck.fat -n B-partition-after-the-run+There are differences between boot sector and its backup.+  65:01/00+Dirty bit is set. Fs was not properly unmounted and some data may be corrupt.+B-partition-after-the-run: 33 files, 2676/80628 clusters+```++The image before the run is clean (`fsck.fat -n` exit 0), and only byte 65+of the boot sector differs in that area. The `fatfs` crate sets this bit on+the first write and clears it in `FileSystem::unmount()` (or on drop);+Rustbelt never unmounts, and `run_init_v2` calls `exit_qemu_with` right+after pid 1 exits. Everything else on the volume is consistent (fsck is+clean once the bit is cleared), so no data is lost. But Windows, macOS and+Linux will all offer to "repair" the disk.++**Request:** when pid 1 exits (and in `reboot`/power-off later, K7),+unmount or flush the mounted file systems before QEMU exits. For FAT that+means calling fatfs's `unmount()`. Our host check+(scripts/check-v2-image.sh) prints a WARN for now instead of failing.+ ## 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) |+| the 28 ABI fixtures (v2: in `B:/bin`, i.e. `/mnt/disk0/bin`, last on PATH) | compiled from `out/kernel-src/user` | the self-test stops running them (they move to the kernel's own tests) |+| the C:/D:/E: test disks (v1 tests only) | `ext2.img`, `exfat.img`, `btrfs.img` from the kernel build | stays: they are kernel-owned fixtures |+| the expected self-test lines | v1: copied into `scripts/run-headless.sh` (same 76 + 12 checks); v2: ours, in `scripts/expect-v2.txt` | — (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 |
@@ -7,27 +7,31 @@ | 1 | Name, place, history | The OS is **Foundry OS**, in `/workspace/foundry` (local git only: no remote, no push). The kernel's `user/` and `disk/` histories were kept with `git subtree split`, done in a scratch clone at a55b41d (`/workspace/foundry-scratch/rk`), never in `/workspace/rust-kernel`. | | 2 | What stays in the kernel | The ABI test programs stay as kernel fixtures: `hello evil spin demo child overflow forktest cowtest mmaptest sigtest threads echoserver ptytest nbtest fputest pathtest libctest coretest unixtest rawabi` and the musl ones `vdsotest piehello piethreads dynhello remaptest`. The shell, the tools and the net/sys programs moved here. | | 3 | Which shell | The Rust shell stays the interactive login shell, renamed **rbsh**, keeping its DOS commands (`run`/`start`, `dir`/`type`/`cls`...) and drive letters. **dash** (later busybox `ash`) becomes `/bin/sh` for POSIX scripts once the root is ext2. Under contract v1 rbsh is still installed as `/bin/sh`, because that is the path the kernel runs. |-| 4 | Root file system | Later: an **ext2 root**, so `A:` = `/` is the OS disk. The FAT32 disk stays as a **data disk** (`B:`). Plus an **exFAT data partition** for sharing files with Windows/macOS. M1 keeps contract v1 (today's layout). |+| 4 | Root file system | An **ext2 root**, so `A:` = `/` is the OS disk. The FAT32 disk stays as a **data disk** (`B:`). Plus an **exFAT share** (`C:`, `/mnt/share`) for files that go to Windows/macOS. Built in M3 (contract v2). | | 5 | Name clashes | The Rust tools stay the default. busybox/sbase applets go under **`/usr/lib/busybox`**, off the default `PATH` (call them by full path, or add the directory to `PATH` yourself). | | 6 | Tarballs | **Not in git.** A git-ignored download cache (`cache/`), each file pinned by SHA256 (`toolchain/musl/musl.sha256` + `fetch.sh`; `ports/<name>/<name>.sha256`). | | 7 | Which kernel | A **pinned commit**: `KERNEL_REV` in `config.mk` (now `50476f4`, Rustbelt 0.21.0; before that `5291332`, 0.20.0), bumped deliberately: see [bumping-the-kernel.md](bumping-the-kernel.md). | | 8 | Box packages | Small build packages are OK (`make`, `bzip2`, `musl-tools`, `autoconf`). | -## Disk layout later (contract v2, not built yet)+## Disk layout (contract v2, built in M3)++The details and the reasons are in [boot-contract.md](boot-contract.md).+One disk, three partitions:  ```-foundry.img (GPT)-├── 1  ext2   "Linux root (x86-64)" type   → mounted at /       (A:)  the OS: /bin /sbin /etc /usr ...-└── 2  exFAT  "Microsoft basic data" type  → /mnt/diskN          data shared with other computers-data.img (separate disk, today's FAT32)    → /mnt/disk0          (B:)  a plain data disk+foundry.img (GPT, 90 MiB)+├── 1  ext2   "Linux root (x86-64)"   → /           (A:)  the OS, from root/+├── 2  FAT32  "Microsoft basic data"  → /mnt/disk0  (B:)  data disk + the kernel's ABI test programs, from rootfs/+└── 3  exFAT  "Microsoft basic data"  → /mnt/share  (C:)  the share, from share/ ```  Inside the ext2 root:  ```-/bin       rbsh, the Rust tools (ls cat grep ...), dash as /bin/sh-/sbin      init (Rust, M3)-/etc       passwd group hosts resolv.conf motd profile rc   (rootfs/etc/)+/sbin/init         Foundry OS init (rust/init)+/bin               rbsh, dash (also /bin/sh), the Rust tools (ls cat grep ...), our C programs+/etc               passwd group hosts resolv.conf motd   (root/etc/)+/scripts           the self-test init runs headless /usr/lib/busybox   busybox + applet symlinks, off the default PATH (M5) ``` @@ -39,6 +43,6 @@ Inside the ext2 root: | M1b | `rbrt` becomes a real library crate; rbsh's parser tests run on the host | next | | **M2** | musl hello + probes in `/bin`, built static-PIE with `toolchain/foundry-cc` | **done**: `hello-musl` and `fprobe` (40 checks incl. timerfd) in `/bin`, checked by `make test` | | M2b | dash built from ports/ as `/bin/dash`, with script checks in `make test` | **done** |-| M3 | dash as `/bin/sh`, ext2 root (contract v2), Rust `/sbin/init` | needs kernel K5 |+| **M3** | dash as `/bin/sh`, ext2 root (contract v2), Rust `/sbin/init`, exFAT share | **done** on Rustbelt 0.21.0: `make test` (v2) passes, plus host fsck of all three file systems; `make test-v1` still passes | | M4 | sbase tools | needs testing per tool (docs/syscall-gaps.md) | | M5 | busybox in `/usr/lib/busybox` | `bzip2` for the tarball |
@@ -80,7 +80,7 @@ ports/<name>/<name>.sha256   "SHA256  <tarball>" ports/<name>/<name>.url      where to download it ports/<name>/patches/        0001-*.patch ... ports/<name>/build.sh        unpack from cache/, patch, CC=toolchain/foundry-cc ./configure --host=x86_64-linux-musl,-                             make, install into out/staging (busybox/sbase: under /usr/lib/busybox)+                             make, install into out/staging-v2/root (busybox/sbase: under /usr/lib/busybox) ```  Then boot it (`make test` / `make run`), try it, and note any missing