From d9d6fd6d70f3f9971c6db65b6962199f9da7913c Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Fri, 31 Mar 2023 10:28:47 +0200 Subject: Add erase and wipe tests --- embassy-boot/boot/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'embassy-boot/boot/src/lib.rs') diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index a2259411f..4c28d7aa4 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -313,7 +313,8 @@ mod tests { )) .is_ok()); } - struct MemFlash([u8; SIZE]); + + pub struct MemFlash(pub [u8; SIZE]); impl NorFlash for MemFlash -- cgit From b1e2195b49129bcccf42121a6f39248bab9e341f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Mon, 3 Apr 2023 14:50:41 +0200 Subject: Remove FirmwareWriter FirmwareWriter currently has a "max-write-size" parameter, but this is a limitation that should be handled by chunking inside the NorFlash driver, and not "up here" in user code. In case that the driver (e.g. qspi driver) is unaware of any max-write limitations, one could simply add an intermediate NorFlash adapter providing the chunk'ing capability. --- embassy-boot/boot/src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'embassy-boot/boot/src/lib.rs') diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 4c28d7aa4..428e7ca2b 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -7,12 +7,10 @@ mod fmt; mod boot_loader; mod firmware_updater; -mod firmware_writer; mod partition; pub use boot_loader::{BootError, BootFlash, BootLoader, Flash, FlashConfig, MultiFlashConfig, SingleFlashConfig}; pub use firmware_updater::{FirmwareUpdater, FirmwareUpdaterError}; -pub use firmware_writer::FirmwareWriter; pub use partition::Partition; pub(crate) const BOOT_MAGIC: u8 = 0xD0; @@ -109,7 +107,7 @@ mod tests { let mut updater = FirmwareUpdater::new(DFU, STATE); let mut offset = 0; for chunk in update.chunks(4096) { - block_on(updater.write_firmware(offset, chunk, &mut flash, 4096)).unwrap(); + block_on(updater.write_firmware(offset, chunk, &mut flash)).unwrap(); offset += chunk.len(); } block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap(); @@ -182,7 +180,7 @@ mod tests { let mut offset = 0; for chunk in update.chunks(2048) { - block_on(updater.write_firmware(offset, chunk, &mut dfu, chunk.len())).unwrap(); + block_on(updater.write_firmware(offset, chunk, &mut dfu)).unwrap(); offset += chunk.len(); } block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); @@ -235,7 +233,7 @@ mod tests { let mut offset = 0; for chunk in update.chunks(4096) { - block_on(updater.write_firmware(offset, chunk, &mut dfu, chunk.len())).unwrap(); + block_on(updater.write_firmware(offset, chunk, &mut dfu)).unwrap(); offset += chunk.len(); } block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); -- cgit From 7c11d85e1ea0d01e5e1b4d6564d258663d66509b Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Mon, 3 Apr 2023 15:33:20 +0200 Subject: Move MemFlash to separate module and add verify_erased_before_write verification --- embassy-boot/boot/src/lib.rs | 155 ++++++------------------------------------- 1 file changed, 22 insertions(+), 133 deletions(-) (limited to 'embassy-boot/boot/src/lib.rs') 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; mod boot_loader; mod firmware_updater; mod firmware_writer; +mod mem_flash; mod partition; pub use boot_loader::{BootError, BootFlash, BootLoader, Flash, FlashConfig, MultiFlashConfig, SingleFlashConfig}; @@ -46,13 +47,10 @@ impl AsMut<[u8]> for AlignedBuffer { #[cfg(test)] mod tests { - use core::convert::Infallible; - - use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; - use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; use futures::executor::block_on; use super::*; + use crate::mem_flash::MemFlash; /* #[test] @@ -75,8 +73,8 @@ mod tests { const ACTIVE: Partition = Partition::new(4096, 61440); const DFU: Partition = Partition::new(61440, 122880); - let mut flash = MemFlash::<131072, 4096, 4>([0xff; 131072]); - flash.0[0..4].copy_from_slice(&[BOOT_MAGIC; 4]); + let mut flash = MemFlash::<131072, 4096, 4>::default(); + flash.mem[0..4].copy_from_slice(&[BOOT_MAGIC; 4]); let mut flash = SingleFlashConfig::new(&mut flash); let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); @@ -95,14 +93,14 @@ mod tests { const STATE: Partition = Partition::new(0, 4096); const ACTIVE: Partition = Partition::new(4096, 61440); const DFU: Partition = Partition::new(61440, 122880); - let mut flash = MemFlash::<131072, 4096, 4>([0xff; 131072]); + let mut flash = MemFlash::<131072, 4096, 4>::random().with_limited_erase_before_write_verification(4..); let original: [u8; ACTIVE.len()] = [rand::random::(); ACTIVE.len()]; let update: [u8; DFU.len()] = [rand::random::(); DFU.len()]; let mut aligned = [0; 4]; for i in ACTIVE.from..ACTIVE.to { - flash.0[i] = original[i - ACTIVE.from]; + flash.mem[i] = original[i - ACTIVE.from]; } let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); @@ -124,12 +122,12 @@ mod tests { ); for i in ACTIVE.from..ACTIVE.to { - assert_eq!(flash.0[i], update[i - ACTIVE.from], "Index {}", i); + assert_eq!(flash.mem[i], update[i - ACTIVE.from], "Index {}", i); } // First DFU page is untouched for i in DFU.from + 4096..DFU.to { - assert_eq!(flash.0[i], original[i - DFU.from - 4096], "Index {}", i); + assert_eq!(flash.mem[i], original[i - DFU.from - 4096], "Index {}", i); } // Running again should cause a revert @@ -141,12 +139,12 @@ mod tests { ); for i in ACTIVE.from..ACTIVE.to { - assert_eq!(flash.0[i], original[i - ACTIVE.from], "Index {}", i); + assert_eq!(flash.mem[i], original[i - ACTIVE.from], "Index {}", i); } // Last page is untouched for i in DFU.from..DFU.to - 4096 { - assert_eq!(flash.0[i], update[i - DFU.from], "Index {}", i); + assert_eq!(flash.mem[i], update[i - DFU.from], "Index {}", i); } // Mark as booted @@ -166,16 +164,16 @@ mod tests { const ACTIVE: Partition = Partition::new(4096, 16384); const DFU: Partition = Partition::new(0, 16384); - let mut active = MemFlash::<16384, 4096, 8>([0xff; 16384]); - let mut dfu = MemFlash::<16384, 2048, 8>([0xff; 16384]); - let mut state = MemFlash::<4096, 128, 4>([0xff; 4096]); + let mut active = MemFlash::<16384, 4096, 8>::random(); + let mut dfu = MemFlash::<16384, 2048, 8>::random(); + let mut state = MemFlash::<4096, 128, 4>::random().with_limited_erase_before_write_verification(2048 + 4..); let mut aligned = [0; 4]; let original: [u8; ACTIVE.len()] = [rand::random::(); ACTIVE.len()]; let update: [u8; DFU.len()] = [rand::random::(); DFU.len()]; for i in ACTIVE.from..ACTIVE.to { - active.0[i] = original[i - ACTIVE.from]; + active.mem[i] = original[i - ACTIVE.from]; } let mut updater = FirmwareUpdater::new(DFU, STATE); @@ -203,12 +201,12 @@ mod tests { ); for i in ACTIVE.from..ACTIVE.to { - assert_eq!(active.0[i], update[i - ACTIVE.from], "Index {}", i); + assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i); } // First DFU page is untouched for i in DFU.from + 4096..DFU.to { - assert_eq!(dfu.0[i], original[i - DFU.from - 4096], "Index {}", i); + assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i); } } @@ -220,15 +218,15 @@ mod tests { const DFU: Partition = Partition::new(0, 16384); let mut aligned = [0; 4]; - let mut active = MemFlash::<16384, 2048, 4>([0xff; 16384]); - let mut dfu = MemFlash::<16384, 4096, 8>([0xff; 16384]); - let mut state = MemFlash::<4096, 128, 4>([0xff; 4096]); + let mut active = MemFlash::<16384, 2048, 4>::random(); + let mut dfu = MemFlash::<16384, 4096, 8>::random(); + let mut state = MemFlash::<4096, 128, 4>::random().with_limited_erase_before_write_verification(2048 + 4..); let original: [u8; ACTIVE.len()] = [rand::random::(); ACTIVE.len()]; let update: [u8; DFU.len()] = [rand::random::(); DFU.len()]; for i in ACTIVE.from..ACTIVE.to { - active.0[i] = original[i - ACTIVE.from]; + active.mem[i] = original[i - ACTIVE.from]; } let mut updater = FirmwareUpdater::new(DFU, STATE); @@ -255,12 +253,12 @@ mod tests { ); for i in ACTIVE.from..ACTIVE.to { - assert_eq!(active.0[i], update[i - ACTIVE.from], "Index {}", i); + assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i); } // First DFU page is untouched for i in DFU.from + 4096..DFU.to { - assert_eq!(dfu.0[i], original[i - DFU.from - 4096], "Index {}", i); + assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i); } } @@ -313,113 +311,4 @@ mod tests { )) .is_ok()); } - - pub struct MemFlash(pub [u8; SIZE]); - - impl NorFlash - for MemFlash - { - const WRITE_SIZE: usize = WRITE_SIZE; - const ERASE_SIZE: usize = ERASE_SIZE; - fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - let from = from as usize; - let to = to as usize; - assert!(from % ERASE_SIZE == 0); - assert!(to % ERASE_SIZE == 0, "To: {}, erase size: {}", to, ERASE_SIZE); - for i in from..to { - self.0[i] = 0xFF; - } - Ok(()) - } - - fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> { - assert!(data.len() % WRITE_SIZE == 0); - assert!(offset as usize % WRITE_SIZE == 0); - assert!(offset as usize + data.len() <= SIZE); - - self.0[offset as usize..offset as usize + data.len()].copy_from_slice(data); - - Ok(()) - } - } - - impl ErrorType - for MemFlash - { - type Error = Infallible; - } - - impl ReadNorFlash - for MemFlash - { - const READ_SIZE: usize = 1; - - fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> { - let len = buf.len(); - buf[..].copy_from_slice(&self.0[offset as usize..offset as usize + len]); - Ok(()) - } - - fn capacity(&self) -> usize { - SIZE - } - } - - impl super::Flash - for MemFlash - { - const BLOCK_SIZE: usize = ERASE_SIZE; - const ERASE_VALUE: u8 = 0xFF; - } - - impl AsyncReadNorFlash - for MemFlash - { - const READ_SIZE: usize = 1; - - async fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> { - let len = buf.len(); - buf[..].copy_from_slice(&self.0[offset as usize..offset as usize + len]); - Ok(()) - } - - fn capacity(&self) -> usize { - SIZE - } - } - - impl AsyncNorFlash - for MemFlash - { - const WRITE_SIZE: usize = WRITE_SIZE; - const ERASE_SIZE: usize = ERASE_SIZE; - - async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - let from = from as usize; - let to = to as usize; - assert!(from % ERASE_SIZE == 0); - assert!(to % ERASE_SIZE == 0); - for i in from..to { - self.0[i] = 0xFF; - } - Ok(()) - } - - async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> { - info!("Writing {} bytes to 0x{:x}", data.len(), offset); - assert!(data.len() % WRITE_SIZE == 0); - assert!(offset as usize % WRITE_SIZE == 0); - assert!( - offset as usize + data.len() <= SIZE, - "OFFSET: {}, LEN: {}, FLASH SIZE: {}", - offset, - data.len(), - SIZE - ); - - self.0[offset as usize..offset as usize + data.len()].copy_from_slice(data); - - Ok(()) - } - } } -- cgit From df3a1e1b9d337c17e08faf41c6e3c50c35eb9a6c Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Tue, 4 Apr 2023 07:18:29 +0200 Subject: Avoid write to not-erased magic This introduces an additional marker to the state partition right after the magic which indicates whether the current progress is valid or not. Validation in tests that we never write without an erase is added. There is currently a FIXME in the FirmwareUpdater. Let me know if we should take the erase value as a parameter. I opened a feature request in embedded-storage to get this value in the trait. Before this, the assumption about ERASE_VALUE=0xFF was the same. --- embassy-boot/boot/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'embassy-boot/boot/src/lib.rs') diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index a5795781f..597ce3fa3 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -93,7 +93,7 @@ mod tests { const STATE: Partition = Partition::new(0, 4096); const ACTIVE: Partition = Partition::new(4096, 61440); const DFU: Partition = Partition::new(61440, 122880); - let mut flash = MemFlash::<131072, 4096, 4>::random().with_limited_erase_before_write_verification(4..); + let mut flash = MemFlash::<131072, 4096, 4>::random(); let original: [u8; ACTIVE.len()] = [rand::random::(); ACTIVE.len()]; let update: [u8; DFU.len()] = [rand::random::(); DFU.len()]; @@ -166,7 +166,7 @@ mod tests { let mut active = MemFlash::<16384, 4096, 8>::random(); let mut dfu = MemFlash::<16384, 2048, 8>::random(); - let mut state = MemFlash::<4096, 128, 4>::random().with_limited_erase_before_write_verification(2048 + 4..); + let mut state = MemFlash::<4096, 128, 4>::random(); let mut aligned = [0; 4]; let original: [u8; ACTIVE.len()] = [rand::random::(); ACTIVE.len()]; @@ -220,7 +220,7 @@ mod tests { let mut aligned = [0; 4]; let mut active = MemFlash::<16384, 2048, 4>::random(); let mut dfu = MemFlash::<16384, 4096, 8>::random(); - let mut state = MemFlash::<4096, 128, 4>::random().with_limited_erase_before_write_verification(2048 + 4..); + let mut state = MemFlash::<4096, 128, 4>::random(); let original: [u8; ACTIVE.len()] = [rand::random::(); ACTIVE.len()]; let update: [u8; DFU.len()] = [rand::random::(); DFU.len()]; -- cgit From 5e19fb6fb976db869696eaa5e8a2cdba751055b1 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Tue, 4 Apr 2023 12:36:50 +0200 Subject: Fix compile error when verification is enabled --- embassy-boot/boot/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'embassy-boot/boot/src/lib.rs') diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index cb12f9dc7..d53c613a3 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs @@ -286,13 +286,13 @@ mod tests { const STATE: Partition = Partition::new(0, 4096); const DFU: Partition = Partition::new(4096, 8192); - let mut flash = MemFlash::<8192, 4096, 4>([0xff; 8192]); + let mut flash = MemFlash::<8192, 4096, 4>::default(); let firmware_len = firmware.len(); let mut write_buf = [0; 4096]; write_buf[0..firmware_len].copy_from_slice(firmware); - NorFlash::write(&mut flash, DFU.from as u32, &write_buf).unwrap(); + DFU.write_blocking(&mut flash, 0, &write_buf).unwrap(); // On with the test -- cgit