Skip to content

Commit 87b8b41

Browse files
committed
libvirt: Disable firmware debug log (isa-debugcon) by default
The isa-debugcon device on IO port 0x402 was unconditionally added to every x86_64 VM, capturing all EDK2 DEBUG() output. When the installed OVMF firmware is built with verbose debug output (the 'verbose-dynamic' feature, which is standard on Debian/Ubuntu), this causes spam like: VirtioSerialIoGetControl:136: Control 0x0 repeated many times during boot. Make the firmware debug log opt-in via a new --firmware-log CLI flag instead of always-on. Assisted-by: OpenCode (Claude Opus 4) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 3856abe commit 87b8b41

File tree

3 files changed

+26
-56
lines changed

3 files changed

+26
-56
lines changed

crates/integration-tests/src/tests/libvirt_verb.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,21 @@ fn test_libvirt_run_no_storage_opts_without_bind_storage() -> TestResult {
686686
"Domain XML should NOT contain bind-storage-ro metadata when flag is not used. Found in XML."
687687
);
688688
println!("✓ Domain XML does not contain bind-storage-ro metadata");
689-
println!("✓ Test passed: STORAGE_OPTS credentials are correctly excluded when --bind-storage-ro is not used");
689+
690+
// Verify that firmware debug log (isa-debugcon) is NOT present by default.
691+
// Verbose OVMF firmware causes debug spam (e.g. VirtioSerialIoGetControl)
692+
// when this device is present, so it must be opt-in via --firmware-log.
693+
if std::env::consts::ARCH == "x86_64" {
694+
assert!(
695+
!domain_xml.contains("isa-debugcon"),
696+
"Domain XML should NOT contain isa-debugcon by default (use --firmware-log to enable)"
697+
);
698+
println!(
699+
"✓ Domain XML does not contain isa-debugcon (firmware debug log disabled by default)"
700+
);
701+
}
702+
703+
println!("✓ Test passed: default domain config has no unexpected extras");
690704
Ok(())
691705
}
692706
integration_test!(test_libvirt_run_no_storage_opts_without_bind_storage);

crates/kit/src/libvirt/domain.rs

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ impl DomainBuilder {
8585
ovmf_code_format: None,
8686
nvram_template: None,
8787
nvram_format: None,
88-
firmware_log: Some(FirmwareLogOutput::Console), // Default to pty for virsh console access
88+
firmware_log: None,
8989
}
9090
}
9191

@@ -776,57 +776,4 @@ mod tests {
776776
assert!(xml_ro.contains("source dir=\"/host/storage\""));
777777
assert!(xml_ro.contains("target dir=\"hoststorage\""));
778778
}
779-
780-
#[test]
781-
fn test_firmware_log_default() {
782-
// By default, firmware log should be enabled (pty/console mode)
783-
let xml = DomainBuilder::new()
784-
.with_name("test-firmware-log-default")
785-
.build_xml()
786-
.unwrap();
787-
788-
// On x86_64, should have isa-debugcon serial device
789-
if std::env::consts::ARCH == "x86_64" {
790-
assert!(xml.contains("serial type=\"pty\""));
791-
assert!(xml.contains("target type=\"isa-debug\""));
792-
assert!(xml.contains("model name=\"isa-debugcon\""));
793-
assert!(xml.contains("address type=\"isa\" iobase=\"0x402\""));
794-
}
795-
}
796-
797-
#[test]
798-
fn test_firmware_log_file() {
799-
// Test firmware log to file
800-
let xml = DomainBuilder::new()
801-
.with_name("test-firmware-log-file")
802-
.with_firmware_log(FirmwareLogOutput::File("/tmp/ovmf-debug.log".to_string()))
803-
.build_xml()
804-
.unwrap();
805-
806-
// On x86_64, should have isa-debugcon with file output
807-
if std::env::consts::ARCH == "x86_64" {
808-
assert!(xml.contains("serial type=\"file\""));
809-
assert!(xml.contains("source path=\"/tmp/ovmf-debug.log\""));
810-
assert!(xml.contains("target type=\"isa-debug\""));
811-
assert!(xml.contains("model name=\"isa-debugcon\""));
812-
assert!(xml.contains("address type=\"isa\" iobase=\"0x402\""));
813-
}
814-
}
815-
816-
#[test]
817-
fn test_firmware_log_disabled() {
818-
// Test disabling firmware log by setting firmware_log to None after construction
819-
// Note: There's no public API to disable it once set, but we can test the XML
820-
// generation doesn't include it on non-x86 architectures
821-
let xml = DomainBuilder::new()
822-
.with_name("test-firmware-log")
823-
.build_xml()
824-
.unwrap();
825-
826-
// On non-x86_64, should NOT have isa-debugcon (it's x86-only)
827-
if std::env::consts::ARCH != "x86_64" {
828-
assert!(!xml.contains("isa-debugcon"));
829-
assert!(!xml.contains("isa-debug"));
830-
}
831-
}
832779
}

crates/kit/src/libvirt/run.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ pub struct LibvirtRunOpts {
285285
#[clap(long)]
286286
pub disable_tpm: bool,
287287

288+
/// Enable firmware debug log (captures OVMF/EDK2 DEBUG output via isa-debugcon)
289+
#[clap(long)]
290+
pub firmware_log: bool,
291+
288292
/// Directory containing secure boot keys (required for uefi-secure)
289293
#[clap(long)]
290294
pub secure_boot_keys: Option<Utf8PathBuf>,
@@ -1099,7 +1103,12 @@ fn create_libvirt_domain_from_disk(
10991103
.with_transient_disk(opts.transient)
11001104
.with_network("none") // Use QEMU args for SSH networking instead
11011105
.with_firmware(opts.firmware)
1102-
.with_tpm(!opts.disable_tpm)
1106+
.with_tpm(!opts.disable_tpm);
1107+
if opts.firmware_log {
1108+
domain_builder =
1109+
domain_builder.with_firmware_log(crate::libvirt::domain::FirmwareLogOutput::Console);
1110+
}
1111+
domain_builder = domain_builder
11031112
.with_metadata("bootc:source-image", &opts.image)
11041113
.with_metadata("bootc:memory-mb", &memory.to_string())
11051114
.with_metadata("bootc:vcpus", &cpus.to_string())

0 commit comments

Comments
 (0)