14
14
///!
15
15
mod fmt;
16
16
17
- use embedded_storage:: nor_flash:: { NorFlash , ReadNorFlash } ;
17
+ use embedded_storage:: nor_flash:: { NorFlash , NorFlashError , NorFlashErrorKind , ReadNorFlash } ;
18
18
use embedded_storage_async:: nor_flash:: AsyncNorFlash ;
19
19
20
20
pub const BOOT_MAGIC : u32 = 0xD00DF00D ;
@@ -44,18 +44,41 @@ pub enum State {
44
44
}
45
45
46
46
#[ derive( PartialEq , Debug ) ]
47
- #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
48
- pub enum BootError < E > {
49
- Flash ( E ) ,
47
+ pub enum BootError {
48
+ Flash ( NorFlashErrorKind ) ,
50
49
BadMagic ,
51
50
}
52
51
53
- impl < E > From < E > for BootError < E > {
52
+ impl < E > From < E > for BootError
53
+ where
54
+ E : NorFlashError ,
55
+ {
54
56
fn from ( error : E ) -> Self {
55
- BootError :: Flash ( error)
57
+ BootError :: Flash ( error. kind ( ) )
56
58
}
57
59
}
58
60
61
+ pub trait FlashConfig {
62
+ const BLOCK_SIZE : usize ;
63
+ type FLASH : NorFlash + ReadNorFlash ;
64
+
65
+ fn flash ( & mut self ) -> & mut Self :: FLASH ;
66
+ }
67
+
68
+ /// Trait defining the flash handles used for active and DFU partition
69
+ pub trait FlashProvider {
70
+ type STATE : FlashConfig ;
71
+ type ACTIVE : FlashConfig ;
72
+ type DFU : FlashConfig ;
73
+
74
+ /// Return flash instance used to write/read to/from active partition.
75
+ fn active ( & mut self ) -> & mut Self :: ACTIVE ;
76
+ /// Return flash instance used to write/read to/from dfu partition.
77
+ fn dfu ( & mut self ) -> & mut Self :: DFU ;
78
+ /// Return flash instance used to write/read to/from bootloader state.
79
+ fn state ( & mut self ) -> & mut Self :: STATE ;
80
+ }
81
+
59
82
/// BootLoader works with any flash implementing embedded_storage and can also work with
60
83
/// different page sizes.
61
84
pub struct BootLoader < const PAGE_SIZE : usize > {
@@ -168,45 +191,44 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
168
191
/// | DFU | 3 | 3 | 2 | 1 | 3 |
169
192
/// +-----------+--------------+--------+--------+--------+--------+
170
193
///
171
- pub fn prepare_boot < F : NorFlash + ReadNorFlash > (
172
- & mut self ,
173
- flash : & mut F ,
174
- ) -> Result < State , BootError < F :: Error > > {
194
+ pub fn prepare_boot < P : FlashProvider > ( & mut self , p : & mut P ) -> Result < State , BootError > {
175
195
// Copy contents from partition N to active
176
- let state = self . read_state ( flash ) ?;
196
+ let state = self . read_state ( p . state ( ) ) ?;
177
197
match state {
178
198
State :: Swap => {
179
199
//
180
200
// Check if we already swapped. If we're in the swap state, this means we should revert
181
201
// since the app has failed to mark boot as successful
182
202
//
183
- if !self . is_swapped ( flash ) ? {
203
+ if !self . is_swapped ( p . state ( ) ) ? {
184
204
trace ! ( "Swapping" ) ;
185
- self . swap ( flash ) ?;
205
+ self . swap ( p ) ?;
186
206
} else {
187
207
trace ! ( "Reverting" ) ;
188
- self . revert ( flash ) ?;
208
+ self . revert ( p ) ?;
189
209
190
210
// Overwrite magic and reset progress
191
- flash. write ( self . state . from as u32 , & [ 0 , 0 , 0 , 0 ] ) ?;
192
- flash. erase ( self . state . from as u32 , self . state . to as u32 ) ?;
193
- flash. write ( self . state . from as u32 , & BOOT_MAGIC . to_le_bytes ( ) ) ?;
211
+ let fstate = p. state ( ) . flash ( ) ;
212
+ fstate. write ( self . state . from as u32 , & [ 0 , 0 , 0 , 0 ] ) ?;
213
+ fstate. erase ( self . state . from as u32 , self . state . to as u32 ) ?;
214
+ fstate. write ( self . state . from as u32 , & BOOT_MAGIC . to_le_bytes ( ) ) ?;
194
215
}
195
216
}
196
217
_ => { }
197
218
}
198
219
Ok ( state)
199
220
}
200
221
201
- fn is_swapped < F : ReadNorFlash > ( & mut self , flash : & mut F ) -> Result < bool , F :: Error > {
222
+ fn is_swapped < P : FlashConfig > ( & mut self , p : & mut P ) -> Result < bool , BootError > {
202
223
let page_count = self . active . len ( ) / PAGE_SIZE ;
203
- let progress = self . current_progress ( flash ) ?;
224
+ let progress = self . current_progress ( p ) ?;
204
225
205
226
Ok ( progress >= page_count * 2 )
206
227
}
207
228
208
- fn current_progress < F : ReadNorFlash > ( & mut self , flash : & mut F ) -> Result < usize , F :: Error > {
229
+ fn current_progress < P : FlashConfig > ( & mut self , p : & mut P ) -> Result < usize , BootError > {
209
230
let max_index = ( ( self . state . len ( ) - 4 ) / 4 ) - 1 ;
231
+ let flash = p. flash ( ) ;
210
232
for i in 0 ..max_index {
211
233
let mut buf: [ u8 ; 4 ] = [ 0 ; 4 ] ;
212
234
flash. read ( ( self . state . from + 4 + i * 4 ) as u32 , & mut buf) ?;
@@ -217,7 +239,8 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
217
239
Ok ( max_index)
218
240
}
219
241
220
- fn update_progress < F : NorFlash > ( & mut self , idx : usize , flash : & mut F ) -> Result < ( ) , F :: Error > {
242
+ fn update_progress < P : FlashConfig > ( & mut self , idx : usize , p : & mut P ) -> Result < ( ) , BootError > {
243
+ let flash = p. flash ( ) ;
221
244
let w = self . state . from + 4 + idx * 4 ;
222
245
flash. write ( w as u32 , & [ 0 , 0 , 0 , 0 ] ) ?;
223
246
Ok ( ( ) )
@@ -231,62 +254,104 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
231
254
self . dfu . from + n * PAGE_SIZE
232
255
}
233
256
234
- fn copy_page_once < F : NorFlash + ReadNorFlash > (
257
+ fn copy_page_once_to_active < P : FlashProvider > (
235
258
& mut self ,
236
259
idx : usize ,
237
- from : usize ,
238
- to : usize ,
239
- flash : & mut F ,
240
- ) -> Result < ( ) , F :: Error > {
260
+ from_page : usize ,
261
+ to_page : usize ,
262
+ p : & mut P ,
263
+ ) -> Result < ( ) , BootError > {
264
+ let mut buf: [ u8 ; PAGE_SIZE ] = [ 0 ; PAGE_SIZE ] ;
265
+ if self . current_progress ( p. state ( ) ) ? <= idx {
266
+ let mut offset = from_page;
267
+ for chunk in buf. chunks_mut ( P :: DFU :: BLOCK_SIZE ) {
268
+ p. dfu ( ) . flash ( ) . read ( offset as u32 , chunk) ?;
269
+ offset += chunk. len ( ) ;
270
+ }
271
+
272
+ p. active ( )
273
+ . flash ( )
274
+ . erase ( to_page as u32 , ( to_page + PAGE_SIZE ) as u32 ) ?;
275
+
276
+ let mut offset = to_page;
277
+ for chunk in buf. chunks ( P :: ACTIVE :: BLOCK_SIZE ) {
278
+ p. active ( ) . flash ( ) . write ( offset as u32 , & chunk) ?;
279
+ offset += chunk. len ( ) ;
280
+ }
281
+ self . update_progress ( idx, p. state ( ) ) ?;
282
+ }
283
+ Ok ( ( ) )
284
+ }
285
+
286
+ fn copy_page_once_to_dfu < P : FlashProvider > (
287
+ & mut self ,
288
+ idx : usize ,
289
+ from_page : usize ,
290
+ to_page : usize ,
291
+ p : & mut P ,
292
+ ) -> Result < ( ) , BootError > {
241
293
let mut buf: [ u8 ; PAGE_SIZE ] = [ 0 ; PAGE_SIZE ] ;
242
- if self . current_progress ( flash) ? <= idx {
243
- flash. read ( from as u32 , & mut buf) ?;
244
- flash. erase ( to as u32 , ( to + PAGE_SIZE ) as u32 ) ?;
245
- flash. write ( to as u32 , & buf) ?;
246
- self . update_progress ( idx, flash) ?;
294
+ if self . current_progress ( p. state ( ) ) ? <= idx {
295
+ let mut offset = from_page;
296
+ for chunk in buf. chunks_mut ( P :: ACTIVE :: BLOCK_SIZE ) {
297
+ p. active ( ) . flash ( ) . read ( offset as u32 , chunk) ?;
298
+ offset += chunk. len ( ) ;
299
+ }
300
+
301
+ p. dfu ( )
302
+ . flash ( )
303
+ . erase ( to_page as u32 , ( to_page + PAGE_SIZE ) as u32 ) ?;
304
+
305
+ let mut offset = to_page;
306
+ for chunk in buf. chunks ( P :: DFU :: BLOCK_SIZE ) {
307
+ p. dfu ( ) . flash ( ) . write ( offset as u32 , chunk) ?;
308
+ offset += chunk. len ( ) ;
309
+ }
310
+ self . update_progress ( idx, p. state ( ) ) ?;
247
311
}
248
312
Ok ( ( ) )
249
313
}
250
314
251
- fn swap < F : NorFlash + ReadNorFlash > ( & mut self , flash : & mut F ) -> Result < ( ) , F :: Error > {
315
+ fn swap < P : FlashProvider > ( & mut self , p : & mut P ) -> Result < ( ) , BootError > {
252
316
let page_count = self . active . len ( ) / PAGE_SIZE ;
253
317
// trace!("Page count: {}", page_count);
254
318
for page in 0 ..page_count {
255
319
// Copy active page to the 'next' DFU page.
256
320
let active_page = self . active_addr ( page_count - 1 - page) ;
257
321
let dfu_page = self . dfu_addr ( page_count - page) ;
258
- // info!("Copy active {} to dfu {}", active_page, dfu_page);
259
- self . copy_page_once ( page * 2 , active_page, dfu_page, flash ) ?;
322
+ info ! ( "Copy active {} to dfu {}" , active_page, dfu_page) ;
323
+ self . copy_page_once_to_dfu ( page * 2 , active_page, dfu_page, p ) ?;
260
324
261
325
// Copy DFU page to the active page
262
326
let active_page = self . active_addr ( page_count - 1 - page) ;
263
327
let dfu_page = self . dfu_addr ( page_count - 1 - page) ;
264
- // info!("Copy dfy {} to active {}", dfu_page, active_page);
265
- self . copy_page_once ( page * 2 + 1 , dfu_page, active_page, flash ) ?;
328
+ info ! ( "Copy dfy {} to active {}" , dfu_page, active_page) ;
329
+ self . copy_page_once_to_active ( page * 2 + 1 , dfu_page, active_page, p ) ?;
266
330
}
267
331
268
332
Ok ( ( ) )
269
333
}
270
334
271
- fn revert < F : NorFlash + ReadNorFlash > ( & mut self , flash : & mut F ) -> Result < ( ) , F :: Error > {
335
+ fn revert < P : FlashProvider > ( & mut self , p : & mut P ) -> Result < ( ) , BootError > {
272
336
let page_count = self . active . len ( ) / PAGE_SIZE ;
273
337
for page in 0 ..page_count {
274
338
// Copy the bad active page to the DFU page
275
339
let active_page = self . active_addr ( page) ;
276
340
let dfu_page = self . dfu_addr ( page) ;
277
- self . copy_page_once ( page_count * 2 + page * 2 , active_page, dfu_page, flash ) ?;
341
+ self . copy_page_once_to_dfu ( page_count * 2 + page * 2 , active_page, dfu_page, p ) ?;
278
342
279
343
// Copy the DFU page back to the active page
280
344
let active_page = self . active_addr ( page) ;
281
345
let dfu_page = self . dfu_addr ( page + 1 ) ;
282
- self . copy_page_once ( page_count * 2 + page * 2 + 1 , dfu_page, active_page, flash ) ?;
346
+ self . copy_page_once_to_active ( page_count * 2 + page * 2 + 1 , dfu_page, active_page, p ) ?;
283
347
}
284
348
285
349
Ok ( ( ) )
286
350
}
287
351
288
- fn read_state < F : ReadNorFlash > ( & mut self , flash : & mut F ) -> Result < State , BootError < F :: Error > > {
352
+ fn read_state < P : FlashConfig > ( & mut self , p : & mut P ) -> Result < State , BootError > {
289
353
let mut magic: [ u8 ; 4 ] = [ 0 ; 4 ] ;
354
+ let flash = p. flash ( ) ;
290
355
flash. read ( self . state . from as u32 , & mut magic) ?;
291
356
292
357
match u32:: from_le_bytes ( magic) {
@@ -296,6 +361,62 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
296
361
}
297
362
}
298
363
364
+ /// Convenience provider that uses a single flash for everything
365
+ pub struct SingleFlashProvider < ' a , F >
366
+ where
367
+ F : NorFlash + ReadNorFlash ,
368
+ {
369
+ config : SingleFlashConfig < ' a , F > ,
370
+ }
371
+
372
+ impl < ' a , F > SingleFlashProvider < ' a , F >
373
+ where
374
+ F : NorFlash + ReadNorFlash ,
375
+ {
376
+ pub fn new ( flash : & ' a mut F ) -> Self {
377
+ Self {
378
+ config : SingleFlashConfig { flash } ,
379
+ }
380
+ }
381
+ }
382
+
383
+ pub struct SingleFlashConfig < ' a , F >
384
+ where
385
+ F : NorFlash + ReadNorFlash ,
386
+ {
387
+ flash : & ' a mut F ,
388
+ }
389
+
390
+ impl < ' a , F > FlashProvider for SingleFlashProvider < ' a , F >
391
+ where
392
+ F : NorFlash + ReadNorFlash ,
393
+ {
394
+ type STATE = SingleFlashConfig < ' a , F > ;
395
+ type ACTIVE = SingleFlashConfig < ' a , F > ;
396
+ type DFU = SingleFlashConfig < ' a , F > ;
397
+
398
+ fn active ( & mut self ) -> & mut Self :: STATE {
399
+ & mut self . config
400
+ }
401
+ fn dfu ( & mut self ) -> & mut Self :: ACTIVE {
402
+ & mut self . config
403
+ }
404
+ fn state ( & mut self ) -> & mut Self :: DFU {
405
+ & mut self . config
406
+ }
407
+ }
408
+
409
+ impl < ' a , F > FlashConfig for SingleFlashConfig < ' a , F >
410
+ where
411
+ F : NorFlash + ReadNorFlash ,
412
+ {
413
+ const BLOCK_SIZE : usize = F :: ERASE_SIZE ;
414
+ type FLASH = F ;
415
+ fn flash ( & mut self ) -> & mut F {
416
+ self . flash
417
+ }
418
+ }
419
+
299
420
/// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to
300
421
/// 'mess up' the internal bootloader state
301
422
pub struct FirmwareUpdater {
@@ -371,7 +492,10 @@ impl FirmwareUpdater {
371
492
offset : usize ,
372
493
data : & [ u8 ] ,
373
494
flash : & mut F ,
495
+ block_size : usize ,
374
496
) -> Result < ( ) , F :: Error > {
497
+ assert ! ( data. len( ) >= F :: ERASE_SIZE ) ;
498
+
375
499
trace ! (
376
500
"Writing firmware at offset 0x{:x} len {}" ,
377
501
self . dfu. from + offset,
@@ -384,7 +508,35 @@ impl FirmwareUpdater {
384
508
( self . dfu . from + offset + data. len ( ) ) as u32 ,
385
509
)
386
510
. await ?;
387
- flash. write ( ( self . dfu . from + offset) as u32 , data) . await
511
+
512
+ trace ! (
513
+ "Erased from {} to {}" ,
514
+ self . dfu. from + offset,
515
+ self . dfu. from + offset + data. len( )
516
+ ) ;
517
+
518
+ let mut write_offset = self . dfu . from + offset;
519
+ for chunk in data. chunks ( block_size) {
520
+ trace ! ( "Wrote chunk at {}: {:?}" , write_offset, chunk) ;
521
+ flash. write ( write_offset as u32 , chunk) . await ?;
522
+ write_offset += chunk. len ( ) ;
523
+ }
524
+ /*
525
+ trace!("Wrote data, reading back for verification");
526
+
527
+ let mut buf: [u8; 4096] = [0; 4096];
528
+ let mut data_offset = 0;
529
+ let mut read_offset = self.dfu.from + offset;
530
+ for chunk in buf.chunks_mut(block_size) {
531
+ flash.read(read_offset as u32, chunk).await?;
532
+ trace!("Read chunk at {}: {:?}", read_offset, chunk);
533
+ assert_eq!(&data[data_offset..data_offset + block_size], chunk);
534
+ read_offset += chunk.len();
535
+ data_offset += chunk.len();
536
+ }
537
+ */
538
+
539
+ Ok ( ( ) )
388
540
}
389
541
}
390
542
0 commit comments