diff --git a/.github/workflows/real-hw-test.yml b/.github/workflows/real-hw-test.yml index 9c5ee7d..f1e2cbb 100644 --- a/.github/workflows/real-hw-test.yml +++ b/.github/workflows/real-hw-test.yml @@ -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: | diff --git a/real-hw-test/scripts/qemu-machine.sh b/real-hw-test/scripts/qemu-machine.sh index 56bbd22..b1daf7a 100644 --- a/real-hw-test/scripts/qemu-machine.sh +++ b/real-hw-test/scripts/qemu-machine.sh @@ -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) diff --git a/real-hw-test/scripts/run-qemu-ci.sh b/real-hw-test/scripts/run-qemu-ci.sh index 9865f18..98f70c0 100755 --- a/real-hw-test/scripts/run-qemu-ci.sh +++ b/real-hw-test/scripts/run-qemu-ci.sh @@ -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 \ @@ -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:-}" +} + # Mid-run extraction from the live FAT image is best-effort progress polling; # only the extraction after QEMU quit is authoritative. extract_persisted_log() { @@ -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 @@ -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'