#!/usr/bin/env bash # Stage 22: headless check of the arm64 bring-up on QEMU virt (Cortex-A53). # Not part of `cargo test` (that's the x86_64 kernel's). Three boots: # 1. normal, starting at EL1, with a virtio rng + block device attached: # banner, MMU, DTB, heap, virtio, 5 ticks, exit status 0 # 2. the same kernel starting at EL2 (virtualization=on): drops to EL1 # 3. built with --features aarch64-fault: a data abort is reported # (ESR/ELR/FAR) and the run ends with status 3 # Logs go to $LOGDIR (default target/aarch64-check). Exit 0 = all good. set -uo pipefail cd "$(dirname "$0")/.." : "${CARGO_TARGET_DIR:=$PWD/target}" export CARGO_TARGET_DIR TRIPLE=aarch64-unknown-none-softfloat LOGDIR="${LOGDIR:-$CARGO_TARGET_DIR/aarch64-check}" mkdir -p "$LOGDIR" FAIL=0 pass() { echo "PASS $1"; } fail() { echo "FAIL $1"; FAIL=1; } expect() { # expect if grep -qE "$3" "$1"; then pass "$2"; else fail "$2 (no /$3/ in $1)"; fi } # The fault kernel first (it's a different build), kept as a copy... cargo build --bin rustbelt-aarch64 --features aarch64-fault --target "$TRIPLE" 2>"$LOGDIR/build-fault.log" \ || { echo "FAIL build (fault)"; cat "$LOGDIR/build-fault.log"; exit 1; } cp "$CARGO_TARGET_DIR/$TRIPLE/debug/rustbelt-aarch64" "$LOGDIR/rustbelt-aarch64-fault.elf" # ...then the normal one, which stays in place for run-aarch64.sh. cargo build --bin rustbelt-aarch64 --features aarch64 --target "$TRIPLE" 2>"$LOGDIR/build.log" \ || { echo "FAIL build"; cat "$LOGDIR/build.log"; exit 1; } DISK="$LOGDIR/blank.img" [ -f "$DISK" ] || truncate -s 1M "$DISK" # 1. Normal boot at EL1. RB_TIMEOUT=30 scripts/run-aarch64.sh --no-build -- \ -device virtio-rng-device \ -drive if=none,id=d0,format=raw,file="$DISK" -device virtio-blk-device,drive=d0 \ >"$LOGDIR/el1.log" 2>&1 rc=$? L="$LOGDIR/el1.log" [ $rc = 0 ] && pass "EL1 boot: QEMU exit status 0" || fail "EL1 boot: QEMU exit status $rc (want 0)" expect "$L" "banner" '^Rustbelt 0\.22\.0 \(stage 22: arm64 bring-up\)' expect "$L" "at EL1" 'entered at EL1, running at EL1' expect "$L" "exception vectors" 'exception vectors installed' expect "$L" "MMU on, higher half reads back" '\[mmu\] on \(SCTLR_EL1\.M = 1\).*reads 0x5ca1ab1e' expect "$L" "UART through the higher half" 'UART at 0xffffff8009000000' expect "$L" "heap" 'sums to 500500' expect "$L" "DTB: GICv2 found" '\[dtb\] .*GICv2, distributor at 0x8000000' expect "$L" "DTB: timer INTID 27" 'virtual timer = PPI 11 \(INTID 27\)' expect "$L" "virtio: rng listed" 'device ID 4 \(entropy' expect "$L" "virtio: block listed" 'device ID 2 \(block' expect "$L" "timer ticks 1..5" '\[timer\] tick 5' expect "$L" "100 ticks timed" '100 ticks took [0-9]+ ms' expect "$L" "clean exit line" 'leaving QEMU through semihosting SYS_EXIT, status 0' # 2. Starting at EL2. RB_TIMEOUT=30 scripts/run-aarch64.sh --no-build --el2 >"$LOGDIR/el2.log" 2>&1 rc=$? L="$LOGDIR/el2.log" [ $rc = 0 ] && pass "EL2 boot: QEMU exit status 0" || fail "EL2 boot: QEMU exit status $rc (want 0)" expect "$L" "EL2 -> EL1 drop" 'entered at EL2, running at EL1' expect "$L" "EL2 boot ticks" '\[timer\] tick 5' # 3. The deliberate data abort. RB_TIMEOUT=30 RB_KERNEL="$LOGDIR/rustbelt-aarch64-fault.elf" scripts/run-aarch64.sh --no-build >"$LOGDIR/fault.log" 2>&1 rc=$? L="$LOGDIR/fault.log" [ $rc = 3 ] && pass "fault: QEMU exit status 3" || fail "fault: QEMU exit status $rc (want 3)" expect "$L" "fault: ESR data abort" 'ESR_EL1=0x96[0-9a-f]{6} \(EC 0x25: data abort' expect "$L" "fault: ELR/FAR" 'ELR_EL1=0x402[0-9a-f]+ FAR_EL1=0x1000000000' grep -h '^\[run-aarch64\] qemu pid' "$LOGDIR"/el1.log "$LOGDIR"/el2.log "$LOGDIR"/fault.log if [ $FAIL = 0 ]; then echo "aarch64-check: ALL PASS (logs in $LOGDIR)"; else echo "aarch64-check: FAILED (logs in $LOGDIR)"; fi exit $FAIL