aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot/src/boot_loader.rs
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-04-04 21:09:30 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-04-04 21:09:30 +0200
commit25577e0eafd8a3d4ffaa4b8f17cb55399fd58038 (patch)
tree8e465872041cd22d1f15c2fd81cd43063d1d1a58 /embassy-boot/boot/src/boot_loader.rs
parent9242ad89d436422fd5abdafadb2faf845e730a16 (diff)
Assert active and dfu have same erase size and copy in smaller chunks
The copy from active to dfu (and vice versa) is now done in smaller portions depending on aligned_buf, which now does not need to be erase_size big.
Diffstat (limited to 'embassy-boot/boot/src/boot_loader.rs')
-rw-r--r--embassy-boot/boot/src/boot_loader.rs66
1 files changed, 31 insertions, 35 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs
index 698075599..db067da5b 100644
--- a/embassy-boot/boot/src/boot_loader.rs
+++ b/embassy-boot/boot/src/boot_loader.rs
@@ -32,14 +32,13 @@ where
32 32
33/// Extension of the embedded-storage flash type information with block size and erase value. 33/// Extension of the embedded-storage flash type information with block size and erase value.
34pub trait Flash: NorFlash { 34pub trait Flash: NorFlash {
35 /// The block size that should be used when writing to flash. For most builtin flashes, this is the same as the erase
36 /// size of the flash, but for external QSPI flash modules, this can be lower.
37 const BLOCK_SIZE: usize;
38 /// The erase value of the flash. Typically the default of 0xFF is used, but some flashes use a different value. 35 /// The erase value of the flash. Typically the default of 0xFF is used, but some flashes use a different value.
39 const ERASE_VALUE: u8 = 0xFF; 36 const ERASE_VALUE: u8 = 0xFF;
40} 37}
41 38
42/// Trait defining the flash handles used for active and DFU partition 39/// Trait defining the flash handles used for active and DFU partition.
40/// The ACTIVE and DFU erase sizes must be equal. If this is not the case, then consider adding an adapter for the
41/// smallest flash to increase its erase size such that they match. See e.g. [`crate::large_erase::LargeErase`].
43pub trait FlashConfig { 42pub trait FlashConfig {
44 /// Flash type used for the state partition. 43 /// Flash type used for the state partition.
45 type STATE: Flash; 44 type STATE: Flash;
@@ -62,12 +61,12 @@ trait FlashConfigEx {
62 61
63impl<T: FlashConfig> FlashConfigEx for T { 62impl<T: FlashConfig> FlashConfigEx for T {
64 fn page_size() -> usize { 63 fn page_size() -> usize {
65 core::cmp::max(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE) 64 assert_eq!(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE);
65 T::ACTIVE::ERASE_SIZE
66 } 66 }
67} 67}
68 68
69/// BootLoader works with any flash implementing embedded_storage and can also work with 69/// BootLoader works with any flash implementing embedded_storage.
70/// different page sizes and flash write sizes.
71pub struct BootLoader { 70pub struct BootLoader {
72 // Page with current state of bootloader. The state partition has the following format: 71 // Page with current state of bootloader. The state partition has the following format:
73 // All ranges are in multiples of WRITE_SIZE bytes. 72 // All ranges are in multiples of WRITE_SIZE bytes.
@@ -184,7 +183,9 @@ impl BootLoader {
184 /// 183 ///
185 pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> { 184 pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> {
186 // Ensure we have enough progress pages to store copy progress 185 // Ensure we have enough progress pages to store copy progress
187 assert_eq!(aligned_buf.len(), P::page_size()); 186 assert_eq!(0, P::page_size() % aligned_buf.len());
187 assert_eq!(0, P::page_size() % P::ACTIVE::WRITE_SIZE);
188 assert_eq!(0, P::page_size() % P::DFU::WRITE_SIZE);
188 assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE); 189 assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE);
189 assert_partitions(self.active, self.dfu, self.state, P::page_size(), P::STATE::WRITE_SIZE); 190 assert_partitions(self.active, self.dfu, self.state, P::page_size(), P::STATE::WRITE_SIZE);
190 191
@@ -277,20 +278,18 @@ impl BootLoader {
277 aligned_buf: &mut [u8], 278 aligned_buf: &mut [u8],
278 ) -> Result<(), BootError> { 279 ) -> Result<(), BootError> {
279 if self.current_progress(p, aligned_buf)? <= idx { 280 if self.current_progress(p, aligned_buf)? <= idx {
280 let mut offset = from_offset; 281 let page_size = P::page_size() as u32;
281 for chunk in aligned_buf.chunks_mut(P::DFU::BLOCK_SIZE) {
282 self.dfu.read_blocking(p.dfu(), offset, chunk)?;
283 offset += chunk.len() as u32;
284 }
285 282
286 self.active 283 self.active
287 .erase_blocking(p.active(), to_offset, to_offset + P::page_size() as u32)?; 284 .erase_blocking(p.active(), to_offset, to_offset + page_size)?;
288 285
289 let mut offset = to_offset; 286 for offset_in_page in (0..page_size).step_by(aligned_buf.len()) {
290 for chunk in aligned_buf.chunks(P::ACTIVE::BLOCK_SIZE) { 287 self.dfu
291 self.active.write_blocking(p.active(), offset, chunk)?; 288 .read_blocking(p.dfu(), from_offset + offset_in_page as u32, aligned_buf)?;
292 offset += chunk.len() as u32; 289 self.active
290 .write_blocking(p.active(), to_offset + offset_in_page as u32, aligned_buf)?;
293 } 291 }
292
294 self.update_progress(idx, p, aligned_buf)?; 293 self.update_progress(idx, p, aligned_buf)?;
295 } 294 }
296 Ok(()) 295 Ok(())
@@ -305,20 +304,18 @@ impl BootLoader {
305 aligned_buf: &mut [u8], 304 aligned_buf: &mut [u8],
306 ) -> Result<(), BootError> { 305 ) -> Result<(), BootError> {
307 if self.current_progress(p, aligned_buf)? <= idx { 306 if self.current_progress(p, aligned_buf)? <= idx {
308 let mut offset = from_offset; 307 let page_size = P::page_size() as u32;
309 for chunk in aligned_buf.chunks_mut(P::ACTIVE::BLOCK_SIZE) {
310 self.active.read_blocking(p.active(), offset, chunk)?;
311 offset += chunk.len() as u32;
312 }
313 308
314 self.dfu 309 self.dfu
315 .erase_blocking(p.dfu(), to_offset as u32, to_offset + P::page_size() as u32)?; 310 .erase_blocking(p.dfu(), to_offset as u32, to_offset + page_size)?;
316 311
317 let mut offset = to_offset; 312 for offset_in_page in (0..page_size).step_by(aligned_buf.len()) {
318 for chunk in aligned_buf.chunks(P::DFU::BLOCK_SIZE) { 313 self.active
319 self.dfu.write_blocking(p.dfu(), offset, chunk)?; 314 .read_blocking(p.active(), from_offset + offset_in_page as u32, aligned_buf)?;
320 offset += chunk.len() as u32; 315 self.dfu
316 .write_blocking(p.dfu(), to_offset + offset_in_page as u32, aligned_buf)?;
321 } 317 }
318
322 self.update_progress(idx, p, aligned_buf)?; 319 self.update_progress(idx, p, aligned_buf)?;
323 } 320 }
324 Ok(()) 321 Ok(())
@@ -389,14 +386,14 @@ fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_s
389} 386}
390 387
391/// A flash wrapper implementing the Flash and embedded_storage traits. 388/// A flash wrapper implementing the Flash and embedded_storage traits.
392pub struct BootFlash<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8 = 0xFF> 389pub struct BootFlash<F, const ERASE_VALUE: u8 = 0xFF>
393where 390where
394 F: NorFlash + ReadNorFlash, 391 F: NorFlash + ReadNorFlash,
395{ 392{
396 flash: F, 393 flash: F,
397} 394}
398 395
399impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 396impl<F, const ERASE_VALUE: u8> BootFlash<F, ERASE_VALUE>
400where 397where
401 F: NorFlash + ReadNorFlash, 398 F: NorFlash + ReadNorFlash,
402{ 399{
@@ -406,22 +403,21 @@ where
406 } 403 }
407} 404}
408 405
409impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> Flash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 406impl<F, const ERASE_VALUE: u8> Flash for BootFlash<F, ERASE_VALUE>
410where 407where
411 F: NorFlash + ReadNorFlash, 408 F: NorFlash + ReadNorFlash,
412{ 409{
413 const BLOCK_SIZE: usize = BLOCK_SIZE;
414 const ERASE_VALUE: u8 = ERASE_VALUE; 410 const ERASE_VALUE: u8 = ERASE_VALUE;
415} 411}
416 412
417impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ErrorType for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 413impl<F, const ERASE_VALUE: u8> ErrorType for BootFlash<F, ERASE_VALUE>
418where 414where
419 F: ReadNorFlash + NorFlash, 415 F: ReadNorFlash + NorFlash,
420{ 416{
421 type Error = F::Error; 417 type Error = F::Error;
422} 418}
423 419
424impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> NorFlash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 420impl<F, const ERASE_VALUE: u8> NorFlash for BootFlash<F, ERASE_VALUE>
425where 421where
426 F: ReadNorFlash + NorFlash, 422 F: ReadNorFlash + NorFlash,
427{ 423{
@@ -437,7 +433,7 @@ where
437 } 433 }
438} 434}
439 435
440impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ReadNorFlash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 436impl<F, const ERASE_VALUE: u8> ReadNorFlash for BootFlash<F, ERASE_VALUE>
441where 437where
442 F: ReadNorFlash + NorFlash, 438 F: ReadNorFlash + NorFlash,
443{ 439{