RustForge

foundry

Foundry OS: the operating system built on the Rustbelt kernel

foundry / README.md
6268 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
# Foundry OS

**Foundry OS** is a small operating system that runs on the **Rustbelt**
kernel, the way Ubuntu runs on Linux. The kernel (in its own repo,
`/workspace/rust-kernel`) drives the hardware; Foundry OS is everything
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 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: init runs the self-test
make run        # boot it in a QEMU window and play
make help       # every target
```

The first `make test` also builds the pinned kernel (a few minutes). You need
the packages the kernel needs plus `make` (all already on the box):
`rustup` (nightly), `qemu-system-x86`, `dosfstools`, `mtools`, `fdisk`,
`e2fsprogs`, `exfatprogs`, `btrfs-progs`, `musl-tools`, `gcc`.

## Make targets

| Target | What it does |
|---|---|
| `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, 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; `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 unit` | host unit tests (`cargo test` on the build machine, no QEMU): rbsh's parser and drive letters. `make rbsh-test` is the old name. |
| `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/`) |

## What is where

```
foundry/
├── Makefile, config.mk   the build; config.mk pins the kernel commit
├── rust/                 the Rust programs (a Cargo workspace)
│   ├── 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
├── 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), orphan
├── ports/                other people's C programs, one directory each (dash: /bin/dash)
├── 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)
```

## How it fits with the kernel

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 (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
kernel repo's git store with `git archive` and compiles it in `out/`, so the
kernel repo itself is never changed. To move to a newer kernel, follow
[docs/bumping-the-kernel.md]docs/bumping-the-kernel.md.

## Where this came from

The programs were in the kernel repo's `user/` folder. They were brought here
with **`git subtree split`**, which keeps their full history: try
`git log --follow rust/coreutils-rs/src/bin/ls.rs`. The kernel keeps its ABI
test programs (`forktest`, `rawabi`...), and for now the image still carries
them because the self-test runs them. See [docs/plan.md]docs/plan.md for
what comes next and [docs/proposal.md]docs/proposal.md for the full
background.

New to these words? **[docs/glossary.md]docs/glossary.md** explains
sysroot, static-PIE, subtree, GPT, musl and the rest.