Files
RedBear-OS/local/scripts/test-uhci-runtime-qemu.sh
T
vasilito 5c6cd18599 tests: fix UHCI proof marker for interpolated controller name
The UHCI runtime proof grepped for the literal
  'uhcid: controller initialized, polling ports'
but uhcid main.rs:535 emits it with ctrl.name interpolated mid-string:
  info!("uhcid: {} controller initialized, polling ports", ctrl.name);
producing e.g. 'uhcid: 0000:00:01.2_uhci controller initialized, polling
ports'. The literal grep never matched and the proof would fail 100% of the
time at runtime.

Fix: grep with a regex anchored on the stable suffix:
  grep -Eq 'uhcid: .* controller initialized, polling ports'

The ohcid, ehcid, usbhidd, and usbscsid markers were re-audited against
driver source and are all correct (ohcid main.rs:341 has no interpolation;
ehcid main.rs:294 interpolates after the matched comma prefix; all others
interpolate at line ends matched by prefix). Only the UHCI init-done marker
was broken.

Comment header and error echo updated to document the interpolated form and
point at main.rs:535 so the regex is not 'simplified' back to a literal.

No QEMU runs. bash -n passes. Verified the regex matches the real emitted
format and does not cross-match ohcid's identical suffix (the 'uhcid:' prefix
anchor disambiguates).
2026-07-20 11:23:33 +09:00

207 lines
7.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Launch or validate UHCI controller enumeration (P1-B) in QEMU.
#
# Topology under test:
# -machine pc (i440fx/PIIX3 chipset) → -device piix3-usb-uhci,id=uhci
# └─ bus=uhci.0 → usb-kbd
#
# Validates: pcid auto-spawns uhcid for the PIIX3 UHCI PCI device (class 0c0300,
# see local/config/drivers.d/20-usb.toml), uhcid maps the I/O base, initializes
# the frame list, and detects the attached usb-kbd (port connect + enumeration
# descriptor read). This is the P1-B UHCI runtime-enumeration proof that closes
# the P8-B gap for UHCI.
#
# Evidence is read from the serial log (no guest-side checker exists that
# validates UHCI enumeration specifically), mirroring the test-xhci-irq-qemu.sh
# proof style. Proof markers come straight from
# local/recipes/drivers/uhcid/source/src/main.rs:
# "UHCI USB 1.1 at <pci_path>" (main.rs:487 — controller bound)
# "uhcid: <name> controller initialized, polling ports" (main.rs:535 — init
# done; note ctrl.name is interpolated, e.g. "uhcid: uhci0_uhci controller
# initialized, polling ports", so the grep uses a regex, not a literal)
# "uhcid: port <n> connect detected" (main.rs:545 — port event)
# "uhcid: port <n> device <vid>:<pid> class <c>" (main.rs:551 — enumerated)
set -euo pipefail
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
}
usage() {
cat <<'USAGE'
Usage: test-uhci-runtime-qemu.sh [--check] [config]
Boot or validate UHCI (USB 1.1) controller enumeration on a Red Bear image in
QEMU. The PIIX3 UHCI companion controller only exists on the i440fx machine
type, so this proof uses `-machine pc` rather than the q35 machine used by the
xHCI suite. Defaults to redbear-mini (mapped to the in-tree redbear-mini image).
USAGE
}
check_mode=0
config="redbear-mini"
for arg in "$@"; do
case "$arg" in
--help|-h|help)
usage
exit 0
;;
--check)
check_mode=1
;;
redbear-*)
config="$arg"
;;
esac
done
firmware="$(find_uefi_firmware)" || {
echo "ERROR: no usable x86_64 UEFI firmware found" >&2
exit 1
}
arch="${ARCH:-$(uname -m)}"
# Prefer the live ISO (canonical build-redbear.sh artifact); harddrive.img is
# only produced by older make-all flows and goes stale, which would test the
# wrong tree. extra.img stays as a data drive in both modes.
iso="build/$arch/$config.iso"
image="build/$arch/$config/harddrive.img"
extra="build/$arch/$config/extra.img"
boot_media=""
if [[ -f "$iso" ]]; then
boot_media="iso"
elif [[ -f "$image" ]]; then
boot_media="harddrive"
else
echo "ERROR: no bootable image found ($iso or $image)" >&2
echo "Build it first with: ./local/scripts/build-redbear.sh $config" >&2
exit 1
fi
if [[ ! -f "$extra" ]]; then
truncate -s 1g "$extra"
fi
if [[ "$boot_media" == "iso" ]]; then
boot_args=(-cdrom "$iso")
else
boot_args=(-drive file="$image",format=raw,if=none,id=drv0,snapshot=on -device nvme,drive=drv0,serial=NVME_SERIAL)
fi
pkill -f "qemu-system-x86_64.*$config" 2>/dev/null || true
sleep 1
if [[ "$check_mode" -eq 1 ]]; then
log_file="build/$arch/$config/uhci-runtime-check.log"
rm -f "$log_file"
set +e
# 180s mirrors the xHCI interrupt proof budget. UHCI enumeration on QEMU's
# emulated PIIX3 is quick once uhcid spawns, but the guest clock runs several
# times slower than wall under boot load (same characteristic latency noted
# in test-usb-hub-qemu.sh).
timeout 180s qemu-system-x86_64 \
-name "Red Bear OS x86_64" \
-machine pc \
-device piix3-usb-uhci,id=uhci \
-device usb-kbd,bus=uhci.0 \
-smp 4 \
-m 2048 \
-bios "$firmware" \
-chardev stdio,id=debug,signal=off,mux=on \
-serial chardev:debug \
-mon chardev=debug \
-device virtio-net,netdev=net0 \
-netdev user,id=net0 \
-object filter-dump,id=f1,netdev=net0,file="build/$arch/$config/network.pcap" \
-nographic -vga none \
"${boot_args[@]}" \
-drive file="$extra",format=raw,if=none,id=drv1,snapshot=on \
-device nvme,drive=drv1,serial=NVME_EXTRA \
-enable-kvm -cpu host \
> "$log_file" 2>&1
status=$?
set -e
# 1. uhcid bound the controller and logged its PCI path. This proves pcid
# matched the PIIX3 UHCI PCI class (0c0300) and spawned uhcid.
if ! grep -q "UHCI USB 1.1 at " "$log_file"; then
echo "ERROR: uhcid did not bind the UHCI controller" >&2
echo " Expected: 'UHCI USB 1.1 at <pci_path>'" >&2
grep -i "uhcid\|UHCI" "$log_file" | tail -10 >&2 || true
echo " See $log_file" >&2
exit 1
fi
# 2. Frame list allocated and the polling loop started.
if ! grep -Eq 'uhcid: .* controller initialized, polling ports' "$log_file"; then
echo "ERROR: uhcid did not finish controller initialization" >&2
echo " Expected: 'uhcid: <name> controller initialized, polling ports'" >&2
echo " (main.rs:535 interpolates ctrl.name, e.g. 'uhcid: uhci0_uhci controller initialized, polling ports')" >&2
echo " See $log_file" >&2
exit 1
fi
# 3. Port connect detected for the attached usb-kbd. This is the
# enumeration-proof marker: the controller saw a device and ran the
# descriptor-read path.
if ! grep -Eq "uhcid: port [0-9]+ connect detected" "$log_file"; then
echo "ERROR: uhcid did not detect a port connect event" >&2
echo " Expected: 'uhcid: port <n> connect detected'" >&2
echo " See $log_file" >&2
exit 1
fi
# 4. No panics anywhere in the boot.
if grep -qiE "panic|RUST_BACKTRACE" "$log_file"; then
echo "ERROR: panic detected in boot log" >&2
grep -iE "panic|RUST_BACKTRACE" "$log_file" | head -5 >&2
echo " See $log_file" >&2
exit 1
fi
echo "UHCI_DRIVER=uhcid"
echo "UHCI_CONTROLLER=piix3-usb-uhci"
echo "UHCI_MACHINE=pc"
echo "UHCI_LOG=$log_file"
echo "UHCI controller enumeration confirmed in $log_file"
exit 0
fi
exec qemu-system-x86_64 \
-name "Red Bear OS x86_64" \
-machine pc \
-device piix3-usb-uhci,id=uhci \
-device usb-kbd,bus=uhci.0 \
-smp 4 \
-m 2048 \
-bios "$firmware" \
-chardev stdio,id=debug,signal=off,mux=on \
-serial chardev:debug \
-mon chardev=debug \
-device virtio-net,netdev=net0 \
-netdev user,id=net0 \
-object filter-dump,id=f1,netdev=net0,file="build/$arch/$config/network.pcap" \
-vga std \
"${boot_args[@]}" \
-drive file="$extra",format=raw,if=none,id=drv1,snapshot=on \
-device nvme,drive=drv1,serial=NVME_EXTRA \
-enable-kvm -cpu host