diff --git a/issues/two-amdvi-boots-in-a-kvm-suite-wrote-not-one-byte.md b/issues/two-amdvi-boots-in-a-kvm-suite-wrote-not-one-byte.md new file mode 100644 index 0000000000..7a7acaf43f --- /dev/null +++ b/issues/two-amdvi-boots-in-a-kvm-suite-wrote-not-one-byte.md @@ -0,0 +1,30 @@ +--- +status: open +kind: defect +opened: 2026-10-28 +--- + +# Two amdvi boots in a KVM suite wrote not one byte + +A full `cargo test --test toyos-build` at `0eb2c09d0` on a Linux x86_64 KVM +host went red on `amdvi_selftest` and `amdvi_firmware_left`, and on nothing +else. Both boots used `tests/images/testcases.toml`, finished building in the +same second and timed out together after 63 s. Both reported `the console +carried: nothing at all` and `uart: nothing at all`. So the 16550 file was +empty, without even the firmware's screen-clearing escapes that the netcase +boots in +`issues/a-netcase-boot-under-host-load-said-nothing-past-the-firmwares-screen-clears.md` +wrote. Both tests passed in that host's suites at `e4bdb0a5d` and `7745af98d`. +`7745af98d` differs from `0eb2c09d0` only in a host-side wait inside +`the_log_lands_on_the_boot_stick`. That suite ran alone on the host, and its +load during these boots was not recorded. Log: +https://github.com/ToyOSOrg/evidence/tree/d06821d0cb6e754f1fec16a5921bc4378d9ba600/pr-1107/r2 + +Not reduced: whether QEMU or the firmware ever ran in those boots. A QMP read +of a silent guest's registers would say. No `red-run-serial` file was empty, +so the empty 16550 files were not kept. + +**Exit**: a silent boot's registers read, naming where it stopped, and the fix +at that cause. If it is the netcase boots' cause, fold this record into that one. + +**Owner**: the orchestrator. diff --git a/tests/toyos.rs b/tests/toyos.rs index 9ff6c2ccbe..117b7aac09 100644 --- a/tests/toyos.rs +++ b/tests/toyos.rs @@ -2954,7 +2954,12 @@ fn the_log_lands_on_the_boot_stick(test_config: &Path) -> Result<(), String> { // power button is pressed, as the metal row's deadline finds it. writeln!(qemu.stdin_mut(), "run {}", metal::STICK_LOAD_JOB).map_err(|e| e.to_string())?; qemu.flush_stdin(); - qemu::await_marker(&mut qemu, &mut console, "stick_load: line 1500 ", "the load to write the stick")?; + // Any line past the first 1500, not one exact line: logkeeper sheds its + // oldest console lines when the console falls behind the load. + let from = console.len(); + qemu::await_guest(&mut qemu, &mut console, "the load to write the stick", |log| { + log[from..].lines().any(|l| stick_load_line(l).is_some_and(|n| n >= 1500)) + })?; qemu::QmpShutdown::open(qemu.qmp_socket(), qemu.budget(qemu::GUEST_QUIET)).power_button(); let by = qemu.budget(Duration::from_secs(60)); console.push_str(&qemu.await_exit(by)?); @@ -2981,6 +2986,12 @@ fn the_log_lands_on_the_boot_stick(test_config: &Path) -> Result<(), String> { usb_stopped_before_the_reset(&log, &console) } +fn stick_load_line(line: &str) -> Option { + let (_, rest) = line.split_once("stick_load: line ")?; + let digits = rest.find(|c: char| !c.is_ascii_digit()).unwrap_or(rest.len()); + rest[..digits].parse().ok() +} + /// usbd ended for the stop with every connected port's reset finished and its /// controller halted and reset (its exit code, which the kernel records, /// because its own line may reach no log), and it ended before the kernel's