From c92658f355ad9e0bdbbfbf8f04de567a7eff712b Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 5 Sep 2024 07:12:22 +0000 Subject: [PATCH 01/12] move smbios table creation out of propolis-standalone --- bin/propolis-standalone/src/main.rs | 126 ---------------------- lib/propolis/src/firmware/smbios/mod.rs | 132 ++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 126 deletions(-) diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index 1f210b661..7af6dc59c 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -833,132 +833,6 @@ fn populate_rom( Ok(()) } -struct SmbiosParams { - memory_size: usize, - rom_size: usize, - rom_version: String, - num_cpus: u8, - cpuid_ident: Option, - cpuid_procname: Option<[cpuid::Entry; 3]>, -} -fn generate_smbios(params: SmbiosParams) -> anyhow::Result { - use smbios::table::{type0, type1, type16, type4}; - let bios_version = params - .rom_version - .try_into() - .expect("bootrom version string doesn't contain NUL bytes"); - let smb_type0 = smbios::table::Type0 { - vendor: "Oxide".try_into().unwrap(), - bios_version, - bios_release_date: "Bureaucracy 41, 3186 YOLD".try_into().unwrap(), - bios_rom_size: ((params.rom_size / (64 * 1024)) - 1) as u8, - bios_characteristics: type0::BiosCharacteristics::UNSUPPORTED, - bios_ext_characteristics: type0::BiosExtCharacteristics::ACPI - | type0::BiosExtCharacteristics::UEFI - | type0::BiosExtCharacteristics::IS_VM, - ..Default::default() - }; - - let smb_type1 = smbios::table::Type1 { - manufacturer: "Oxide".try_into().unwrap(), - product_name: "OxVM".try_into().unwrap(), - wake_up_type: type1::WakeUpType::PowerSwitch, - ..Default::default() - }; - - let cpuid_vendor = cpuid::host_query(cpuid::Ident(0x0, None)); - let cpuid_ident = params - .cpuid_ident - .unwrap_or_else(|| cpuid::host_query(cpuid::Ident(0x1, None))); - let family = match cpuid_ident.eax & 0xf00 { - // If family ID is 0xf, extended family is added to it - 0xf00 => (cpuid_ident.eax >> 20 & 0xff) + 0xf, - // ... otherwise base family ID is used - base => base >> 8, - }; - - let vendor = cpuid::VendorKind::try_from(cpuid_vendor); - let proc_manufacturer = match vendor { - Ok(cpuid::VendorKind::Intel) => "Intel", - Ok(cpuid::VendorKind::Amd) => "Advanced Micro Devices, Inc.", - _ => "", - } - .try_into() - .unwrap(); - let proc_family = match (vendor, family) { - // Zen - (Ok(cpuid::VendorKind::Amd), family) if family >= 0x17 => 0x6b, - //unknown - _ => 0x2, - }; - let proc_id = u64::from(cpuid_ident.eax) | u64::from(cpuid_ident.edx) << 32; - let procname_entries = params.cpuid_procname.or_else(|| { - if cpuid::host_query(cpuid::Ident(0x8000_0000, None)).eax >= 0x8000_0004 - { - Some([ - cpuid::host_query(cpuid::Ident(0x8000_0002, None)), - cpuid::host_query(cpuid::Ident(0x8000_0003, None)), - cpuid::host_query(cpuid::Ident(0x8000_0004, None)), - ]) - } else { - None - } - }); - let proc_version = procname_entries - .and_then(|e| cpuid::parse_brand_string(e).ok()) - .unwrap_or("".to_string()); - - let smb_type4 = smbios::table::Type4 { - proc_type: type4::ProcType::Central, - proc_family, - proc_manufacturer, - proc_id, - proc_version: proc_version.as_str().try_into().unwrap_or_default(), - status: type4::ProcStatus::Enabled, - // unknown - proc_upgrade: 0x2, - // make core and thread counts equal for now - core_count: params.num_cpus, - core_enabled: params.num_cpus, - thread_count: params.num_cpus, - proc_characteristics: type4::Characteristics::IS_64_BIT - | type4::Characteristics::MULTI_CORE, - ..Default::default() - }; - - let mut smb_type16 = smbios::table::Type16 { - location: type16::Location::SystemBoard, - array_use: type16::ArrayUse::System, - error_correction: type16::ErrorCorrection::Unknown, - num_mem_devices: 1, - ..Default::default() - }; - smb_type16.set_max_capacity(params.memory_size); - let phys_mem_array_handle = 0x1600.into(); - - let mut smb_type17 = smbios::table::Type17 { - phys_mem_array_handle, - // Unknown - form_factor: 0x2, - // Unknown - memory_type: 0x2, - ..Default::default() - }; - smb_type17.set_size(Some(params.memory_size)); - - let smb_type32 = smbios::table::Type32::default(); - - let mut smb_tables = smbios::Tables::new(0x7f00.into()); - smb_tables.add(0x0000.into(), &smb_type0).unwrap(); - smb_tables.add(0x0100.into(), &smb_type1).unwrap(); - smb_tables.add(0x0300.into(), &smb_type4).unwrap(); - smb_tables.add(phys_mem_array_handle, &smb_type16).unwrap(); - smb_tables.add(0x1700.into(), &smb_type17).unwrap(); - smb_tables.add(0x3200.into(), &smb_type32).unwrap(); - - Ok(smb_tables.commit()) -} - fn generate_bootorder(config: &config::Config) -> anyhow::Result { let names = config.main.boot_order.as_ref().unwrap(); diff --git a/lib/propolis/src/firmware/smbios/mod.rs b/lib/propolis/src/firmware/smbios/mod.rs index 0e8047232..8ae5e6673 100644 --- a/lib/propolis/src/firmware/smbios/mod.rs +++ b/lib/propolis/src/firmware/smbios/mod.rs @@ -5,6 +5,7 @@ use std::collections::BTreeMap; use std::fmt; +use crate::cpuid; use table::{Table, Type127}; mod bits; @@ -196,3 +197,134 @@ impl TryFrom for SmbString { #[derive(thiserror::Error, Debug)] #[error("String contains NUL byte")] pub struct SmbStringNulError(); + +pub struct SmbiosParams { + pub memory_size: usize, + pub rom_size: usize, + pub rom_release_date: String, + pub rom_version: String, + pub num_cpus: u8, + pub cpuid_ident: Option, + pub cpuid_procname: Option<[cpuid::Entry; 3]>, +} + +impl SmbiosParams { + pub fn generate_table(&self) -> anyhow::Result { + use table::{type0, type1, type16, type4}; + let bios_version = self + .rom_version + .as_str() + .try_into() + .expect("bootrom version string doesn't contain NUL bytes"); + let smb_type0 = table::Type0 { + vendor: "Oxide".try_into().unwrap(), + bios_version, + bios_release_date: self.rom_release_date.as_str().try_into().unwrap(), // TODO: "Bureaucracy 41, 3186 YOLD".try_into().unwrap(), + bios_rom_size: ((self.rom_size / (64 * 1024)) - 1) as u8, + bios_characteristics: type0::BiosCharacteristics::UNSUPPORTED, + bios_ext_characteristics: type0::BiosExtCharacteristics::ACPI + | type0::BiosExtCharacteristics::UEFI + | type0::BiosExtCharacteristics::IS_VM, + ..Default::default() + }; + + let smb_type1 = table::Type1 { + manufacturer: "Oxide".try_into().unwrap(), + product_name: "OxVM".try_into().unwrap(), + wake_up_type: type1::WakeUpType::PowerSwitch, + ..Default::default() + }; + + let cpuid_vendor = cpuid::host_query(cpuid::Ident(0x0, None)); + let cpuid_ident = self + .cpuid_ident + .unwrap_or_else(|| cpuid::host_query(cpuid::Ident(0x1, None))); + let family = match cpuid_ident.eax & 0xf00 { + // If family ID is 0xf, extended family is added to it + 0xf00 => (cpuid_ident.eax >> 20 & 0xff) + 0xf, + // ... otherwise base family ID is used + base => base >> 8, + }; + + let vendor = cpuid::VendorKind::try_from(cpuid_vendor); + let proc_manufacturer = match vendor { + Ok(cpuid::VendorKind::Intel) => "Intel", + Ok(cpuid::VendorKind::Amd) => "Advanced Micro Devices, Inc.", + _ => "", + } + .try_into() + .unwrap(); + let proc_family = match (vendor, family) { + // Zen + (Ok(cpuid::VendorKind::Amd), family) if family >= 0x17 => 0x6b, + //unknown + _ => 0x2, + }; + let proc_id = u64::from(cpuid_ident.eax) | u64::from(cpuid_ident.edx) << 32; + let procname_entries = self.cpuid_procname.or_else(|| { + if cpuid::host_query(cpuid::Ident(0x8000_0000, None)).eax >= 0x8000_0004 + { + Some([ + cpuid::host_query(cpuid::Ident(0x8000_0002, None)), + cpuid::host_query(cpuid::Ident(0x8000_0003, None)), + cpuid::host_query(cpuid::Ident(0x8000_0004, None)), + ]) + } else { + None + } + }); + let proc_version = procname_entries + .and_then(|e| cpuid::parse_brand_string(e).ok()) + .unwrap_or("".to_string()); + + let smb_type4 = table::Type4 { + proc_type: type4::ProcType::Central, + proc_family, + proc_manufacturer, + proc_id, + proc_version: proc_version.as_str().try_into().unwrap_or_default(), + status: type4::ProcStatus::Enabled, + // unknown + proc_upgrade: 0x2, + // make core and thread counts equal for now + core_count: self.num_cpus, + core_enabled: self.num_cpus, + thread_count: self.num_cpus, + proc_characteristics: type4::Characteristics::IS_64_BIT + | type4::Characteristics::MULTI_CORE, + ..Default::default() + }; + + let mut smb_type16 = table::Type16 { + location: type16::Location::SystemBoard, + array_use: type16::ArrayUse::System, + error_correction: type16::ErrorCorrection::Unknown, + num_mem_devices: 1, + ..Default::default() + }; + smb_type16.set_max_capacity(self.memory_size); + let phys_mem_array_handle = 0x1600.into(); + + let mut smb_type17 = table::Type17 { + phys_mem_array_handle, + // Unknown + form_factor: 0x2, + // Unknown + memory_type: 0x2, + ..Default::default() + }; + smb_type17.set_size(Some(self.memory_size)); + + let smb_type32 = table::Type32::default(); + + let mut smb_tables = Tables::new(0x7f00.into()); + smb_tables.add(0x0000.into(), &smb_type0).unwrap(); + smb_tables.add(0x0100.into(), &smb_type1).unwrap(); + smb_tables.add(0x0300.into(), &smb_type4).unwrap(); + smb_tables.add(phys_mem_array_handle, &smb_type16).unwrap(); + smb_tables.add(0x1700.into(), &smb_type17).unwrap(); + smb_tables.add(0x3200.into(), &smb_type32).unwrap(); + + Ok(smb_tables.commit()) + } +} From 4eef88429da423a1ae11550684df2c5ce7bbbb39 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 5 Sep 2024 07:43:52 +0000 Subject: [PATCH 02/12] cpuid_vendor is a parameter to smbios tables too --- bin/propolis-standalone/src/main.rs | 13 +++++++++---- lib/propolis/src/firmware/smbios/mod.rs | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index 7af6dc59c..314b28166 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1135,6 +1135,7 @@ fn setup_instance( let cpuid_profile = config::parse_cpuid(&config)?; + let cpuid_vendor = cpuid::host_query(cpuid::Ident(0x0, None)); let cpuid_ident = cpuid_profile .as_ref() .and_then(|p| p.get(cpuid::Ident(0x1, None))) @@ -1151,8 +1152,8 @@ fn setup_instance( }); // generate SMBIOS data and expose via fw_cfg - let smbios::TableBytes { entry_point, structure_table } = - generate_smbios(SmbiosParams { + let smbios::TableBytes { entry_point, structure_table } = { + let smbios_params = propolis::firmware::smbios::SmbiosParams { memory_size: memsize, rom_size: rom_len, rom_version: config @@ -1160,11 +1161,15 @@ fn setup_instance( .bootrom_version .clone() .unwrap_or_else(|| "v0.0.1-alpha 1".to_string()), + rom_release_date: "Bureaucracy 41, 3186 YOLD".to_string(), num_cpus: cpus, + cpuid_vendor, cpuid_ident, cpuid_procname, - }) - .unwrap(); + }; + smbios_params.generate_table() + .unwrap() + }; fwcfg .insert_named( "etc/smbios/smbios-tables", diff --git a/lib/propolis/src/firmware/smbios/mod.rs b/lib/propolis/src/firmware/smbios/mod.rs index 8ae5e6673..b19fc188a 100644 --- a/lib/propolis/src/firmware/smbios/mod.rs +++ b/lib/propolis/src/firmware/smbios/mod.rs @@ -204,6 +204,7 @@ pub struct SmbiosParams { pub rom_release_date: String, pub rom_version: String, pub num_cpus: u8, + pub cpuid_vendor: cpuid::Entry, pub cpuid_ident: Option, pub cpuid_procname: Option<[cpuid::Entry; 3]>, } @@ -219,7 +220,7 @@ impl SmbiosParams { let smb_type0 = table::Type0 { vendor: "Oxide".try_into().unwrap(), bios_version, - bios_release_date: self.rom_release_date.as_str().try_into().unwrap(), // TODO: "Bureaucracy 41, 3186 YOLD".try_into().unwrap(), + bios_release_date: self.rom_release_date.as_str().try_into().unwrap(), bios_rom_size: ((self.rom_size / (64 * 1024)) - 1) as u8, bios_characteristics: type0::BiosCharacteristics::UNSUPPORTED, bios_ext_characteristics: type0::BiosExtCharacteristics::ACPI @@ -235,7 +236,6 @@ impl SmbiosParams { ..Default::default() }; - let cpuid_vendor = cpuid::host_query(cpuid::Ident(0x0, None)); let cpuid_ident = self .cpuid_ident .unwrap_or_else(|| cpuid::host_query(cpuid::Ident(0x1, None))); @@ -246,7 +246,7 @@ impl SmbiosParams { base => base >> 8, }; - let vendor = cpuid::VendorKind::try_from(cpuid_vendor); + let vendor = cpuid::VendorKind::try_from(self.cpuid_vendor); let proc_manufacturer = match vendor { Ok(cpuid::VendorKind::Intel) => "Intel", Ok(cpuid::VendorKind::Amd) => "Advanced Micro Devices, Inc.", From adab4ef0e1d57f58d7481d1c53b812fb180022d8 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 5 Sep 2024 07:45:59 +0000 Subject: [PATCH 03/12] start adjusting propolis-server smbios code to match propolis --- bin/propolis-server/src/lib/initializer.rs | 67 ++++++++++++++-------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index 6f5ac4209..1d7e6a60d 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -930,25 +930,53 @@ impl<'a> MachineInitializer<'a> { } fn generate_smbios(&self) -> smbios::TableBytes { - use propolis::cpuid; - use smbios::table::{type0, type1, type16, type4}; + let memsize_bytes = (self.properties.memory as usize) * MB; + let memory_size = memsize_bytes; let rom_size = self.state.rom_size_bytes.expect("ROM is already populated"); - let bios_version = self + + let rom_version: String = self .toml_config .bootrom_version .as_deref() .unwrap_or("v0.8") - .try_into() - .expect("bootrom version string doesn't contain NUL bytes"); + .to_string(); + + let rom_release_date: String = "The Aftermath 30, 3185 YOLD".to_string(); + + let num_cpus = self.properties.vcpus; + + use propolis::cpuid; + + // Once CPUID profiles are integrated, these will need to take that into + // account, rather than blindly querying from the host + let cpuid_vendor = cpuid::host_query(cpuid::Ident(0x0, None)); + let cpuid_ident = cpuid::host_query(cpuid::Ident(0x1, None)); + let cpuid_procname = [ + cpuid::host_query(cpuid::Ident(0x8000_0002, None)), + cpuid::host_query(cpuid::Ident(0x8000_0003, None)), + cpuid::host_query(cpuid::Ident(0x8000_0004, None)), + ]; + + let smbios_params = SmbiosParams { + memory_size, + rom_size, + rom_release_date, + rom_version, + num_cpus, + cpuid_vendor, + cpuid_ident, + cpuid_procname, + } + + use smbios::table::{type0, type1, type16, type4}; + let smb_type0 = smbios::table::Type0 { vendor: "Oxide".try_into().unwrap(), bios_version, - bios_release_date: "The Aftermath 30, 3185 YOLD" - .try_into() - .unwrap(), - bios_rom_size: ((rom_size / (64 * 1024)) - 1) as u8, + bios_release_date: smbios_params.rom_release_date.as_str().try_into().unwrap(), + bios_rom_size: ((smbios_params.rom_size / (64 * 1024)) - 1) as u8, bios_characteristics: type0::BiosCharacteristics::UNSUPPORTED, bios_ext_characteristics: type0::BiosExtCharacteristics::ACPI | type0::BiosExtCharacteristics::UEFI @@ -972,16 +1000,6 @@ impl<'a> MachineInitializer<'a> { ..Default::default() }; - // Once CPUID profiles are integrated, these will need to take that into - // account, rather than blindly querying from the host - let cpuid_vendor = cpuid::host_query(cpuid::Ident(0x0, None)); - let cpuid_ident = cpuid::host_query(cpuid::Ident(0x1, None)); - let cpuid_procname = [ - cpuid::host_query(cpuid::Ident(0x8000_0002, None)), - cpuid::host_query(cpuid::Ident(0x8000_0003, None)), - cpuid::host_query(cpuid::Ident(0x8000_0004, None)), - ]; - let family = match cpuid_ident.eax & 0xf00 { // If family ID is 0xf, extended family is added to it 0xf00 => (cpuid_ident.eax >> 20 & 0xff) + 0xf, @@ -1022,15 +1040,14 @@ impl<'a> MachineInitializer<'a> { // unknown proc_upgrade: 0x2, // make core and thread counts equal for now - core_count: self.properties.vcpus, - core_enabled: self.properties.vcpus, - thread_count: self.properties.vcpus, + core_count: smbios_params.num_cpus, + core_enabled: smbios_params.num_cpus, + thread_count: smbios_params.num_cpus, proc_characteristics: type4::Characteristics::IS_64_BIT | type4::Characteristics::MULTI_CORE, ..Default::default() }; - let memsize_bytes = (self.properties.memory as usize) * MB; let mut smb_type16 = smbios::table::Type16 { location: type16::Location::SystemBoard, array_use: type16::ArrayUse::System, @@ -1038,7 +1055,7 @@ impl<'a> MachineInitializer<'a> { num_mem_devices: 1, ..Default::default() }; - smb_type16.set_max_capacity(memsize_bytes); + smb_type16.set_max_capacity(self.memory_size); let phys_mem_array_handle = 0x1600.into(); let mut smb_type17 = smbios::table::Type17 { @@ -1049,7 +1066,7 @@ impl<'a> MachineInitializer<'a> { memory_type: 0x2, ..Default::default() }; - smb_type17.set_size(Some(memsize_bytes)); + smb_type17.set_size(Some(self.memory_size)); let smb_type32 = smbios::table::Type32::default(); From 45261391a2d466bdd51198f791d31c1957aefb43 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 5 Sep 2024 08:36:41 +0000 Subject: [PATCH 04/12] hadn't been checking propolis-server compiles cpuid_ident is non-optional, any defaulting happens in applications --- bin/propolis-server/src/lib/initializer.rs | 27 ++++++++++++---------- bin/propolis-standalone/src/main.rs | 3 +++ lib/propolis/src/firmware/smbios/mod.rs | 16 +++++++------ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index 1d7e6a60d..2ae706858 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -959,7 +959,9 @@ impl<'a> MachineInitializer<'a> { cpuid::host_query(cpuid::Ident(0x8000_0004, None)), ]; - let smbios_params = SmbiosParams { + let system_id: uuid::Uuid = self.properties.id; + + let smbios_params = propolis::firmware::smbios::SmbiosParams { memory_size, rom_size, rom_release_date, @@ -967,11 +969,17 @@ impl<'a> MachineInitializer<'a> { num_cpus, cpuid_vendor, cpuid_ident, - cpuid_procname, - } + cpuid_procname: Some(cpuid_procname), + system_id, + }; use smbios::table::{type0, type1, type16, type4}; + let bios_version = smbios_params + .rom_version + .as_str() + .try_into() + .expect("bootrom version string doesn't contain NUL bytes"); let smb_type0 = smbios::table::Type0 { vendor: "Oxide".try_into().unwrap(), bios_version, @@ -988,13 +996,8 @@ impl<'a> MachineInitializer<'a> { manufacturer: "Oxide".try_into().unwrap(), product_name: "OxVM".try_into().unwrap(), - serial_number: self - .properties - .id - .to_string() - .try_into() - .unwrap_or_default(), - uuid: self.properties.id.to_bytes_le(), + serial_number: smbios_params.system_id.to_string().try_into().unwrap_or_default(), + uuid: smbios_params.system_id.to_bytes_le(), wake_up_type: type1::WakeUpType::PowerSwitch, ..Default::default() @@ -1055,7 +1058,7 @@ impl<'a> MachineInitializer<'a> { num_mem_devices: 1, ..Default::default() }; - smb_type16.set_max_capacity(self.memory_size); + smb_type16.set_max_capacity(smbios_params.memory_size); let phys_mem_array_handle = 0x1600.into(); let mut smb_type17 = smbios::table::Type17 { @@ -1066,7 +1069,7 @@ impl<'a> MachineInitializer<'a> { memory_type: 0x2, ..Default::default() }; - smb_type17.set_size(Some(self.memory_size)); + smb_type17.set_size(Some(smbios_params.memory_size)); let smb_type32 = smbios::table::Type32::default(); diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index 314b28166..c0dc05097 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1153,6 +1153,8 @@ fn setup_instance( // generate SMBIOS data and expose via fw_cfg let smbios::TableBytes { entry_point, structure_table } = { + let cpuid_ident = cpuid_ident + .unwrap_or_else(|| cpuid::host_query(cpuid::Ident(0x1, None))); let smbios_params = propolis::firmware::smbios::SmbiosParams { memory_size: memsize, rom_size: rom_len, @@ -1166,6 +1168,7 @@ fn setup_instance( cpuid_vendor, cpuid_ident, cpuid_procname, + system_id: uuid::Uuid::default(), }; smbios_params.generate_table() .unwrap() diff --git a/lib/propolis/src/firmware/smbios/mod.rs b/lib/propolis/src/firmware/smbios/mod.rs index b19fc188a..80cc7b637 100644 --- a/lib/propolis/src/firmware/smbios/mod.rs +++ b/lib/propolis/src/firmware/smbios/mod.rs @@ -205,8 +205,9 @@ pub struct SmbiosParams { pub rom_version: String, pub num_cpus: u8, pub cpuid_vendor: cpuid::Entry, - pub cpuid_ident: Option, + pub cpuid_ident: cpuid::Entry, pub cpuid_procname: Option<[cpuid::Entry; 3]>, + pub system_id: uuid::Uuid, } impl SmbiosParams { @@ -232,16 +233,17 @@ impl SmbiosParams { let smb_type1 = table::Type1 { manufacturer: "Oxide".try_into().unwrap(), product_name: "OxVM".try_into().unwrap(), + + serial_number: self.system_id.to_string().try_into().unwrap_or_default(), + uuid: self.system_id.to_bytes_le(), + wake_up_type: type1::WakeUpType::PowerSwitch, ..Default::default() }; - let cpuid_ident = self - .cpuid_ident - .unwrap_or_else(|| cpuid::host_query(cpuid::Ident(0x1, None))); - let family = match cpuid_ident.eax & 0xf00 { + let family = match self.cpuid_ident.eax & 0xf00 { // If family ID is 0xf, extended family is added to it - 0xf00 => (cpuid_ident.eax >> 20 & 0xff) + 0xf, + 0xf00 => (self.cpuid_ident.eax >> 20 & 0xff) + 0xf, // ... otherwise base family ID is used base => base >> 8, }; @@ -260,7 +262,7 @@ impl SmbiosParams { //unknown _ => 0x2, }; - let proc_id = u64::from(cpuid_ident.eax) | u64::from(cpuid_ident.edx) << 32; + let proc_id = u64::from(self.cpuid_ident.eax) | u64::from(self.cpuid_ident.edx) << 32; let procname_entries = self.cpuid_procname.or_else(|| { if cpuid::host_query(cpuid::Ident(0x8000_0000, None)).eax >= 0x8000_0004 { From df6ae6ba920a22f5fbf812383868d00babf0a7f5 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 5 Sep 2024 08:44:14 +0000 Subject: [PATCH 05/12] read cpuid_ident from smbios_params --- bin/propolis-server/src/lib/initializer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index 2ae706858..90e111ee8 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -1003,9 +1003,9 @@ impl<'a> MachineInitializer<'a> { ..Default::default() }; - let family = match cpuid_ident.eax & 0xf00 { + let family = match smbios_params.cpuid_ident.eax & 0xf00 { // If family ID is 0xf, extended family is added to it - 0xf00 => (cpuid_ident.eax >> 20 & 0xff) + 0xf, + 0xf00 => (smbios_params.cpuid_ident.eax >> 20 & 0xff) + 0xf, // ... otherwise base family ID is used base => base >> 8, }; @@ -1029,7 +1029,7 @@ impl<'a> MachineInitializer<'a> { _ => 0x2, }; let proc_id = - u64::from(cpuid_ident.eax) | u64::from(cpuid_ident.edx) << 32; + u64::from(smbios_params.cpuid_ident.eax) | u64::from(smbios_params.cpuid_ident.edx) << 32; let proc_version = cpuid::parse_brand_string(cpuid_procname).unwrap_or("".to_string()); From 571ad41a8d3bc911b73221081b273dfe278e794e Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 5 Sep 2024 15:12:04 +0000 Subject: [PATCH 06/12] deoption cpuid_procname, copy a comment to make smbios tables *really* identical --- bin/propolis-server/src/lib/initializer.rs | 2 +- bin/propolis-standalone/src/main.rs | 16 ++++++++++++++ lib/propolis/src/firmware/smbios/mod.rs | 25 ++++++++-------------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index 90e111ee8..dbc5c9d6e 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -969,7 +969,7 @@ impl<'a> MachineInitializer<'a> { num_cpus, cpuid_vendor, cpuid_ident, - cpuid_procname: Some(cpuid_procname), + cpuid_procname, system_id, }; diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index c0dc05097..117eca665 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1155,6 +1155,22 @@ fn setup_instance( let smbios::TableBytes { entry_point, structure_table } = { let cpuid_ident = cpuid_ident .unwrap_or_else(|| cpuid::host_query(cpuid::Ident(0x1, None))); + let cpuid_procname = cpuid_procname.unwrap_or_else(|| { + if cpuid::host_query(cpuid::Ident(0x8000_0000, None)).eax >= 0x8000_0004 + { + [ + cpuid::host_query(cpuid::Ident(0x8000_0002, None)), + cpuid::host_query(cpuid::Ident(0x8000_0003, None)), + cpuid::host_query(cpuid::Ident(0x8000_0004, None)), + ] + } else { + [ + cpuid::Entry::zero(), + cpuid::Entry::zero(), + cpuid::Entry::zero(), + ] + } + }); let smbios_params = propolis::firmware::smbios::SmbiosParams { memory_size: memsize, rom_size: rom_len, diff --git a/lib/propolis/src/firmware/smbios/mod.rs b/lib/propolis/src/firmware/smbios/mod.rs index 80cc7b637..f8bafd9e5 100644 --- a/lib/propolis/src/firmware/smbios/mod.rs +++ b/lib/propolis/src/firmware/smbios/mod.rs @@ -206,7 +206,7 @@ pub struct SmbiosParams { pub num_cpus: u8, pub cpuid_vendor: cpuid::Entry, pub cpuid_ident: cpuid::Entry, - pub cpuid_procname: Option<[cpuid::Entry; 3]>, + pub cpuid_procname: [cpuid::Entry; 3], pub system_id: uuid::Uuid, } @@ -263,21 +263,9 @@ impl SmbiosParams { _ => 0x2, }; let proc_id = u64::from(self.cpuid_ident.eax) | u64::from(self.cpuid_ident.edx) << 32; - let procname_entries = self.cpuid_procname.or_else(|| { - if cpuid::host_query(cpuid::Ident(0x8000_0000, None)).eax >= 0x8000_0004 - { - Some([ - cpuid::host_query(cpuid::Ident(0x8000_0002, None)), - cpuid::host_query(cpuid::Ident(0x8000_0003, None)), - cpuid::host_query(cpuid::Ident(0x8000_0004, None)), - ]) - } else { - None - } - }); - let proc_version = procname_entries - .and_then(|e| cpuid::parse_brand_string(e).ok()) - .unwrap_or("".to_string()); + // TODO(ixi): do not ignore the error here + let proc_version = cpuid::parse_brand_string(self.cpuid_procname) + .unwrap_or_else(|_| "".to_string()); let smb_type4 = table::Type4 { proc_type: type4::ProcType::Central, @@ -319,6 +307,11 @@ impl SmbiosParams { let smb_type32 = table::Type32::default(); + // With "only" types 0, 1, 4, 16, 17, and 32, we are technically missing + // some (types 3, 7, 9, 19) of the data required by the 2.7 spec. The + // data provided here were what we determined was a reasonable + // collection to start with. Should further requirements arise, we may + // expand on it. let mut smb_tables = Tables::new(0x7f00.into()); smb_tables.add(0x0000.into(), &smb_type0).unwrap(); smb_tables.add(0x0100.into(), &smb_type1).unwrap(); From b5e5d02b824ad748b8a4fc03b84948221153f9d1 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 5 Sep 2024 15:17:22 +0000 Subject: [PATCH 07/12] one fewer smbios table implementations --- bin/propolis-server/src/lib/initializer.rs | 116 +-------------------- lib/propolis/src/firmware/smbios/mod.rs | 8 +- 2 files changed, 8 insertions(+), 116 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index dbc5c9d6e..361f576cf 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -973,120 +973,8 @@ impl<'a> MachineInitializer<'a> { system_id, }; - use smbios::table::{type0, type1, type16, type4}; - - let bios_version = smbios_params - .rom_version - .as_str() - .try_into() - .expect("bootrom version string doesn't contain NUL bytes"); - let smb_type0 = smbios::table::Type0 { - vendor: "Oxide".try_into().unwrap(), - bios_version, - bios_release_date: smbios_params.rom_release_date.as_str().try_into().unwrap(), - bios_rom_size: ((smbios_params.rom_size / (64 * 1024)) - 1) as u8, - bios_characteristics: type0::BiosCharacteristics::UNSUPPORTED, - bios_ext_characteristics: type0::BiosExtCharacteristics::ACPI - | type0::BiosExtCharacteristics::UEFI - | type0::BiosExtCharacteristics::IS_VM, - ..Default::default() - }; - - let smb_type1 = smbios::table::Type1 { - manufacturer: "Oxide".try_into().unwrap(), - product_name: "OxVM".try_into().unwrap(), - - serial_number: smbios_params.system_id.to_string().try_into().unwrap_or_default(), - uuid: smbios_params.system_id.to_bytes_le(), - - wake_up_type: type1::WakeUpType::PowerSwitch, - ..Default::default() - }; - - let family = match smbios_params.cpuid_ident.eax & 0xf00 { - // If family ID is 0xf, extended family is added to it - 0xf00 => (smbios_params.cpuid_ident.eax >> 20 & 0xff) + 0xf, - // ... otherwise base family ID is used - base => base >> 8, - }; - - let vendor = cpuid::VendorKind::try_from(cpuid_vendor); - let proc_manufacturer = match vendor { - Ok(cpuid::VendorKind::Intel) => "Intel", - Ok(cpuid::VendorKind::Amd) => "Advanced Micro Devices, Inc.", - _ => "", - } - .try_into() - .unwrap(); - let proc_family = match (vendor, family) { - // Explicitly match for Zen-based CPUs - // - // Although this family identifier is not valid in SMBIOS 2.7, - // having been defined in 3.x, we pass it through anyways. - (Ok(cpuid::VendorKind::Amd), family) if family >= 0x17 => 0x6b, - - // Emit Unknown for everything else - _ => 0x2, - }; - let proc_id = - u64::from(smbios_params.cpuid_ident.eax) | u64::from(smbios_params.cpuid_ident.edx) << 32; - let proc_version = - cpuid::parse_brand_string(cpuid_procname).unwrap_or("".to_string()); - - let smb_type4 = smbios::table::Type4 { - proc_type: type4::ProcType::Central, - proc_family, - proc_manufacturer, - proc_id, - proc_version: proc_version.try_into().unwrap_or_default(), - status: type4::ProcStatus::Enabled, - // unknown - proc_upgrade: 0x2, - // make core and thread counts equal for now - core_count: smbios_params.num_cpus, - core_enabled: smbios_params.num_cpus, - thread_count: smbios_params.num_cpus, - proc_characteristics: type4::Characteristics::IS_64_BIT - | type4::Characteristics::MULTI_CORE, - ..Default::default() - }; - - let mut smb_type16 = smbios::table::Type16 { - location: type16::Location::SystemBoard, - array_use: type16::ArrayUse::System, - error_correction: type16::ErrorCorrection::Unknown, - num_mem_devices: 1, - ..Default::default() - }; - smb_type16.set_max_capacity(smbios_params.memory_size); - let phys_mem_array_handle = 0x1600.into(); - - let mut smb_type17 = smbios::table::Type17 { - phys_mem_array_handle, - // Unknown - form_factor: 0x2, - // Unknown - memory_type: 0x2, - ..Default::default() - }; - smb_type17.set_size(Some(smbios_params.memory_size)); - - let smb_type32 = smbios::table::Type32::default(); - - // With "only" types 0, 1, 4, 16, 17, and 32, we are technically missing - // some (types 3, 7, 9, 19) of the data required by the 2.7 spec. The - // data provided here were what we determined was a reasonable - // collection to start with. Should further requirements arise, we may - // expand on it. - let mut smb_tables = smbios::Tables::new(0x7f00.into()); - smb_tables.add(0x0000.into(), &smb_type0).unwrap(); - smb_tables.add(0x0100.into(), &smb_type1).unwrap(); - smb_tables.add(0x0300.into(), &smb_type4).unwrap(); - smb_tables.add(phys_mem_array_handle, &smb_type16).unwrap(); - smb_tables.add(0x1700.into(), &smb_type17).unwrap(); - smb_tables.add(0x3200.into(), &smb_type32).unwrap(); - - smb_tables.commit() + smbios_params.generate_table() + .expect("can generate smbios tables") } /// Initialize qemu `fw_cfg` device, and populate it with data including CPU diff --git a/lib/propolis/src/firmware/smbios/mod.rs b/lib/propolis/src/firmware/smbios/mod.rs index f8bafd9e5..578d25f07 100644 --- a/lib/propolis/src/firmware/smbios/mod.rs +++ b/lib/propolis/src/firmware/smbios/mod.rs @@ -257,9 +257,13 @@ impl SmbiosParams { .try_into() .unwrap(); let proc_family = match (vendor, family) { - // Zen + // Explicitly match for Zen-based CPUs + // + // Although this family identifier is not valid in SMBIOS 2.7, + // having been defined in 3.x, we pass it through anyways. (Ok(cpuid::VendorKind::Amd), family) if family >= 0x17 => 0x6b, - //unknown + + // Emit Unknown for everything else _ => 0x2, }; let proc_id = u64::from(self.cpuid_ident.eax) | u64::from(self.cpuid_ident.edx) << 32; From acb6da12e4e68b8793879a89bd91d786ae715b31 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 5 Sep 2024 15:29:27 +0000 Subject: [PATCH 08/12] a bit of cleanup for propolis-server SmbiosPAram init --- bin/propolis-server/src/lib/initializer.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index 361f576cf..1727da0e7 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -930,9 +930,6 @@ impl<'a> MachineInitializer<'a> { } fn generate_smbios(&self) -> smbios::TableBytes { - let memsize_bytes = (self.properties.memory as usize) * MB; - let memory_size = memsize_bytes; - let rom_size = self.state.rom_size_bytes.expect("ROM is already populated"); @@ -943,10 +940,6 @@ impl<'a> MachineInitializer<'a> { .unwrap_or("v0.8") .to_string(); - let rom_release_date: String = "The Aftermath 30, 3185 YOLD".to_string(); - - let num_cpus = self.properties.vcpus; - use propolis::cpuid; // Once CPUID profiles are integrated, these will need to take that into @@ -959,18 +952,16 @@ impl<'a> MachineInitializer<'a> { cpuid::host_query(cpuid::Ident(0x8000_0004, None)), ]; - let system_id: uuid::Uuid = self.properties.id; - let smbios_params = propolis::firmware::smbios::SmbiosParams { - memory_size, + memory_size: (self.properties.memory as usize) * MB, rom_size, - rom_release_date, + rom_release_date: "The Aftermath 30, 3185 YOLD".to_string(), rom_version, - num_cpus, + num_cpus: self.properties.vcpus, cpuid_vendor, cpuid_ident, cpuid_procname, - system_id, + system_id: self.properties.id, }; smbios_params.generate_table() From 2b8d1fdc188812f724dce9cf2034e73edb936e53 Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 6 Sep 2024 00:09:21 +0000 Subject: [PATCH 09/12] bonus: take rom_size explicitly not really sure how i feel about this, but it seems interesting this is the only state in MachineInitializerState right now.. --- bin/propolis-server/src/lib/initializer.rs | 21 +++++---------------- bin/propolis-server/src/lib/vm/ensure.rs | 7 +++---- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index 1727da0e7..3541bdf87 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -107,11 +107,6 @@ struct StorageBackendInstance { crucible: Option<(uuid::Uuid, Arc)>, } -#[derive(Default)] -pub struct MachineInitializerState { - rom_size_bytes: Option, -} - pub struct MachineInitializer<'a> { pub(crate) log: slog::Logger, pub(crate) machine: &'a Machine, @@ -122,7 +117,6 @@ pub struct MachineInitializer<'a> { pub(crate) properties: &'a InstanceProperties, pub(crate) toml_config: &'a crate::server::VmTomlConfig, pub(crate) producer_registry: Option, - pub(crate) state: MachineInitializerState, pub(crate) kstat_sampler: Option, } @@ -130,7 +124,7 @@ impl<'a> MachineInitializer<'a> { pub fn initialize_rom( &mut self, path: &std::path::Path, - ) -> Result<(), Error> { + ) -> Result { fn open_bootrom(path: &std::path::Path) -> Result<(File, usize)> { let fp = File::open(path)?; let len = fp.metadata()?.len(); @@ -162,8 +156,7 @@ impl<'a> MachineInitializer<'a> { // TODO: Handle short read return Err(Error::new(ErrorKind::InvalidData, "short read")); } - self.state.rom_size_bytes = Some(rom_len); - Ok(()) + Ok(rom_len) } pub fn initialize_rtc( @@ -929,10 +922,7 @@ impl<'a> MachineInitializer<'a> { Ok(()) } - fn generate_smbios(&self) -> smbios::TableBytes { - let rom_size = - self.state.rom_size_bytes.expect("ROM is already populated"); - + fn generate_smbios(&self, rom_size: usize) -> smbios::TableBytes { let rom_version: String = self .toml_config .bootrom_version @@ -970,11 +960,10 @@ impl<'a> MachineInitializer<'a> { /// Initialize qemu `fw_cfg` device, and populate it with data including CPU /// count, SMBIOS tables, and attached RAM-FB device. - /// - /// Should not be called before [`Self::initialize_rom()`]. pub fn initialize_fwcfg( &mut self, cpus: u8, + rom_size: usize, ) -> Result, Error> { let fwcfg = fwcfg::FwCfg::new(); fwcfg @@ -985,7 +974,7 @@ impl<'a> MachineInitializer<'a> { .unwrap(); let smbios::TableBytes { entry_point, structure_table } = - self.generate_smbios(); + self.generate_smbios(rom_size); fwcfg .insert_named( "etc/smbios/smbios-tables", diff --git a/bin/propolis-server/src/lib/vm/ensure.rs b/bin/propolis-server/src/lib/vm/ensure.rs index 65c97fd14..dd30ebbe6 100644 --- a/bin/propolis-server/src/lib/vm/ensure.rs +++ b/bin/propolis-server/src/lib/vm/ensure.rs @@ -38,7 +38,7 @@ use slog::{debug, info}; use crate::{ initializer::{ - build_instance, MachineInitializer, MachineInitializerState, + build_instance, MachineInitializer, }, stats::create_kstat_sampler, vm::request_queue::InstanceAutoStart, @@ -180,7 +180,6 @@ impl<'a> VmEnsureNotStarted<'a> { properties, toml_config: &options.toml_config, producer_registry: options.oximeter_registry.clone(), - state: MachineInitializerState::default(), kstat_sampler: initialize_kstat_sampler( self.log, properties, @@ -189,7 +188,7 @@ impl<'a> VmEnsureNotStarted<'a> { ), }; - init.initialize_rom(options.toml_config.bootrom.as_path())?; + let rom_size = init.initialize_rom(options.toml_config.bootrom.as_path())?; let chipset = init.initialize_chipset( &(event_queue.clone() as Arc), @@ -221,7 +220,7 @@ impl<'a> VmEnsureNotStarted<'a> { init.initialize_storage_devices(&chipset, options.nexus_client.clone()) .await?; - let ramfb = init.initialize_fwcfg(v0_spec.devices.board.cpus)?; + let ramfb = init.initialize_fwcfg(v0_spec.devices.board.cpus, rom_size)?; init.initialize_cpus().await?; From 105ef30bba65c92d4a744e4c6d8b2c1c1b8b32b9 Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 6 Sep 2024 00:09:36 +0000 Subject: [PATCH 10/12] rustfmt --- bin/propolis-server/src/lib/initializer.rs | 3 +-- bin/propolis-server/src/lib/vm/ensure.rs | 10 +++++----- bin/propolis-standalone/src/main.rs | 6 +++--- lib/propolis/src/firmware/smbios/mod.rs | 15 ++++++++++++--- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index 3541bdf87..52d331e21 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -954,8 +954,7 @@ impl<'a> MachineInitializer<'a> { system_id: self.properties.id, }; - smbios_params.generate_table() - .expect("can generate smbios tables") + smbios_params.generate_table().expect("can generate smbios tables") } /// Initialize qemu `fw_cfg` device, and populate it with data including CPU diff --git a/bin/propolis-server/src/lib/vm/ensure.rs b/bin/propolis-server/src/lib/vm/ensure.rs index dd30ebbe6..95c24564e 100644 --- a/bin/propolis-server/src/lib/vm/ensure.rs +++ b/bin/propolis-server/src/lib/vm/ensure.rs @@ -37,9 +37,7 @@ use propolis_api_types::{ use slog::{debug, info}; use crate::{ - initializer::{ - build_instance, MachineInitializer, - }, + initializer::{build_instance, MachineInitializer}, stats::create_kstat_sampler, vm::request_queue::InstanceAutoStart, }; @@ -188,7 +186,8 @@ impl<'a> VmEnsureNotStarted<'a> { ), }; - let rom_size = init.initialize_rom(options.toml_config.bootrom.as_path())?; + let rom_size = + init.initialize_rom(options.toml_config.bootrom.as_path())?; let chipset = init.initialize_chipset( &(event_queue.clone() as Arc), @@ -220,7 +219,8 @@ impl<'a> VmEnsureNotStarted<'a> { init.initialize_storage_devices(&chipset, options.nexus_client.clone()) .await?; - let ramfb = init.initialize_fwcfg(v0_spec.devices.board.cpus, rom_size)?; + let ramfb = + init.initialize_fwcfg(v0_spec.devices.board.cpus, rom_size)?; init.initialize_cpus().await?; diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index 117eca665..b2bcea98a 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1156,7 +1156,8 @@ fn setup_instance( let cpuid_ident = cpuid_ident .unwrap_or_else(|| cpuid::host_query(cpuid::Ident(0x1, None))); let cpuid_procname = cpuid_procname.unwrap_or_else(|| { - if cpuid::host_query(cpuid::Ident(0x8000_0000, None)).eax >= 0x8000_0004 + if cpuid::host_query(cpuid::Ident(0x8000_0000, None)).eax + >= 0x8000_0004 { [ cpuid::host_query(cpuid::Ident(0x8000_0002, None)), @@ -1186,8 +1187,7 @@ fn setup_instance( cpuid_procname, system_id: uuid::Uuid::default(), }; - smbios_params.generate_table() - .unwrap() + smbios_params.generate_table().unwrap() }; fwcfg .insert_named( diff --git a/lib/propolis/src/firmware/smbios/mod.rs b/lib/propolis/src/firmware/smbios/mod.rs index 578d25f07..1703b3bca 100644 --- a/lib/propolis/src/firmware/smbios/mod.rs +++ b/lib/propolis/src/firmware/smbios/mod.rs @@ -221,7 +221,11 @@ impl SmbiosParams { let smb_type0 = table::Type0 { vendor: "Oxide".try_into().unwrap(), bios_version, - bios_release_date: self.rom_release_date.as_str().try_into().unwrap(), + bios_release_date: self + .rom_release_date + .as_str() + .try_into() + .unwrap(), bios_rom_size: ((self.rom_size / (64 * 1024)) - 1) as u8, bios_characteristics: type0::BiosCharacteristics::UNSUPPORTED, bios_ext_characteristics: type0::BiosExtCharacteristics::ACPI @@ -234,7 +238,11 @@ impl SmbiosParams { manufacturer: "Oxide".try_into().unwrap(), product_name: "OxVM".try_into().unwrap(), - serial_number: self.system_id.to_string().try_into().unwrap_or_default(), + serial_number: self + .system_id + .to_string() + .try_into() + .unwrap_or_default(), uuid: self.system_id.to_bytes_le(), wake_up_type: type1::WakeUpType::PowerSwitch, @@ -266,7 +274,8 @@ impl SmbiosParams { // Emit Unknown for everything else _ => 0x2, }; - let proc_id = u64::from(self.cpuid_ident.eax) | u64::from(self.cpuid_ident.edx) << 32; + let proc_id = u64::from(self.cpuid_ident.eax) + | u64::from(self.cpuid_ident.edx) << 32; // TODO(ixi): do not ignore the error here let proc_version = cpuid::parse_brand_string(self.cpuid_procname) .unwrap_or_else(|_| "".to_string()); From b6c1b3bceaf6660e079c5a3cee25c2014e07a0b9 Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 6 Sep 2024 14:52:35 +0000 Subject: [PATCH 11/12] leave top-level smbios table construction to applications --- bin/propolis-server/src/lib/initializer.rs | 18 ++++++- bin/propolis-standalone/src/main.rs | 24 +++++++++- lib/propolis/src/firmware/smbios/mod.rs | 56 ++++++++++++---------- 3 files changed, 71 insertions(+), 27 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index 52d331e21..b7d855d2a 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -954,7 +954,23 @@ impl<'a> MachineInitializer<'a> { system_id: self.properties.id, }; - smbios_params.generate_table().expect("can generate smbios tables") + let mut smb_tables = smbios::Tables::new(0x7f00.into()); + smb_tables.add(0x0000.into(), &smbios_params.table_type0()).unwrap(); + smb_tables.add(0x0100.into(), &smbios_params.table_type1()).unwrap(); + smb_tables.add(0x0300.into(), &smbios_params.table_type4()).unwrap(); + let phys_mem_array_handle = 0x1600.into(); + smb_tables + .add(phys_mem_array_handle, &smbios_params.table_type16()) + .unwrap(); + smb_tables + .add( + 0x1700.into(), + &smbios_params.table_type17(phys_mem_array_handle), + ) + .unwrap(); + smb_tables.add(0x3200.into(), &smbios_params.table_type32()).unwrap(); + + smb_tables.commit() } /// Initialize qemu `fw_cfg` device, and populate it with data including CPU diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index b2bcea98a..8ca66cad4 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1187,7 +1187,29 @@ fn setup_instance( cpuid_procname, system_id: uuid::Uuid::default(), }; - smbios_params.generate_table().unwrap() + + // With "only" types 0, 1, 4, 16, 17, and 32, we are technically missing + // some (types 3, 7, 9, 19) of the data required by the 2.7 spec. The + // data provided here were what we determined was a reasonable + // collection to start with. Should further requirements arise, we may + // expand on it. + let mut smb_tables = smbios::Tables::new(0x7f00.into()); + smb_tables.add(0x0000.into(), &smbios_params.table_type0()).unwrap(); + smb_tables.add(0x0100.into(), &smbios_params.table_type1()).unwrap(); + smb_tables.add(0x0300.into(), &smbios_params.table_type4()).unwrap(); + let phys_mem_array_handle = 0x1600.into(); + smb_tables + .add(phys_mem_array_handle, &smbios_params.table_type16()) + .unwrap(); + smb_tables + .add( + 0x1700.into(), + &smbios_params.table_type17(phys_mem_array_handle), + ) + .unwrap(); + smb_tables.add(0x3200.into(), &smbios_params.table_type32()).unwrap(); + + smb_tables.commit() }; fwcfg .insert_named( diff --git a/lib/propolis/src/firmware/smbios/mod.rs b/lib/propolis/src/firmware/smbios/mod.rs index 1703b3bca..226ac9a69 100644 --- a/lib/propolis/src/firmware/smbios/mod.rs +++ b/lib/propolis/src/firmware/smbios/mod.rs @@ -211,14 +211,15 @@ pub struct SmbiosParams { } impl SmbiosParams { - pub fn generate_table(&self) -> anyhow::Result { - use table::{type0, type1, type16, type4}; + pub fn table_type0(&self) -> table::Type0 { + use table::type0; + let bios_version = self .rom_version .as_str() .try_into() .expect("bootrom version string doesn't contain NUL bytes"); - let smb_type0 = table::Type0 { + table::Type0 { vendor: "Oxide".try_into().unwrap(), bios_version, bios_release_date: self @@ -232,9 +233,13 @@ impl SmbiosParams { | type0::BiosExtCharacteristics::UEFI | type0::BiosExtCharacteristics::IS_VM, ..Default::default() - }; + } + } - let smb_type1 = table::Type1 { + pub fn table_type1(&self) -> table::Type1 { + use table::type1; + + table::Type1 { manufacturer: "Oxide".try_into().unwrap(), product_name: "OxVM".try_into().unwrap(), @@ -247,7 +252,11 @@ impl SmbiosParams { wake_up_type: type1::WakeUpType::PowerSwitch, ..Default::default() - }; + } + } + + pub fn table_type4(&self) -> table::Type4 { + use table::type4; let family = match self.cpuid_ident.eax & 0xf00 { // If family ID is 0xf, extended family is added to it @@ -280,7 +289,7 @@ impl SmbiosParams { let proc_version = cpuid::parse_brand_string(self.cpuid_procname) .unwrap_or_else(|_| "".to_string()); - let smb_type4 = table::Type4 { + table::Type4 { proc_type: type4::ProcType::Central, proc_family, proc_manufacturer, @@ -296,7 +305,11 @@ impl SmbiosParams { proc_characteristics: type4::Characteristics::IS_64_BIT | type4::Characteristics::MULTI_CORE, ..Default::default() - }; + } + } + + pub fn table_type16(&self) -> table::Type16 { + use table::type16; let mut smb_type16 = table::Type16 { location: type16::Location::SystemBoard, @@ -306,7 +319,11 @@ impl SmbiosParams { ..Default::default() }; smb_type16.set_max_capacity(self.memory_size); - let phys_mem_array_handle = 0x1600.into(); + smb_type16 + } + + pub fn table_type17(&self, table16_handle: Handle) -> table::Type17 { + let phys_mem_array_handle = table16_handle.into(); let mut smb_type17 = table::Type17 { phys_mem_array_handle, @@ -317,22 +334,11 @@ impl SmbiosParams { ..Default::default() }; smb_type17.set_size(Some(self.memory_size)); + smb_type17 + } - let smb_type32 = table::Type32::default(); - - // With "only" types 0, 1, 4, 16, 17, and 32, we are technically missing - // some (types 3, 7, 9, 19) of the data required by the 2.7 spec. The - // data provided here were what we determined was a reasonable - // collection to start with. Should further requirements arise, we may - // expand on it. - let mut smb_tables = Tables::new(0x7f00.into()); - smb_tables.add(0x0000.into(), &smb_type0).unwrap(); - smb_tables.add(0x0100.into(), &smb_type1).unwrap(); - smb_tables.add(0x0300.into(), &smb_type4).unwrap(); - smb_tables.add(phys_mem_array_handle, &smb_type16).unwrap(); - smb_tables.add(0x1700.into(), &smb_type17).unwrap(); - smb_tables.add(0x3200.into(), &smb_type32).unwrap(); - - Ok(smb_tables.commit()) + pub fn table_type32(&self) -> table::Type32 { + // We don't yet set anything interesting into table type 32. + table::Type32::default() } } From c35b7e14f171c6d3fc7503e206248c0b7558800b Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 6 Sep 2024 23:27:45 +0000 Subject: [PATCH 12/12] meant to keep that comment in propolis-server --- bin/propolis-server/src/lib/initializer.rs | 5 +++++ bin/propolis-standalone/src/main.rs | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index b7d855d2a..b51b7b98e 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -954,6 +954,11 @@ impl<'a> MachineInitializer<'a> { system_id: self.properties.id, }; + // With "only" types 0, 1, 4, 16, 17, and 32, we are technically missing + // some (types 3, 7, 9, 19) of the data required by the 2.7 spec. The + // data provided here were what we determined was a reasonable + // collection to start with. Should further requirements arise, we may + // expand on it. let mut smb_tables = smbios::Tables::new(0x7f00.into()); smb_tables.add(0x0000.into(), &smbios_params.table_type0()).unwrap(); smb_tables.add(0x0100.into(), &smbios_params.table_type1()).unwrap(); diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index 8ca66cad4..eb0cdef23 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1188,11 +1188,6 @@ fn setup_instance( system_id: uuid::Uuid::default(), }; - // With "only" types 0, 1, 4, 16, 17, and 32, we are technically missing - // some (types 3, 7, 9, 19) of the data required by the 2.7 spec. The - // data provided here were what we determined was a reasonable - // collection to start with. Should further requirements arise, we may - // expand on it. let mut smb_tables = smbios::Tables::new(0x7f00.into()); smb_tables.add(0x0000.into(), &smbios_params.table_type0()).unwrap(); smb_tables.add(0x0100.into(), &smbios_params.table_type1()).unwrap();