ffbe098ef8
TLC (Twilight Commander) was missing from both ISO configs. Added
tlc = {} to [packages] in redbear-mini.toml and redbear-full.toml.
Created missing symlink: recipes/tui/tlc -> ../../local/recipes/tui/tlc.
298 lines
10 KiB
Bash
Executable File
298 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# test-redbear-full-qemu.sh — boot the redbear-full desktop target in QEMU and
|
|
# capture the serial console to a timestamped boot log.
|
|
#
|
|
# This script is the canonical QEMU launcher for the redbear-full live ISO
|
|
# (or harddrive.img) per the Red Bear OS desktop path plan. It exercises:
|
|
# - ACPI / GPE / Notify plumbing (acpid + kernel AML interpreter)
|
|
# - v6.0 input architecture (evdevd + virtio-keyboard / virtio-mouse)
|
|
# - MSI-X USB (xhcid via virtio xhci passthrough) and EHCIfallback (ehcid)
|
|
# - multi-queue NVMe (nvmed with multiple queues via NVMe device)
|
|
# - virtio-gpu (redox-drm via /scheme/drm/card0)
|
|
# - virtio-net (e1000d / virtio-netd via net0 user-mode networking)
|
|
# - D-Bus system bus (dbus) and redbear-sessiond
|
|
# - SDDM + KWin Wayland compositor (when targeting redbear-full)
|
|
#
|
|
# The script auto-stops QEMU after BOOT_TIMEOUT seconds (default 60). The
|
|
# captured log is written to local/docs/boot-logs/ and is suitable for offline
|
|
# analysis (login presence, service startup, GPU registration, etc.).
|
|
#
|
|
# Usage:
|
|
# ./local/scripts/test-redbear-full-qemu.sh # default: ISO, 60s
|
|
# ./local/scripts/test-redbear-full-qemu.sh --img # use harddrive.img
|
|
# ./local/scripts/test-redbear-full-qemu.sh --timeout 30 # custom boot window
|
|
# ./local/scripts/test-redbear-full-qemu.sh --no-kvm # disable KVM (TCG)
|
|
# ./local/scripts/test-redbear-full-qemu.sh --fallback mini # boot redbear-mini if full ISO is missing
|
|
#
|
|
# Exit code 0: log captured (boot outcome is in the log, not the exit code).
|
|
# Exit code 1: prerequisites missing (firmware, qemu, image).
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
cd "$PROJECT_ROOT"
|
|
|
|
BOOT_TIMEOUT=60
|
|
USE_IMG=0
|
|
USE_KVM=1
|
|
USE_GPU=0
|
|
USE_INPUT=0
|
|
FALLBACK=""
|
|
LOG_DIR="local/docs/boot-logs"
|
|
EXTRA_QEMU_ARGS=()
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: test-redbear-full-qemu.sh [OPTIONS]
|
|
|
|
Boot the Red Bear OS redbear-full live ISO (or harddrive.img) in QEMU and
|
|
capture the full serial console log to local/docs/boot-logs/.
|
|
|
|
Options:
|
|
--img Boot build/x86_64/redbear-full/harddrive.img instead of the ISO
|
|
--timeout SECONDS Auto-quit QEMU after this many seconds (default 60)
|
|
--no-kvm Disable KVM (fall back to TCG)
|
|
--with-gpu Add a virtio-gpu-pci device (only when redbear-full image is bootable)
|
|
--with-input Add virtio-keyboard-pci / virtio-mouse-pci (v6.0 input arch proof)
|
|
--fallback CONFIG Fall back to this config's ISO if redbear-full is missing
|
|
(e.g. --fallback redbear-mini)
|
|
--log-dir DIR Override the log directory (default local/docs/boot-logs)
|
|
-- QEMU_ARG ... Pass extra QEMU arguments after --
|
|
-h, --help Show this help
|
|
USAGE
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--img)
|
|
USE_IMG=1
|
|
;;
|
|
--timeout)
|
|
BOOT_TIMEOUT="${2:-}"
|
|
[[ -z "$BOOT_TIMEOUT" ]] && { echo "ERROR: --timeout requires a value" >&2; exit 1; }
|
|
shift
|
|
;;
|
|
--no-kvm)
|
|
USE_KVM=0
|
|
;;
|
|
--with-gpu)
|
|
USE_GPU=1
|
|
;;
|
|
--with-input)
|
|
USE_INPUT=1
|
|
;;
|
|
--fallback)
|
|
FALLBACK="${2:-}"
|
|
[[ -z "$FALLBACK" ]] && { echo "ERROR: --fallback requires a value" >&2; exit 1; }
|
|
shift
|
|
;;
|
|
--log-dir)
|
|
LOG_DIR="${2:-}"
|
|
[[ -z "$LOG_DIR" ]] && { echo "ERROR: --log-dir requires a value" >&2; exit 1; }
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--)
|
|
shift
|
|
EXTRA_QEMU_ARGS=("$@")
|
|
break
|
|
;;
|
|
*)
|
|
echo "ERROR: unknown argument $1" >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# Locate UEFI firmware (q35 + OVMF is the same pattern as the other
|
|
# test-*qemu.sh launchers in this directory).
|
|
find_uefi_firmware() {
|
|
local candidates=(
|
|
"/usr/share/ovmf/x64/OVMF.4m.fd"
|
|
"/usr/share/OVMF/x64/OVMF.4m.fd"
|
|
"/usr/share/ovmf/x64/OVMF_CODE.4m.fd"
|
|
"/usr/share/OVMF/x64/OVMF_CODE.4m.fd"
|
|
"/usr/share/ovmf/OVMF.fd"
|
|
"/usr/share/OVMF/OVMF_CODE.fd"
|
|
"/usr/share/qemu/edk2-x86_64-code.fd"
|
|
)
|
|
local path
|
|
for path in "${candidates[@]}"; do
|
|
if [[ -f "$path" ]]; then
|
|
printf '%s\n' "$path"
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
firmware="$(find_uefi_firmware)" || {
|
|
echo "ERROR: no usable x86_64 UEFI firmware found" >&2
|
|
exit 1
|
|
}
|
|
|
|
arch="${ARCH:-$(uname -m)}"
|
|
config="redbear-full"
|
|
|
|
# Resolve the boot artifact. Prefer ISO; fall back to harddrive.img; fall back
|
|
# to the user-specified --fallback config if the redbear-full ISO is missing.
|
|
if [[ "$USE_IMG" -eq 0 ]]; then
|
|
image="build/$arch/$config.iso"
|
|
if [[ ! -f "$image" ]]; then
|
|
image="build/$arch/$config/harddrive.img"
|
|
if [[ ! -f "$image" ]]; then
|
|
if [[ -n "$FALLBACK" ]]; then
|
|
image="build/$arch/$FALLBACK.iso"
|
|
if [[ ! -f "$image" ]]; then
|
|
image="build/$arch/$FALLBACK/harddrive.img"
|
|
fi
|
|
if [[ -f "$image" ]]; then
|
|
config="$FALLBACK"
|
|
echo "WARNING: redbear-full image missing; using $config fallback: $image" >&2
|
|
else
|
|
echo "ERROR: redbear-full and fallback $FALLBACK images both missing" >&2
|
|
echo "Build with: ./local/scripts/build-redbear.sh redbear-full" >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "ERROR: missing image $image" >&2
|
|
echo "Build it first with: ./local/scripts/build-redbear.sh redbear-full" >&2
|
|
echo "(or pass --fallback redbear-mini to use the existing text-only ISO)" >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
USE_IMG=1
|
|
fi
|
|
fi
|
|
else
|
|
image="build/$arch/$config/harddrive.img"
|
|
fi
|
|
|
|
mkdir -p "$LOG_DIR"
|
|
timestamp="$(date -u +%Y%m%d-%H%M%S)"
|
|
log_path="$LOG_DIR/redbear-full-boot-$timestamp.log"
|
|
|
|
# A scratch extra disk (some validation suites attach a second NVMe for write
|
|
# tests). Created lazily if absent.
|
|
extra="build/$arch/$config/extra.img"
|
|
if [[ ! -f "$extra" ]]; then
|
|
truncate -s 1g "$extra"
|
|
fi
|
|
|
|
# Kill any prior QEMU instance pointing at the same image.
|
|
pkill -f "qemu-system-x86_64.*$image" 2>/dev/null || true
|
|
sleep 1
|
|
|
|
# KVM is opportunistic: if /dev/kvm is missing or the user disabled it,
|
|
# fall back to TCG (slow but works in CI containers).
|
|
kvm_args=()
|
|
if [[ "$USE_KVM" -eq 1 ]] && [[ -e /dev/kvm ]] && [[ -r /dev/kvm ]] && [[ -w /dev/kvm ]]; then
|
|
kvm_args=(-enable-kvm -cpu host)
|
|
else
|
|
kvm_args=(-cpu max)
|
|
if [[ "$USE_KVM" -eq 1 ]]; then
|
|
echo "NOTE: /dev/kvm unavailable, falling back to TCG" >&2
|
|
fi
|
|
fi
|
|
|
|
echo "=== Red Bear OS redbear-full QEMU Boot Test ==="
|
|
echo "Config: $config"
|
|
echo "Image: $image"
|
|
echo "UEFI: $firmware"
|
|
echo "KVM: $([[ "$USE_KVM" -eq 1 ]] && echo yes || echo no)"
|
|
echo "Timeout: ${BOOT_TIMEOUT}s"
|
|
echo "Log: $log_path"
|
|
echo
|
|
|
|
# Build the QEMU command. We deliberately mirror the per-target test
|
|
# launchers in this directory (test-ps2-qemu.sh, test-greeter-qemu.sh,
|
|
# test-phase4-wayland-qemu.sh) so behavior is consistent.
|
|
# Display is hidden — the boot log is the source of truth, not a UI surface.
|
|
# The standard display path is /scheme/drm/card0 via redox-drm (NO VESA
|
|
# primary surface, per project policy); QEMU's virtio-gpu-pci exposes the
|
|
# DRM/KMS device the redbear-full driver stack targets.
|
|
|
|
qemu_args=(
|
|
qemu-system-x86_64
|
|
-name "Red Bear OS redbear-full"
|
|
-M q35
|
|
-smp 4
|
|
-m 4G
|
|
-bios "$firmware"
|
|
-chardev stdio,id=debug,signal=off,mux=on
|
|
-serial chardev:debug
|
|
-mon chardev=debug
|
|
-vga none
|
|
-device qemu-xhci
|
|
-device ich9-intel-hda
|
|
-device hda-output
|
|
-device virtio-net-pci,netdev=net0
|
|
-netdev user,id=net0
|
|
)
|
|
|
|
# Optional virtio-gpu-pci (only when targeting a real redbear-full bootable image
|
|
# with a DRM/KMS driver in the initfs). The text-only redbear-mini ISO does not
|
|
# ship a virtio-gpu DRM driver, so attaching the device can stall the kernel's
|
|
# framebuffer probe and starve the init of output. Keep it gated.
|
|
if [[ "$USE_GPU" -eq 1 ]]; then
|
|
qemu_args+=(-device virtio-gpu-pci)
|
|
fi
|
|
|
|
# Optional v6.0 input architecture proof devices.
|
|
if [[ "$USE_INPUT" -eq 1 ]]; then
|
|
qemu_args+=(-device virtio-keyboard-pci -device virtio-mouse-pci)
|
|
fi
|
|
|
|
if [[ "$USE_IMG" -eq 0 ]]; then
|
|
# Boot the live ISO from the virtio CD-ROM-equivalent. We attach via a
|
|
# raw virtio-blk rather than ide-cd so the bootloader can find it
|
|
# without needing AHCI (still useful for coverage; the kernel sees
|
|
# both pathways). snapshot=on is mandatory: without it, kernel writes
|
|
# to the live ISO corrupt the build artifact across re-runs.
|
|
qemu_args+=(
|
|
-drive file="$image",format=raw,if=virtio,snapshot=on,readonly=on
|
|
-drive file="$extra",format=raw,if=none,id=drv1,snapshot=on
|
|
-device nvme,drive=drv1,serial=NVME_EXTRA
|
|
)
|
|
else
|
|
qemu_args+=(
|
|
-drive file="$image",format=raw,if=none,id=drv0,snapshot=on
|
|
-device nvme,drive=drv0,serial=NVME_SERIAL
|
|
-drive file="$extra",format=raw,if=none,id=drv1,snapshot=on
|
|
-device nvme,drive=drv1,serial=NVME_EXTRA
|
|
)
|
|
fi
|
|
|
|
qemu_args+=("${kvm_args[@]}")
|
|
qemu_args+=("${EXTRA_QEMU_ARGS[@]}")
|
|
|
|
# Use the `timeout` wrapper to enforce BOOT_TIMEOUT. The `-k 5` sends SIGKILL
|
|
# 5 seconds after SIGTERM to avoid a hung QEMU holding /dev/kvm.
|
|
timeout_cmd=(timeout --foreground -k 5 "$BOOT_TIMEOUT")
|
|
|
|
# Run QEMU; capture both stdout and stderr. We split the run from the log
|
|
# capture so that a build-side failure (no image, no KVM) is reported
|
|
# distinctly from a kernel-side boot failure.
|
|
"${timeout_cmd[@]}" "${qemu_args[@]}" >"$log_path" 2>&1 || true
|
|
|
|
# Always print a footer with the captured log size and last lines so a
|
|
# human reader can spot tail-time crashes without re-opening the file.
|
|
log_size=$(wc -c <"$log_path" 2>/dev/null || echo 0)
|
|
echo
|
|
echo "=== Boot test finished ==="
|
|
echo "Log: $log_path"
|
|
echo "Size: ${log_size} bytes"
|
|
echo
|
|
echo "--- Last 20 lines of captured log ---"
|
|
tail -20 "$log_path" 2>/dev/null || echo "(log unavailable)"
|
|
echo "--- End of log ---"
|
|
|
|
# Don't fail the script on boot failure — the log is the deliverable.
|
|
exit 0
|