#!/usr/bin/env bash # Stage 21: boot contract v2, end to end. Boots the real (headless) kernel # with the usual four data disks plus a writable copy of the GPT test disk # (target/rootfs-gpt.img, made by build.rs), so main.rs finds the # "Linux root (x86-64)" partition, mounts it at /, starts /sbin/init # (user/inittest.c) as pid 1, and ends the run with init's exit status. # # inittest exits 7 when all its checks pass, and the kernel turns exit(n) # into QEMU exit code 33 + 2n, so this script wants QEMU to exit with 47. # Afterwards it runs e2fsck and fsck.exfat on the two partitions of the # copy, which init wrote to. Since 0.21.1, B: (disk.img) is a writable copy # too: init writes a file there, and fsck.fat must find the FAT32 partition # clean, with no dirty bit (the kernel unmounts everything when pid 1 exits). # # Usage: ./scripts/boot-v2-check.sh set -euo pipefail cd "$(dirname "$0")/.." T="${CARGO_TARGET_DIR:-target}" export PATH="$HOME/.cargo/bin:$PATH:/usr/sbin:/sbin" # e2fsck, fsck.exfat, fsck.fat, sfdisk cargo build --features headless touch $T/x86_64-rust_kernel/debug/rustbelt # (see scripts/runner.sh) cargo bootimage --features headless IMG=$T/x86_64-rust_kernel/debug/bootimage-rustbelt.bin ROOT=$T/boot-v2-root.img cp $T/rootfs-gpt.img "$ROOT" B=$T/boot-v2-disk0.img # stage 21.1: a writable copy of B: cp $T/disk.img "$B" LOG=$T/boot-v2-serial.log set +e timeout 60 qemu-system-x86_64 -smp 4 -cpu max \ -drive format=raw,file="$IMG" \ -drive file="$B",format=raw,if=virtio \ -drive file=$T/ext2.img,format=raw,if=virtio,snapshot=on \ -drive file=$T/exfat.img,format=raw,if=virtio,snapshot=on \ -drive file=$T/btrfs.img,format=raw,if=virtio,snapshot=on \ -drive file="$ROOT",format=raw,if=virtio \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ -serial stdio -display none -no-reboot | tee "$LOG" code=${PIPESTATUS[0]} set -e ok=1 for line in "mounted at / (root partition)" "mounted at /mnt/share" \ "[inittest] started as /sbin/init" "[inittest] ok: I am pid 1" \ 'headless: argv[1] is "selftest"' "[inittest] 0 failed" \ "[init] pid 1 (/sbin/init) exited: Exited(7)" \ "[shutdown] unmounted /mnt/disk0 (fat32)" "[shutdown] unmounted / (ext2)"; do grep -qF -- "$line" "$LOG" || { echo "[boot-v2] MISSING: $line"; ok=0; } done [ "$code" = 47 ] || { echo "[boot-v2] QEMU exited with $code, not 47 (= exit(7))"; ok=0; } # The partitions (start and size in 512-byte sectors, as build.rs made them). dd if="$ROOT" of=$T/boot-v2-p1.img bs=512 skip=2048 count=24576 status=none dd if="$ROOT" of=$T/boot-v2-p2.img bs=512 skip=26624 count=16384 status=none e2fsck -fn $T/boot-v2-p1.img >/dev/null || { echo "[boot-v2] e2fsck found errors on the root"; ok=0; } fsck.exfat -n $T/boot-v2-p2.img >/dev/null || { echo "[boot-v2] fsck.exfat found errors on the share"; ok=0; } rm -f $T/boot-v2-p1.img $T/boot-v2-p2.img # B:'s FAT32 partition (the first one on disk.img): no dirty bit (stage 21.1). read -r BSTART BSIZE < <(sfdisk -d "$B" | awk -F'[=,]' '/start=/ {gsub(/ /,""); print $2, $4; exit}') dd if="$B" of=$T/boot-v2-b1.img bs=512 skip="$BSTART" count="$BSIZE" status=none if ! FATOUT=$(fsck.fat -n $T/boot-v2-b1.img 2>&1) || grep -qi dirty <<<"$FATOUT"; then echo "[boot-v2] fsck.fat isn't happy with B:"; echo "$FATOUT"; ok=0 fi grep -q "from-init.txt" < <(mdir -i $T/boot-v2-b1.img -b :: 2>/dev/null || true) \ || [ -z "$(command -v mdir)" ] || { echo "[boot-v2] init's file isn't on B:"; ok=0; } rm -f $T/boot-v2-b1.img "$B" if [ $ok = 1 ]; then echo "[boot-v2] OK: init ran as pid 1, QEMU exited 47 (= exit 7), both partitions fsck-clean, B: has no dirty bit" exit 0 fi exit 1