aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-04-04 19:06:14 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-04-04 19:06:14 +0200
commit54b82d99666c35e63dc402955068557ef0bb1cf0 (patch)
treea5f0202eb0616a432ecb0e5f9570aebd46b51e67 /embassy-boot
parent7c6936a2e398e43ea3dc89736dc385402822933f (diff)
parent5923e143e35547b1972f2e48082e93dfbe1dadac (diff)
Merge remote-tracking branch 'upstream/master' into incremental-hash
Diffstat (limited to 'embassy-boot')
-rw-r--r--embassy-boot/boot/src/boot_loader.rs43
-rw-r--r--embassy-boot/boot/src/firmware_updater.rs34
-rw-r--r--embassy-boot/boot/src/lib.rs159
-rw-r--r--embassy-boot/boot/src/mem_flash.rs156
-rw-r--r--embassy-boot/boot/src/partition.rs40
5 files changed, 253 insertions, 179 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.
diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs
index 2d1b26980..819e20201 100644
--- a/embassy-boot/boot/src/firmware_updater.rs
+++ b/embassy-boot/boot/src/firmware_updater.rs
@@ -234,11 +234,24 @@ impl FirmwareUpdater {
234 self.state.read(state_flash, 0, aligned).await?; 234 self.state.read(state_flash, 0, aligned).await?;
235 235
236 if aligned.iter().any(|&b| b != magic) { 236 if aligned.iter().any(|&b| b != magic) {
237 aligned.fill(0); 237 // Read progress validity
238 self.state.read(state_flash, F::WRITE_SIZE as u32, aligned).await?;
239
240 // FIXME: Do not make this assumption.
241 const STATE_ERASE_VALUE: u8 = 0xFF;
242
243 if aligned.iter().any(|&b| b != STATE_ERASE_VALUE) {
244 // The current progress validity marker is invalid
245 } else {
246 // Invalidate progress
247 aligned.fill(!STATE_ERASE_VALUE);
248 self.state.write(state_flash, F::WRITE_SIZE as u32, aligned).await?;
249 }
238 250
239 self.state.write(state_flash, 0, aligned).await?; 251 // Clear magic and progress
240 self.state.wipe(state_flash).await?; 252 self.state.wipe(state_flash).await?;
241 253
254 // Set magic
242 aligned.fill(magic); 255 aligned.fill(magic);
243 self.state.write(state_flash, 0, aligned).await?; 256 self.state.write(state_flash, 0, aligned).await?;
244 } 257 }
@@ -441,11 +454,24 @@ impl FirmwareUpdater {
441 self.state.read_blocking(state_flash, 0, aligned)?; 454 self.state.read_blocking(state_flash, 0, aligned)?;
442 455
443 if aligned.iter().any(|&b| b != magic) { 456 if aligned.iter().any(|&b| b != magic) {
444 aligned.fill(0); 457 // Read progress validity
458 self.state.read_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?;
459
460 // FIXME: Do not make this assumption.
461 const STATE_ERASE_VALUE: u8 = 0xFF;
462
463 if aligned.iter().any(|&b| b != STATE_ERASE_VALUE) {
464 // The current progress validity marker is invalid
465 } else {
466 // Invalidate progress
467 aligned.fill(!STATE_ERASE_VALUE);
468 self.state.write_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?;
469 }
445 470
446 self.state.write_blocking(state_flash, 0, aligned)?; 471 // Clear magic and progress
447 self.state.wipe_blocking(state_flash)?; 472 self.state.wipe_blocking(state_flash)?;
448 473
474 // Set magic
449 aligned.fill(magic); 475 aligned.fill(magic);
450 self.state.write_blocking(state_flash, 0, aligned)?; 476 self.state.write_blocking(state_flash, 0, aligned)?;
451 } 477 }
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index da9055476..d4078f1cb 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -8,6 +8,7 @@ mod fmt;
8mod boot_loader; 8mod boot_loader;
9mod digest_adapters; 9mod digest_adapters;
10mod firmware_updater; 10mod firmware_updater;
11mod mem_flash;
11mod partition; 12mod partition;
12 13
13pub use boot_loader::{BootError, BootFlash, BootLoader, Flash, FlashConfig, MultiFlashConfig, SingleFlashConfig}; 14pub use boot_loader::{BootError, BootFlash, BootLoader, Flash, FlashConfig, MultiFlashConfig, SingleFlashConfig};
@@ -45,13 +46,10 @@ impl<const N: usize> AsMut<[u8]> for AlignedBuffer<N> {
45 46
46#[cfg(test)] 47#[cfg(test)]
47mod tests { 48mod tests {
48 use core::convert::Infallible;
49
50 use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
51 use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
52 use futures::executor::block_on; 49 use futures::executor::block_on;
53 50
54 use super::*; 51 use super::*;
52 use crate::mem_flash::MemFlash;
55 53
56 /* 54 /*
57 #[test] 55 #[test]
@@ -74,8 +72,8 @@ mod tests {
74 const ACTIVE: Partition = Partition::new(4096, 61440); 72 const ACTIVE: Partition = Partition::new(4096, 61440);
75 const DFU: Partition = Partition::new(61440, 122880); 73 const DFU: Partition = Partition::new(61440, 122880);
76 74
77 let mut flash = MemFlash::<131072, 4096, 4>([0xff; 131072]); 75 let mut flash = MemFlash::<131072, 4096, 4>::default();
78 flash.0[0..4].copy_from_slice(&[BOOT_MAGIC; 4]); 76 flash.mem[0..4].copy_from_slice(&[BOOT_MAGIC; 4]);
79 let mut flash = SingleFlashConfig::new(&mut flash); 77 let mut flash = SingleFlashConfig::new(&mut flash);
80 78
81 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 79 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
@@ -94,14 +92,14 @@ mod tests {
94 const STATE: Partition = Partition::new(0, 4096); 92 const STATE: Partition = Partition::new(0, 4096);
95 const ACTIVE: Partition = Partition::new(4096, 61440); 93 const ACTIVE: Partition = Partition::new(4096, 61440);
96 const DFU: Partition = Partition::new(61440, 122880); 94 const DFU: Partition = Partition::new(61440, 122880);
97 let mut flash = MemFlash::<131072, 4096, 4>([0xff; 131072]); 95 let mut flash = MemFlash::<131072, 4096, 4>::random();
98 96
99 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 97 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()];
100 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 98 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()];
101 let mut aligned = [0; 4]; 99 let mut aligned = [0; 4];
102 100
103 for i in ACTIVE.from..ACTIVE.to { 101 for i in ACTIVE.from..ACTIVE.to {
104 flash.0[i] = original[i - ACTIVE.from]; 102 flash.mem[i] = original[i - ACTIVE.from];
105 } 103 }
106 104
107 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 105 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
@@ -123,12 +121,12 @@ mod tests {
123 ); 121 );
124 122
125 for i in ACTIVE.from..ACTIVE.to { 123 for i in ACTIVE.from..ACTIVE.to {
126 assert_eq!(flash.0[i], update[i - ACTIVE.from], "Index {}", i); 124 assert_eq!(flash.mem[i], update[i - ACTIVE.from], "Index {}", i);
127 } 125 }
128 126
129 // First DFU page is untouched 127 // First DFU page is untouched
130 for i in DFU.from + 4096..DFU.to { 128 for i in DFU.from + 4096..DFU.to {
131 assert_eq!(flash.0[i], original[i - DFU.from - 4096], "Index {}", i); 129 assert_eq!(flash.mem[i], original[i - DFU.from - 4096], "Index {}", i);
132 } 130 }
133 131
134 // Running again should cause a revert 132 // Running again should cause a revert
@@ -140,12 +138,12 @@ mod tests {
140 ); 138 );
141 139
142 for i in ACTIVE.from..ACTIVE.to { 140 for i in ACTIVE.from..ACTIVE.to {
143 assert_eq!(flash.0[i], original[i - ACTIVE.from], "Index {}", i); 141 assert_eq!(flash.mem[i], original[i - ACTIVE.from], "Index {}", i);
144 } 142 }
145 143
146 // Last page is untouched 144 // Last page is untouched
147 for i in DFU.from..DFU.to - 4096 { 145 for i in DFU.from..DFU.to - 4096 {
148 assert_eq!(flash.0[i], update[i - DFU.from], "Index {}", i); 146 assert_eq!(flash.mem[i], update[i - DFU.from], "Index {}", i);
149 } 147 }
150 148
151 // Mark as booted 149 // Mark as booted
@@ -165,16 +163,16 @@ mod tests {
165 const ACTIVE: Partition = Partition::new(4096, 16384); 163 const ACTIVE: Partition = Partition::new(4096, 16384);
166 const DFU: Partition = Partition::new(0, 16384); 164 const DFU: Partition = Partition::new(0, 16384);
167 165
168 let mut active = MemFlash::<16384, 4096, 8>([0xff; 16384]); 166 let mut active = MemFlash::<16384, 4096, 8>::random();
169 let mut dfu = MemFlash::<16384, 2048, 8>([0xff; 16384]); 167 let mut dfu = MemFlash::<16384, 2048, 8>::random();
170 let mut state = MemFlash::<4096, 128, 4>([0xff; 4096]); 168 let mut state = MemFlash::<4096, 128, 4>::random();
171 let mut aligned = [0; 4]; 169 let mut aligned = [0; 4];
172 170
173 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 171 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()];
174 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 172 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()];
175 173
176 for i in ACTIVE.from..ACTIVE.to { 174 for i in ACTIVE.from..ACTIVE.to {
177 active.0[i] = original[i - ACTIVE.from]; 175 active.mem[i] = original[i - ACTIVE.from];
178 } 176 }
179 177
180 let mut updater = FirmwareUpdater::new(DFU, STATE); 178 let mut updater = FirmwareUpdater::new(DFU, STATE);
@@ -202,12 +200,12 @@ mod tests {
202 ); 200 );
203 201
204 for i in ACTIVE.from..ACTIVE.to { 202 for i in ACTIVE.from..ACTIVE.to {
205 assert_eq!(active.0[i], update[i - ACTIVE.from], "Index {}", i); 203 assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i);
206 } 204 }
207 205
208 // First DFU page is untouched 206 // First DFU page is untouched
209 for i in DFU.from + 4096..DFU.to { 207 for i in DFU.from + 4096..DFU.to {
210 assert_eq!(dfu.0[i], original[i - DFU.from - 4096], "Index {}", i); 208 assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i);
211 } 209 }
212 } 210 }
213 211
@@ -219,15 +217,15 @@ mod tests {
219 const DFU: Partition = Partition::new(0, 16384); 217 const DFU: Partition = Partition::new(0, 16384);
220 218
221 let mut aligned = [0; 4]; 219 let mut aligned = [0; 4];
222 let mut active = MemFlash::<16384, 2048, 4>([0xff; 16384]); 220 let mut active = MemFlash::<16384, 2048, 4>::random();
223 let mut dfu = MemFlash::<16384, 4096, 8>([0xff; 16384]); 221 let mut dfu = MemFlash::<16384, 4096, 8>::random();
224 let mut state = MemFlash::<4096, 128, 4>([0xff; 4096]); 222 let mut state = MemFlash::<4096, 128, 4>::random();
225 223
226 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 224 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()];
227 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 225 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()];
228 226
229 for i in ACTIVE.from..ACTIVE.to { 227 for i in ACTIVE.from..ACTIVE.to {
230 active.0[i] = original[i - ACTIVE.from]; 228 active.mem[i] = original[i - ACTIVE.from];
231 } 229 }
232 230
233 let mut updater = FirmwareUpdater::new(DFU, STATE); 231 let mut updater = FirmwareUpdater::new(DFU, STATE);
@@ -254,12 +252,12 @@ mod tests {
254 ); 252 );
255 253
256 for i in ACTIVE.from..ACTIVE.to { 254 for i in ACTIVE.from..ACTIVE.to {
257 assert_eq!(active.0[i], update[i - ACTIVE.from], "Index {}", i); 255 assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i);
258 } 256 }
259 257
260 // First DFU page is untouched 258 // First DFU page is untouched
261 for i in DFU.from + 4096..DFU.to { 259 for i in DFU.from + 4096..DFU.to {
262 assert_eq!(dfu.0[i], original[i - DFU.from - 4096], "Index {}", i); 260 assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i);
263 } 261 }
264 } 262 }
265 263
@@ -289,13 +287,13 @@ mod tests {
289 287
290 const STATE: Partition = Partition::new(0, 4096); 288 const STATE: Partition = Partition::new(0, 4096);
291 const DFU: Partition = Partition::new(4096, 8192); 289 const DFU: Partition = Partition::new(4096, 8192);
292 let mut flash = MemFlash::<8192, 4096, 4>([0xff; 8192]); 290 let mut flash = MemFlash::<8192, 4096, 4>::default();
293 291
294 let firmware_len = firmware.len(); 292 let firmware_len = firmware.len();
295 293
296 let mut write_buf = [0; 4096]; 294 let mut write_buf = [0; 4096];
297 write_buf[0..firmware_len].copy_from_slice(firmware); 295 write_buf[0..firmware_len].copy_from_slice(firmware);
298 NorFlash::write(&mut flash, DFU.from as u32, &write_buf).unwrap(); 296 DFU.write_blocking(&mut flash, 0, &write_buf).unwrap();
299 297
300 // On with the test 298 // On with the test
301 299
@@ -312,113 +310,4 @@ mod tests {
312 )) 310 ))
313 .is_ok()); 311 .is_ok());
314 } 312 }
315
316 pub struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize>(pub [u8; SIZE]);
317
318 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> NorFlash
319 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
320 {
321 const WRITE_SIZE: usize = WRITE_SIZE;
322 const ERASE_SIZE: usize = ERASE_SIZE;
323 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
324 let from = from as usize;
325 let to = to as usize;
326 assert!(from % ERASE_SIZE == 0);
327 assert!(to % ERASE_SIZE == 0, "To: {}, erase size: {}", to, ERASE_SIZE);
328 for i in from..to {
329 self.0[i] = 0xFF;
330 }
331 Ok(())
332 }
333
334 fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
335 assert!(data.len() % WRITE_SIZE == 0);
336 assert!(offset as usize % WRITE_SIZE == 0);
337 assert!(offset as usize + data.len() <= SIZE);
338
339 self.0[offset as usize..offset as usize + data.len()].copy_from_slice(data);
340
341 Ok(())
342 }
343 }
344
345 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> ErrorType
346 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
347 {
348 type Error = Infallible;
349 }
350
351 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> ReadNorFlash
352 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
353 {
354 const READ_SIZE: usize = 1;
355
356 fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
357 let len = buf.len();
358 buf[..].copy_from_slice(&self.0[offset as usize..offset as usize + len]);
359 Ok(())
360 }
361
362 fn capacity(&self) -> usize {
363 SIZE
364 }
365 }
366
367 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> super::Flash
368 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
369 {
370 const BLOCK_SIZE: usize = ERASE_SIZE;
371 const ERASE_VALUE: u8 = 0xFF;
372 }
373
374 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> AsyncReadNorFlash
375 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
376 {
377 const READ_SIZE: usize = 1;
378
379 async fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
380 let len = buf.len();
381 buf[..].copy_from_slice(&self.0[offset as usize..offset as usize + len]);
382 Ok(())
383 }
384
385 fn capacity(&self) -> usize {
386 SIZE
387 }
388 }
389
390 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> AsyncNorFlash
391 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
392 {
393 const WRITE_SIZE: usize = WRITE_SIZE;
394 const ERASE_SIZE: usize = ERASE_SIZE;
395
396 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
397 let from = from as usize;
398 let to = to as usize;
399 assert!(from % ERASE_SIZE == 0);
400 assert!(to % ERASE_SIZE == 0);
401 for i in from..to {
402 self.0[i] = 0xFF;
403 }
404 Ok(())
405 }
406
407 async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
408 info!("Writing {} bytes to 0x{:x}", data.len(), offset);
409 assert!(data.len() % WRITE_SIZE == 0);
410 assert!(offset as usize % WRITE_SIZE == 0);
411 assert!(
412 offset as usize + data.len() <= SIZE,
413 "OFFSET: {}, LEN: {}, FLASH SIZE: {}",
414 offset,
415 data.len(),
416 SIZE
417 );
418
419 self.0[offset as usize..offset as usize + data.len()].copy_from_slice(data);
420
421 Ok(())
422 }
423 }
424} 313}
diff --git a/embassy-boot/boot/src/mem_flash.rs b/embassy-boot/boot/src/mem_flash.rs
new file mode 100644
index 000000000..828aad9d9
--- /dev/null
+++ b/embassy-boot/boot/src/mem_flash.rs
@@ -0,0 +1,156 @@
1#![allow(unused)]
2
3use core::ops::{Bound, Range, RangeBounds};
4
5use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
6use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
7
8use crate::Flash;
9
10pub struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> {
11 pub mem: [u8; SIZE],
12 pub pending_write_successes: Option<usize>,
13}
14
15#[derive(Debug)]
16pub struct MemFlashError;
17
18impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE> {
19 pub const fn new(fill: u8) -> Self {
20 Self {
21 mem: [fill; SIZE],
22 pending_write_successes: None,
23 }
24 }
25
26 #[cfg(test)]
27 pub fn random() -> Self {
28 let mut mem = [0; SIZE];
29 for byte in mem.iter_mut() {
30 *byte = rand::random::<u8>();
31 }
32 Self {
33 mem,
34 pending_write_successes: None,
35 }
36 }
37}
38
39impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> Default
40 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
41{
42 fn default() -> Self {
43 Self::new(0xFF)
44 }
45}
46
47impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> Flash
48 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
49{
50 const BLOCK_SIZE: usize = ERASE_SIZE;
51 const ERASE_VALUE: u8 = 0xFF;
52}
53
54impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> ErrorType
55 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
56{
57 type Error = MemFlashError;
58}
59
60impl NorFlashError for MemFlashError {
61 fn kind(&self) -> NorFlashErrorKind {
62 NorFlashErrorKind::Other
63 }
64}
65
66impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> ReadNorFlash
67 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
68{
69 const READ_SIZE: usize = 1;
70
71 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
72 let len = bytes.len();
73 bytes.copy_from_slice(&self.mem[offset as usize..offset as usize + len]);
74 Ok(())
75 }
76
77 fn capacity(&self) -> usize {
78 SIZE
79 }
80}
81
82impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> NorFlash
83 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
84{
85 const WRITE_SIZE: usize = WRITE_SIZE;
86 const ERASE_SIZE: usize = ERASE_SIZE;
87
88 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
89 let from = from as usize;
90 let to = to as usize;
91 assert!(from % ERASE_SIZE == 0);
92 assert!(to % ERASE_SIZE == 0, "To: {}, erase size: {}", to, ERASE_SIZE);
93 for i in from..to {
94 self.mem[i] = 0xFF;
95 }
96 Ok(())
97 }
98
99 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
100 let offset = offset as usize;
101 assert!(bytes.len() % WRITE_SIZE == 0);
102 assert!(offset % WRITE_SIZE == 0);
103 assert!(offset + bytes.len() <= SIZE);
104
105 if let Some(pending_successes) = self.pending_write_successes {
106 if pending_successes > 0 {
107 self.pending_write_successes = Some(pending_successes - 1);
108 } else {
109 return Err(MemFlashError);
110 }
111 }
112
113 for ((offset, mem_byte), new_byte) in self
114 .mem
115 .iter_mut()
116 .enumerate()
117 .skip(offset)
118 .take(bytes.len())
119 .zip(bytes)
120 {
121 assert_eq!(0xFF, *mem_byte, "Offset {} is not erased", offset);
122 *mem_byte = *new_byte;
123 }
124
125 Ok(())
126 }
127}
128
129impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> AsyncReadNorFlash
130 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
131{
132 const READ_SIZE: usize = 1;
133
134 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
135 <Self as ReadNorFlash>::read(self, offset, bytes)
136 }
137
138 fn capacity(&self) -> usize {
139 <Self as ReadNorFlash>::capacity(self)
140 }
141}
142
143impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> AsyncNorFlash
144 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
145{
146 const WRITE_SIZE: usize = WRITE_SIZE;
147 const ERASE_SIZE: usize = ERASE_SIZE;
148
149 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
150 <Self as NorFlash>::erase(self, from, to)
151 }
152
153 async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
154 <Self as NorFlash>::write(self, offset, bytes)
155 }
156}
diff --git a/embassy-boot/boot/src/partition.rs b/embassy-boot/boot/src/partition.rs
index 3ccd4dd76..ac6b0ed0f 100644
--- a/embassy-boot/boot/src/partition.rs
+++ b/embassy-boot/boot/src/partition.rs
@@ -24,7 +24,7 @@ impl Partition {
24 } 24 }
25 25
26 /// Read from the partition on the provided flash 26 /// Read from the partition on the provided flash
27 pub(crate) async fn read<F: AsyncReadNorFlash>( 27 pub async fn read<F: AsyncReadNorFlash>(
28 &self, 28 &self,
29 flash: &mut F, 29 flash: &mut F,
30 offset: u32, 30 offset: u32,
@@ -35,12 +35,7 @@ impl Partition {
35 } 35 }
36 36
37 /// Write to the partition on the provided flash 37 /// Write to the partition on the provided flash
38 pub(crate) async fn write<F: AsyncNorFlash>( 38 pub async fn write<F: AsyncNorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> {
39 &self,
40 flash: &mut F,
41 offset: u32,
42 bytes: &[u8],
43 ) -> Result<(), F::Error> {
44 let offset = self.from as u32 + offset; 39 let offset = self.from as u32 + offset;
45 flash.write(offset, bytes).await?; 40 flash.write(offset, bytes).await?;
46 trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); 41 trace!("Wrote from 0x{:x} len {}", offset, bytes.len());
@@ -48,7 +43,7 @@ impl Partition {
48 } 43 }
49 44
50 /// Erase part of the partition on the provided flash 45 /// Erase part of the partition on the provided flash
51 pub(crate) async fn erase<F: AsyncNorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { 46 pub async fn erase<F: AsyncNorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> {
52 let from = self.from as u32 + from; 47 let from = self.from as u32 + from;
53 let to = self.from as u32 + to; 48 let to = self.from as u32 + to;
54 flash.erase(from, to).await?; 49 flash.erase(from, to).await?;
@@ -66,18 +61,13 @@ impl Partition {
66 } 61 }
67 62
68 /// Read from the partition on the provided flash 63 /// Read from the partition on the provided flash
69 pub(crate) fn read_blocking<F: ReadNorFlash>( 64 pub fn read_blocking<F: ReadNorFlash>(&self, flash: &mut F, offset: u32, bytes: &mut [u8]) -> Result<(), F::Error> {
70 &self,
71 flash: &mut F,
72 offset: u32,
73 bytes: &mut [u8],
74 ) -> Result<(), F::Error> {
75 let offset = self.from as u32 + offset; 65 let offset = self.from as u32 + offset;
76 flash.read(offset, bytes) 66 flash.read(offset, bytes)
77 } 67 }
78 68
79 /// Write to the partition on the provided flash 69 /// Write to the partition on the provided flash
80 pub(crate) fn write_blocking<F: NorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> { 70 pub fn write_blocking<F: NorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> {
81 let offset = self.from as u32 + offset; 71 let offset = self.from as u32 + offset;
82 flash.write(offset, bytes)?; 72 flash.write(offset, bytes)?;
83 trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); 73 trace!("Wrote from 0x{:x} len {}", offset, bytes.len());
@@ -85,7 +75,7 @@ impl Partition {
85 } 75 }
86 76
87 /// Erase part of the partition on the provided flash 77 /// Erase part of the partition on the provided flash
88 pub(crate) fn erase_blocking<F: NorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { 78 pub fn erase_blocking<F: NorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> {
89 let from = self.from as u32 + from; 79 let from = self.from as u32 + from;
90 let to = self.from as u32 + to; 80 let to = self.from as u32 + to;
91 flash.erase(from, to)?; 81 flash.erase(from, to)?;
@@ -105,45 +95,45 @@ impl Partition {
105 95
106#[cfg(test)] 96#[cfg(test)]
107mod tests { 97mod tests {
108 use crate::tests::MemFlash; 98 use crate::mem_flash::MemFlash;
109 use crate::Partition; 99 use crate::Partition;
110 100
111 #[test] 101 #[test]
112 fn can_erase() { 102 fn can_erase() {
113 let mut flash = MemFlash::<1024, 64, 4>([0x00; 1024]); 103 let mut flash = MemFlash::<1024, 64, 4>::new(0x00);
114 let partition = Partition::new(256, 512); 104 let partition = Partition::new(256, 512);
115 105
116 partition.erase_blocking(&mut flash, 64, 192).unwrap(); 106 partition.erase_blocking(&mut flash, 64, 192).unwrap();
117 107
118 for (index, byte) in flash.0.iter().copied().enumerate().take(256 + 64) { 108 for (index, byte) in flash.mem.iter().copied().enumerate().take(256 + 64) {
119 assert_eq!(0x00, byte, "Index {}", index); 109 assert_eq!(0x00, byte, "Index {}", index);
120 } 110 }
121 111
122 for (index, byte) in flash.0.iter().copied().enumerate().skip(256 + 64).take(128) { 112 for (index, byte) in flash.mem.iter().copied().enumerate().skip(256 + 64).take(128) {
123 assert_eq!(0xFF, byte, "Index {}", index); 113 assert_eq!(0xFF, byte, "Index {}", index);
124 } 114 }
125 115
126 for (index, byte) in flash.0.iter().copied().enumerate().skip(256 + 64 + 128) { 116 for (index, byte) in flash.mem.iter().copied().enumerate().skip(256 + 64 + 128) {
127 assert_eq!(0x00, byte, "Index {}", index); 117 assert_eq!(0x00, byte, "Index {}", index);
128 } 118 }
129 } 119 }
130 120
131 #[test] 121 #[test]
132 fn can_wipe() { 122 fn can_wipe() {
133 let mut flash = MemFlash::<1024, 64, 4>([0x00; 1024]); 123 let mut flash = MemFlash::<1024, 64, 4>::new(0x00);
134 let partition = Partition::new(256, 512); 124 let partition = Partition::new(256, 512);
135 125
136 partition.wipe_blocking(&mut flash).unwrap(); 126 partition.wipe_blocking(&mut flash).unwrap();
137 127
138 for (index, byte) in flash.0.iter().copied().enumerate().take(256) { 128 for (index, byte) in flash.mem.iter().copied().enumerate().take(256) {
139 assert_eq!(0x00, byte, "Index {}", index); 129 assert_eq!(0x00, byte, "Index {}", index);
140 } 130 }
141 131
142 for (index, byte) in flash.0.iter().copied().enumerate().skip(256).take(256) { 132 for (index, byte) in flash.mem.iter().copied().enumerate().skip(256).take(256) {
143 assert_eq!(0xFF, byte, "Index {}", index); 133 assert_eq!(0xFF, byte, "Index {}", index);
144 } 134 }
145 135
146 for (index, byte) in flash.0.iter().copied().enumerate().skip(512) { 136 for (index, byte) in flash.mem.iter().copied().enumerate().skip(512) {
147 assert_eq!(0x00, byte, "Index {}", index); 137 assert_eq!(0x00, byte, "Index {}", index);
148 } 138 }
149 } 139 }