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
+3 -18
View File
@@ -31,6 +31,7 @@ use linux_loader::loader::elf::start_info::{
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info, hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
}; };
use log::{debug, error, info}; use log::{debug, error, info};
pub use smbios::SmbiosConfig;
use thiserror::Error; use thiserror::Error;
use vm_memory::{ use vm_memory::{
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
@@ -1059,9 +1060,7 @@ pub fn configure_system(
_num_cpus: u32, _num_cpus: u32,
setup_header: Option<setup_header>, setup_header: Option<setup_header>,
rsdp_addr: Option<GuestAddress>, rsdp_addr: Option<GuestAddress>,
serial_number: Option<&str>, smbios: Option<&SmbiosConfig>,
uuid: Option<&str>,
oem_strings: Option<&[String]>,
topology: Option<(u16, u16, u16, u16)>, topology: Option<(u16, u16, u16, u16)>,
) -> super::Result<()> { ) -> super::Result<()> {
// Write EBDA address to location where ACPICA expects to find it // 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) .write_obj((layout::EBDA_START.0 >> 4) as u16, layout::EBDA_POINTER)
.map_err(Error::EbdaSetup)?; .map_err(Error::EbdaSetup)?;
let size = smbios::setup_smbios( let size = smbios::setup_smbios(guest_mem, smbios).map_err(Error::SmbiosSetup)?;
guest_mem,
serial_number,
uuid,
oem_strings.unwrap_or_default(),
)
.map_err(Error::SmbiosSetup)?;
// Place the MP table after the SMIOS table aligned to 16 bytes // Place the MP table after the SMIOS table aligned to 16 bytes
let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size); let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size);
@@ -1620,8 +1613,6 @@ mod unit_tests {
Some(layout::RSDP_POINTER), Some(layout::RSDP_POINTER),
None, None,
None, None,
None,
None,
); );
config_err.unwrap_err(); config_err.unwrap_err();
@@ -1644,8 +1635,6 @@ mod unit_tests {
None, None,
None, None,
None, None,
None,
None,
) )
.unwrap(); .unwrap();
@@ -1673,8 +1662,6 @@ mod unit_tests {
None, None,
None, None,
None, None,
None,
None,
) )
.unwrap(); .unwrap();
@@ -1688,8 +1675,6 @@ mod unit_tests {
None, None,
None, None,
None, None,
None,
None,
) )
.unwrap(); .unwrap();
} }
+18 -7
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_MANUFACTURER: &str = "Cloud Hypervisor";
pub const DEFAULT_SYSTEM_PRODUCT_NAME: &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 { fn compute_checksum<T: Copy>(v: &T) -> u8 {
let v: *const T = v; let v: *const T = v;
// SAFETY: we are only reading the bytes within the size of the `T` reference `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(()) Ok(())
} }
pub fn setup_smbios( pub fn setup_smbios(mem: &GuestMemoryMmap, smbios: Option<&SmbiosConfig>) -> Result<u64> {
mem: &GuestMemoryMmap, let serial_number = smbios.and_then(|cfg| cfg.serial_number.as_deref());
serial_number: Option<&str>, let uuid = smbios.and_then(|cfg| cfg.uuid.as_deref());
uuid: Option<&str>, let oem_strings: &[String] = smbios.map_or(&[], |cfg| &cfg.oem_strings);
oem_strings: &[String],
) -> Result<u64> {
let physptr = GuestAddress(SMBIOS_START) let physptr = GuestAddress(SMBIOS_START)
.checked_add(mem::size_of::<Smbios30Entrypoint>() as u64) .checked_add(mem::size_of::<Smbios30Entrypoint>() as u64)
.ok_or(Error::NotEnoughMemory)?; .ok_or(Error::NotEnoughMemory)?;
@@ -333,7 +344,7 @@ mod unit_tests {
fn entrypoint_checksum() { fn entrypoint_checksum() {
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(SMBIOS_START), 4096)]).unwrap(); 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(); let smbios_ep: Smbios30Entrypoint = mem.read_obj(GuestAddress(SMBIOS_START)).unwrap();
+3 -21
View File
@@ -1855,29 +1855,13 @@ impl Vm {
let boot_vcpus = self.cpu_manager.lock().unwrap().boot_vcpus(); let boot_vcpus = self.cpu_manager.lock().unwrap().boot_vcpus();
let serial_number = self let smbios = self
.config .config
.lock() .lock()
.unwrap() .unwrap()
.platform .platform
.as_ref() .as_ref()
.and_then(|p| p.serial_number.clone()); .and_then(|p| p.smbios_config());
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());
let topology = self.cpu_manager.lock().unwrap().get_vcpu_topology(); let topology = self.cpu_manager.lock().unwrap().get_vcpu_topology();
@@ -1889,9 +1873,7 @@ impl Vm {
boot_vcpus, boot_vcpus,
entry_addr.setup_header, entry_addr.setup_header,
rsdp_addr, rsdp_addr,
serial_number.as_deref(), smbios.as_ref(),
uuid.as_deref(),
oem_strings.as_deref(),
topology, topology,
) )
.map_err(Error::ConfigureSystem)?; .map_err(Error::ConfigureSystem)?;
+15
View File
@@ -149,6 +149,21 @@ pub struct PlatformConfig {
pub vfio_p2p_dma: bool, 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; pub const DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT: u32 = 1;
fn default_pci_segment_aperture_weight() -> u32 { fn default_pci_segment_aperture_weight() -> u32 {