Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/real-hw-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,15 @@ jobs:
- name: Install QEMU, firmware, and harness tools
run: |
sudo apt-get update
packages=(dosfstools mtools socat)
if [[ "${{ matrix.arch }}" == x86_64 ]]; then
sudo apt-get install -y dosfstools mtools ovmf qemu-system-x86 socat
packages+=(ovmf qemu-system-x86)
else
sudo apt-get install -y dosfstools mtools qemu-efi-aarch64 qemu-system-arm socat
packages+=(qemu-efi-aarch64 qemu-system-arm)
fi
sudo apt-get install -y "${packages[@]}"
# QEMU and firmware versions follow the runner image.
dpkg-query -W "${packages[@]}"
- name: Run deterministic UEFI checks
working-directory: real-hw-test
run: |
Expand Down
8 changes: 7 additions & 1 deletion real-hw-test/scripts/qemu-machine.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,14 @@ qemu_machine_setup() {
# Writable per-run variable store; the template may be read-only on disk.
cp "$aavmf_vars" "$vars_file"
chmod u+w "$vars_file"
# Under TCG, a fixed CPU model instead of max: AAVMF 2025.11 (Ubuntu
# 26.04) hangs before BDS with QEMU 10.2's max. KVM needs max (host).
local cpu=max
if [[ "$accel" == tcg ]]; then
cpu=neoverse-n1
fi
# virt has no built-in keyboard; the UEFI prompts need one.
machine_args=(-machine "virt,accel=$accel" -cpu max -m 512M
machine_args=(-machine "virt,accel=$accel" -cpu "$cpu" -m 512M
-drive "if=pflash,format=raw,file=$aavmf_code,readonly=on"
-drive "if=pflash,format=raw,file=$vars_file"
-device qemu-xhci -device usb-kbd)
Expand Down
47 changes: 36 additions & 11 deletions real-hw-test/scripts/run-qemu-ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,26 @@ mkfs.vfat "$disk" >/dev/null
mmd -i "$disk" ::/EFI ::/EFI/BOOT
mcopy -i "$disk" "$artifact" "::/EFI/BOOT/$boot_name"

"$qemu" \
"${machine_args[@]}" \
-drive "format=raw,file=$disk" \
-nic none \
-display none \
-monitor "unix:$monitor,server,nowait" \
-serial "file:$console_log" \
-chardev "file,id=pci_serial,path=$pci_log" \
-device pci-serial,chardev=pci_serial \
-no-reboot &
qemu_args=(
"${machine_args[@]}"
-drive "format=raw,file=$disk"
-nic none
-display none
-monitor "unix:$monitor,server,nowait"
-serial "file:$console_log"
-chardev "file,id=pci_serial,path=$pci_log"
-device "pci-serial,chardev=pci_serial"
-no-reboot
)
# Host QEMU and firmware change with the CI runner image; log what this run
# actually used.
"$qemu" --version | head -n1
echo "$qemu ${qemu_args[*]}"
"$qemu" "${qemu_args[@]}" &
qemu_pid=$!
trap 'kill -9 "$qemu_pid" 2>/dev/null || true' EXIT
deadline=$(($(date +%s) + timeout_s))
start=$(date +%s)
deadline=$((start + timeout_s))

monitor_cmd() {
printf '%s\n' "$1" | socat -t 1 - "UNIX-CONNECT:$monitor" >/dev/null 2>&1 \
Expand All @@ -70,6 +77,22 @@ qemu_alive() {
kill -0 "$qemu_pid" 2>/dev/null
}

# A periodic snapshot of the console shows where a stuck run stopped, e.g.,
# in firmware before the application started, without waiting for the
# timeout to dump the logs.
progress_interval_s=5
last_progress=$start
report_progress() {
local now last_line
now=$(date +%s)
((now - last_progress >= progress_interval_s)) || return 0
last_progress=$now
# Strip CSI sequences and carriage returns of the firmware console.
last_line=$(sed -E 's/\x1b\[[0-9;=?]*[A-Za-z]//g; s/\r//g' "$console_log" \
2>/dev/null | grep -v '^[[:space:]]*$' | tail -n1 || true)
echo "[$((now - start))s] console: ${last_line:-<empty>}"
}

# Mid-run extraction from the live FAT image is best-effort progress polling;
# only the extraction after QEMU quit is authoritative.
extract_persisted_log() {
Expand Down Expand Up @@ -109,6 +132,7 @@ until extract_persisted_log | grep -qF 'then press Enter.'; do
if (($(date +%s) >= deadline)); then
fail_run "timeout waiting for the first operator prompt"
fi
report_progress
sleep 2
done

Expand All @@ -122,6 +146,7 @@ while (($(date +%s) < deadline)); do
# A queued Enter can finish the final prompt early; the persisted log then
# already contains every line the assertions below need.
qemu_alive || break
report_progress
monitor_cmd 'sendkey ret'
sleep 1
monitor_cmd 'sendkey esc'
Expand Down
Loading