RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / scripts / aarch64-check.sh
3836 bytes ยท raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/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 <log> <description> <grep -E pattern>
    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