Skip to content

Commit 377a317

Browse files
Merge pull request #85 from FrameworkComputer/ccg8
2 parents 2df6fc6 + 66bdcbc commit 377a317

File tree

5 files changed

+148
-5
lines changed

5 files changed

+148
-5
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@ see the [Support Matrices](support-matrices.md).
2525
- [x] ESRT table (UEFI and Linux only) (`--esrt`)
2626
- [x] SMBIOS
2727
- [x] Get firmware version from binary file
28-
- [x] EC (`--ec-bin`)
28+
- [x] MCHP EC on Intel Platform (`--ec-bin`)
29+
- [ ] NPC EC on Framework 16
2930
- [x] CCG5 PD (11th Gen TigerLake) (`--pd-bin`)
3031
- [x] CCG6 PD (12th Gen AlderLake) (`--pd-bin`)
32+
- [x] CCG8 PD (Framework 16) (`--pd-bin`)
3133
- [x] HO2 BIOS Capsule (`--ho2-capsule`)
3234
- [x] BIOS Version
3335
- [x] EC Version
3436
- [x] CCG5/CCG6 PD Version
37+
- [x] UEFI Capsule (`--capsule`)
3538
- [x] Parse metadata from capsule binary
3639
- [x] Determine type (GUID) of capsule binary
3740
- [x] Extract bitmap image from winux capsule to file

framework_lib/src/ccgx/binary.rs

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,14 @@ fn read_metadata(
9696
file_buffer: &[u8],
9797
flash_row_size: u32,
9898
metadata_offset: u32,
99+
ccgx: SiliconId,
99100
) -> Option<(u32, u32)> {
100101
let buffer = read_256_bytes(file_buffer, metadata_offset, flash_row_size)?;
101-
parse_metadata_cyacd(&buffer)
102+
match ccgx {
103+
SiliconId::Ccg5 | SiliconId::Ccg6 => parse_metadata_cyacd(&buffer),
104+
SiliconId::Ccg8 => parse_metadata_cyacd2(&buffer)
105+
.map(|(fw_row_start, fw_size)| (fw_row_start / flash_row_size, fw_size)),
106+
}
102107
}
103108

104109
/// Read 256 bytes starting from a particular row
@@ -121,8 +126,10 @@ fn read_version(
121126
file_buffer: &[u8],
122127
flash_row_size: u32,
123128
metadata_offset: u32,
129+
ccgx: SiliconId,
124130
) -> Option<PdFirmware> {
125-
let (fw_row_start, fw_size) = read_metadata(file_buffer, flash_row_size, metadata_offset)?;
131+
let (fw_row_start, fw_size) =
132+
read_metadata(file_buffer, flash_row_size, metadata_offset, ccgx)?;
126133
let data = read_256_bytes(file_buffer, fw_row_start, flash_row_size)?;
127134
let data = &data[FW_VERSION_OFFSET..];
128135

@@ -152,9 +159,10 @@ pub fn read_versions(file_buffer: &[u8], ccgx: SiliconId) -> Option<PdFirmwareFi
152159
let (flash_row_size, f1_metadata_row, fw2_metadata_row) = match ccgx {
153160
SiliconId::Ccg5 => (0x100, FW1_METADATA_ROW, FW2_METADATA_ROW_CCG5),
154161
SiliconId::Ccg6 => (0x80, FW1_METADATA_ROW, FW2_METADATA_ROW_CCG6),
162+
SiliconId::Ccg8 => (0x100, FW1_METADATA_ROW_CCG8, FW2_METADATA_ROW_CCG8),
155163
};
156-
let backup_fw = read_version(file_buffer, flash_row_size, f1_metadata_row)?;
157-
let main_fw = read_version(file_buffer, flash_row_size, fw2_metadata_row)?;
164+
let backup_fw = read_version(file_buffer, flash_row_size, f1_metadata_row, ccgx)?;
165+
let main_fw = read_version(file_buffer, flash_row_size, fw2_metadata_row, ccgx)?;
158166

159167
Some(PdFirmwareFile { backup_fw, main_fw })
160168
}
@@ -190,8 +198,10 @@ mod tests {
190198
let data = fs::read(pd_bin_path).unwrap();
191199
let ccg5_ver = read_versions(&data, SiliconId::Ccg5);
192200
let ccg6_ver = read_versions(&data, SiliconId::Ccg6);
201+
let ccg8_ver = read_versions(&data, SiliconId::Ccg8);
193202
assert!(ccg5_ver.is_some());
194203
assert!(ccg6_ver.is_none());
204+
assert!(ccg8_ver.is_none());
195205

196206
assert_eq!(
197207
ccg5_ver,
@@ -248,8 +258,10 @@ mod tests {
248258
let data = fs::read(pd_bin_path).unwrap();
249259
let ccg5_ver = read_versions(&data, SiliconId::Ccg5);
250260
let ccg6_ver = read_versions(&data, SiliconId::Ccg6);
261+
let ccg8_ver = read_versions(&data, SiliconId::Ccg8);
251262
assert!(ccg5_ver.is_none());
252263
assert!(ccg6_ver.is_some());
264+
assert!(ccg8_ver.is_none());
253265

254266
assert_eq!(
255267
ccg6_ver,
@@ -297,4 +309,64 @@ mod tests {
297309
})
298310
);
299311
}
312+
313+
#[test]
314+
fn can_parse_ccg8_binary() {
315+
let mut pd_bin_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
316+
pd_bin_path.push("test_bins/fl16-pd-0.0.03.bin");
317+
318+
let data = fs::read(pd_bin_path).unwrap();
319+
let ccg5_ver = read_versions(&data, SiliconId::Ccg5);
320+
let ccg6_ver = read_versions(&data, SiliconId::Ccg6);
321+
let ccg8_ver = read_versions(&data, SiliconId::Ccg8);
322+
assert!(ccg5_ver.is_none());
323+
assert!(ccg6_ver.is_none());
324+
assert!(ccg8_ver.is_some());
325+
326+
assert_eq!(
327+
ccg8_ver,
328+
Some({
329+
PdFirmwareFile {
330+
backup_fw: PdFirmware {
331+
silicon_id: 0x11C5,
332+
silicon_family: 0x3580,
333+
base_version: BaseVersion {
334+
major: 3,
335+
minor: 6,
336+
patch: 0,
337+
build_number: 160,
338+
},
339+
app_version: AppVersion {
340+
application: Application::Notebook,
341+
major: 0,
342+
minor: 0,
343+
circuit: 3,
344+
},
345+
start_row: 290,
346+
size: 111536,
347+
row_size: 0x100,
348+
},
349+
main_fw: PdFirmware {
350+
silicon_id: 0x11C5,
351+
silicon_family: 0x3580,
352+
base_version: BaseVersion {
353+
major: 3,
354+
minor: 6,
355+
patch: 0,
356+
build_number: 160,
357+
},
358+
app_version: AppVersion {
359+
application: Application::Notebook,
360+
major: 0,
361+
minor: 0,
362+
circuit: 3,
363+
},
364+
start_row: 29,
365+
size: 42312,
366+
row_size: 0x100,
367+
},
368+
}
369+
})
370+
);
371+
}
300372
}

framework_lib/src/ccgx/mod.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ pub mod device;
1515
pub mod hid;
1616

1717
const FW1_METADATA_ROW: u32 = 0x1FE;
18+
const FW1_METADATA_ROW_CCG8: u32 = 0x3FE;
1819
const FW2_METADATA_ROW_CCG5: u32 = 0x1FF;
1920
const FW2_METADATA_ROW_CCG6: u32 = 0x1FD;
21+
const FW2_METADATA_ROW_CCG8: u32 = 0x3FF;
2022
const METADATA_OFFSET: usize = 0xC0; // TODO: Is this 0x40 on ADL?
23+
const CCG8_METADATA_OFFSET: usize = 0x80;
2124
const METADATA_MAGIC: u16 = u16::from_le_bytes([b'Y', b'C']); // CY (Cypress)
25+
const CCG8_METADATA_MAGIC: u16 = u16::from_le_bytes([b'F', b'I']); // IF (Infineon)
2226

2327
#[repr(packed)]
2428
#[derive(Debug, Copy, Clone)]
@@ -53,11 +57,47 @@ struct CyAcdMetadata {
5357
_boot_seq: u32,
5458
}
5559

60+
// TODO: Would be nice to check the checksums
61+
#[repr(packed)]
62+
#[derive(Debug, Copy, Clone)]
63+
struct CyAcd2Metadata {
64+
/// Offset 00: App Firmware Start
65+
fw_start: u32,
66+
/// Offset 04: App Firmware Size
67+
fw_size: u32,
68+
/// Offset 08: Boot wait time
69+
_boot_app_id: u16,
70+
/// Offset 0A: Last Flash row of Bootloader or previous firmware
71+
/// Is (fw_start/FLASH_ROW_SIZE) - 1
72+
_boot_last_row: u16,
73+
/// Offset 0C: Verify Start Address
74+
_config_fw_start: u32,
75+
/// Offset 10: Verify Size
76+
_config_fw_size: u32,
77+
/// Offset 14: Boot sequence number field. Boot-loader will load the valid
78+
/// FW copy that has the higher sequence number associated with it
79+
/// Not relevant when checking the update binary file
80+
_boot_seq: u32,
81+
/// Offset 18: Reserved
82+
_reserved_1: [u32; 15],
83+
/// Offset 54: Version of the metadata structure
84+
metadata_version: u16,
85+
/// Offset 56: Metadata Valid field. Valid if contains ASCII "IF"
86+
metadata_valid: u16,
87+
/// Offset 58: App Fw CRC32 checksum
88+
_fw_crc32: u32,
89+
/// Offset 5C: Reserved
90+
_reserved_2: [u32; 8],
91+
/// Offset 7C: Metadata CRC32 checksum
92+
_md_crc32: u32,
93+
}
94+
5695
#[non_exhaustive]
5796
#[derive(Debug, PartialEq, FromPrimitive, Clone, Copy)]
5897
pub enum SiliconId {
5998
Ccg5 = 0x2100,
6099
Ccg6 = 0x3000,
100+
Ccg8 = 0x3580,
61101
}
62102

63103
#[derive(Debug, PartialEq)]
@@ -192,3 +232,21 @@ fn parse_metadata_cyacd(buffer: &[u8]) -> Option<(u32, u32)> {
192232
None
193233
}
194234
}
235+
236+
fn parse_metadata_cyacd2(buffer: &[u8]) -> Option<(u32, u32)> {
237+
let buffer = &buffer[CCG8_METADATA_OFFSET..];
238+
let metadata_len = std::mem::size_of::<CyAcd2Metadata>();
239+
let metadata: CyAcd2Metadata =
240+
unsafe { std::ptr::read(buffer[0..metadata_len].as_ptr() as *const _) };
241+
//println!("Metadata: {:?}", metadata);
242+
if metadata.metadata_valid == CCG8_METADATA_MAGIC {
243+
if metadata.metadata_version == 1 {
244+
Some((metadata.fw_start, metadata.fw_size))
245+
} else {
246+
println!("Unknown CCG8 metadata version");
247+
None
248+
}
249+
} else {
250+
None
251+
}
252+
}

framework_lib/src/commandline/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,16 @@ fn smbios_info() {
601601
fn analyze_ccgx_pd_fw(data: &[u8]) {
602602
let mut succeeded = false;
603603

604+
if let Some(versions) = ccgx::binary::read_versions(data, Ccg8) {
605+
succeeded = true;
606+
println!("Detected CCG8 firmware");
607+
println!("FW 1");
608+
ccgx::binary::print_fw(&versions.backup_fw);
609+
610+
println!("FW 2");
611+
ccgx::binary::print_fw(&versions.main_fw);
612+
}
613+
604614
if let Some(versions) = ccgx::binary::read_versions(data, Ccg5) {
605615
succeeded = true;
606616
println!("Detected CCG5 firmware");
256 KB
Binary file not shown.

0 commit comments

Comments
 (0)