Skip to content

Commit 8791adb

Browse files
committed
libvirt: Switch to UEFI (and tpm2) by default
Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 1acf965 commit 8791adb

File tree

5 files changed

+152
-3
lines changed

5 files changed

+152
-3
lines changed

crates/kit/src/libvirt/create.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ pub struct LibvirtCreateOpts {
8181
#[clap(long)]
8282
pub disk_size: Option<String>,
8383

84+
/// Firmware type for the VM (\"uefi\", \"uefi-secure\", or \"bios\", defaults to \"uefi\")
85+
#[clap(long, default_value = "uefi")]
86+
pub firmware: String,
87+
88+
/// Disable TPM 2.0 support (enabled by default)
89+
#[clap(long)]
90+
pub disable_tpm: bool,
91+
8492
/// Memory size for installation VM during auto-upload (e.g. 2G, 1024M)
8593
#[clap(flatten)]
8694
pub install_memory: MemoryOpts,
@@ -487,7 +495,9 @@ impl LibvirtCreateOpts {
487495
.with_memory(memory_mb)
488496
.with_vcpus(self.vcpus.unwrap_or_else(default_vcpus))
489497
.with_disk(&domain_volume_path)
490-
.with_network(network_config);
498+
.with_network(network_config)
499+
.with_firmware(&self.firmware)
500+
.with_tpm(!self.disable_tpm);
491501

492502
// Add QEMU arguments if we have any
493503
if !qemu_args.is_empty() {

crates/kit/src/libvirt/domain.rs

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ pub struct DomainBuilder {
3636
metadata: HashMap<String, String>,
3737
qemu_args: Vec<String>,
3838
virtiofs_filesystems: Vec<VirtiofsFilesystem>,
39+
firmware: Option<String>, // "uefi" (default), "uefi-secure", or "bios"
40+
tpm: bool,
3941
}
4042

4143
impl Default for DomainBuilder {
@@ -59,6 +61,8 @@ impl DomainBuilder {
5961
metadata: HashMap::new(),
6062
qemu_args: Vec::new(),
6163
virtiofs_filesystems: Vec::new(),
64+
firmware: None, // Defaults to UEFI
65+
tpm: true, // Default to enabled
6266
}
6367
}
6468

@@ -122,6 +126,18 @@ impl DomainBuilder {
122126
self
123127
}
124128

129+
/// Set firmware type (\"uefi\", \"uefi-secure\", or \"bios\", defaults to \"uefi\")
130+
pub fn with_firmware(mut self, firmware: &str) -> Self {
131+
self.firmware = Some(firmware.to_string());
132+
self
133+
}
134+
135+
/// Enable TPM 2.0 support using swtpm
136+
pub fn with_tpm(mut self, tpm: bool) -> Self {
137+
self.tpm = tpm;
138+
self
139+
}
140+
125141
/// Build the domain XML
126142
pub fn build_xml(self) -> Result<String> {
127143
let name = self.name.ok_or_else(|| eyre!("Domain name is required"))?;
@@ -160,8 +176,16 @@ impl DomainBuilder {
160176
)?;
161177
writer.write_text_element("vcpu", &vcpus.to_string())?;
162178

163-
// OS section
164-
writer.start_element("os", &[])?;
179+
// OS section with firmware configuration
180+
let use_uefi = self.firmware.as_deref() != Some("bios");
181+
let secure_boot = self.firmware.as_deref() == Some("uefi-secure");
182+
183+
if use_uefi {
184+
writer.start_element("os", &[("firmware", "efi")])?;
185+
} else {
186+
writer.start_element("os", &[])?;
187+
}
188+
165189
writer.write_text_element_with_attrs(
166190
"type",
167191
&arch_config.os_type,
@@ -170,6 +194,12 @@ impl DomainBuilder {
170194
("machine", &arch_config.machine),
171195
],
172196
)?;
197+
198+
if use_uefi && secure_boot {
199+
// Modern libvirt handles firmware paths automatically for secure boot
200+
writer.write_empty_element("loader", &[("secure", "yes")])?;
201+
}
202+
173203
writer.write_empty_element("boot", &[("dev", "hd")])?;
174204

175205
// Add kernel arguments if specified (for direct boot)
@@ -283,6 +313,13 @@ impl DomainBuilder {
283313
writer.end_element("filesystem")?;
284314
}
285315

316+
// TPM device
317+
if self.tpm {
318+
writer.start_element("tpm", &[("model", "tpm-tis")])?;
319+
writer.write_empty_element("backend", &[("type", "emulator"), ("version", "2.0")])?;
320+
writer.end_element("tpm")?;
321+
}
322+
286323
writer.end_element("devices")?;
287324

288325
// QEMU commandline section (if we have QEMU args)
@@ -437,6 +474,78 @@ mod tests {
437474
assert!(xml.contains("<timer name=\"rtc\""));
438475
}
439476

477+
#[test]
478+
fn test_secure_boot_configuration() {
479+
let builder = DomainBuilder::new()
480+
.with_name("test-secure-boot")
481+
.with_firmware("uefi-secure");
482+
483+
let xml = builder.build_xml().unwrap();
484+
485+
// Should include secure boot loader configuration
486+
assert!(xml.contains("loader"));
487+
assert!(xml.contains("secure=\"yes\""));
488+
489+
// Should use firmware="efi" for UEFI
490+
assert!(xml.contains("firmware=\"efi\""));
491+
492+
// Test regular UEFI without secure boot
493+
let xml_regular = DomainBuilder::new()
494+
.with_name("test-regular-uefi")
495+
.with_firmware("uefi")
496+
.build_xml()
497+
.unwrap();
498+
499+
// Should use libvirt auto firmware selection
500+
assert!(xml_regular.contains("firmware=\"efi\""));
501+
assert!(!xml_regular.contains("secure=\"yes\""));
502+
503+
// Test BIOS firmware (no secure boot)
504+
let xml_bios = DomainBuilder::new()
505+
.with_name("test-bios")
506+
.with_firmware("bios")
507+
.build_xml()
508+
.unwrap();
509+
510+
// Should not have firmware="efi" or secure boot settings
511+
assert!(!xml_bios.contains("firmware=\"efi\""));
512+
assert!(!xml_bios.contains("secure=\"yes\""));
513+
}
514+
515+
#[test]
516+
fn test_tpm_configuration() {
517+
// Test TPM enabled (default)
518+
let xml = DomainBuilder::new()
519+
.with_name("test-tpm-enabled")
520+
.build_xml()
521+
.unwrap();
522+
523+
// Should include TPM device by default
524+
assert!(xml.contains("<tpm model=\"tpm-tis\">"));
525+
assert!(xml.contains("<backend type=\"emulator\" version=\"2.0\"/>"));
526+
527+
// Test TPM explicitly enabled
528+
let xml_enabled = DomainBuilder::new()
529+
.with_name("test-tpm-explicit")
530+
.with_tpm(true)
531+
.build_xml()
532+
.unwrap();
533+
534+
assert!(xml_enabled.contains("<tpm model=\"tpm-tis\">"));
535+
assert!(xml_enabled.contains("backend type=\"emulator\""));
536+
537+
// Test TPM disabled
538+
let xml_disabled = DomainBuilder::new()
539+
.with_name("test-tpm-disabled")
540+
.with_tpm(false)
541+
.build_xml()
542+
.unwrap();
543+
544+
// Should not contain TPM configuration
545+
assert!(!xml_disabled.contains("<tpm"));
546+
assert!(!xml_disabled.contains("backend type=\"emulator\""));
547+
}
548+
440549
#[test]
441550
fn test_virtiofs_filesystem_configuration() {
442551
// Test read-write virtiofs filesystem

crates/kit/src/libvirt/run.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ pub struct LibvirtRunOpts {
6565
/// Mount host container storage (RO) at /run/virtiofs-mnt-hoststorage
6666
#[clap(long = "bind-storage-ro")]
6767
pub bind_storage_ro: bool,
68+
69+
/// Firmware type for the VM ("uefi", "uefi-secure", or "bios", defaults to "uefi")
70+
#[clap(long, default_value = "uefi")]
71+
pub firmware: String,
72+
73+
/// Disable TPM 2.0 support (enabled by default)
74+
#[clap(long)]
75+
pub disable_tpm: bool,
6876
}
6977

7078
/// Execute the libvirt run command
@@ -542,6 +550,8 @@ fn create_libvirt_domain_from_disk(
542550
.with_vcpus(opts.cpus)
543551
.with_disk(disk_path.as_str())
544552
.with_network("none") // Use QEMU args for SSH networking instead
553+
.with_firmware(&opts.firmware)
554+
.with_tpm(!opts.disable_tpm)
545555
.with_metadata("bootc:source-image", &opts.image)
546556
.with_metadata("bootc:memory-mb", &opts.memory.to_string())
547557
.with_metadata("bootc:vcpus", &opts.cpus.to_string())

docs/src/man/bcvk-libvirt-create.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ Create and start domains from uploaded bootc volumes
8585

8686
Size of the disk image for automatic upload (e.g., '20G', '10240M')
8787

88+
**--firmware**=*FIRMWARE*
89+
90+
Firmware type for the VM (\"uefi\", \"uefi-secure\", or \"bios\", defaults to \"uefi\")
91+
92+
Default: uefi
93+
94+
**--disable-tpm**
95+
96+
Disable TPM 2.0 support (enabled by default)
97+
8898
**--memory**=*MEMORY*
8999

90100
Memory size (e.g. 4G, 2048M, or plain number for MB)

docs/src/man/bcvk-libvirt-run.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ Run a bootable container as a persistent VM
7373

7474
Mount host container storage (RO) at /run/virtiofs-mnt-hoststorage
7575

76+
**--firmware**=*FIRMWARE*
77+
78+
Firmware type for the VM ("uefi", "uefi-secure", or "bios", defaults to "uefi")
79+
80+
Default: uefi
81+
82+
**--disable-tpm**
83+
84+
Disable TPM 2.0 support (enabled by default)
85+
7686
<!-- END GENERATED OPTIONS -->
7787

7888
# EXAMPLES

0 commit comments

Comments
 (0)