diff options
Diffstat (limited to 'embassy-boot/boot/src/boot_loader.rs')
| -rw-r--r-- | embassy-boot/boot/src/boot_loader.rs | 66 |
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. |
| 34 | pub trait Flash: NorFlash { | 34 | pub 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`]. | ||
| 43 | pub trait FlashConfig { | 42 | pub 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 | ||
| 63 | impl<T: FlashConfig> FlashConfigEx for T { | 62 | impl<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. | ||
| 71 | pub struct BootLoader { | 70 | pub 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. |
| 392 | pub struct BootFlash<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8 = 0xFF> | 389 | pub struct BootFlash<F, const ERASE_VALUE: u8 = 0xFF> |
| 393 | where | 390 | where |
| 394 | F: NorFlash + ReadNorFlash, | 391 | F: NorFlash + ReadNorFlash, |
| 395 | { | 392 | { |
| 396 | flash: F, | 393 | flash: F, |
| 397 | } | 394 | } |
| 398 | 395 | ||
| 399 | impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> BootFlash<F, BLOCK_SIZE, ERASE_VALUE> | 396 | impl<F, const ERASE_VALUE: u8> BootFlash<F, ERASE_VALUE> |
| 400 | where | 397 | where |
| 401 | F: NorFlash + ReadNorFlash, | 398 | F: NorFlash + ReadNorFlash, |
| 402 | { | 399 | { |
| @@ -406,22 +403,21 @@ where | |||
| 406 | } | 403 | } |
| 407 | } | 404 | } |
| 408 | 405 | ||
| 409 | impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> Flash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> | 406 | impl<F, const ERASE_VALUE: u8> Flash for BootFlash<F, ERASE_VALUE> |
| 410 | where | 407 | where |
| 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 | ||
| 417 | impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ErrorType for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> | 413 | impl<F, const ERASE_VALUE: u8> ErrorType for BootFlash<F, ERASE_VALUE> |
| 418 | where | 414 | where |
| 419 | F: ReadNorFlash + NorFlash, | 415 | F: ReadNorFlash + NorFlash, |
| 420 | { | 416 | { |
| 421 | type Error = F::Error; | 417 | type Error = F::Error; |
| 422 | } | 418 | } |
| 423 | 419 | ||
| 424 | impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> NorFlash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> | 420 | impl<F, const ERASE_VALUE: u8> NorFlash for BootFlash<F, ERASE_VALUE> |
| 425 | where | 421 | where |
| 426 | F: ReadNorFlash + NorFlash, | 422 | F: ReadNorFlash + NorFlash, |
| 427 | { | 423 | { |
| @@ -437,7 +433,7 @@ where | |||
| 437 | } | 433 | } |
| 438 | } | 434 | } |
| 439 | 435 | ||
| 440 | impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ReadNorFlash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> | 436 | impl<F, const ERASE_VALUE: u8> ReadNorFlash for BootFlash<F, ERASE_VALUE> |
| 441 | where | 437 | where |
| 442 | F: ReadNorFlash + NorFlash, | 438 | F: ReadNorFlash + NorFlash, |
| 443 | { | 439 | { |
