Skip to content

Commit 39a9171

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

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

EXAMPLES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ EC Firmware
157157
PD Controllers
158158
Right (01): 0.0.0E (MainFw)
159159
Left (23): 0.0.0E (MainFw)
160+
AGESA: AGESA!V9 StrixKrackanPI-FP8 1.1.0.0c
160161
[...]
161162
```
162163

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: 52 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,57 @@ pub fn get_family() -> Option<PlatformFamily> {
174174
get_platform().and_then(Platform::which_family)
175175
}
176176

177+
/// Minimum size of an Additional Information entry (SMBIOS Type 40)
178+
const DMI_A_INFO_ENT_MIN_SIZE: usize = 6;
179+
180+
/// Extract AGESA version string from an SMBIOS Type 40 (Additional Information) structure.
181+
///
182+
/// On AMD Zen systems, the AGESA version is stored here.
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+
// raw.data layout (after the 4-byte header):
190+
// [0]: count — number of Additional Information entries
191+
// [1..]: entries, each starting with a length byte
192+
let count = *raw.data.first()? as usize;
193+
let mut remaining = raw.data.get(1..)?;
194+
195+
for _ in 0..count {
196+
if remaining.len() < DMI_A_INFO_ENT_MIN_SIZE {
197+
break;
198+
}
199+
let entry_len = remaining[0] as usize;
200+
if entry_len == 0 || entry_len > remaining.len() {
201+
break;
202+
}
203+
// String number is at offset 4 within the entry
204+
let str_num = remaining[4];
205+
if let Ok(s) = raw.find_string(str_num) {
206+
if s.starts_with("AGESA") {
207+
return Some(s.to_string());
208+
}
209+
}
210+
remaining = &remaining[entry_len..];
211+
}
212+
213+
None
214+
}
215+
216+
/// Get the AGESA version from SMBIOS Type 40 Additional Information entries
217+
pub fn get_agesa_version() -> Option<String> {
218+
let smbios = get_smbios()?;
219+
smbios.structures().find_map(|result| {
220+
if let Ok(Structure::Other(ref raw)) = result {
221+
find_agesa_in_type40(raw)
222+
} else {
223+
None
224+
}
225+
})
226+
}
227+
177228
pub fn get_platform() -> Option<Platform> {
178229
#[cfg(feature = "uefi")]
179230
let mut cached_platform = CACHED_PLATFORM.lock();

0 commit comments

Comments
 (0)