Skip to content

Commit a3ccff9

Browse files
committed
Implement firmware flashing for EC
1 parent b02a98e commit a3ccff9

File tree

2 files changed

+165
-15
lines changed

2 files changed

+165
-15
lines changed

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/ec.rs

Lines changed: 160 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use ecflash::{Ec, EcFile, EcFlash};
22
use ectool::{
33
Firmware,
4+
Spi,
5+
SpiRom,
6+
SpiTarget,
47
Timeout,
58
};
69
use std::{
@@ -39,6 +42,96 @@ impl Timeout for UefiTimeout {
3942
}
4043
}
4144

45+
unsafe fn flash_read<S: Spi>(spi: &mut SpiRom<S, UefiTimeout>, rom: &mut [u8], sector_size: usize) -> core::result::Result<(), ectool::Error> {
46+
let mut address = 0;
47+
while address < rom.len() {
48+
print!("\rSPI Read {}K", address / 1024);
49+
let next_address = address + sector_size;
50+
let count = spi.read_at(address as u32, &mut rom[address..next_address])?;
51+
if count != sector_size {
52+
println!("\ncount {} did not match sector size {}", count, sector_size);
53+
return Err(ectool::Error::Verify);
54+
}
55+
address = next_address;
56+
}
57+
println!("\rSPI Read {}K", address / 1024);
58+
Ok(())
59+
}
60+
61+
unsafe fn flash_inner(ec: &mut ectool::Ec<UefiTimeout>, firmware: &Firmware, target: SpiTarget, scratch: bool) -> core::result::Result<(), ectool::Error> {
62+
let rom_size = 128 * 1024;
63+
let sector_size = 1024;
64+
65+
let mut new_rom = firmware.data.to_vec();
66+
while new_rom.len() < rom_size {
67+
new_rom.push(0xFF);
68+
}
69+
70+
let mut spi_bus = ec.spi(target, scratch)?;
71+
let mut spi = SpiRom::new(
72+
&mut spi_bus,
73+
UefiTimeout::new(1_000_000)
74+
);
75+
76+
let mut rom = vec![0xFF; rom_size];
77+
flash_read(&mut spi, &mut rom, sector_size)?;
78+
79+
// Program chip, sector by sector
80+
//TODO: write signature last
81+
{
82+
let mut address = 0;
83+
while address < rom_size {
84+
print!("\rSPI Write {}K", address / 1024);
85+
86+
let next_address = address + sector_size;
87+
88+
let mut matches = true;
89+
let mut erased = true;
90+
let mut new_erased = true;
91+
for i in address..next_address {
92+
if rom[i] != new_rom[i] {
93+
matches = false;
94+
}
95+
if rom[i] != 0xFF {
96+
erased = false;
97+
}
98+
if new_rom[i] != 0xFF {
99+
new_erased = false;
100+
}
101+
}
102+
103+
if ! matches {
104+
if ! erased {
105+
spi.erase_sector(address as u32)?;
106+
}
107+
if ! new_erased {
108+
let count = spi.write_at(address as u32, &new_rom[address..next_address])?;
109+
if count != sector_size {
110+
println!("\nWrite count {} did not match sector size {}", count, sector_size);
111+
return Err(ectool::Error::Verify);
112+
}
113+
}
114+
}
115+
116+
address = next_address;
117+
}
118+
println!("\rSPI Write {}K", address / 1024);
119+
120+
// Verify chip write
121+
flash_read(&mut spi, &mut rom, sector_size)?;
122+
for i in 0..rom.len() {
123+
if rom[i] != new_rom[i] {
124+
println!("Failed to program: {:X} is {:X} instead of {:X}", i, rom[i], new_rom[i]);
125+
return Err(ectool::Error::Verify);
126+
}
127+
}
128+
}
129+
130+
println!("Successfully programmed SPI ROM");
131+
132+
Ok(())
133+
}
134+
42135
enum EcKind {
43136
System76(ectool::Ec<UefiTimeout>),
44137
Legacy(EcFlash),
@@ -47,7 +140,7 @@ enum EcKind {
47140

48141
impl EcKind {
49142
unsafe fn new(primary: bool) -> Self {
50-
if let Ok(ec) = ectool::Ec::new(primary, UefiTimeout::new(100_000)) {
143+
if let Ok(ec) = ectool::Ec::new(UefiTimeout::new(100_000)) {
51144
return EcKind::System76(ec);
52145
}
53146

@@ -98,7 +191,7 @@ impl EcKind {
98191
match self {
99192
EcKind::System76(_) => {
100193
if let Some(firmware) = Firmware::new(&data) {
101-
if let Ok(string) = str::from_utf8(firmware.version) {
194+
if let Ok(string) = str::from_utf8(firmware.board) {
102195
return string.to_string();
103196
}
104197
}
@@ -136,10 +229,61 @@ impl EcComponent {
136229
}
137230

138231
pub fn validate_data(&self, data: Vec<u8>) -> bool {
232+
let firmware_model = self.ec.firmware_model(data);
139233
! self.model.is_empty() &&
140234
! self.version.is_empty() &&
141-
self.ec.firmware_model(data) == self.model
235+
firmware_model == self.model
236+
}
237+
}
238+
239+
unsafe fn flash(firmware_data: &[u8]) -> core::result::Result<(), ectool::Error> {
240+
let target = SpiTarget::Main;
241+
let scratch = true;
242+
243+
let firmware = match Firmware::new(&firmware_data) {
244+
Some(some) => some,
245+
None => {
246+
println!("failed to parse firmware");
247+
return Err(ectool::Error::Verify);
248+
}
249+
};
250+
println!("file board: {:?}", str::from_utf8(firmware.board));
251+
println!("file version: {:?}", str::from_utf8(firmware.version));
252+
253+
let mut ec = ectool::Ec::new(UefiTimeout::new(1_000_000))?;
254+
255+
{
256+
let mut data = [0; 256];
257+
let size = ec.board(&mut data)?;
258+
259+
let ec_board = &data[..size];
260+
println!("ec board: {:?}", str::from_utf8(ec_board));
261+
262+
if ec_board != firmware.board {
263+
println!("file board does not match ec board");
264+
return Err(ectool::Error::Verify);
265+
}
266+
}
267+
268+
{
269+
let mut data = [0; 256];
270+
let size = ec.version(&mut data)?;
271+
272+
let ec_version = &data[..size];
273+
println!("ec version: {:?}", str::from_utf8(ec_version));
142274
}
275+
276+
let res = flash_inner(&mut ec, &firmware, target, scratch);
277+
println!("Result: {:X?}", res);
278+
279+
if scratch {
280+
println!("System will shut off in 5 seconds");
281+
let _ = (std::system_table().BootServices.Stall)(5_000_000);
282+
283+
ec.reset()?;
284+
}
285+
286+
res
143287
}
144288

145289
impl Component for EcComponent {
@@ -175,8 +319,14 @@ impl Component for EcComponent {
175319
fn flash(&self) -> Result<()> {
176320
match &self.ec {
177321
EcKind::System76(_) => {
178-
println!("{} Failed to flash EcKind::System76", self.name());
179-
return Err(Error::DeviceError);
322+
let firmware_data = load(self.path())?;
323+
match unsafe { flash(&firmware_data) } {
324+
Ok(()) => Ok(()),
325+
Err(err) => {
326+
println!("{} Flash Error: {:X?}", self.name(), err);
327+
Err(Error::DeviceError)
328+
}
329+
}
180330
},
181331
EcKind::Legacy(_) => {
182332
find(FIRMWARENSH)?;
@@ -188,16 +338,16 @@ impl Component for EcComponent {
188338
};
189339

190340
let status = shell(&cmd)?;
191-
if status != 0 {
341+
if status == 0 {
342+
Ok(())
343+
} else {
192344
println!("{} Flash Error: {}", self.name(), status);
193-
return Err(Error::DeviceError);
345+
Err(Error::DeviceError)
194346
}
195-
196-
Ok(())
197347
},
198348
EcKind::Unknown => {
199349
println!("{} Failed to flash EcKind::Unknown", self.name());
200-
return Err(Error::DeviceError);
350+
Err(Error::DeviceError)
201351
},
202352
}
203353
}

0 commit comments

Comments
 (0)