Skip to content

Commit 1dc3b22

Browse files
committed
--versions: Get AGESA version from SMBIOS Type 40
Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent 6f2713d commit 1dc3b22

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

framework_lib/src/commandline/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,10 @@ fn print_versions(ec: &CrosEc) {
766766
println!(" Unknown");
767767
}
768768
}
769+
770+
if let Some(agesa) = smbios::get_agesa_version() {
771+
println!("AGESA: {}", agesa);
772+
}
769773
#[cfg(feature = "rusb")]
770774
let _ignore_err = check_camera_version();
771775

framework_lib/src/smbios.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::prelude::v1::*;
44

55
use crate::util::Config;
66
pub use crate::util::{Platform, PlatformFamily};
7-
use dmidecode::{EntryPoint, Structure};
7+
use dmidecode::{EntryPoint, InfoType, RawStructure, Structure};
88
use num_derive::FromPrimitive;
99
use num_traits::FromPrimitive;
1010
#[cfg(feature = "uefi")]
@@ -174,6 +174,64 @@ pub fn get_family() -> Option<PlatformFamily> {
174174
get_platform().and_then(Platform::which_family)
175175
}
176176

177+
/// SMBIOS Type 40 Additional Information entry minimum size
178+
const DMI_A_INFO_ENT_MIN_SIZE: usize = 6;
179+
180+
/// Extract AGESA version string from SMBIOS Type 40 (Additional Information) entries.
181+
///
182+
/// On AMD Zen systems, the AGESA version is stored in a Type 40 entry.
183+
/// Sample string: "AGESA!V9 StrixKrackanPI-FP8 1.1.0.0c"
184+
fn find_agesa_in_type40(raw: &RawStructure) -> Option<String> {
185+
if raw.info != InfoType::Oem(40) {
186+
return None;
187+
}
188+
189+
// Type 40 formatted area (after 4-byte header):
190+
// offset 0x04: count (u8) — number of Additional Information entries
191+
// offset 0x05+: entries
192+
// raw.data starts after the header, so count is at data[0], entries at data[1..]
193+
let count = *raw.data.first()?;
194+
if count < 1 {
195+
return None;
196+
}
197+
198+
let mut pos = 1; // start of entries in raw.data
199+
let data = raw.data;
200+
201+
for _ in 0..count {
202+
if pos + DMI_A_INFO_ENT_MIN_SIZE > data.len() {
203+
break;
204+
}
205+
let entry_len = data[pos] as usize;
206+
if entry_len == 0 {
207+
break;
208+
}
209+
// str_num is at offset 4 within the entry (pos+4)
210+
let str_num = data[pos + 4];
211+
if let Ok(s) = raw.find_string(str_num) {
212+
if s.starts_with("AGESA") {
213+
return Some(s.to_string());
214+
}
215+
}
216+
pos += entry_len;
217+
}
218+
219+
None
220+
}
221+
222+
/// Get the AGESA version from SMBIOS Type 40 Additional Information entries
223+
pub fn get_agesa_version() -> Option<String> {
224+
let smbios = get_smbios()?;
225+
for result in smbios.structures() {
226+
if let Ok(Structure::Other(ref raw)) = result {
227+
if let Some(agesa) = find_agesa_in_type40(raw) {
228+
return Some(agesa);
229+
}
230+
}
231+
}
232+
None
233+
}
234+
177235
pub fn get_platform() -> Option<Platform> {
178236
#[cfg(feature = "uefi")]
179237
let mut cached_platform = CACHED_PLATFORM.lock();

0 commit comments

Comments
 (0)