Skip to content

Commit ff8db28

Browse files
authored
Verify (#16)
* Implement Verify * Simplify a bit
1 parent 499d17a commit ff8db28

File tree

6 files changed

+133
-25
lines changed

6 files changed

+133
-25
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ edition = "2018"
55
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
66

77
[dependencies]
8-
panic-never = "0.1.0"
8+
panic-never = "0.1.0"
99
ufmt = { version = "0.1.0", optional = true }
1010

1111

ld/esp32.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ MEMORY {
22
/* Middle of SRAM0 */
33
IRAM : ORIGIN = 0x40090000, LENGTH = 0x10000
44
}
5+
56
/*
67
ESP32 ROM address table
78
Generated for ROM with MD5sum:

src/api.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ pub unsafe extern "C" fn ProgramPage(adr: u32, sz: u32, buf: *const u8) -> i32 {
2222
crate::ProgramPage_impl(adr, sz, buf)
2323
}
2424

25+
#[no_mangle]
26+
pub unsafe extern "C" fn Verify(adr: u32, sz: u32, buf: *const u8) -> i32 {
27+
crate::Verify_impl(adr, sz, buf)
28+
}
29+
2530
#[no_mangle]
2631
pub unsafe extern "C" fn ReadFlash(adr: u32, sz: u32, buf: *mut u8) -> i32 {
2732
crate::ReadFlash_impl(adr, sz, buf)

src/api_xtensa.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,23 @@ pub unsafe extern "C" fn ProgramPage(adr: u32, sz: u32, buf: *const u8) -> i32 {
8686
)
8787
}
8888

89+
#[no_mangle]
90+
#[naked]
91+
pub unsafe extern "C" fn Verify(adr: u32, sz: u32, buf: *const u8) -> i32 {
92+
asm!(
93+
"
94+
.global Verify_impl
95+
l32r a1, STACK_PTR
96+
mov.n a6, a2
97+
mov.n a7, a3
98+
mov.n a8, a4
99+
call4 Verify_impl
100+
mov.n a2, a6
101+
",
102+
options(noreturn)
103+
)
104+
}
105+
89106
#[no_mangle]
90107
#[naked]
91108
pub unsafe extern "C" fn ReadFlash(adr: u32, sz: u32, buf: *mut u8) -> i32 {

src/main.rs

Lines changed: 103 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ pub unsafe extern "C" fn ProgramPage_impl(adr: u32, sz: u32, buf: *const u8) ->
178178
}
179179

180180
#[no_mangle]
181-
pub unsafe extern "C" fn ReadFlash_impl(adr: u32, sz: u32, buf: *mut u8) -> i32 {
181+
pub unsafe extern "C" fn Verify_impl(adr: u32, sz: u32, buf: *const u8) -> i32 {
182182
if !is_inited() {
183183
return ERROR_BASE_INTERNAL - 1;
184184
};
@@ -188,26 +188,44 @@ pub unsafe extern "C" fn ReadFlash_impl(adr: u32, sz: u32, buf: *mut u8) -> i32
188188
return ERROR_BASE_INTERNAL - 5;
189189
}
190190

191-
dprintln!("READ FLASH {} bytes @ {}", sz, adr);
191+
dprintln!("PROGRAM {} bytes @ {}", sz, adr);
192192

193-
let buffer = core::slice::from_raw_parts_mut(buf, sz as usize);
194-
crate::flash::read_flash(adr, buffer)
193+
let input = core::slice::from_raw_parts(buf, sz as usize);
194+
195+
(*DECOMPRESSOR).verify(adr, input)
195196
}
196197

197198
#[no_mangle]
198-
pub unsafe extern "C" fn UnInit_impl(_fnc: u32) -> i32 {
199+
pub unsafe extern "C" fn ReadFlash_impl(adr: u32, sz: u32, buf: *mut u8) -> i32 {
199200
if !is_inited() {
200201
return ERROR_BASE_INTERNAL - 1;
201202
};
202203

203-
(*DECOMPRESSOR).flush();
204+
if (buf as u32) % 4 != 0 {
205+
dprintln!("ERROR buf not word aligned");
206+
return ERROR_BASE_INTERNAL - 5;
207+
}
208+
209+
dprintln!("READ FLASH {} bytes @ {}", sz, adr);
210+
211+
let buf = core::slice::from_raw_parts_mut(buf, sz as usize);
212+
crate::flash::read_flash(adr, buf)
213+
}
204214

205-
// The flash ROM functions don't wait for the end of the last operation.
206-
let r = flash::wait_for_idle();
215+
#[no_mangle]
216+
pub unsafe extern "C" fn UnInit_impl(fnc: u32) -> i32 {
217+
if !is_inited() {
218+
return ERROR_BASE_INTERNAL - 1;
219+
};
207220

208221
*INITED = 0;
209222

210-
r
223+
if fnc == 2 {
224+
// The flash ROM functions don't wait for the end of the last operation.
225+
flash::wait_for_idle()
226+
} else {
227+
0
228+
}
211229
}
212230

213231
pub struct Decompressor {
@@ -239,7 +257,7 @@ impl Decompressor {
239257
self.output.take(|_| {});
240258
}
241259

242-
fn decompress(&mut self, input: &[u8]) -> i32 {
260+
fn decompress(&mut self, input: &[u8], process: fn(u32, &[u8]) -> i32) -> i32 {
243261
if self.remaining_compressed == 0 {
244262
return ERROR_BASE_INTERNAL - 3;
245263
}
@@ -262,7 +280,7 @@ impl Decompressor {
262280
if status == TINFL_STATUS_DONE as i32 || self.output.full() {
263281
// We're either finished or the decompressor can't continue
264282
// until we flush the buffer.
265-
let flush_status = self.flush();
283+
let flush_status = self.flush(process);
266284

267285
if flush_status < 0 {
268286
return ERROR_BASE_FLASH + flush_status;
@@ -277,26 +295,29 @@ impl Decompressor {
277295
}
278296
}
279297

280-
pub fn flush(&mut self) -> i32 {
298+
pub fn flush(&mut self, process: fn(address: u32, data: &[u8]) -> i32) -> i32 {
281299
let mut offset = self.offset;
282300
let address = self.image_start + offset;
283301

284302
// Take buffer contents, write to flash and update offset.
285303
let status = self.output.take(|data| {
286304
offset += data.len() as u32;
287-
crate::flash::write_flash(address, data)
305+
306+
process(address, data)
288307
});
289308

290309
self.offset = offset;
291310

292311
status
293312
}
294313

295-
pub fn program(&mut self, address: u32, mut data: &[u8]) -> i32 {
314+
fn handle_compressed(
315+
&mut self,
316+
address: u32,
317+
mut data: &[u8],
318+
process: fn(u32, &[u8]) -> i32,
319+
) -> i32 {
296320
if self.image_start != address {
297-
// Finish previous image
298-
self.flush();
299-
300321
if data.len() < 4 {
301322
// We don't have enough bytes to read the length
302323
return ERROR_BASE_INTERNAL - 4;
@@ -315,6 +336,70 @@ impl Decompressor {
315336

316337
self.reinit(address, compressed_length);
317338
}
318-
self.decompress(data)
339+
self.decompress(data, process)
340+
}
341+
342+
pub fn program(&mut self, address: u32, data: &[u8]) -> i32 {
343+
self.handle_compressed(address, data, write_to_flash)
344+
}
345+
346+
pub fn verify(&mut self, address: u32, data: &[u8]) -> i32 {
347+
// We're supposed to return the address up to which we've verified.
348+
// However, we process compressed data and the caller expects us to respond in terms of
349+
// compressed offsets, so we don't actually know where comparison fails.
350+
let status = if self.handle_compressed(address, data, verify_flash) == 0 {
351+
address + data.len() as u32
352+
} else {
353+
address
354+
};
355+
356+
status as i32
357+
}
358+
}
359+
360+
fn write_to_flash(address: u32, data: &[u8]) -> i32 {
361+
let status = crate::flash::write_flash(address, data);
362+
363+
if status < 0 {
364+
return ERROR_BASE_FLASH + status;
365+
}
366+
367+
0
368+
}
369+
370+
fn verify_flash(mut address: u32, mut data: &[u8]) -> i32 {
371+
const READBACK_BUFFER: usize = 256;
372+
let mut readback = unsafe {
373+
let mut buf = core::mem::MaybeUninit::<[u8; READBACK_BUFFER]>::uninit();
374+
for i in 0..READBACK_BUFFER {
375+
buf.as_mut_ptr().cast::<u8>().write_volatile(i as u8);
376+
}
377+
buf.assume_init()
378+
};
379+
380+
while !data.is_empty() {
381+
let chunk_size = READBACK_BUFFER.min(data.len());
382+
let (slice, rest) = unsafe {
383+
// SAFETY: skip is always at most `data.len()`
384+
data.split_at_unchecked(chunk_size)
385+
};
386+
data = rest;
387+
388+
let readback_slice = &mut readback[..chunk_size];
389+
390+
let status = crate::flash::read_flash(address, readback_slice);
391+
if status < 0 {
392+
return -1;
393+
}
394+
395+
for (a, b) in slice.iter().zip(readback_slice.iter()) {
396+
if a != b {
397+
return -1;
398+
}
399+
}
400+
401+
address += chunk_size as u32;
319402
}
403+
404+
0
320405
}

0 commit comments

Comments
 (0)