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 <leander.kohler@cyberus-technology.de>
This commit is contained in:
Leander Kohler
2026-02-09 15:34:16 +01:00
committed by Rob Bradford
parent 0141635a5c
commit e097d7d495
4 changed files with 39 additions and 46 deletions

View File

@@ -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<setup_header>,
rsdp_addr: Option<GuestAddress>,
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();
}

View File

@@ -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<String>,
pub uuid: Option<String>,
pub oem_strings: Box<[String]>,
}
impl SmbiosConfig {
pub fn is_empty(&self) -> bool {
*self == Self::default()
}
}
fn compute_checksum<T: Copy>(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<u64> {
pub fn setup_smbios(mem: &GuestMemoryMmap, smbios: Option<&SmbiosConfig>) -> Result<u64> {
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::<Smbios30Entrypoint>() 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();

View File

@@ -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)?;

View File

@@ -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<arch::x86_64::SmbiosConfig> {
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 {