RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / scripts / run-headless.sh
3065 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
#!/usr/bin/env bash
# Build the kernel with the `headless` feature and boot it in QEMU with no
# window. Serial output goes to this terminal; the kernel powers QEMU off via
# the isa-debug-exit device when done. A timeout guards against hangs.
#
# A normal boot runs the shell self-test (disk/scripts/selftest.sh); the
# shell's exit code decides success, and this script then also checks that
# the expected lines appear in the output.
#
# Usage: ./scripts/run-headless.sh                 # boot + shell self-test
#        ./scripts/run-headless.sh stack-overflow  # extra cargo features, comma separated
set -euo pipefail
cd "$(dirname "$0")/.."

cargo build --features "headless${1:+,$1}"
# Force bootimage to repack the disk image (see scripts/runner.sh for why).
touch target/x86_64-rust_kernel/debug/rust_kernel
cargo bootimage --features "headless${1:+,$1}"
IMG=target/x86_64-rust_kernel/debug/bootimage-rust_kernel.bin

LOG=target/headless-serial.log
set +e
timeout 90 qemu-system-x86_64 \
    -drive format=raw,file="$IMG" \
    -drive file=target/disk.img,format=raw,if=virtio,snapshot=on \
    -device isa-debug-exit,iobase=0xf4,iosize=0x04 \
    -serial stdio -display none -no-reboot | tee "$LOG"
code=${PIPESTATUS[0]}
set -e

# Lines the shell self-test must have printed (only for a plain boot).
if [ -z "${1:-}" ] && [ "$code" = 33 ]; then
    expect=(
        "Rustbelt 0.7.0 (stage 7: shell) x86_64"      # ver
        "D:  /mnt/disk0   fat32"                       # drives
        "D:/ $ ls"                                     # cd D: changed the prompt
        "readme.txt  scripts/"                         # ls in columns
        "In the Rustbelt shell this disk is drive D:"  # type D:/readme.txt
        "second line"                                  # >> and <
        "       125  todo.txt"                         # cp + ls -l
        '[trace 18] open("/mnt/disk0/notes/todo.txt", 0o0) = 3'   # run --trace
        "sleep started in the background"              # start
        "[done] pid 19 (start sleep 1), exit code 0"   # wait
        "[exit code 139]"                              # run evil
        "sh: nosuchprogram: command not found"
        "cd: there is no drive Q:"
        "C:/tmp $ pwd"
    )
    missing=0
    for line in "${expect[@]}"; do
        grep -qF -- "$line" "$LOG" || { echo "[run-headless] MISSING: $line"; missing=1; }
    done
    # Pipe results: `... | grep -i EXT | wc -l` -> 1, `dir bin | wc -l` -> 15.
    for n in 1 15; do
        grep -qx -- "$n" "$LOG" || { echo "[run-headless] MISSING pipe result: $n"; missing=1; }
    done
    [ $missing = 0 ] && echo "[run-headless] all ${#expect[@]}+2 expected shell lines found" || code=35
fi

# isa-debug-exit: QEMU exit status = (value << 1) | 1, so Success(0x10) -> 33.
case $code in
    33)  echo "[run-headless] kernel exited OK"; exit 0 ;;
    35)  echo "[run-headless] kernel reported FAILURE"; exit 1 ;;
    124) echo "[run-headless] timed out (kernel hung?)"; exit 124 ;;
    *)   echo "[run-headless] QEMU exited with $code"; exit "$code" ;;
esac