Skip to content

Commit

Permalink
Merge pull request #27 from FrameworkComputer/zephyr-ec-bin-info
Browse files Browse the repository at this point in the history
framework_lib: Parse zephyr EC binary
  • Loading branch information
JohnAZoidberg authored Apr 28, 2024
2 parents 5e4989f + 8eae1fb commit fa3ee6d
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 25 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand Down
11 changes: 9 additions & 2 deletions framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,8 +807,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")
}
Expand Down
139 changes: 118 additions & 21 deletions framework_lib/src/ec_binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -102,13 +110,13 @@ fn parse_ec_version(data: &_ImageVersionData) -> Option<ImageVersionData> {
})
}

//#[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(),
Expand All @@ -117,16 +125,40 @@ fn parse_ec_version(data: &_ImageVersionData) -> Option<ImageVersionData> {
/// 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<ImageVersionDetails> {
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::<u32>().ok()?;
let minor = caps.get(3)?.as_str().parse::<u32>().ok()?;
let patch = caps.get(4)?.as_str().parse::<u32>().ok()?;
let commit = caps.get(5)?.as_str().to_string();
// Skipping second
let major = caps.get(3)?.as_str().parse::<u32>().ok()?;
let minor = caps.get(4)?.as_str().parse::<u32>().ok()?;
let patch = caps.get(5)?.as_str().parse::<u32>().ok()?;
// Skipping sixth
let commit = caps.get(7)?.as_str().to_string();

Some(ImageVersionDetails {
platform,
Expand All @@ -138,19 +170,38 @@ pub fn parse_ec_version_str(version: &str) -> Option<ImageVersionDetails> {
}

/// Parse version information from EC FW image buffer
pub fn read_ec_version(data: &[u8]) -> Option<ImageVersionData> {
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<ImageVersionData> {
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)]
Expand Down Expand Up @@ -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({
Expand All @@ -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));
}
}
Binary file added framework_lib/test_bins/amd-fl13-ec-3.05.bin
Binary file not shown.
Binary file added framework_lib/test_bins/amd-fl16-ec-3.03.bin
Binary file not shown.

0 comments on commit fa3ee6d

Please sign in to comment.