@@ -6,7 +6,13 @@ use alloc::string::ToString;
66const CROS_EC_IMAGE_DATA_COOKIE1 : u32 = 0xce778899 ;
77const CROS_EC_IMAGE_DATA_COOKIE2 : u32 = 0xceaabbdd ;
88// Absolute offset of the version struct inside the entire EC binary
9- const EC_VERSION_OFFSET : usize = 0x1158 ;
9+ // Legacy
10+ // const EC_VERSION_OFFSET: usize = 0x1158; // Bootloader?
11+ const EC_RO_VER_OFFSET : usize = 0x2430 ;
12+ const EC_RW_VER_OFFSET : usize = 0x402f0 ;
13+ // Zephyr
14+ const EC_RO_VER_OFFSET_ZEPHYR : usize = 0x00180 ;
15+ const EC_RW_VER_OFFSET_ZEPHYR : usize = 0x40140 ;
1016pub const EC_LEN : usize = 0x8_0000 ;
1117
1218#[ cfg( not( feature = "uefi" ) ) ]
@@ -16,6 +22,7 @@ use regex;
1622#[ cfg( feature = "uefi" ) ]
1723use core:: prelude:: rust_2021:: derive;
1824
25+ // Defined in EC code as `struct image_data` in include/cros_version.h
1926#[ derive( Clone , Copy , Debug ) ]
2027#[ repr( C , packed) ]
2128struct _ImageVersionData {
@@ -52,8 +59,9 @@ pub struct ImageVersionDetails {
5259}
5360
5461/// Print pretty information about the EC version
55- pub fn print_ec_version ( ver : & ImageVersionData ) {
62+ pub fn print_ec_version ( ver : & ImageVersionData , ro : bool ) {
5663 println ! ( "EC" ) ;
64+ println ! ( " Type: {:>20}" , if ro { "RO" } else { "RW" } ) ;
5765 println ! ( " Version: {:>20}" , ver. version) ;
5866 println ! ( " RollbackVer:{:>20}" , ver. rollback_version) ;
5967 println ! ( " Platform: {:>20}" , ver. details. platform) ;
@@ -102,13 +110,13 @@ fn parse_ec_version(data: &_ImageVersionData) -> Option<ImageVersionData> {
102110 } )
103111}
104112
105- //#[cfg(not(feature = "uefi"))]
106113/// Parse the EC version string into its components
107114///
108115/// # Examples
109116///
110117/// ```
111118/// use framework_lib::ec_binary::*;
119+ /// // Legacy EC
112120/// let ver = parse_ec_version_str("hx30_v0.0.1-7a61a89");
113121/// assert_eq!(ver, Some(ImageVersionDetails {
114122/// platform: "hx30".to_string(),
@@ -117,16 +125,40 @@ fn parse_ec_version(data: &_ImageVersionData) -> Option<ImageVersionData> {
117125/// patch: 1,
118126/// commit: "7a61a89".to_string(),
119127/// }));
128+ ///
129+ /// // Zephyr based EC 2023
130+ /// let ver = parse_ec_version_str("lotus_v3.2.103876-ec:a3a7cb,os:");
131+ /// assert_eq!(ver, Some(ImageVersionDetails {
132+ /// platform: "lotus".to_string(),
133+ /// major: 3,
134+ /// minor: 2,
135+ /// patch: 103876,
136+ /// commit: "a3a7cb".to_string(),
137+ /// }));
138+ ///
139+ /// // Zephyr based EC 2024
140+ /// let ver = parse_ec_version_str("lotus-0.0.0-c6c7ac3");
141+ /// assert_eq!(ver, Some(ImageVersionDetails {
142+ /// platform: "lotus".to_string(),
143+ /// major: 0,
144+ /// minor: 0,
145+ /// patch: 0,
146+ /// commit: "c6c7ac3".to_string(),
147+ /// }));
120148/// ```
121149#[ cfg( not( feature = "uefi" ) ) ]
122150pub fn parse_ec_version_str ( version : & str ) -> Option < ImageVersionDetails > {
123- let re = regex:: Regex :: new ( r"([a-z0-9]+)_v([0-9])\.([0-9])\.([0-9])-([0-9a-f]+)" ) . unwrap ( ) ;
124- let caps = re. captures ( version) . unwrap ( ) ;
151+ debug ! ( "Trying to parse version: {:?}" , version) ;
152+ let re = regex:: Regex :: new ( r"([a-z0-9]+)(_v|-)([0-9])\.([0-9])\.([0-9]+)-(ec:)?([0-9a-f]+)" )
153+ . unwrap ( ) ;
154+ let caps = re. captures ( version) ?;
125155 let platform = caps. get ( 1 ) ?. as_str ( ) . to_string ( ) ;
126- let major = caps. get ( 2 ) ?. as_str ( ) . parse :: < u32 > ( ) . ok ( ) ?;
127- let minor = caps. get ( 3 ) ?. as_str ( ) . parse :: < u32 > ( ) . ok ( ) ?;
128- let patch = caps. get ( 4 ) ?. as_str ( ) . parse :: < u32 > ( ) . ok ( ) ?;
129- let commit = caps. get ( 5 ) ?. as_str ( ) . to_string ( ) ;
156+ // Skipping second
157+ let major = caps. get ( 3 ) ?. as_str ( ) . parse :: < u32 > ( ) . ok ( ) ?;
158+ let minor = caps. get ( 4 ) ?. as_str ( ) . parse :: < u32 > ( ) . ok ( ) ?;
159+ let patch = caps. get ( 5 ) ?. as_str ( ) . parse :: < u32 > ( ) . ok ( ) ?;
160+ // Skipping sixth
161+ let commit = caps. get ( 7 ) ?. as_str ( ) . to_string ( ) ;
130162
131163 Some ( ImageVersionDetails {
132164 platform,
@@ -138,19 +170,38 @@ pub fn parse_ec_version_str(version: &str) -> Option<ImageVersionDetails> {
138170}
139171
140172/// Parse version information from EC FW image buffer
141- pub fn read_ec_version ( data : & [ u8 ] ) -> Option < ImageVersionData > {
142- let v: _ImageVersionData =
143- unsafe { std:: ptr:: read ( data[ EC_VERSION_OFFSET ..] . as_ptr ( ) as * const _ ) } ;
173+ pub fn read_ec_version ( data : & [ u8 ] , ro : bool ) -> Option < ImageVersionData > {
174+ let offset = if ro {
175+ EC_RO_VER_OFFSET
176+ } else {
177+ EC_RW_VER_OFFSET
178+ } ;
179+ let offset_zephyr = if ro {
180+ EC_RO_VER_OFFSET_ZEPHYR
181+ } else {
182+ EC_RW_VER_OFFSET_ZEPHYR
183+ } ;
184+
185+ let v: _ImageVersionData = unsafe { std:: ptr:: read ( data[ offset..] . as_ptr ( ) as * const _ ) } ;
144186 if v. cookie1 != CROS_EC_IMAGE_DATA_COOKIE1 {
145- error ! ( "Failed to find Cookie 1" ) ;
146- return None ;
187+ debug ! ( "Failed to find Cookie 1. Found: {:X?}" , { v. cookie1 } ) ;
188+ } else if v. cookie2 != CROS_EC_IMAGE_DATA_COOKIE2 {
189+ debug ! ( "Failed to find Cookie 2. Found: {:X?}" , { v. cookie2 } ) ;
190+ } else {
191+ return parse_ec_version ( & v) ;
147192 }
148- if v. cookie2 != CROS_EC_IMAGE_DATA_COOKIE2 {
149- error ! ( "Failed to find Cookie 2" ) ;
150- return None ;
193+
194+ let v: _ImageVersionData =
195+ unsafe { std:: ptr:: read ( data[ offset_zephyr..] . as_ptr ( ) as * const _ ) } ;
196+ if v. cookie1 != CROS_EC_IMAGE_DATA_COOKIE1 {
197+ debug ! ( "Failed to find Cookie 1. Found: {:X?}" , { v. cookie1 } ) ;
198+ } else if v. cookie2 != CROS_EC_IMAGE_DATA_COOKIE2 {
199+ debug ! ( "Failed to find Cookie 2. Found: {:X?}" , { v. cookie2 } ) ;
200+ } else {
201+ return parse_ec_version ( & v) ;
151202 }
152203
153- parse_ec_version ( & v )
204+ None
154205}
155206
156207#[ cfg( test) ]
@@ -188,11 +239,11 @@ mod tests {
188239 }
189240
190241 #[ test]
191- fn can_parse_binary ( ) {
242+ fn can_parse_adl_ec ( ) {
192243 let mut ec_bin_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
193244 ec_bin_path. push ( "test_bins/adl-ec-0.0.1.bin" ) ;
194245 let data = fs:: read ( ec_bin_path) . unwrap ( ) ;
195- let ver = read_ec_version ( & data) ;
246+ let ver = read_ec_version ( & data, false ) ;
196247 assert_eq ! (
197248 ver,
198249 Some ( {
@@ -205,10 +256,56 @@ mod tests {
205256 patch: 1 ,
206257 commit: "7a61a89" . to_string( ) ,
207258 } ,
208- size: 2868 ,
259+ size: 136900 ,
209260 rollback_version: 0 ,
210261 }
211262 } )
212263 ) ;
213264 }
265+
266+ #[ test]
267+ fn can_parse_amd_fl13_ec ( ) {
268+ let mut ec_bin_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
269+ ec_bin_path. push ( "test_bins/amd-fl13-ec-3.05.bin" ) ;
270+ let data = fs:: read ( ec_bin_path) . unwrap ( ) ;
271+ let expected = Some ( {
272+ ImageVersionData {
273+ version : "azalea_v3.4.113353-ec:b4c1fb,os" . to_string ( ) ,
274+ details : ImageVersionDetails {
275+ platform : "azalea" . to_string ( ) ,
276+ major : 3 ,
277+ minor : 4 ,
278+ patch : 113353 ,
279+ commit : "b4c1fb" . to_string ( ) ,
280+ } ,
281+ size : 258048 ,
282+ rollback_version : 0 ,
283+ }
284+ } ) ;
285+ assert_eq ! ( expected, read_ec_version( & data, false ) ) ;
286+ assert_eq ! ( expected, read_ec_version( & data, true ) ) ;
287+ }
288+
289+ #[ test]
290+ fn can_parse_amd_fl16_ec ( ) {
291+ let mut ec_bin_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
292+ ec_bin_path. push ( "test_bins/amd-fl16-ec-3.03.bin" ) ;
293+ let data = fs:: read ( ec_bin_path) . unwrap ( ) ;
294+ let expected = Some ( {
295+ ImageVersionData {
296+ version : "lotus_v3.4.113353-ec:b4c1fb,os:" . to_string ( ) ,
297+ details : ImageVersionDetails {
298+ platform : "lotus" . to_string ( ) ,
299+ major : 3 ,
300+ minor : 4 ,
301+ patch : 113353 ,
302+ commit : "b4c1fb" . to_string ( ) ,
303+ } ,
304+ size : 258048 ,
305+ rollback_version : 0 ,
306+ }
307+ } ) ;
308+ assert_eq ! ( expected, read_ec_version( & data, false ) ) ;
309+ assert_eq ! ( expected, read_ec_version( & data, true ) ) ;
310+ }
214311}
0 commit comments