boot2

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

seed-accept.sh (10218B)


      1 #!/bin/sh
      2 ## tests/seed-accept.sh — seed-driver acceptance tests.
      3 ##
      4 ## One script, three modes:
      5 ##
      6 ##   kernel   (default)  Tier-2 acceptance for boot0/1/2 on seed-kernel:
      7 ##                       loads boot2-built scheme1 as /init, runs a
      8 ##                       driver.scm that exercises read/write/openat/
      9 ##                       close/brk/exit_group + clone/execve/waitid via
     10 ##                       a child catm spawn. Verifies transcript markers
     11 ##                       and that the extracted output file is correct.
     12 ##
     13 ##   boot34              Run boot3 (and optionally boot4 with WITH_BOOT4=1)
     14 ##                       under DRIVER=seed and assert byte-identical
     15 ##                       outputs vs the podman reference.
     16 ##
     17 ##   boot5               Run boot5 under DRIVER=seed and assert byte-
     18 ##                       identical libc.a / crt1.o / crti.o / crtn.o /
     19 ##                       hello vs the podman reference.
     20 ##
     21 ## All three modes target ARCH=aarch64 (the only seed-driver-complete
     22 ## arch today). Prereq for every mode: build/aarch64/podman/boot{0..6}/
     23 ## populated via `./boot/boot.sh aarch64` (default DRIVER=podman),
     24 ## including boot6/Image as the seed kernel.
     25 ##
     26 ## Usage:
     27 ##   tests/seed-accept.sh                    # mode=kernel
     28 ##   tests/seed-accept.sh kernel
     29 ##   tests/seed-accept.sh boot34             # also: WITH_BOOT4=1 …
     30 ##   tests/seed-accept.sh boot5
     31 
     32 set -eu
     33 
     34 MODE=${1:-kernel}
     35 case "$MODE" in
     36     kernel|boot34|boot5) ;;
     37     *) echo "$0: unknown mode '$MODE' (kernel | boot34 | boot5)" >&2; exit 2 ;;
     38 esac
     39 
     40 ARCH=aarch64
     41 ROOT=$(cd "$(dirname "$0")/.." && pwd)
     42 cd "$ROOT"
     43 
     44 PODMAN=build/$ARCH/podman
     45 SEED=build/$ARCH/seed
     46 KERNEL=$PODMAN/boot6/Image
     47 
     48 [ -f "$KERNEL" ] || {
     49     echo "missing $KERNEL — run ./boot/boot.sh $ARCH (default DRIVER=podman) first" >&2
     50     exit 1
     51 }
     52 
     53 # ─── Mode: boot34 ─────────────────────────────────────────────────────
     54 if [ "$MODE" = "boot34" ]; then
     55     [ -x $PODMAN/boot3/tcc0 ] || {
     56         echo "$PODMAN/boot3/tcc0 missing — run boot/boot3.sh aarch64" >&2
     57         exit 1
     58     }
     59 
     60     echo "[seed-accept boot34] DRIVER=seed boot/boot3.sh $ARCH"
     61     DRIVER=seed boot/boot3.sh $ARCH
     62 
     63     if ! cmp -s $SEED/boot3/tcc0 $PODMAN/boot3/tcc0; then
     64         s_seed=$(wc -c < $SEED/boot3/tcc0)
     65         s_ref=$(wc -c < $PODMAN/boot3/tcc0)
     66         echo "[seed-accept boot34] boot3 FAIL: tcc0 differs (seed=$s_seed podman=$s_ref)" >&2
     67         exit 3
     68     fi
     69     echo "[seed-accept boot34] boot3 PASS — tcc0 byte-identical vs podman"
     70 
     71     if [ "${WITH_BOOT4:-0}" != 1 ]; then
     72         exit 0
     73     fi
     74 
     75     [ -x $PODMAN/boot4/tcc3 ] || {
     76         echo "$PODMAN/boot4/tcc3 missing — run boot/boot4.sh aarch64 under podman first" >&2
     77         exit 1
     78     }
     79 
     80     echo "[seed-accept boot34] DRIVER=seed boot/boot4.sh $ARCH"
     81     DRIVER=seed boot/boot4.sh $ARCH
     82 
     83     fail=0
     84     # All boot4 outputs — including the intermediate crt1.o / libc.a /
     85     # libtcc1.a — must match podman byte-for-byte. The strip-file-prefix
     86     # tcc patch (simple-patches/tcc-0.9.26/) drops the /work/in/[tcc-lib/]
     87     # mount prefix from STT_FILE entries, so seed's flat-basename staging
     88     # and podman's /work/in/ mounts produce identical .o relocations.
     89     for f in tcc3 hello crt1.o libc.a libtcc1.a; do
     90         if ! cmp -s $SEED/boot4/$f $PODMAN/boot4/$f; then
     91             s_seed=$(wc -c < $SEED/boot4/$f)
     92             s_ref=$(wc -c < $PODMAN/boot4/$f)
     93             echo "[seed-accept boot34] boot4 DIFF $f: seed=$s_seed podman=$s_ref" >&2
     94             fail=1
     95         fi
     96     done
     97     [ $fail -eq 0 ] || exit 4
     98     echo "[seed-accept boot34] boot4 PASS — tcc3/hello/crt1.o/libc.a/libtcc1.a byte-identical vs podman"
     99     exit 0
    100 fi
    101 
    102 # ─── Mode: boot5 ──────────────────────────────────────────────────────
    103 if [ "$MODE" = "boot5" ]; then
    104     [ -d $PODMAN/boot5 ] || {
    105         echo "$PODMAN/boot5 missing — run boot/boot5.sh aarch64" >&2
    106         exit 1
    107     }
    108     for f in libc.a crt1.o crti.o crtn.o hello; do
    109         [ -e $PODMAN/boot5/$f ] || {
    110             echo "$PODMAN/boot5/$f missing — run boot/boot5.sh aarch64" >&2
    111             exit 1
    112         }
    113     done
    114 
    115     echo "[seed-accept boot5] DRIVER=seed boot/boot5.sh $ARCH"
    116     DRIVER=seed boot/boot5.sh $ARCH
    117 
    118     fails=0
    119     for f in libc.a crt1.o crti.o crtn.o hello; do
    120         seed_size=$(wc -c < $SEED/boot5/$f)
    121         ref_size=$(wc -c < $PODMAN/boot5/$f)
    122         if cmp -s $SEED/boot5/$f $PODMAN/boot5/$f; then
    123             echo "[seed-accept boot5] $f: byte-identical ($seed_size bytes)"
    124         else
    125             echo "[seed-accept boot5] $f: DIFF (seed=$seed_size podman=$ref_size)"
    126             fails=$((fails + 1))
    127         fi
    128     done
    129 
    130     if [ $fails -eq 0 ]; then
    131         echo "[seed-accept boot5] PASS — all 5 outputs byte-identical"
    132         exit 0
    133     else
    134         echo "[seed-accept boot5] FAIL — $fails outputs differ" >&2
    135         exit 4
    136     fi
    137 fi
    138 
    139 # ─── Mode: kernel ─────────────────────────────────────────────────────
    140 
    141 EXTRACT=seed-kernel/scripts/extract-blk.sh
    142 SCHEME1=$PODMAN/boot2/scheme1
    143 CATM=$PODMAN/boot2/catm
    144 PRELUDE=scheme1/prelude.scm
    145 
    146 [ -x "$SCHEME1" ]  || { echo "missing $SCHEME1 — run boot2 first" >&2; exit 1; }
    147 [ -x "$CATM" ]     || { echo "missing $CATM — run boot2 first" >&2; exit 1; }
    148 
    149 OUTDIR=$ROOT/build/$ARCH/seed-accept
    150 rm -rf "$OUTDIR"; mkdir -p "$OUTDIR"
    151 
    152 STAGE=$(mktemp -d -t seed-accept.XXXXXX)
    153 trap 'rm -rf "$STAGE"' EXIT
    154 
    155 # ─── driver.scm — the in-VM acceptance program ────────────────────────
    156 cat > "$STAGE/driver.scm" <<'SCM'
    157 ;; driver.scm — Tier-2 acceptance for seed-kernel.
    158 (write-string stdout "scheme1: hello from acceptance driver\n")
    159 (write-string stdout "scheme1: spawning child-prog (catm) C <- A + B\n")
    160 
    161 (let ((r (run "child-prog" "C" "A" "B")))
    162   (if (car r)
    163       (begin
    164         (write-string stdout "scheme1: child returned\n"))
    165       (begin
    166         (write-string stdout "scheme1: spawn FAILED\n")
    167         (exit 1))))
    168 
    169 (let ((rp (open-input "C")))
    170   (if (car rp)
    171       (let* ((p (cdr rp))
    172              (rb (read-all p)))
    173         (if (car rb)
    174             (begin
    175               (write-string stdout "scheme1: read C: [")
    176               (write-bytes stdout (cdr rb))
    177               (write-string stdout "]\n"))
    178             (write-string stdout "scheme1: read C FAILED\n"))
    179         (close p))
    180       (write-string stdout "scheme1: open C FAILED\n")))
    181 
    182 (write-string stdout "scheme1: ALL-OK\n")
    183 (exit 0)
    184 SCM
    185 
    186 # ─── Combine prelude + driver via host catm — this matches the chain's
    187 #     own boot-run-scheme1.sh wrapper, so the .scm shape is identical
    188 #     to what scheme1 expects everywhere. ──────────────────────────────
    189 cat "$PRELUDE" "$STAGE/driver.scm" > "$STAGE/combined.scm"
    190 
    191 # ─── Two demo input files. catm reads them from the in-VM tmpfs. ──────
    192 printf 'Hello, ' > "$STAGE/A"
    193 printf 'seed-kernel!\n' > "$STAGE/B"
    194 
    195 # ─── Stage the cpio: /init=scheme1, /child-prog=catm, plus inputs. ────
    196 mkdir -p "$STAGE/cpio"
    197 cp "$SCHEME1"          "$STAGE/cpio/init";       chmod +x "$STAGE/cpio/init"
    198 cp "$CATM"             "$STAGE/cpio/child-prog"; chmod +x "$STAGE/cpio/child-prog"
    199 cp "$STAGE/combined.scm" "$STAGE/cpio/combined.scm"
    200 cp "$STAGE/A"          "$STAGE/cpio/A"
    201 cp "$STAGE/B"          "$STAGE/cpio/B"
    202 
    203 NAMES='init
    204 child-prog
    205 combined.scm
    206 A
    207 B'
    208 
    209 ( cd "$STAGE/cpio" && printf '%s\n' "$NAMES" | cpio -o -H newc 2>/dev/null ) > "$STAGE/initramfs.cpio"
    210 sz=$(wc -c < "$STAGE/initramfs.cpio")
    211 pad=$(( (512 - sz % 512) % 512 ))
    212 if [ "$pad" -gt 0 ]; then
    213     head -c "$pad" /dev/zero >> "$STAGE/initramfs.cpio"
    214 fi
    215 mv "$STAGE/initramfs.cpio" "$STAGE/in.img"
    216 truncate -s 256M "$STAGE/out.img"
    217 
    218 TRANSCRIPT=$OUTDIR/transcript.txt
    219 echo "[seed-accept] booting scheme1 + driver.scm on seed-kernel"
    220 qemu-system-aarch64 \
    221     -machine virt,gic-version=3,accel=hvf -cpu host -m 2048M \
    222     -nographic -no-reboot \
    223     -global virtio-mmio.force-legacy=false \
    224     -kernel "$KERNEL" \
    225     -drive file="$STAGE/in.img",if=none,format=raw,id=hd0,readonly=on \
    226     -device virtio-blk-device,drive=hd0 \
    227     -drive file="$STAGE/out.img",if=none,format=raw,id=hd1 \
    228     -device virtio-blk-device,drive=hd1 \
    229     -append "init combined.scm" \
    230     > "$TRANSCRIPT" 2>&1 &
    231 QPID=$!
    232 ( sleep 240; kill -9 $QPID 2>/dev/null ) </dev/null >/dev/null 2>&1 &
    233 WATCHER=$!
    234 wait $QPID 2>/dev/null || true
    235 kill $WATCHER 2>/dev/null || true
    236 
    237 # Extract files (we want C from the tmpfs).
    238 if ! "$EXTRACT" "$OUTDIR" "$STAGE/out.img" >/dev/null 2>&1; then
    239     echo "[seed-accept] FAIL: extract-blk failed (kernel didn't reach exit?)" >&2
    240     tail -60 "$TRANSCRIPT" >&2
    241     exit 3
    242 fi
    243 
    244 # ─── Verify ───────────────────────────────────────────────────────────
    245 fail=0
    246 for needle in \
    247     'scheme1: hello from acceptance driver' \
    248     'scheme1: spawning child-prog' \
    249     'scheme1: child returned' \
    250     'scheme1: read C: \[Hello, seed-kernel!' \
    251     'scheme1: ALL-OK' \
    252     'exit_group(0)'
    253 do
    254     if ! grep -q "$needle" "$TRANSCRIPT"; then
    255         echo "[seed-accept] MISSING in transcript: $needle" >&2
    256         fail=1
    257     fi
    258 done
    259 
    260 if [ ! -f "$OUTDIR/C" ]; then
    261     echo "[seed-accept] MISSING extracted file: $OUTDIR/C" >&2
    262     fail=1
    263 elif ! diff -q "$OUTDIR/C" - <<EOF >/dev/null
    264 Hello, seed-kernel!
    265 EOF
    266 then
    267     echo "[seed-accept] C differs from expected:" >&2
    268     od -c "$OUTDIR/C" | head -3 >&2
    269     fail=1
    270 fi
    271 
    272 if [ $fail -ne 0 ]; then
    273     echo "[seed-accept] FAIL — see $TRANSCRIPT" >&2
    274     exit 4
    275 fi
    276 
    277 echo ""
    278 echo "=== driver log (excerpt from transcript) ==="
    279 grep '^scheme1:' "$TRANSCRIPT" || true
    280 echo "==========================================="
    281 echo ""
    282 echo "[seed-accept] PASS — scheme1 + .scm + child-prog cycle complete"
    283 echo "[seed-accept] artifacts in $OUTDIR/"