aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot/src/lib.rs
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-04-03 15:33:20 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-04-03 15:33:20 +0200
commit7c11d85e1ea0d01e5e1b4d6564d258663d66509b (patch)
tree861eef5f9485c7fe2c775a2a28d9366d5efb5928 /embassy-boot/boot/src/lib.rs
parent0909a6cd3ff6fb953aa2d83fb5da37384ad7dae2 (diff)
Move MemFlash to separate module and add verify_erased_before_write verification
Diffstat (limited to 'embassy-boot/boot/src/lib.rs')
-rw-r--r--embassy-boot/boot/src/lib.rs155
1 files changed, 22 insertions, 133 deletions
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 4c28d7aa4..a5795781f 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 firmware_updater; 9mod firmware_updater;
10mod firmware_writer; 10mod firmware_writer;
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};
@@ -46,13 +47,10 @@ impl<const N: usize> AsMut<[u8]> for AlignedBuffer<N> {
46 47
47#[cfg(test)] 48#[cfg(test)]
48mod tests { 49mod tests {
49 use core::convert::Infallible;
50
51 use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
52 use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
53 use futures::executor::block_on; 50 use futures::executor::block_on;
54 51
55 use super::*; 52 use super::*;
53 use crate::mem_flash::MemFlash;
56 54
57 /* 55 /*
58 #[test] 56 #[test]
@@ -75,8 +73,8 @@ mod tests {
75 const ACTIVE: Partition = Partition::new(4096, 61440); 73 const ACTIVE: Partition = Partition::new(4096, 61440);
76 const DFU: Partition = Partition::new(61440, 122880); 74 const DFU: Partition = Partition::new(61440, 122880);
77 75
78 let mut flash = MemFlash::<131072, 4096, 4>([0xff; 131072]); 76 let mut flash = MemFlash::<131072, 4096, 4>::default();
79 flash.0[0..4].copy_from_slice(&[BOOT_MAGIC; 4]); 77 flash.mem[0..4].copy_from_slice(&[BOOT_MAGIC; 4]);
80 let mut flash = SingleFlashConfig::new(&mut flash); 78 let mut flash = SingleFlashConfig::new(&mut flash);
81 79
82 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 80 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
@@ -95,14 +93,14 @@ mod tests {
95 const STATE: Partition = Partition::new(0, 4096); 93 const STATE: Partition = Partition::new(0, 4096);
96 const ACTIVE: Partition = Partition::new(4096, 61440); 94 const ACTIVE: Partition = Partition::new(4096, 61440);
97 const DFU: Partition = Partition::new(61440, 122880); 95 const DFU: Partition = Partition::new(61440, 122880);
98 let mut flash = MemFlash::<131072, 4096, 4>([0xff; 131072]); 96 let mut flash = MemFlash::<131072, 4096, 4>::random().with_limited_erase_before_write_verification(4..);
99 97
100 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 98 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()];
101 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 99 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()];
102 let mut aligned = [0; 4]; 100 let mut aligned = [0; 4];
103 101
104 for i in ACTIVE.from..ACTIVE.to { 102 for i in ACTIVE.from..ACTIVE.to {
105 flash.0[i] = original[i - ACTIVE.from]; 103 flash.mem[i] = original[i - ACTIVE.from];
106 } 104 }
107 105
108 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 106 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
@@ -124,12 +122,12 @@ mod tests {
124 ); 122 );
125 123
126 for i in ACTIVE.from..ACTIVE.to { 124 for i in ACTIVE.from..ACTIVE.to {
127 assert_eq!(flash.0[i], update[i - ACTIVE.from], "Index {}", i); 125 assert_eq!(flash.mem[i], update[i - ACTIVE.from], "Index {}", i);
128 } 126 }
129 127
130 // First DFU page is untouched 128 // First DFU page is untouched
131 for i in DFU.from + 4096..DFU.to { 129 for i in DFU.from + 4096..DFU.to {
132 assert_eq!(flash.0[i], original[i - DFU.from - 4096], "Index {}", i); 130 assert_eq!(flash.mem[i], original[i - DFU.from - 4096], "Index {}", i);
133 } 131 }
134 132
135 // Running again should cause a revert 133 // Running again should cause a revert
@@ -141,12 +139,12 @@ mod tests {
141 ); 139 );
142 140
143 for i in ACTIVE.from..ACTIVE.to { 141 for i in ACTIVE.from..ACTIVE.to {
144 assert_eq!(flash.0[i], original[i - ACTIVE.from], "Index {}", i); 142 assert_eq!(flash.mem[i], original[i - ACTIVE.from], "Index {}", i);
145 } 143 }
146 144
147 // Last page is untouched 145 // Last page is untouched
148 for i in DFU.from..DFU.to - 4096 { 146 for i in DFU.from..DFU.to - 4096 {
149 assert_eq!(flash.0[i], update[i - DFU.from], "Index {}", i); 147 assert_eq!(flash.mem[i], update[i - DFU.from], "Index {}", i);
150 } 148 }
151 149
152 // Mark as booted 150 // Mark as booted
@@ -166,16 +164,16 @@ mod tests {
166 const ACTIVE: Partition = Partition::new(4096, 16384); 164 const ACTIVE: Partition = Partition::new(4096, 16384);
167 const DFU: Partition = Partition::new(0, 16384); 165 const DFU: Partition = Partition::new(0, 16384);
168 166
169 let mut active = MemFlash::<16384, 4096, 8>([0xff; 16384]); 167 let mut active = MemFlash::<16384, 4096, 8>::random();
170 let mut dfu = MemFlash::<16384, 2048, 8>([0xff; 16384]); 168 let mut dfu = MemFlash::<16384, 2048, 8>::random();
171 let mut state = MemFlash::<4096, 128, 4>([0xff; 4096]); 169 let mut state = MemFlash::<4096, 128, 4>::random().with_limited_erase_before_write_verification(2048 + 4..);
172 let mut aligned = [0; 4]; 170 let mut aligned = [0; 4];
173 171
174 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 172 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()];
175 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 173 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()];
176 174
177 for i in ACTIVE.from..ACTIVE.to { 175 for i in ACTIVE.from..ACTIVE.to {
178 active.0[i] = original[i - ACTIVE.from]; 176 active.mem[i] = original[i - ACTIVE.from];
179 } 177 }
180 178
181 let mut updater = FirmwareUpdater::new(DFU, STATE); 179 let mut updater = FirmwareUpdater::new(DFU, STATE);
@@ -203,12 +201,12 @@ mod tests {
203 ); 201 );
204 202
205 for i in ACTIVE.from..ACTIVE.to { 203 for i in ACTIVE.from..ACTIVE.to {
206 assert_eq!(active.0[i], update[i - ACTIVE.from], "Index {}", i); 204 assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i);
207 } 205 }
208 206
209 // First DFU page is untouched 207 // First DFU page is untouched
210 for i in DFU.from + 4096..DFU.to { 208 for i in DFU.from + 4096..DFU.to {
211 assert_eq!(dfu.0[i], original[i - DFU.from - 4096], "Index {}", i); 209 assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i);
212 } 210 }
213 } 211 }
214 212
@@ -220,15 +218,15 @@ mod tests {
220 const DFU: Partition = Partition::new(0, 16384); 218 const DFU: Partition = Partition::new(0, 16384);
221 219
222 let mut aligned = [0; 4]; 220 let mut aligned = [0; 4];
223 let mut active = MemFlash::<16384, 2048, 4>([0xff; 16384]); 221 let mut active = MemFlash::<16384, 2048, 4>::random();
224 let mut dfu = MemFlash::<16384, 4096, 8>([0xff; 16384]); 222 let mut dfu = MemFlash::<16384, 4096, 8>::random();
225 let mut state = MemFlash::<4096, 128, 4>([0xff; 4096]); 223 let mut state = MemFlash::<4096, 128, 4>::random().with_limited_erase_before_write_verification(2048 + 4..);
226 224
227 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 225 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()];
228 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 226 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()];
229 227
230 for i in ACTIVE.from..ACTIVE.to { 228 for i in ACTIVE.from..ACTIVE.to {
231 active.0[i] = original[i - ACTIVE.from]; 229 active.mem[i] = original[i - ACTIVE.from];
232 } 230 }
233 231
234 let mut updater = FirmwareUpdater::new(DFU, STATE); 232 let mut updater = FirmwareUpdater::new(DFU, STATE);
@@ -255,12 +253,12 @@ mod tests {
255 ); 253 );
256 254
257 for i in ACTIVE.from..ACTIVE.to { 255 for i in ACTIVE.from..ACTIVE.to {
258 assert_eq!(active.0[i], update[i - ACTIVE.from], "Index {}", i); 256 assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i);
259 } 257 }
260 258
261 // First DFU page is untouched 259 // First DFU page is untouched
262 for i in DFU.from + 4096..DFU.to { 260 for i in DFU.from + 4096..DFU.to {
263 assert_eq!(dfu.0[i], original[i - DFU.from - 4096], "Index {}", i); 261 assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i);
264 } 262 }
265 } 263 }
266 264
@@ -313,113 +311,4 @@ mod tests {
313 )) 311 ))
314 .is_ok()); 312 .is_ok());
315 } 313 }
316
317 pub struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize>(pub [u8; SIZE]);
318
319 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> NorFlash
320 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
321 {
322 const WRITE_SIZE: usize = WRITE_SIZE;
323 const ERASE_SIZE: usize = ERASE_SIZE;
324 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
325 let from = from as usize;
326 let to = to as usize;
327 assert!(from % ERASE_SIZE == 0);
328 assert!(to % ERASE_SIZE == 0, "To: {}, erase size: {}", to, ERASE_SIZE);
329 for i in from..to {
330 self.0[i] = 0xFF;
331 }
332 Ok(())
333 }
334
335 fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
336 assert!(data.len() % WRITE_SIZE == 0);
337 assert!(offset as usize % WRITE_SIZE == 0);
338 assert!(offset as usize + data.len() <= SIZE);
339
340 self.0[offset as usize..offset as usize + data.len()].copy_from_slice(data);
341
342 Ok(())
343 }
344 }
345
346 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> ErrorType
347 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
348 {
349 type Error = Infallible;
350 }
351
352 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> ReadNorFlash
353 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
354 {
355 const READ_SIZE: usize = 1;
356
357 fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
358 let len = buf.len();
359 buf[..].copy_from_slice(&self.0[offset as usize..offset as usize + len]);
360 Ok(())
361 }
362
363 fn capacity(&self) -> usize {
364 SIZE
365 }
366 }
367
368 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> super::Flash
369 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
370 {
371 const BLOCK_SIZE: usize = ERASE_SIZE;
372 const ERASE_VALUE: u8 = 0xFF;
373 }
374
375 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> AsyncReadNorFlash
376 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
377 {
378 const READ_SIZE: usize = 1;
379
380 async fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
381 let len = buf.len();
382 buf[..].copy_from_slice(&self.0[offset as usize..offset as usize + len]);
383 Ok(())
384 }
385
386 fn capacity(&self) -> usize {
387 SIZE
388 }
389 }
390
391 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> AsyncNorFlash
392 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
393 {
394 const WRITE_SIZE: usize = WRITE_SIZE;
395 const ERASE_SIZE: usize = ERASE_SIZE;
396
397 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
398 let from = from as usize;
399 let to = to as usize;
400 assert!(from % ERASE_SIZE == 0);
401 assert!(to % ERASE_SIZE == 0);
402 for i in from..to {
403 self.0[i] = 0xFF;
404 }
405 Ok(())
406 }
407
408 async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
409 info!("Writing {} bytes to 0x{:x}", data.len(), offset);
410 assert!(data.len() % WRITE_SIZE == 0);
411 assert!(offset as usize % WRITE_SIZE == 0);
412 assert!(
413 offset as usize + data.len() <= SIZE,
414 "OFFSET: {}, LEN: {}, FLASH SIZE: {}",
415 offset,
416 data.len(),
417 SIZE
418 );
419
420 self.0[offset as usize..offset as usize + data.len()].copy_from_slice(data);
421
422 Ok(())
423 }
424 }
425} 314}