RustForge

foundry

Foundry OS: the operating system built on the Rustbelt kernel

authorGrok Bot <grokbot@localhost>2026-10-31 19:18:31 -0700
commiteeb17191ca987aed8a182690ff99acbfd3360053
parent3219ac028e84cecb701829744852c66efa89e4e6
treebrowse files at this commit
M2: build c/ with foundry-cc, put hello-musl and fprobe in /bin, check them in make test

- make cprogs: toolchain/foundry-cc (static-PIE); builds musl first if needed.
- selftest.sh: a marked 'Foundry OS' block at the end runs both programs.
- scripts/expect-foundry.txt: their expected lines (EXTRA_EXPECT for make
  test only; test-reference keeps the kernel's own list).
- compare-image.sh: leaves FOUNDRY_BIN out of the list comparison and cuts
  the Foundry OS block out of selftest.sh before comparing it.
MMakefile+29 -9
Mconfig.mk+6 -0
Mrootfs/scripts/selftest.sh+8 -0
Mscripts/compare-image.sh+12 -3
Ascripts/expect-foundry.txt+20 -0

5 files changed, 75 insertions, 12 deletions

@@ -14,9 +14,14 @@ KSRC       := $(OUT)/kernel-src KTARGET    := $(OUT)/kernel-target KBOOT      := $(OUT)/kernel/bootimage.bin KBOOT_HL   := $(OUT)/kernel/bootimage-headless.bin+SYSROOT    := $(OUT)/sysroot+FCC        := $(CURDIR)/toolchain/foundry-cc+C_OUT      := $(OUT)/c+# Everything in /bin, in order: the kernel's list, then Foundry OS's own.+ALL_BIN    := $(BIN_ORDER) $(FOUNDRY_C)  .DEFAULT_GOAL := image-.PHONY: help image rust fixtures staging kernel kernel-src run test test-reference compare musl clean distclean+.PHONY: help image rust fixtures cprogs staging kernel kernel-src run test test-reference compare musl clean distclean  help: 	@echo "Foundry OS (userland for the Rustbelt kernel $(KERNEL_VERSION) @ $(KERNEL_REV))"@@ -24,13 +29,14 @@ help: 	@echo "  make / make image   build out/$(IMAGE_NAME), the disk image (contract $(CONTRACT))" 	@echo "  make rust           cargo build the Rust programs in rust/" 	@echo "  make fixtures       build the kernel's ABI test programs from the pinned kernel"+	@echo "  make cprogs         build our C programs (c/) as static-PIEs with toolchain/foundry-cc" 	@echo "  make staging        assemble out/staging (rootfs/ + /bin)" 	@echo "  make kernel         build the pinned kernel into out/kernel-target" 	@echo "  make run            boot the image in a QEMU window" 	@echo "  make test           headless boot + the shell self-test + expected-line checks" 	@echo "  make test-reference  the same headless test, but booting the kernel's own disk.img (baseline)" 	@echo "  make compare        compare out/$(IMAGE_NAME) with the kernel's own disk.img"-	@echo "  make musl           fetch (cache/) + build musl $(MUSL_VERSION) into out/sysroot (not in the image yet)"+	@echo "  make musl           fetch (cache/) + build musl $(MUSL_VERSION) into out/sysroot" 	@echo "  make clean          rm -rf out   (distclean also removes cache/)"  # ---- the pinned kernel -------------------------------------------------------@@ -47,18 +53,27 @@ rust: fixtures: kernel-src 	scripts/build-fixtures.sh $(KSRC) $(FIXTURES) "$(FIXTURE_RUST)" "$(FIXTURE_C)" "$(FIXTURE_MUSL)" +# Our own C programs: gcc + our musl, static-PIE (docs/porting.md).+cprogs: $(SYSROOT)/lib/musl-pie.specs+	mkdir -p $(C_OUT)+	for p in $(FOUNDRY_C); do \+	    $(FCC) -O2 -Wall -Wextra -pthread -Wl,--build-id=none c/$$p.c -o $(C_OUT)/$$p || exit 1; \+	done+	@echo "[cprogs] built $(FOUNDRY_C) into $(C_OUT)"+ # ---- the image --------------------------------------------------------------- # Contract v1: rootfs/ minus etc/ (etc/ is for the contract-v2 ext2 root, # see docs/plan.md) goes to the top of the FAT32 volume, programs to /bin.-staging: rust fixtures+staging: rust fixtures cprogs 	rm -rf $(STAGING) && mkdir -p $(STAGING)/bin 	cd rootfs && for e in $$(ls -A); do [ "$$e" = etc ] && [ "$(CONTRACT)" = v1 ] && continue; cp -r "$$e" $(STAGING)/; done 	for p in $(filter-out sh,$(RUST_PROGRAMS)); do cp $(RUST_OUT)/$$p $(STAGING)/bin/; done 	cp $(RUST_OUT)/rbsh $(STAGING)/bin/sh    # contract v1: the kernel runs /mnt/disk0/bin/sh 	cp $(FIXTURES)/* $(STAGING)/bin/+	for p in $(FOUNDRY_C); do cp $(C_OUT)/$$p $(STAGING)/bin/; done  image: staging-	scripts/mkimage.sh $(STAGING) $(IMAGE) $(IMAGE_MIB) $(IMAGE_LABEL) "$(BIN_ORDER)"+	scripts/mkimage.sh $(STAGING) $(IMAGE) $(IMAGE_MIB) $(IMAGE_LABEL) "$(ALL_BIN)"  # ---- booting ---------------------------------------------------------------- run: image kernel@@ -68,21 +83,26 @@ run: image kernel TEST_ENV   := KERNEL_BANNER="$(KERNEL_BANNER)" KERNEL_VERSION=$(KERNEL_VERSION)  test: image kernel-	$(TEST_ENV) BIN_COUNT=$(words $(BIN_ORDER)) \+	$(TEST_ENV) BIN_COUNT=$(words $(ALL_BIN)) EXTRA_EXPECT=scripts/expect-foundry.txt \ 	    scripts/run-headless.sh $(IMAGE) $(KBOOT_HL) $(KTARGET) $(OUT) -# The baseline: the kernel's own disk.img through the very same checks.+# The baseline: the kernel's own disk.img through the very same checks+# (without Foundry OS's own programs and expected lines, which it lacks). test-reference: kernel 	$(TEST_ENV) BIN_COUNT=$(words $(BIN_ORDER)) \ 	    scripts/run-headless.sh $(KTARGET)/disk.img $(KBOOT_HL) $(KTARGET) $(OUT)/reference  compare: image kernel-	scripts/compare-image.sh $(IMAGE) $(KTARGET)/disk.img $(OUT)+	FOUNDRY_BIN="$(FOUNDRY_C)" scripts/compare-image.sh $(IMAGE) $(KTARGET)/disk.img $(OUT) -# ---- toolchain (M2 groundwork; not used by the v1 image) ---------------------+# ---- toolchain ---------------------------------------------------------------+# musl is built once; delete out/sysroot (or run `make musl`) to rebuild it. musl: 	toolchain/musl/fetch.sh cache-	toolchain/musl/build.sh cache $(OUT)/musl-build $(OUT)/sysroot+	toolchain/musl/build.sh cache $(OUT)/musl-build $(SYSROOT)++$(SYSROOT)/lib/musl-pie.specs: toolchain/musl/musl.sha256 toolchain/musl/musl-pie.specs.in toolchain/musl/build.sh+	$(MAKE) musl  clean: 	rm -rf out
@@ -53,5 +53,11 @@ BIN_ORDER      := sh ls cat wc grep mkdir rm touch cp sleep \                   rawabi vdsotest piehello piethreads dynhello remaptest \                   exechello execthreads timerfdtest +# Foundry OS's own C programs (c/NAME.c), built with toolchain/foundry-cc+# as static-PIEs against our musl (milestone M2). They go to /bin after the+# programs above, and the self-test runs them (rootfs/scripts/selftest.sh,+# the "Foundry OS" block; expected lines in scripts/expect-foundry.txt).+FOUNDRY_C      := hello-musl fprobe+ # ---- Toolchain pins (downloaded into cache/, checked by SHA256) ----------- MUSL_VERSION   ?= 1.2.5
@@ -117,4 +117,12 @@ nosuchprogram cd Q: cd A:/tmp pwd+# ---- Foundry OS ----+# Foundry OS's own programs (milestone M2): C on musl, built by+# toolchain/foundry-cc as static-PIEs. hello-musl prints one line; fprobe+# checks the C library's view of the kernel (files, processes, signals,+# threads, mmap, clocks, timerfd) and prints a summary line at the end.+hello-musl+fprobe+# ---- end Foundry OS ---- exit 0
@@ -9,17 +9,26 @@ # in bytes from the kernel's single-file rustc builds (Cargo adds crate # metadata), so only list equality and non-program files fail the check. #-# Usage: scripts/compare-image.sh OURS KERNELS OUT_DIR+# Since M2 our image has more than the kernel's: Foundry OS's own programs+# (env FOUNDRY_BIN, left out of the list comparison) and a "Foundry OS"+# block in scripts/selftest.sh (cut out before comparing that file).+#+# Usage: [FOUNDRY_BIN="prog ..."] scripts/compare-image.sh OURS KERNELS OUT_DIR set -euo pipefail+fail=0 OURS=$1 THEIRS=$2 OUT=$(realpath -m "$3")/compare export MTOOLS_SKIP_CHECK=1 rm -rf "$OUT" && mkdir -p "$OUT/ours" "$OUT/kernel" mcopy -s -n -i "$OURS@@1M" '::/*' "$OUT/ours/" mcopy -s -n -i "$THEIRS@@1M" '::/*' "$OUT/kernel/" -(cd "$OUT/ours/bin" && ls | LC_ALL=C sort) > "$OUT/bin-ours.txt"+(cd "$OUT/ours/bin" && ls | LC_ALL=C sort) > "$OUT/bin-ours-all.txt"+grep -vxF -f <(printf '%s\n' ${FOUNDRY_BIN:-} '') "$OUT/bin-ours-all.txt" > "$OUT/bin-ours.txt" || true+echo "== Foundry OS's own programs (not in the kernel's image): ${FOUNDRY_BIN:-none}"+for p in ${FOUNDRY_BIN:-}; do [ -f "$OUT/ours/bin/$p" ] || { echo "   MISSING /bin/$p"; fail=1; }; done+# Our selftest.sh = the kernel's + a "Foundry OS" block; compare without it.+sed -i '/^# ---- Foundry OS ----$/,/^# ---- end Foundry OS ----$/d' "$OUT/ours/scripts/selftest.sh" (cd "$OUT/kernel/bin" && ls | LC_ALL=C sort) > "$OUT/bin-kernel.txt"-fail=0 echo "== /bin program list: ours $(wc -l < "$OUT/bin-ours.txt"), kernel $(wc -l < "$OUT/bin-kernel.txt")" if diff -u "$OUT/bin-kernel.txt" "$OUT/bin-ours.txt"; then     echo "   same list"
@@ -0,0 +1,20 @@+# Lines Foundry OS's own part of the self-test must print (the "Foundry OS"+# block at the end of rootfs/scripts/selftest.sh). `make test` passes this+# file to scripts/run-headless.sh as EXTRA_EXPECT; `make test-reference`+# (the kernel's own image) doesn't. One line per check, matched as a fixed+# string anywhere in the serial log. @KERNEL_VERSION@ = config.mk's value.+# Blank lines and lines starting with # are skipped.++# hello-musl: a static-PIE C program on our musl.+hello from musl on Rustbelt @KERNEL_VERSION@ (Foundry OS, static-PIE)++# fprobe (c/fprobe.c): a few key checks by name, then the summary, which+# also pins the number of checks (so none can silently go missing).+fprobe: Foundry OS libc self-check on Rustbelt @KERNEL_VERSION@+  static-PIE: ET_DYN without PT_INTERP           ok+  4 threads x 20000 mutex increments = 80000     ok+  timerfd one-shot: read blocks ~150 ms, count 1 ok+  timerfd 60 ms interval: 5-14 expirations in 700 ms ok+  timerfd wakes epoll_wait                       ok+  TFD_TIMER_CANCEL_ON_SET -> EINVAL (Rustbelt)   ok+fprobe: all 40 checks passed