From e097d7d495304f3adbf17a3f3f4609e6602a6bb3 Mon Sep 17 00:00:00 2001 From: Leander Kohler Date: Mon, 9 Feb 2026 15:34:16 +0100 Subject: [PATCH] vmm: plumb legacy SMBIOS config Add a small SMBIOS config that carries serial_number, uuid, and OEM strings, and pass it from platform config into x86_64 setup. On-behalf-of: SAP leander.kohler@sap.com Signed-off-by: Leander Kohler --- arch/src/x86_64/mod.rs | 21 +++------------------ arch/src/x86_64/smbios.rs | 25 ++++++++++++++++++------- vmm/src/vm.rs | 24 +++--------------------- vmm/src/vm_config.rs | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 46 deletions(-) diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index f9f53e2df..6c983bcd2 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -31,6 +31,7 @@ use linux_loader::loader::elf::start_info::{ hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info, }; use log::{debug, error, info}; +pub use smbios::SmbiosConfig; use thiserror::Error; use vm_memory::{ Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, @@ -1059,9 +1060,7 @@ pub fn configure_system( _num_cpus: u32, setup_header: Option, rsdp_addr: Option, - serial_number: Option<&str>, - uuid: Option<&str>, - oem_strings: Option<&[String]>, + smbios: Option<&SmbiosConfig>, topology: Option<(u16, u16, u16, u16)>, ) -> super::Result<()> { // Write EBDA address to location where ACPICA expects to find it @@ -1069,13 +1068,7 @@ pub fn configure_system( .write_obj((layout::EBDA_START.0 >> 4) as u16, layout::EBDA_POINTER) .map_err(Error::EbdaSetup)?; - let size = smbios::setup_smbios( - guest_mem, - serial_number, - uuid, - oem_strings.unwrap_or_default(), - ) - .map_err(Error::SmbiosSetup)?; + let size = smbios::setup_smbios(guest_mem, smbios).map_err(Error::SmbiosSetup)?; // Place the MP table after the SMIOS table aligned to 16 bytes let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size); @@ -1620,8 +1613,6 @@ mod unit_tests { Some(layout::RSDP_POINTER), None, None, - None, - None, ); config_err.unwrap_err(); @@ -1644,8 +1635,6 @@ mod unit_tests { None, None, None, - None, - None, ) .unwrap(); @@ -1673,8 +1662,6 @@ mod unit_tests { None, None, None, - None, - None, ) .unwrap(); @@ -1688,8 +1675,6 @@ mod unit_tests { None, None, None, - None, - None, ) .unwrap(); } diff --git a/arch/src/x86_64/smbios.rs b/arch/src/x86_64/smbios.rs index 87c8f00d9..4cef9b5e1 100644 --- a/arch/src/x86_64/smbios.rs +++ b/arch/src/x86_64/smbios.rs @@ -50,6 +50,19 @@ const IS_VIRTUAL_MACHINE: u8 = 1 << 4; pub const DEFAULT_SYSTEM_MANUFACTURER: &str = "Cloud Hypervisor"; pub const DEFAULT_SYSTEM_PRODUCT_NAME: &str = "cloud-hypervisor"; +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct SmbiosConfig { + pub serial_number: Option, + pub uuid: Option, + pub oem_strings: Box<[String]>, +} + +impl SmbiosConfig { + pub fn is_empty(&self) -> bool { + *self == Self::default() + } +} + fn compute_checksum(v: &T) -> u8 { let v: *const T = v; // SAFETY: we are only reading the bytes within the size of the `T` reference `v`. @@ -222,12 +235,10 @@ fn write_type1_system( Ok(()) } -pub fn setup_smbios( - mem: &GuestMemoryMmap, - serial_number: Option<&str>, - uuid: Option<&str>, - oem_strings: &[String], -) -> Result { +pub fn setup_smbios(mem: &GuestMemoryMmap, smbios: Option<&SmbiosConfig>) -> Result { + let serial_number = smbios.and_then(|cfg| cfg.serial_number.as_deref()); + let uuid = smbios.and_then(|cfg| cfg.uuid.as_deref()); + let oem_strings: &[String] = smbios.map_or(&[], |cfg| &cfg.oem_strings); let physptr = GuestAddress(SMBIOS_START) .checked_add(mem::size_of::() as u64) .ok_or(Error::NotEnoughMemory)?; @@ -333,7 +344,7 @@ mod unit_tests { fn entrypoint_checksum() { let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(SMBIOS_START), 4096)]).unwrap(); - setup_smbios(&mem, None, None, &[]).unwrap(); + setup_smbios(&mem, None).unwrap(); let smbios_ep: Smbios30Entrypoint = mem.read_obj(GuestAddress(SMBIOS_START)).unwrap(); diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 75fada61c..f397892a9 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -1855,29 +1855,13 @@ impl Vm { let boot_vcpus = self.cpu_manager.lock().unwrap().boot_vcpus(); - let serial_number = self + let smbios = self .config .lock() .unwrap() .platform .as_ref() - .and_then(|p| p.serial_number.clone()); - - let uuid = self - .config - .lock() - .unwrap() - .platform - .as_ref() - .and_then(|p| p.uuid.clone()); - - let oem_strings = self - .config - .lock() - .unwrap() - .platform - .as_ref() - .and_then(|p| p.oem_strings.clone()); + .and_then(|p| p.smbios_config()); let topology = self.cpu_manager.lock().unwrap().get_vcpu_topology(); @@ -1889,9 +1873,7 @@ impl Vm { boot_vcpus, entry_addr.setup_header, rsdp_addr, - serial_number.as_deref(), - uuid.as_deref(), - oem_strings.as_deref(), + smbios.as_ref(), topology, ) .map_err(Error::ConfigureSystem)?; diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index 745ae0d69..aa2ac6bef 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -149,6 +149,21 @@ pub struct PlatformConfig { pub vfio_p2p_dma: bool, } +#[cfg(target_arch = "x86_64")] +impl PlatformConfig { + /// Returns `None` if no SMBIOS-relevant platform fields are set, otherwise + /// `Some` with a [`SmbiosConfig`] built from the populated fields. + pub fn smbios_config(&self) -> Option { + let smbios = arch::x86_64::SmbiosConfig { + serial_number: self.serial_number.clone(), + uuid: self.uuid.clone(), + oem_strings: self.oem_strings.clone().unwrap_or_default(), + }; + + (!smbios.is_empty()).then_some(smbios) + } +} + pub const DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT: u32 = 1; fn default_pci_segment_aperture_weight() -> u32 {