diff --git a/README.md b/README.md index fc30882..0bb53cf 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ see the [Support Matrices](support-matrices.md). - [x] ESRT table (UEFI and Linux only) (`--esrt`) - [x] SMBIOS - [x] Get firmware version from binary file - - [x] MCHP EC on Intel Platform (`--ec-bin`) - - [ ] NPC EC on Framework 16 + - [x] Legacy EC (Intel 13th Gen and earlier) (`--ec-bin`) + - [x] Zephyr EC (AMD) (`--ec-bin`) - [x] CCG5 PD (11th Gen TigerLake) (`--pd-bin`) - [x] CCG6 PD (12th Gen AlderLake) (`--pd-bin`) - [x] CCG8 PD (Framework 16) (`--pd-bin`) diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index e94ce35..0504a51 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -806,8 +806,15 @@ fn analyze_ccgx_pd_fw(data: &[u8]) { } pub fn analyze_ec_fw(data: &[u8]) { - if let Some(ver) = ec_binary::read_ec_version(data) { - ec_binary::print_ec_version(&ver); + // Readonly firmware + if let Some(ver) = ec_binary::read_ec_version(data, true) { + ec_binary::print_ec_version(&ver, true); + } else { + println!("Failed to read version") + } + // Readwrite firmware + if let Some(ver) = ec_binary::read_ec_version(data, false) { + ec_binary::print_ec_version(&ver, false); } else { println!("Failed to read version") } diff --git a/framework_lib/src/ec_binary.rs b/framework_lib/src/ec_binary.rs index 7631fc4..938576c 100644 --- a/framework_lib/src/ec_binary.rs +++ b/framework_lib/src/ec_binary.rs @@ -6,7 +6,13 @@ use alloc::string::ToString; const CROS_EC_IMAGE_DATA_COOKIE1: u32 = 0xce778899; const CROS_EC_IMAGE_DATA_COOKIE2: u32 = 0xceaabbdd; // Absolute offset of the version struct inside the entire EC binary -const EC_VERSION_OFFSET: usize = 0x1158; +// Legacy +// const EC_VERSION_OFFSET: usize = 0x1158; // Bootloader? +const EC_RO_VER_OFFSET: usize = 0x2430; +const EC_RW_VER_OFFSET: usize = 0x402f0; +// Zephyr +const EC_RO_VER_OFFSET_ZEPHYR: usize = 0x00180; +const EC_RW_VER_OFFSET_ZEPHYR: usize = 0x40140; pub const EC_LEN: usize = 0x8_0000; #[cfg(not(feature = "uefi"))] @@ -16,6 +22,7 @@ use regex; #[cfg(feature = "uefi")] use core::prelude::rust_2021::derive; +// Defined in EC code as `struct image_data` in include/cros_version.h #[derive(Clone, Copy, Debug)] #[repr(C, packed)] struct _ImageVersionData { @@ -52,8 +59,9 @@ pub struct ImageVersionDetails { } /// Print pretty information about the EC version -pub fn print_ec_version(ver: &ImageVersionData) { +pub fn print_ec_version(ver: &ImageVersionData, ro: bool) { println!("EC"); + println!(" Type: {:>20}", if ro { "RO" } else { "RW" }); println!(" Version: {:>20}", ver.version); println!(" RollbackVer:{:>20}", ver.rollback_version); println!(" Platform: {:>20}", ver.details.platform); @@ -102,13 +110,13 @@ fn parse_ec_version(data: &_ImageVersionData) -> Option { }) } -//#[cfg(not(feature = "uefi"))] /// Parse the EC version string into its components /// /// # Examples /// /// ``` /// use framework_lib::ec_binary::*; +/// // Legacy EC /// let ver = parse_ec_version_str("hx30_v0.0.1-7a61a89"); /// assert_eq!(ver, Some(ImageVersionDetails { /// platform: "hx30".to_string(), @@ -117,16 +125,40 @@ fn parse_ec_version(data: &_ImageVersionData) -> Option { /// patch: 1, /// commit: "7a61a89".to_string(), /// })); +/// +/// // Zephyr based EC 2023 +/// let ver = parse_ec_version_str("lotus_v3.2.103876-ec:a3a7cb,os:"); +/// assert_eq!(ver, Some(ImageVersionDetails { +/// platform: "lotus".to_string(), +/// major: 3, +/// minor: 2, +/// patch: 103876, +/// commit: "a3a7cb".to_string(), +/// })); +/// +/// // Zephyr based EC 2024 +/// let ver = parse_ec_version_str("lotus-0.0.0-c6c7ac3"); +/// assert_eq!(ver, Some(ImageVersionDetails { +/// platform: "lotus".to_string(), +/// major: 0, +/// minor: 0, +/// patch: 0, +/// commit: "c6c7ac3".to_string(), +/// })); /// ``` #[cfg(not(feature = "uefi"))] pub fn parse_ec_version_str(version: &str) -> Option { - let re = regex::Regex::new(r"([a-z0-9]+)_v([0-9])\.([0-9])\.([0-9])-([0-9a-f]+)").unwrap(); - let caps = re.captures(version).unwrap(); + debug!("Trying to parse version: {:?}", version); + let re = regex::Regex::new(r"([a-z0-9]+)(_v|-)([0-9])\.([0-9])\.([0-9]+)-(ec:)?([0-9a-f]+)") + .unwrap(); + let caps = re.captures(version)?; let platform = caps.get(1)?.as_str().to_string(); - let major = caps.get(2)?.as_str().parse::().ok()?; - let minor = caps.get(3)?.as_str().parse::().ok()?; - let patch = caps.get(4)?.as_str().parse::().ok()?; - let commit = caps.get(5)?.as_str().to_string(); + // Skipping second + let major = caps.get(3)?.as_str().parse::().ok()?; + let minor = caps.get(4)?.as_str().parse::().ok()?; + let patch = caps.get(5)?.as_str().parse::().ok()?; + // Skipping sixth + let commit = caps.get(7)?.as_str().to_string(); Some(ImageVersionDetails { platform, @@ -138,19 +170,38 @@ pub fn parse_ec_version_str(version: &str) -> Option { } /// Parse version information from EC FW image buffer -pub fn read_ec_version(data: &[u8]) -> Option { - let v: _ImageVersionData = - unsafe { std::ptr::read(data[EC_VERSION_OFFSET..].as_ptr() as *const _) }; +pub fn read_ec_version(data: &[u8], ro: bool) -> Option { + let offset = if ro { + EC_RO_VER_OFFSET + } else { + EC_RW_VER_OFFSET + }; + let offset_zephyr = if ro { + EC_RO_VER_OFFSET_ZEPHYR + } else { + EC_RW_VER_OFFSET_ZEPHYR + }; + + let v: _ImageVersionData = unsafe { std::ptr::read(data[offset..].as_ptr() as *const _) }; if v.cookie1 != CROS_EC_IMAGE_DATA_COOKIE1 { - error!("Failed to find Cookie 1"); - return None; + debug!("Failed to find Cookie 1. Found: {:X?}", { v.cookie1 }); + } else if v.cookie2 != CROS_EC_IMAGE_DATA_COOKIE2 { + debug!("Failed to find Cookie 2. Found: {:X?}", { v.cookie2 }); + } else { + return parse_ec_version(&v); } - if v.cookie2 != CROS_EC_IMAGE_DATA_COOKIE2 { - error!("Failed to find Cookie 2"); - return None; + + let v: _ImageVersionData = + unsafe { std::ptr::read(data[offset_zephyr..].as_ptr() as *const _) }; + if v.cookie1 != CROS_EC_IMAGE_DATA_COOKIE1 { + debug!("Failed to find Cookie 1. Found: {:X?}", { v.cookie1 }); + } else if v.cookie2 != CROS_EC_IMAGE_DATA_COOKIE2 { + debug!("Failed to find Cookie 2. Found: {:X?}", { v.cookie2 }); + } else { + return parse_ec_version(&v); } - parse_ec_version(&v) + None } #[cfg(test)] @@ -188,11 +239,11 @@ mod tests { } #[test] - fn can_parse_binary() { + fn can_parse_adl_ec() { let mut ec_bin_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); ec_bin_path.push("test_bins/adl-ec-0.0.1.bin"); let data = fs::read(ec_bin_path).unwrap(); - let ver = read_ec_version(&data); + let ver = read_ec_version(&data, false); assert_eq!( ver, Some({ @@ -205,10 +256,56 @@ mod tests { patch: 1, commit: "7a61a89".to_string(), }, - size: 2868, + size: 136900, rollback_version: 0, } }) ); } + + #[test] + fn can_parse_amd_fl13_ec() { + let mut ec_bin_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + ec_bin_path.push("test_bins/amd-fl13-ec-3.05.bin"); + let data = fs::read(ec_bin_path).unwrap(); + let expected = Some({ + ImageVersionData { + version: "azalea_v3.4.113353-ec:b4c1fb,os".to_string(), + details: ImageVersionDetails { + platform: "azalea".to_string(), + major: 3, + minor: 4, + patch: 113353, + commit: "b4c1fb".to_string(), + }, + size: 258048, + rollback_version: 0, + } + }); + assert_eq!(expected, read_ec_version(&data, false)); + assert_eq!(expected, read_ec_version(&data, true)); + } + + #[test] + fn can_parse_amd_fl16_ec() { + let mut ec_bin_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + ec_bin_path.push("test_bins/amd-fl16-ec-3.03.bin"); + let data = fs::read(ec_bin_path).unwrap(); + let expected = Some({ + ImageVersionData { + version: "lotus_v3.4.113353-ec:b4c1fb,os:".to_string(), + details: ImageVersionDetails { + platform: "lotus".to_string(), + major: 3, + minor: 4, + patch: 113353, + commit: "b4c1fb".to_string(), + }, + size: 258048, + rollback_version: 0, + } + }); + assert_eq!(expected, read_ec_version(&data, false)); + assert_eq!(expected, read_ec_version(&data, true)); + } } diff --git a/framework_lib/test_bins/amd-fl13-ec-3.05.bin b/framework_lib/test_bins/amd-fl13-ec-3.05.bin new file mode 100644 index 0000000..082bc95 Binary files /dev/null and b/framework_lib/test_bins/amd-fl13-ec-3.05.bin differ diff --git a/framework_lib/test_bins/amd-fl16-ec-3.03.bin b/framework_lib/test_bins/amd-fl16-ec-3.03.bin new file mode 100644 index 0000000..ad980cd Binary files /dev/null and b/framework_lib/test_bins/amd-fl16-ec-3.03.bin differ