aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot/src/boot_loader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-boot/boot/src/boot_loader.rs')
-rw-r--r--embassy-boot/boot/src/boot_loader.rs43
1 files changed, 28 insertions, 15 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs
index e2e361e3c..9d047f778 100644
--- a/embassy-boot/boot/src/boot_loader.rs
+++ b/embassy-boot/boot/src/boot_loader.rs
@@ -31,7 +31,7 @@ where
31} 31}
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 + ReadNorFlash { 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 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. 36 /// size of the flash, but for external QSPI flash modules, this can be lower.
37 const BLOCK_SIZE: usize; 37 const BLOCK_SIZE: usize;
@@ -60,9 +60,11 @@ pub trait FlashConfig {
60/// different page sizes and flash write sizes. 60/// different page sizes and flash write sizes.
61pub struct BootLoader { 61pub struct BootLoader {
62 // Page with current state of bootloader. The state partition has the following format: 62 // Page with current state of bootloader. The state partition has the following format:
63 // | Range | Description | 63 // All ranges are in multiples of WRITE_SIZE bytes.
64 // | 0 - WRITE_SIZE | Magic indicating bootloader state. BOOT_MAGIC means boot, SWAP_MAGIC means swap. | 64 // | Range | Description |
65 // | WRITE_SIZE - N | Progress index used while swapping or reverting | 65 // | 0..1 | Magic indicating bootloader state. BOOT_MAGIC means boot, SWAP_MAGIC means swap. |
66 // | 1..2 | Progress validity. ERASE_VALUE means valid, !ERASE_VALUE means invalid. |
67 // | 2..2 + N | Progress index used while swapping or reverting |
66 state: Partition, 68 state: Partition,
67 // Location of the partition which will be booted from 69 // Location of the partition which will be booted from
68 active: Partition, 70 active: Partition,
@@ -192,12 +194,17 @@ impl BootLoader {
192 trace!("Reverting"); 194 trace!("Reverting");
193 self.revert(p, magic, page)?; 195 self.revert(p, magic, page)?;
194 196
195 // Overwrite magic and reset progress
196 let state_flash = p.state(); 197 let state_flash = p.state();
198
199 // Invalidate progress
197 magic.fill(!P::STATE::ERASE_VALUE); 200 magic.fill(!P::STATE::ERASE_VALUE);
198 self.state.write_blocking(state_flash, 0, magic)?; 201 self.state
202 .write_blocking(state_flash, P::STATE::WRITE_SIZE as u32, magic)?;
203
204 // Clear magic and progress
199 self.state.wipe_blocking(state_flash)?; 205 self.state.wipe_blocking(state_flash)?;
200 206
207 // Set magic
201 magic.fill(BOOT_MAGIC); 208 magic.fill(BOOT_MAGIC);
202 self.state.write_blocking(state_flash, 0, magic)?; 209 self.state.write_blocking(state_flash, 0, magic)?;
203 } 210 }
@@ -215,28 +222,34 @@ impl BootLoader {
215 222
216 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned: &mut [u8]) -> Result<usize, BootError> { 223 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned: &mut [u8]) -> Result<usize, BootError> {
217 let write_size = aligned.len(); 224 let write_size = aligned.len();
218 let max_index = ((self.state.len() - write_size) / write_size) - 1; 225 let max_index = ((self.state.len() - write_size) / write_size) - 2;
219 aligned.fill(!P::STATE::ERASE_VALUE); 226 aligned.fill(!P::STATE::ERASE_VALUE);
220 227
221 let state_flash = config.state(); 228 let state_flash = config.state();
222 for i in 0..max_index { 229
230 self.state
231 .read_blocking(state_flash, P::STATE::WRITE_SIZE as u32, aligned)?;
232 if aligned.iter().any(|&b| b != P::STATE::ERASE_VALUE) {
233 // Progress is invalid
234 return Ok(max_index);
235 }
236
237 for index in 0..max_index {
223 self.state 238 self.state
224 .read_blocking(state_flash, (write_size + i * write_size) as u32, aligned)?; 239 .read_blocking(state_flash, (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, aligned)?;
225 240
226 if aligned.iter().any(|&b| b == P::STATE::ERASE_VALUE) { 241 if aligned.iter().any(|&b| b == P::STATE::ERASE_VALUE) {
227 return Ok(i); 242 return Ok(index);
228 } 243 }
229 } 244 }
230 Ok(max_index) 245 Ok(max_index)
231 } 246 }
232 247
233 fn update_progress<P: FlashConfig>(&mut self, idx: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> { 248 fn update_progress<P: FlashConfig>(&mut self, index: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> {
234 let write_size = magic.len();
235
236 let aligned = magic; 249 let aligned = magic;
237 aligned.fill(!P::STATE::ERASE_VALUE); 250 aligned.fill(!P::STATE::ERASE_VALUE);
238 self.state 251 self.state
239 .write_blocking(p.state(), (write_size + idx * write_size) as u32, aligned)?; 252 .write_blocking(p.state(), (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, aligned)?;
240 Ok(()) 253 Ok(())
241 } 254 }
242 255
@@ -360,7 +373,7 @@ fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_s
360 assert_eq!(active.len() % page_size, 0); 373 assert_eq!(active.len() % page_size, 0);
361 assert_eq!(dfu.len() % page_size, 0); 374 assert_eq!(dfu.len() % page_size, 0);
362 assert!(dfu.len() - active.len() >= page_size); 375 assert!(dfu.len() - active.len() >= page_size);
363 assert!(2 * (active.len() / page_size) <= (state.len() - write_size) / write_size); 376 assert!(2 + 2 * (active.len() / page_size) <= state.len() / write_size);
364} 377}
365 378
366/// A flash wrapper implementing the Flash and embedded_storage traits. 379/// A flash wrapper implementing the Flash and embedded_storage traits.