Skip to content

Commit 9e32643

Browse files
committed
chromium_ec: Allow flashing single EC FW
Only RO, only RW or both. Signed-off-by: Daniel Schaefer <[email protected]>
1 parent 1597082 commit 9e32643

File tree

4 files changed

+127
-51
lines changed

4 files changed

+127
-51
lines changed

framework_lib/src/chromium_ec/mod.rs

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ const FLASH_RW_BASE: u32 = 0x40000;
5959
const FLASH_RW_SIZE: u32 = 0x39000;
6060
const FLASH_PROGRAM_OFFSET: u32 = 0x1000;
6161

62+
#[derive(Clone, Debug, PartialEq)]
63+
pub enum EcFlashType {
64+
Full,
65+
Ro,
66+
Rw,
67+
}
68+
6269
#[derive(PartialEq)]
6370
pub enum MecFlashNotify {
6471
AccessSpi = 0x00,
@@ -237,11 +244,11 @@ impl CrosEc {
237244
};
238245

239246
Some((
240-
std::str::from_utf8(&v.version_string_rw)
247+
std::str::from_utf8(&v.version_string_ro)
241248
.ok()?
242249
.trim_end_matches(char::from(0))
243250
.to_string(),
244-
std::str::from_utf8(&v.version_string_ro)
251+
std::str::from_utf8(&v.version_string_rw)
245252
.ok()?
246253
.trim_end_matches(char::from(0))
247254
.to_string(),
@@ -368,49 +375,77 @@ impl CrosEc {
368375
}
369376

370377
/// Overwrite RO and RW regions of EC flash
371-
/// | Start | End | Size | Region |
372-
/// | 00000 | 3BFFF | 3C000 | RO Region |
373-
/// | 3C000 | 3FFFF | 04000 | Preserved |
374-
/// | 40000 | 3C000 | 39000 | RO Region |
375-
/// | 79000 | 79FFF | 07000 | Preserved |
376-
pub fn reflash(&self, data: &[u8]) -> EcResult<()> {
377-
let mut _flash_bin: Vec<u8> = Vec::with_capacity(EC_FLASH_SIZE);
378+
/// MEC/Legacy EC
379+
/// | Start | End | Size | Region |
380+
/// | 00000 | 3BFFF | 3C000 | RO Region |
381+
/// | 3C000 | 3FFFF | 04000 | Preserved |
382+
/// | 40000 | 3C000 | 39000 | RO Region |
383+
/// | 79000 | 79FFF | 01000 | Preserved |
384+
/// | 80000 | 80FFF | 01000 | Flash Flags |
385+
///
386+
/// NPC/Zephyr
387+
/// | Start | End | Size | Region |
388+
/// | 00000 | 3BFFF | 3C000 | RO Region |
389+
/// | 3C000 | 3FFFF | 04000 | Preserved |
390+
/// | 40000 | 3C000 | 39000 | RO Region |
391+
/// | 79000 | 79FFF | 01000 | Flash Flags |
392+
pub fn reflash(&self, data: &[u8], ft: EcFlashType) -> EcResult<()> {
393+
if ft == EcFlashType::Full || ft == EcFlashType::Ro {
394+
println!("For safety reasons flashing RO firmware is disabled.");
395+
return Ok(());
396+
}
397+
378398
println!("Unlocking flash");
379399
self.flash_notify(MecFlashNotify::AccessSpi)?;
380400
self.flash_notify(MecFlashNotify::FirmwareStart)?;
381401

382-
//println!("Erasing RO region");
383-
//self.erase_ec_flash(FLASH_BASE + FLASH_RO_BASE, FLASH_RO_SIZE)?;
384-
println!("Erasing RW region");
385-
self.erase_ec_flash(FLASH_BASE + FLASH_RW_BASE, FLASH_RW_SIZE)?;
402+
// TODO: Check if erase was successful
403+
// 1. First erase 0x10000 bytes
404+
// 2. Read back two rows and make sure it's all 0xFF
405+
// 3. Write each row (128B) individually
386406

387-
let ro_data = &data[FLASH_RO_BASE as usize..(FLASH_RO_BASE + FLASH_RO_SIZE) as usize];
388-
//println!("Writing RO region");
389-
//self.write_ec_flash(FLASH_BASE + FLASH_RO_BASE, ro_data);
407+
if ft == EcFlashType::Full || ft == EcFlashType::Rw {
408+
let rw_data = &data[FLASH_RW_BASE as usize..(FLASH_RW_BASE + FLASH_RW_SIZE) as usize];
390409

391-
let rw_data = &data[FLASH_RW_BASE as usize..(FLASH_RW_BASE + FLASH_RW_SIZE) as usize];
392-
println!("Writing RW region");
393-
self.write_ec_flash(FLASH_BASE + FLASH_RW_BASE, rw_data)?;
410+
println!("Erasing RW region");
411+
self.erase_ec_flash(FLASH_BASE + FLASH_RW_BASE, FLASH_RW_SIZE)?;
394412

395-
println!("Verifying");
396-
let flash_ro_data = self.read_ec_flash(FLASH_BASE + FLASH_RO_BASE, FLASH_RO_SIZE)?;
397-
if ro_data == flash_ro_data {
398-
println!("RO verify success");
399-
} else {
400-
println!("RO verify fail");
413+
println!("Writing RW region");
414+
self.write_ec_flash(FLASH_BASE + FLASH_RW_BASE, rw_data)?;
415+
416+
println!("Verifying RW region");
417+
let flash_rw_data = self.read_ec_flash(FLASH_BASE + FLASH_RW_BASE, FLASH_RW_SIZE)?;
418+
if rw_data == flash_rw_data {
419+
println!("RW verify success");
420+
} else {
421+
println!("RW verify fail");
422+
}
401423
}
402-
let flash_rw_data = self.read_ec_flash(FLASH_BASE + FLASH_RW_BASE, FLASH_RW_SIZE)?;
403-
if rw_data == flash_rw_data {
404-
println!("RW verify success");
405-
} else {
406-
println!("RW verify fail");
424+
425+
if ft == EcFlashType::Full || ft == EcFlashType::Ro {
426+
let ro_data = &data[FLASH_RO_BASE as usize..(FLASH_RO_BASE + FLASH_RO_SIZE) as usize];
427+
428+
println!("Erasing RO region");
429+
self.erase_ec_flash(FLASH_BASE + FLASH_RO_BASE, FLASH_RO_SIZE)?;
430+
431+
println!("Writing RO region");
432+
self.write_ec_flash(FLASH_BASE + FLASH_RO_BASE, ro_data)?;
433+
434+
println!("Verifying RO region");
435+
let flash_ro_data = self.read_ec_flash(FLASH_BASE + FLASH_RO_BASE, FLASH_RO_SIZE)?;
436+
if ro_data == flash_ro_data {
437+
println!("RO verify success");
438+
} else {
439+
println!("RO verify fail");
440+
}
407441
}
408442

409443
println!("Locking flash");
410444
self.flash_notify(MecFlashNotify::AccessSpiDone)?;
411445
self.flash_notify(MecFlashNotify::FirmwareDone)?;
412446

413447
println!("Flashing EC done. You can reboot the EC now");
448+
// TODO: Should we force a reboot if currently running one was reflashed?
414449

415450
Ok(())
416451
}

framework_lib/src/commandline/clap_std.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ struct ClapCli {
8585
#[arg(long)]
8686
flash_ec: Option<std::path::PathBuf>,
8787

88+
/// Flash EC with new RO firmware from file
89+
#[arg(long)]
90+
flash_ro_ec: Option<std::path::PathBuf>,
91+
92+
/// Flash EC with new RW firmware from file
93+
#[arg(long)]
94+
flash_rw_ec: Option<std::path::PathBuf>,
95+
8896
/// Show status of intrusion switch
8997
#[arg(long)]
9098
intrusion: bool,
@@ -170,6 +178,12 @@ pub fn parse(args: &[String]) -> Cli {
170178
flash_ec: args
171179
.flash_ec
172180
.map(|x| x.into_os_string().into_string().unwrap()),
181+
flash_ro_ec: args
182+
.flash_ro_ec
183+
.map(|x| x.into_os_string().into_string().unwrap()),
184+
flash_rw_ec: args
185+
.flash_rw_ec
186+
.map(|x| x.into_os_string().into_string().unwrap()),
173187
intrusion: args.intrusion,
174188
inputmodules: args.inputmodules,
175189
input_deck_mode: args.input_deck_mode,

framework_lib/src/commandline/mod.rs

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::chromium_ec;
3333
use crate::chromium_ec::commands::DeckStateMode;
3434
use crate::chromium_ec::commands::FpLedBrightnessLevel;
3535
use crate::chromium_ec::commands::RebootEcCmd;
36-
use crate::chromium_ec::print_err;
36+
use crate::chromium_ec::{print_err, EcFlashType};
3737
use crate::chromium_ec::{EcError, EcResult};
3838
#[cfg(feature = "linux")]
3939
use crate::csme;
@@ -131,6 +131,8 @@ pub struct Cli {
131131
pub ho2_capsule: Option<String>,
132132
pub dump_ec_flash: Option<String>,
133133
pub flash_ec: Option<String>,
134+
pub flash_ro_ec: Option<String>,
135+
pub flash_rw_ec: Option<String>,
134136
pub driver: Option<CrosEcDriverType>,
135137
pub test: bool,
136138
pub intrusion: bool,
@@ -396,25 +398,31 @@ fn print_esrt() {
396398
}
397399
}
398400

399-
#[cfg(feature = "uefi")]
400-
fn flash_ec(ec: &CrosEc, ec_bin_path: &str) {
401+
fn flash_ec(ec: &CrosEc, ec_bin_path: &str, flash_type: EcFlashType) {
401402
#[cfg(feature = "uefi")]
402403
let data = crate::uefi::fs::shell_read_file(ec_bin_path);
403404
#[cfg(not(feature = "uefi"))]
404-
let data = match fs::read(ec_bin_path) {
405-
Ok(data) => Some(data),
406-
// TODO: Perhaps a more user-friendly error
407-
Err(e) => {
408-
println!("Error {:?}", e);
409-
None
410-
}
405+
let data: Option<Vec<u8>> = {
406+
let _data = match fs::read(ec_bin_path) {
407+
Ok(data) => Some(data),
408+
// TODO: Perhaps a more user-friendly error
409+
Err(e) => {
410+
println!("Error {:?}", e);
411+
None
412+
}
413+
};
414+
415+
// EC communication from OS is not stable enough yet,
416+
// it can't be trusted to reliably flash the EC without risk of damage.
417+
println!("Sorry, flashing EC from the OS is not supported yet.");
418+
None
411419
};
412420

413421
if let Some(data) = data {
414422
println!("File");
415423
println!(" Size: {:>20} B", data.len());
416424
println!(" Size: {:>20} KB", data.len() / 1024);
417-
if let Err(err) = ec.reflash(&data) {
425+
if let Err(err) = ec.reflash(&data, flash_type) {
418426
println!("Error: {:?}", err);
419427
} else {
420428
println!("Success!");
@@ -708,15 +716,14 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
708716
}
709717
} else if let Some(dump_path) = &args.dump_ec_flash {
710718
println!("Dumping to {}", dump_path);
719+
// TODO: Should have progress indicator
711720
dump_ec_flash(&ec, dump_path);
712-
} else if let Some(_ec_bin_path) = &args.flash_ec {
713-
// EC communication from OS is not stable enough yet,
714-
// it can't be trusted to reliably flash the EC without risk of damage.
715-
#[cfg(not(feature = "uefi"))]
716-
println!("Sorry, flashing EC from the OS is not supported yet.");
717-
718-
#[cfg(feature = "uefi")]
719-
flash_ec(&ec, _ec_bin_path);
721+
} else if let Some(ec_bin_path) = &args.flash_ec {
722+
flash_ec(&ec, ec_bin_path, EcFlashType::Full);
723+
} else if let Some(ec_bin_path) = &args.flash_ro_ec {
724+
flash_ec(&ec, ec_bin_path, EcFlashType::Ro);
725+
} else if let Some(ec_bin_path) = &args.flash_rw_ec {
726+
flash_ec(&ec, ec_bin_path, EcFlashType::Rw);
720727
} else if let Some(hash_file) = &args.hash {
721728
println!("Hashing file: {}", hash_file);
722729
#[cfg(feature = "uefi")]
@@ -764,6 +771,9 @@ Options:
764771
--pd-bin <PD_BIN> Parse versions from PD firmware binary file
765772
--ec-bin <EC_BIN> Parse versions from EC firmware binary file
766773
--capsule <CAPSULE> Parse UEFI Capsule information from binary file
774+
--flash-ec <FLASH_EC> Flash EC with new firmware from file
775+
--flash-ro-ec <FLASH_EC> Flash EC with new firmware from file
776+
--flash-rw-ec <FLASH_EC> Flash EC with new firmware from file
767777
--intrusion Show status of intrusion switch
768778
--inputmodules Show status of the input modules (Framework 16 only)
769779
--charge-limit [<VAL>] Get or set battery charge limit (Percentage number as arg, e.g. '100')
@@ -772,7 +782,6 @@ Options:
772782
--console <CONSOLE> Get EC console, choose whether recent or to follow the output [possible values: recent, follow]
773783
--reboot-ec Control EC RO/RW jump [possible values: reboot, jump-ro, jump-rw, cancel-jump, disable-jump]
774784
--dump-ec-flash <DUMP_EC_FLASH> Dump EC flash contents
775-
--flash-ec <FLASH_EC> Flash EC with new firmware from file
776785
-t, --test Run self-test to check if interaction with EC is possible
777786
-h, --help Print help information
778787
"#

framework_lib/src/commandline/uefi.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ pub fn parse(args: &[String]) -> Cli {
6969
ec_bin: None,
7070
dump_ec_flash: None,
7171
flash_ec: None,
72+
flash_ro_ec: None,
73+
flash_rw_ec: None,
7274
capsule: None,
7375
dump: None,
7476
ho2_capsule: None,
@@ -306,7 +308,23 @@ pub fn parse(args: &[String]) -> Cli {
306308
cli.flash_ec = if args.len() > i + 1 {
307309
Some(args[i + 1].clone())
308310
} else {
309-
println!("--flash_ec requires extra argument to denote input file");
311+
println!("--flash-ec requires extra argument to denote input file");
312+
None
313+
};
314+
found_an_option = true;
315+
} else if arg == "--flash-ro-ec" {
316+
cli.flash_ro_ec = if args.len() > i + 1 {
317+
Some(args[i + 1].clone())
318+
} else {
319+
println!("--flash-ro-ec requires extra argument to denote input file");
320+
None
321+
};
322+
found_an_option = true;
323+
} else if arg == "--flash-rw-ec" {
324+
cli.flash_rw_ec = if args.len() > i + 1 {
325+
Some(args[i + 1].clone())
326+
} else {
327+
println!("--flash-rw-ec requires extra argument to denote input file");
310328
None
311329
};
312330
found_an_option = true;

0 commit comments

Comments
 (0)