Skip to content

Commit 1ced1d0

Browse files
committed
chromium_ec: Improve flash reading selftest
Signed-off-by: Daniel Schaefer <[email protected]>
1 parent 9e32643 commit 1ced1d0

File tree

2 files changed

+119
-35
lines changed

2 files changed

+119
-35
lines changed

framework_lib/src/chromium_ec/mod.rs

Lines changed: 117 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::os_specific;
1212
use crate::smbios;
1313
#[cfg(feature = "uefi")]
1414
use crate::uefi::shell_get_execution_break_flag;
15-
use crate::util::assert_win_len;
15+
use crate::util::{self, Platform};
1616

1717
use log::Level;
1818
use num_derive::FromPrimitive;
@@ -57,6 +57,8 @@ const FLASH_RO_BASE: u32 = 0x0;
5757
const FLASH_RO_SIZE: u32 = 0x3C000;
5858
const FLASH_RW_BASE: u32 = 0x40000;
5959
const FLASH_RW_SIZE: u32 = 0x39000;
60+
const MEC_FLASH_FLAGS: u32 = 0x80000;
61+
const NPC_FLASH_FLAGS: u32 = 0x7F000;
6062
const FLASH_PROGRAM_OFFSET: u32 = 0x1000;
6163

6264
#[derive(Clone, Debug, PartialEq)]
@@ -116,6 +118,13 @@ pub enum EcResponseStatus {
116118
Busy = 16,
117119
}
118120

121+
pub fn has_mec() -> bool {
122+
!matches!(
123+
smbios::get_platform().unwrap(),
124+
Platform::Framework13Amd | Platform::Framework16
125+
)
126+
}
127+
119128
pub trait CrosEcDriver {
120129
fn read_memory(&self, offset: u16, length: u16) -> Option<Vec<u8>>;
121130
fn send_command(&self, command: u16, command_version: u8, data: &[u8]) -> EcResult<Vec<u8>>;
@@ -270,7 +279,7 @@ impl CrosEc {
270279
let limits = &[ChargeLimitControlModes::Set as u8, max, min];
271280
let data = self.send_command(EcCommands::ChargeLimitControl as u16, 0, limits)?;
272281

273-
assert_win_len(data.len(), 0);
282+
util::assert_win_len(data.len(), 0);
274283

275284
Ok(())
276285
}
@@ -298,7 +307,7 @@ impl CrosEc {
298307
let limits = &[level as u8, 0x00];
299308
let data = self.send_command(EcCommands::FpLedLevelControl as u16, 0, limits)?;
300309

301-
assert_win_len(data.len(), 0);
310+
util::assert_win_len(data.len(), 0);
302311

303312
Ok(())
304313
}
@@ -594,39 +603,122 @@ impl CrosEc {
594603
}
595604

596605
pub fn test_ec_flash_read(&self) -> EcResult<()> {
606+
let mut res = Ok(());
597607
// TODO: Perhaps we could have some more global flag to avoid setting and unsetting that ever time
598608
self.flash_notify(MecFlashNotify::AccessSpi)?;
599609

600-
println!(" EC Test");
601-
println!(" Read first row of flash.");
602-
// Make sure we can read a full flash row
610+
// ===== Test 1 =====
611+
// Read the first row of flash.
612+
// It's the beginning of RO firmware
613+
println!(" Read first row of flash (RO FW)");
603614
let data = self.read_ec_flash(0, 0x80).unwrap();
604-
if data[0..4] != [0x10, 0x00, 0x00, 0xF7] {
615+
616+
debug!("{:02X?}", data);
617+
println!(" {:02X?}", &data[..8]);
618+
if data.iter().all(|x| *x == 0xFF) {
619+
println!(" Erased!");
620+
}
621+
622+
// 4 magic bytes at the beginning
623+
let legacy_start = [0x10, 0x00, 0x00, 0xF7];
624+
// TODO: Does zephyr always start like this?
625+
let zephyr_start = [0x5E, 0x4D, 0x3B, 0x2A];
626+
if data[0..4] != legacy_start && data[0..4] != zephyr_start {
605627
println!(" INVALID start");
606-
return Err(EcError::DeviceError("INVALID start".to_string()));
628+
res = Err(EcError::DeviceError("INVALID start".to_string()));
607629
}
608-
if !data[4..].iter().all(|x| *x == 0xFF) {
630+
// Legacy EC is all 0xFF until the end of the row
631+
// Zephyr EC I'm not quite sure but it has a section of 0x00
632+
let legacy_comp = !data[4..].iter().all(|x| *x == 0xFF);
633+
let zephyr_comp = !data[0x20..0x40].iter().all(|x| *x == 0x00);
634+
if legacy_comp && zephyr_comp {
609635
println!(" INVALID end");
610-
return Err(EcError::DeviceError("INVALID end".to_string()));
636+
res = Err(EcError::DeviceError("INVALID end".to_string()));
637+
}
638+
639+
// ===== Test 2 =====
640+
// DISABLED
641+
// TODO: Haven't figure out a pattern yet
642+
//
643+
// Read the first row of the second half of flash
644+
// It's the beginning of RW firmware
645+
println!(" Read first row of RW FW");
646+
let data = self.read_ec_flash(0x40000, 0x80).unwrap();
647+
648+
println!(" {:02X?}", &data[..8]);
649+
if data.iter().all(|x| *x == 0xFF) {
650+
println!(" Erased!");
651+
res = Err(EcError::DeviceError("RW Erased".to_string()));
652+
}
653+
654+
// TODO: How can we identify if the RO image is valid?
655+
// //debug!("Expected TODO and rest all FF");
656+
// debug!("Expecting 80 7D 0C 20 and 0x20-0x2C all 00");
657+
// let legacy_start = []; // TODO
658+
// let zephyr_start = [0x80, 0x7D, 0x0C, 0x20];
659+
// if data[0..4] != legacy_start && data[0..4] != zephyr_start {
660+
// println!(" INVALID start");
661+
// res = Err(EcError::DeviceError("INVALID start".to_string()));
662+
// }
663+
// let legacy_comp = !data[4..].iter().all(|x| *x == 0xFF);
664+
// let zephyr_comp = !data[0x20..0x2C].iter().all(|x| *x == 0x00);
665+
// if legacy_comp && zephyr_comp {
666+
// println!(" INVALID end");
667+
// res = Err(EcError::DeviceError("INVALID end".to_string()));
668+
// }
669+
670+
// ===== Test 3 =====
671+
//
672+
// MEC EC has program code at 0x1000 with magic bytes that spell
673+
// MCHP (Microchip) in ASCII backwards.
674+
// Everything before is probably a header.
675+
// TODO: I don't think there are magic bytes on zephyr firmware
676+
//
677+
if has_mec() {
678+
println!(" Check MCHP magic byte at start of firmware code.");
679+
// Make sure we can read at an offset and with arbitrary length
680+
let data = self.read_ec_flash(FLASH_PROGRAM_OFFSET, 16).unwrap();
681+
debug!("Expecting beginning with 50 48 43 4D ('PHCM' in ASCII)");
682+
debug!("{:02X?}", data);
683+
println!(
684+
" {:02X?} ASCII:{:?}",
685+
&data[..4],
686+
core::str::from_utf8(&data[..4])
687+
);
688+
689+
if data[0..4] != [0x50, 0x48, 0x43, 0x4D] {
690+
println!(" INVALID: {:02X?}", &data[0..3]);
691+
res = Err(EcError::DeviceError(format!(
692+
"INVALID: {:02X?}",
693+
&data[0..3]
694+
)));
695+
}
611696
}
612-
debug!("Expected 10 00 00 F7 and rest all FF");
613-
debug!("{:02X?}", data);
614697

615-
println!(" Read first 16 bytes of firmware.");
616-
// Make sure we can read at an offset and with arbitrary length
617-
let data = self.read_ec_flash(FLASH_PROGRAM_OFFSET, 16).unwrap();
618-
if data[0..4] != [0x50, 0x48, 0x43, 0x4D] {
619-
println!(" INVALID: {:02X?}", &data[0..3]);
620-
return Err(EcError::DeviceError(format!(
621-
"INVALID: {:02X?}",
622-
&data[0..3]
623-
)));
624-
}
625-
debug!("Expected beginning with 50 48 43 4D ('PHCM' in ASCII)");
626-
debug!("{:02X?}", data);
698+
// ===== Test 4 =====
699+
println!(" Read flash flags");
700+
let data = if has_mec() {
701+
self.read_ec_flash(MEC_FLASH_FLAGS, 0x80).unwrap()
702+
} else {
703+
self.read_ec_flash(NPC_FLASH_FLAGS, 0x80).unwrap()
704+
};
705+
let flash_flags_magic = [0xA3, 0xF1, 0x00, 0x00];
706+
let flash_flags_ver = [0x01, 0x0, 0x00, 0x00];
707+
// All 0xFF if just reflashed and not reinitialized by EC
708+
if data[0..4] == flash_flags_magic && data[8..12] == flash_flags_ver {
709+
println!(" Valid flash flags");
710+
} else if data.iter().all(|x| *x == 0xFF) {
711+
println!(" Erased flash flags");
712+
res = Err(EcError::DeviceError("Erased flash flags".to_string()));
713+
} else {
714+
println!(" INVALID flash flags: {:02X?}", &data[0..12]);
715+
// TODO: Disable error until I confirm flash flags on MEC
716+
// res = Err(EcError::DeviceError("INVALID flash flags".to_string()));
717+
}
627718

628719
self.flash_notify(MecFlashNotify::AccessSpiDone)?;
629-
Ok(())
720+
721+
res
630722
}
631723

632724
/// Requests recent console output from EC and constantly asks for more

framework_lib/src/chromium_ec/portio.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::chromium_ec::{EcError, EcResponseStatus, EcResult};
2-
use crate::smbios;
32
use alloc::format;
43
use alloc::string::ToString;
54
use alloc::vec;
@@ -15,16 +14,9 @@ use num::FromPrimitive;
1514
#[cfg(feature = "linux_pio")]
1615
use std::sync::{Arc, Mutex};
1716

18-
use crate::chromium_ec::portio_mec;
17+
use crate::chromium_ec::{has_mec, portio_mec};
1918
use crate::os_specific;
20-
use crate::util::{self, Platform};
21-
22-
fn has_mec() -> bool {
23-
!matches!(
24-
smbios::get_platform().unwrap(),
25-
Platform::Framework13Amd | Platform::Framework16
26-
)
27-
}
19+
use crate::util;
2820

2921
/*
3022
* Value written to legacy command port / prefix byte to indicate protocol

0 commit comments

Comments
 (0)