From 39a917194229fbfe6e0dc451b06d08577b2c5ec6 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 7 Apr 2026 14:11:08 +0800 Subject: [PATCH] --versions: Get AGESA version from SMBIOS Type 40 Signed-off-by: Daniel Schaefer --- EXAMPLES.md | 1 + framework_lib/src/commandline/mod.rs | 4 +++ framework_lib/src/smbios.rs | 53 +++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index be79a3c..f64fbff 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -157,6 +157,7 @@ EC Firmware PD Controllers Right (01): 0.0.0E (MainFw) Left (23): 0.0.0E (MainFw) +AGESA: AGESA!V9 StrixKrackanPI-FP8 1.1.0.0c [...] ``` diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 7114c7a..c0dd8cd 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -766,6 +766,10 @@ fn print_versions(ec: &CrosEc) { println!(" Unknown"); } } + + if let Some(agesa) = smbios::get_agesa_version() { + println!("AGESA: {}", agesa); + } #[cfg(feature = "rusb")] let _ignore_err = check_camera_version(); diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index 3ef77b7..6ccf77e 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -4,7 +4,7 @@ use std::prelude::v1::*; use crate::util::Config; pub use crate::util::{Platform, PlatformFamily}; -use dmidecode::{EntryPoint, Structure}; +use dmidecode::{EntryPoint, InfoType, RawStructure, Structure}; use num_derive::FromPrimitive; use num_traits::FromPrimitive; #[cfg(feature = "uefi")] @@ -174,6 +174,57 @@ pub fn get_family() -> Option { get_platform().and_then(Platform::which_family) } +/// Minimum size of an Additional Information entry (SMBIOS Type 40) +const DMI_A_INFO_ENT_MIN_SIZE: usize = 6; + +/// Extract AGESA version string from an SMBIOS Type 40 (Additional Information) structure. +/// +/// On AMD Zen systems, the AGESA version is stored here. +/// Sample string: "AGESA!V9 StrixKrackanPI-FP8 1.1.0.0c" +fn find_agesa_in_type40(raw: &RawStructure) -> Option { + if raw.info != InfoType::Oem(40) { + return None; + } + + // raw.data layout (after the 4-byte header): + // [0]: count — number of Additional Information entries + // [1..]: entries, each starting with a length byte + let count = *raw.data.first()? as usize; + let mut remaining = raw.data.get(1..)?; + + for _ in 0..count { + if remaining.len() < DMI_A_INFO_ENT_MIN_SIZE { + break; + } + let entry_len = remaining[0] as usize; + if entry_len == 0 || entry_len > remaining.len() { + break; + } + // String number is at offset 4 within the entry + let str_num = remaining[4]; + if let Ok(s) = raw.find_string(str_num) { + if s.starts_with("AGESA") { + return Some(s.to_string()); + } + } + remaining = &remaining[entry_len..]; + } + + None +} + +/// Get the AGESA version from SMBIOS Type 40 Additional Information entries +pub fn get_agesa_version() -> Option { + let smbios = get_smbios()?; + smbios.structures().find_map(|result| { + if let Ok(Structure::Other(ref raw)) = result { + find_agesa_in_type40(raw) + } else { + None + } + }) +} + pub fn get_platform() -> Option { #[cfg(feature = "uefi")] let mut cached_platform = CACHED_PLATFORM.lock();