boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit e33c8d156b4908f97cefbbaf230a2721719e92fd
parent c26c833c509d82ff3c9c7023792eab3cb1745e23
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed,  6 May 2026 15:31:02 -0700

prep: fold musl skip filter into prep-src; calibration is manual

Drop bootprep/prep-musl.sh and require vendor/musl/skip-<arch>.txt up
front. prep-src.sh now applies the skip filter inline after the musl
unpack and runs boot5-enumerate + boot5-gen-runscm alongside the boot4
and boot6 run.scm generation. Re-running calibration when the patch
set, arch, or tcc version changes is a manual call to
bootprep/boot5-calibrate.sh; boot.sh no longer invokes it implicitly.

Diffstat:
Mboot/boot.sh | 40++--------------------------------------
Mboot/boot5.sh | 8++++----
Mboot/lib-arch.sh | 2+-
Mbootprep/boot5-enumerate.sh | 8++++----
Mbootprep/boot5-gen-runscm.sh | 3+--
Dbootprep/prep-musl.sh | 80-------------------------------------------------------------------------------
Mbootprep/prep-src.sh | 55++++++++++++++++++++++++++++++++++++-------------------
7 files changed, 48 insertions(+), 148 deletions(-)

diff --git a/boot/boot.sh b/boot/boot.sh @@ -1,18 +1,5 @@ #!/bin/sh ## boot.sh — drive boot0 → boot6 end-to-end under one driver. -## -## Usage: boot/boot.sh <arch> -## DRIVER=seed boot/boot.sh <amd64|aarch64|riscv64> -## DRIVER=podman boot/boot.sh <amd64|aarch64|riscv64> -## -## DRIVER (default podman) is exported and consumed by each bootN.sh. -## Outputs land at build/$ARCH/$DRIVER/bootN/, so the two driver trees -## coexist on disk. DRIVER=seed runs the build pipeline on top of the -## podman-built boot6 kernel at build/$ARCH/podman/boot6/{Image,kernel.elf}; -## first-time setup therefore requires one prior podman pass: -## ./boot/boot.sh <arch> # default DRIVER=podman -## DRIVER=seed ./boot/boot.sh <arch> # re-run on tcc-built kernel -## Subsequent DRIVER=seed runs reuse the Image directly — no stashing. set -eu @@ -36,12 +23,6 @@ Environment variables (all optional): BOOT5_TIMEOUT (default 7200) boot5 (musl) wall-clock seconds. BOOT6_TIMEOUT (default 1200) boot6 (kernel) wall-clock seconds. QEMU_MEM (default 3072M) guest RAM passed to the seed-driver qemu. - TCC_BOOTSTRAP_RELAX_FIXEDPOINT set to 1 in boot4 to accept tcc2 != tcc3. - After a codegen-altering tcc patch the - two-stage rule needs a third bounce to - converge; the next boot4 run, started - from this run's tcc3, will reach - tcc2 == tcc3 with no extra knob. EOF exit 0 ;; @@ -59,32 +40,15 @@ if [ "$DRIVER" = seed ]; then fi fi -# Wipe only this driver's tree so the other driver's outputs survive -# (the seed driver consumes build/$ARCH/podman/boot6/$KERNEL_NAME). -rm -rf build/$ARCH/$DRIVER - -# Per-stage timing comes from each child's own bootlib EXIT trap -# (`[bootN/$DRIVER/$ARCH] done in Xs (cum Ys)`); this orchestrator only -# adds its own total at the end (also via the lib trap). -# A0a: build the canonical generated source tree at build/$ARCH/src/. -# Boot stages read source from there exclusively (no flatten/unpack/ -# patch inside boot{N}.sh). +# Boot stages read source from build/$ARCH/src/ exclusively. ./bootprep/prep-src.sh $ARCH +rm -rf build/$ARCH/$DRIVER ./boot/boot0.sh $ARCH ./boot/boot1.sh $ARCH ./boot/boot2.sh $ARCH ./boot/boot3.sh $ARCH ./boot/boot4.sh $ARCH - -# A0b: apply the per-arch musl skip filter (needs tcc3 from boot4 if -# the calibration list is missing; the committed list is the common -# case and runs without compiler). -./bootprep/prep-musl.sh $ARCH - ./boot/boot5.sh $ARCH - -# boot6 builds the seed-kernel ELF/Image with boot4's tcc3 (no `ld -T`, -# no objcopy). ./boot/boot6.sh $ARCH diff --git a/boot/boot5.sh b/boot/boot5.sh @@ -21,7 +21,7 @@ ## ─── Tools ──────────────────────────────────────────────────────────── ## scheme1 evaluates the prep-time run.scm at ## build/$ARCH/src/run/boot5.scm (generated by -## bootprep/boot5-gen-runscm.sh after prep-musl) against the flat +## bootprep/boot5-gen-runscm.sh during prep-src) against the flat ## staging root. ## ## ─── Outputs ───────────────────────────────────────────────────────── @@ -48,8 +48,8 @@ MUSL_DIR=$SRC/src/musl require_prev "$BOOT4" tcc3 require_prev "$BOOT2" catm scheme1 require_file "$BOOT4/libtcc1.a" "run boot/boot4.sh $ARCH" -require_file "$MUSL_DIR" "run bootprep/prep-src.sh $ARCH and bootprep/prep-musl.sh $ARCH" -require_file "$MUSL_DIR/skip.txt" "run bootprep/prep-musl.sh $ARCH" +require_file "$MUSL_DIR" "run bootprep/prep-src.sh $ARCH" +require_file "$MUSL_DIR/skip.txt" "run bootprep/prep-src.sh $ARCH" require_file "$SRC/src/tcc/stdarg-bridge.h" "run bootprep/prep-src.sh $ARCH" # ── prepare staging dirs ────────────────────────────────────────────── @@ -65,7 +65,7 @@ runscm_runscm "$SRC/run/boot5.scm" # primitive). Per-source list is the build-srcs.txt produced by # bootprep/boot5-enumerate.sh at prep time. SRCS=$SRC/run/boot5/build-srcs.txt -require_file "$SRCS" "run bootprep/prep-musl.sh $ARCH" +require_file "$SRCS" "run bootprep/prep-src.sh $ARCH" COBJ=$STAGE/out/obj/musl mkdir -p "$COBJ/crt" awk ' diff --git a/boot/lib-arch.sh b/boot/lib-arch.sh @@ -74,7 +74,7 @@ _bootlib_finish() { fi # Record this stage's time. Boot stages have OUT (set by driver_init); # the orchestrator (BOOT_STAGE=boot) doesn't write — its time would - # double-count. Other stages without OUT (prep-src, prep-musl) write + # double-count. Other stages without OUT (prep-src) write # to a per-arch sidecar dir. if [ "$BOOT_STAGE" != boot ]; then if [ -n "${OUT:-}" ] && [ -d "$OUT" ]; then diff --git a/bootprep/boot5-enumerate.sh b/bootprep/boot5-enumerate.sh @@ -1,14 +1,14 @@ #!/bin/sh ## boot5-enumerate.sh — enumerate musl sources from the canonical -## post-prep-musl tree and emit the build-srcs / crt-mode files that +## musl tree and emit the build-srcs / crt-mode files that ## boot5-gen-runscm.sh consumes. ## ## Mirrors musl's Makefile rule: a per-arch override (under ## $d/$MUSL_ARCH/) replaces the same-stem base file (under $d/). The ## canonical tree already had the per-arch skip filter applied by -## prep-musl.sh, so no skip subtraction is needed here. +## prep-src.sh, so no skip subtraction is needed here. ## -## Inputs: build/<arch>/src/src/musl/ (post-prep-musl tree) +## Inputs: build/<arch>/src/src/musl/ (filtered tree) ## Outputs: build/<arch>/src/run/boot5/build-srcs.txt ## build/<arch>/src/run/boot5/crt-mode ("asm" or "c") ## @@ -27,7 +27,7 @@ esac MUSL_DIR=build/$ARCH/src/src/musl OUT_DIR=build/$ARCH/src/run/boot5 -[ -d "$MUSL_DIR" ] || { echo "missing $MUSL_DIR (run bootprep/prep-musl.sh $ARCH)" >&2; exit 1; } +[ -d "$MUSL_DIR" ] || { echo "missing $MUSL_DIR (run bootprep/prep-src.sh $ARCH)" >&2; exit 1; } mkdir -p "$OUT_DIR" SRC_TOP="src/aio src/conf src/crypt src/ctype src/dirent diff --git a/bootprep/boot5-gen-runscm.sh b/bootprep/boot5-gen-runscm.sh @@ -13,8 +13,7 @@ ## Conventions (cwd-relative; resolves to / under seed init, /work under ## podman bind-mount): ## musl tree in/musl/<rel-path> (read-only; canonical -## tree from prep-src/ -## prep-musl) +## tree from prep-src) ## pre-gen hdrs in/musl/obj/include/bits/{alltypes,syscall}.h, ## in/musl/obj/src/internal/version.h ## .o outputs out/obj/musl/<src-with-.o> (rw; pre-mkdir'd by host) diff --git a/bootprep/prep-musl.sh b/bootprep/prep-musl.sh @@ -1,80 +0,0 @@ -#!/bin/sh -## prep-musl.sh — A0b: apply the per-arch musl skip filter on top of -## build/<arch>/src/src/musl/. -## -## prep-src.sh (A0a) leaves the musl tree at build/<arch>/src/src/musl/ -## with overrides merged, deletes applied, and pre-generated alltypes.h -## / syscall.h dropped in. boot5-calibrate.sh's per-arch skip list (the -## set of musl translation units tcc 0.9.26 cannot compile) needs a -## working tcc3, so it can't be folded into A0a. -## -## A0b is a single transform: read the skip list (committed or freshly -## calibrated), copy it into the canonical tree as skip.txt, and remove -## every listed path from src/musl/. After A0b the tree is the exact -## set of files boot5 will compile — no skip enumeration at boot time. -## -## Skip-list source policy: -## - if vendor/musl/skip-<arch>.txt exists, use it -## verbatim (the common case — calibrations are committed). -## - else run bootprep/boot5-calibrate.sh <arch>, which itself depends -## on boot4/tcc3. The script writes the committed file for us. -## -## Usage: bootprep/prep-musl.sh <arch> -## <arch> ∈ {aarch64, amd64, riscv64} - -set -eu - -. boot/lib-arch.sh -bootlib_init prep-musl "${1:-}" - -DST=$ROOT/build/$ARCH/src -DST_MUSL=$DST/src/musl -SKIP_COMMITTED=vendor/musl/skip-$ARCH.txt - -TAG="[$BOOT_TAG]" - -[ -d "$DST_MUSL" ] || { - echo "$TAG missing $DST_MUSL — run bootprep/prep-src.sh $ARCH first" >&2 - exit 1 -} - -# ── (1) materialize the skip list ───────────────────────────────────── -if [ ! -e "$SKIP_COMMITTED" ]; then - echo "$TAG no committed skip list at $SKIP_COMMITTED — calibrating" - bootprep/boot5-calibrate.sh "$ARCH" - [ -e "$SKIP_COMMITTED" ] || { - echo "$TAG calibration did not produce $SKIP_COMMITTED" >&2 - exit 1 - } -fi -cp "$SKIP_COMMITTED" "$DST_MUSL/skip.txt" - -# ── (2) apply filter — drop every listed path from src/musl/ ────────── -n_skip=0 -n_missing=0 -while read -r rel; do - [ -n "$rel" ] || continue - case "$rel" in - \#*) continue ;; - esac - if [ -e "$DST_MUSL/$rel" ]; then - rm -rf "$DST_MUSL/$rel" - n_skip=$((n_skip + 1)) - else - n_missing=$((n_missing + 1)) - fi -done < "$DST_MUSL/skip.txt" - -if [ "$n_missing" -gt 0 ]; then - echo "$TAG WARN: $n_missing skip-list entries were not present in $DST_MUSL" >&2 -fi - -n_remaining=$(find "$DST_MUSL" -type f | wc -l | tr -d ' ') -echo "$TAG OK filtered=$n_skip remaining=$n_remaining files in $DST_MUSL" - -# ── (3) enumerate musl sources + generate boot5 run.scm ─────────────── -# The filtered tree is now stable; emit the build-srcs + crt-mode that -# boot5-gen-runscm consumes, then emit boot5.scm itself. boot5.sh just -# reads the result. -bootprep/boot5-enumerate.sh "$ARCH" -bootprep/boot5-gen-runscm.sh "$ARCH" diff --git a/bootprep/prep-src.sh b/bootprep/prep-src.sh @@ -1,12 +1,12 @@ #!/bin/sh -## prep-src.sh — A0a: build the canonical generated source tree. +## prep-src.sh — build the canonical generated source tree. ## ## All host-side source preparation happens once, up front, into a ## single canonical tree at build/<arch>/src/. This tree is the audit ## basis and the only thing boot stages should read for source. Boot ## stages do no flattening, no unpacking, no patching, no calibration. ## -## Layout produced (see docs/PLAN.md §A0): +## Layout produced: ## build/<arch>/src/ ## bin/ binary inputs not built by a stage ## hex0-seed vendored seed only @@ -26,22 +26,21 @@ ## libc/ libc.flat.c (mes-libc flattened) ## musl/ filtered musl-1.2.5 tree (overrides ## merged, deletes applied, generated -## alltypes.h/syscall.h dropped in). -## prep-musl.sh applies the per-arch -## skip filter on top. +## alltypes.h/syscall.h dropped in, +## per-arch skip filter applied). ## kernel/ seed-kernel sources for this arch ## test-fixtures/ boot-hello.c smoke binary ## run/ run.scm files driving each bootN stage ## boot3.scm static (copied from bootprep/assets/) ## boot4.scm generated by bootprep/boot4-gen-runscm.sh ## boot5.scm generated by bootprep/boot5-gen-runscm.sh -## (after prep-musl.sh) ## boot6.scm generated by bootprep/boot6-gen-runscm.sh ## -## A0 is split: prep-src.sh runs before boot0 and produces everything -## that doesn't need a working compiler. prep-musl.sh runs after boot4 -## (or copies the committed skip list) and applies the calibration -## filter on top of src/musl/. +## The musl skip list (vendor/musl/skip-<arch>.txt) is calibrated +## offline by bootprep/boot5-calibrate.sh and committed; prep-src.sh +## reads it and applies the filter inline. Re-run boot5-calibrate.sh +## manually when the patch set, calibration arch, or tcc version +## changes. ## ## Usage: bootprep/prep-src.sh <arch> ## <arch> ∈ {aarch64, amd64, riscv64} @@ -160,11 +159,13 @@ MUSL_TARBALL=vendor/musl/1.2.5.tar.gz MUSL_OVERRIDES=vendor/musl/overrides MUSL_DELETES=vendor/musl/deletes.txt MUSL_GENERATED=vendor/musl/generated/$MUSL_ARCH +MUSL_SKIP=vendor/musl/skip-$ARCH.txt [ -e "$MUSL_TARBALL" ] || { echo "$TAG missing $MUSL_TARBALL" >&2; exit 1; } [ -d "$MUSL_OVERRIDES" ] || { echo "$TAG missing $MUSL_OVERRIDES" >&2; exit 1; } [ -e "$MUSL_DELETES" ] || { echo "$TAG missing $MUSL_DELETES" >&2; exit 1; } [ -d "$MUSL_GENERATED" ] || { echo "$TAG missing $MUSL_GENERATED (run bootprep/musl-vendor.sh)" >&2; exit 1; } +[ -e "$MUSL_SKIP" ] || { echo "$TAG missing $MUSL_SKIP (run bootprep/boot5-calibrate.sh $ARCH)" >&2; exit 1; } echo "$TAG unpack musl-1.2.5 + apply overrides/deletes" MUSL_TMP=$(mktemp -d) @@ -189,21 +190,37 @@ mkdir -p "$DST_SRC/musl" # Move into place — the canonical tree owns this from now on. ( cd "$MUSL_TMP/musl-1.2.5" && tar cf - . ) | ( cd "$DST_SRC/musl" && tar xf - ) -# Seed src/musl/skip.txt with the committed skip list when one exists, -# so the canonical tree carries metadata even before prep-musl.sh -# applies the filter. prep-musl.sh refreshes/regenerates this. -SKIP_COMMITTED=vendor/musl/skip-$ARCH.txt -if [ -e "$SKIP_COMMITTED" ]; then - cp "$SKIP_COMMITTED" "$DST_SRC/musl/skip.txt" +# Apply the committed per-arch skip filter inline: copy the list as +# skip.txt metadata, then drop every listed path from src/musl/. +cp "$MUSL_SKIP" "$DST_SRC/musl/skip.txt" +n_skip=0 +n_missing=0 +while read -r rel; do + [ -n "$rel" ] || continue + case "$rel" in + \#*) continue ;; + esac + if [ -e "$DST_SRC/musl/$rel" ]; then + rm -rf "$DST_SRC/musl/$rel" + n_skip=$((n_skip + 1)) + else + n_missing=$((n_missing + 1)) + fi +done < "$DST_SRC/musl/skip.txt" +if [ "$n_missing" -gt 0 ]; then + echo "$TAG WARN: $n_missing skip-list entries were not present in $DST_SRC/musl" >&2 fi +echo "$TAG musl skip filter: dropped=$n_skip" # ── (7) run.scm files ───────────────────────────────────────────────── -# Static run.scm (boot3) copied verbatim; boot4/boot6 generated here. -# boot5.scm needs the post-prep-musl tree, so it's generated by -# prep-musl.sh. +# Static run.scm (boot3) copied verbatim; the rest are generated. The +# musl tree is now stable, so boot5-enumerate + boot5-gen-runscm can +# run alongside boot4/boot6 generation. mkdir -p "$DST/run" cp bootprep/assets/boot3-run.scm "$DST/run/boot3.scm" bootprep/boot4-gen-runscm.sh "$ARCH" +bootprep/boot5-enumerate.sh "$ARCH" +bootprep/boot5-gen-runscm.sh "$ARCH" bootprep/boot6-gen-runscm.sh "$ARCH" # ── summary ───────────────────────────────────────────────────────────