From 42931b51f25ca22d7df3a6e8e98bfab7904eb11e Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Fri, 31 Mar 2023 10:18:19 +0200 Subject: [PATCH 1/2] Let bootloader partition have read/write/erase operations This change should not have any breaking changes. --- embassy-boot/boot/src/boot_loader.rs | 102 +++++++------ embassy-boot/boot/src/firmware_updater.rs | 174 +++++++--------------- embassy-boot/boot/src/firmware_writer.rs | 54 +------ embassy-boot/boot/src/partition.rs | 88 ++++++++++- 4 files changed, 195 insertions(+), 223 deletions(-) diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index ad673511..e2e361e3 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs @@ -79,7 +79,7 @@ impl BootLoader { Self { active, dfu, state } } - /// Return the boot address for the active partition. + /// Return the offset of the active partition into the active flash. pub fn boot_address(&self) -> usize { self.active.from } @@ -193,13 +193,13 @@ impl BootLoader { self.revert(p, magic, page)?; // Overwrite magic and reset progress - let fstate = p.state(); + let state_flash = p.state(); magic.fill(!P::STATE::ERASE_VALUE); - fstate.write(self.state.from as u32, magic)?; - fstate.erase(self.state.from as u32, self.state.to as u32)?; + self.state.write_blocking(state_flash, 0, magic)?; + self.state.wipe_blocking(state_flash)?; magic.fill(BOOT_MAGIC); - fstate.write(self.state.from as u32, magic)?; + self.state.write_blocking(state_flash, 0, magic)?; } } Ok(state) @@ -218,9 +218,10 @@ impl BootLoader { let max_index = ((self.state.len() - write_size) / write_size) - 1; aligned.fill(!P::STATE::ERASE_VALUE); - let flash = config.state(); + let state_flash = config.state(); for i in 0..max_index { - flash.read((self.state.from + write_size + i * write_size) as u32, aligned)?; + self.state + .read_blocking(state_flash, (write_size + i * write_size) as u32, aligned)?; if aligned.iter().any(|&b| b == P::STATE::ERASE_VALUE) { return Ok(i); @@ -230,47 +231,39 @@ impl BootLoader { } fn update_progress(&mut self, idx: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> { - let flash = p.state(); let write_size = magic.len(); - let w = self.state.from + write_size + idx * write_size; let aligned = magic; aligned.fill(!P::STATE::ERASE_VALUE); - flash.write(w as u32, aligned)?; + self.state + .write_blocking(p.state(), (write_size + idx * write_size) as u32, aligned)?; Ok(()) } - fn active_addr(&self, n: usize, page_size: usize) -> usize { - self.active.from + n * page_size - } - - fn dfu_addr(&self, n: usize, page_size: usize) -> usize { - self.dfu.from + n * page_size - } - fn copy_page_once_to_active( &mut self, idx: usize, - from_page: usize, - to_page: usize, + from_offset: u32, + to_offset: u32, p: &mut P, magic: &mut [u8], page: &mut [u8], ) -> Result<(), BootError> { let buf = page; if self.current_progress(p, magic)? <= idx { - let mut offset = from_page; + let mut offset = from_offset; for chunk in buf.chunks_mut(P::DFU::BLOCK_SIZE) { - p.dfu().read(offset as u32, chunk)?; - offset += chunk.len(); + self.dfu.read_blocking(p.dfu(), offset, chunk)?; + offset += chunk.len() as u32; } - p.active().erase(to_page as u32, (to_page + buf.len()) as u32)?; + self.active + .erase_blocking(p.active(), to_offset, to_offset + buf.len() as u32)?; - let mut offset = to_page; + let mut offset = to_offset; for chunk in buf.chunks(P::ACTIVE::BLOCK_SIZE) { - p.active().write(offset as u32, chunk)?; - offset += chunk.len(); + self.active.write_blocking(p.active(), offset, chunk)?; + offset += chunk.len() as u32; } self.update_progress(idx, p, magic)?; } @@ -280,26 +273,27 @@ impl BootLoader { fn copy_page_once_to_dfu( &mut self, idx: usize, - from_page: usize, - to_page: usize, + from_offset: u32, + to_offset: u32, p: &mut P, magic: &mut [u8], page: &mut [u8], ) -> Result<(), BootError> { let buf = page; if self.current_progress(p, magic)? <= idx { - let mut offset = from_page; + let mut offset = from_offset; for chunk in buf.chunks_mut(P::ACTIVE::BLOCK_SIZE) { - p.active().read(offset as u32, chunk)?; - offset += chunk.len(); + self.active.read_blocking(p.active(), offset, chunk)?; + offset += chunk.len() as u32; } - p.dfu().erase(to_page as u32, (to_page + buf.len()) as u32)?; + self.dfu + .erase_blocking(p.dfu(), to_offset as u32, to_offset + buf.len() as u32)?; - let mut offset = to_page; + let mut offset = to_offset; for chunk in buf.chunks(P::DFU::BLOCK_SIZE) { - p.dfu().write(offset as u32, chunk)?; - offset += chunk.len(); + self.dfu.write_blocking(p.dfu(), offset, chunk)?; + offset += chunk.len() as u32; } self.update_progress(idx, p, magic)?; } @@ -312,17 +306,20 @@ impl BootLoader { trace!("Page count: {}", page_count); for page_num in 0..page_count { trace!("COPY PAGE {}", page_num); + + let idx = page_num * 2; + // Copy active page to the 'next' DFU page. - let active_page = self.active_addr(page_count - 1 - page_num, page_size); - let dfu_page = self.dfu_addr(page_count - page_num, page_size); - //trace!("Copy active {} to dfu {}", active_page, dfu_page); - self.copy_page_once_to_dfu(page_num * 2, active_page, dfu_page, p, magic, page)?; + let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32; + let dfu_to_offset = ((page_count - page_num) * page_size) as u32; + //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); + self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; // Copy DFU page to the active page - let active_page = self.active_addr(page_count - 1 - page_num, page_size); - let dfu_page = self.dfu_addr(page_count - 1 - page_num, page_size); - //trace!("Copy dfy {} to active {}", dfu_page, active_page); - self.copy_page_once_to_active(page_num * 2 + 1, dfu_page, active_page, p, magic, page)?; + let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32; + let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32; + //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); + self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; } Ok(()) @@ -332,23 +329,24 @@ impl BootLoader { let page_size = page.len(); let page_count = self.active.len() / page_size; for page_num in 0..page_count { + let idx = page_count * 2 + page_num * 2; + // Copy the bad active page to the DFU page - let active_page = self.active_addr(page_num, page_size); - let dfu_page = self.dfu_addr(page_num, page_size); - self.copy_page_once_to_dfu(page_count * 2 + page_num * 2, active_page, dfu_page, p, magic, page)?; + let active_from_offset = (page_num * page_size) as u32; + let dfu_to_offset = (page_num * page_size) as u32; + self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; // Copy the DFU page back to the active page - let active_page = self.active_addr(page_num, page_size); - let dfu_page = self.dfu_addr(page_num + 1, page_size); - self.copy_page_once_to_active(page_count * 2 + page_num * 2 + 1, dfu_page, active_page, p, magic, page)?; + let active_to_offset = (page_num * page_size) as u32; + let dfu_from_offset = ((page_num + 1) * page_size) as u32; + self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; } Ok(()) } fn read_state(&mut self, config: &mut P, magic: &mut [u8]) -> Result { - let flash = config.state(); - flash.read(self.state.from as u32, magic)?; + self.state.read_blocking(config.state(), 0, magic)?; if !magic.iter().any(|&b| b != SWAP_MAGIC) { Ok(State::Swap) diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs index 2d871227..af1ba114 100644 --- a/embassy-boot/boot/src/firmware_updater.rs +++ b/embassy-boot/boot/src/firmware_updater.rs @@ -84,10 +84,10 @@ impl FirmwareUpdater { /// `mark_booted`. pub async fn get_state( &mut self, - flash: &mut F, + state_flash: &mut F, aligned: &mut [u8], ) -> Result { - flash.read(self.state.from as u32, aligned).await?; + self.state.read(state_flash, 0, aligned).await?; if !aligned.iter().any(|&b| b != SWAP_MAGIC) { Ok(State::Swap) @@ -115,17 +115,16 @@ impl FirmwareUpdater { #[cfg(feature = "_verify")] pub async fn verify_and_mark_updated( &mut self, - _flash: &mut F, + _state_and_dfu_flash: &mut F, _public_key: &[u8], _signature: &[u8], _update_len: usize, _aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { - let _end = self.dfu.from + _update_len; let _read_size = _aligned.len(); assert_eq!(_aligned.len(), F::WRITE_SIZE); - assert!(_end <= self.dfu.to); + assert!(_update_len <= self.dfu.len()); #[cfg(feature = "ed25519-dalek")] { @@ -137,21 +136,10 @@ impl FirmwareUpdater { let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; let mut digest = Sha512::new(); - - let mut offset = self.dfu.from; - let last_offset = _end / _read_size * _read_size; - - while offset < last_offset { - _flash.read(offset as u32, _aligned).await?; - digest.update(&_aligned); - offset += _read_size; - } - - let remaining = _end % _read_size; - - if remaining > 0 { - _flash.read(last_offset as u32, _aligned).await?; - digest.update(&_aligned[0..remaining]); + for offset in (0.._update_len).step_by(_aligned.len()) { + self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; + let len = core::cmp::min(_update_len - offset, _aligned.len()); + digest.update(&_aligned[..len]); } public_key @@ -173,21 +161,10 @@ impl FirmwareUpdater { let signature = Signature::try_from(&signature).map_err(into_signature_error)?; let mut digest = Sha512::new(); - - let mut offset = self.dfu.from; - let last_offset = _end / _read_size * _read_size; - - while offset < last_offset { - _flash.read(offset as u32, _aligned).await?; - digest.update(&_aligned); - offset += _read_size; - } - - let remaining = _end % _read_size; - - if remaining > 0 { - _flash.read(last_offset as u32, _aligned).await?; - digest.update(&_aligned[0..remaining]); + for offset in (0.._update_len).step_by(_aligned.len()) { + self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; + let len = core::cmp::min(_update_len - offset, _aligned.len()); + digest.update(&_aligned[..len]); } let message = digest.finalize(); @@ -202,7 +179,7 @@ impl FirmwareUpdater { r.map_err(into_signature_error)? } - self.set_magic(_aligned, SWAP_MAGIC, _flash).await + self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await } /// Mark to trigger firmware swap on next boot. @@ -213,11 +190,11 @@ impl FirmwareUpdater { #[cfg(not(feature = "_verify"))] pub async fn mark_updated( &mut self, - flash: &mut F, + state_flash: &mut F, aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { assert_eq!(aligned.len(), F::WRITE_SIZE); - self.set_magic(aligned, SWAP_MAGIC, flash).await + self.set_magic(aligned, SWAP_MAGIC, state_flash).await } /// Mark firmware boot successful and stop rollback on reset. @@ -227,29 +204,29 @@ impl FirmwareUpdater { /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. pub async fn mark_booted( &mut self, - flash: &mut F, + state_flash: &mut F, aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { assert_eq!(aligned.len(), F::WRITE_SIZE); - self.set_magic(aligned, BOOT_MAGIC, flash).await + self.set_magic(aligned, BOOT_MAGIC, state_flash).await } async fn set_magic( &mut self, aligned: &mut [u8], magic: u8, - flash: &mut F, + state_flash: &mut F, ) -> Result<(), FirmwareUpdaterError> { - flash.read(self.state.from as u32, aligned).await?; + self.state.read(state_flash, 0, aligned).await?; if aligned.iter().any(|&b| b != magic) { aligned.fill(0); - flash.write(self.state.from as u32, aligned).await?; - flash.erase(self.state.from as u32, self.state.to as u32).await?; + self.state.write(state_flash, 0, aligned).await?; + self.state.wipe(state_flash).await?; aligned.fill(magic); - flash.write(self.state.from as u32, aligned).await?; + self.state.write(state_flash, 0, aligned).await?; } Ok(()) } @@ -265,26 +242,17 @@ impl FirmwareUpdater { &mut self, offset: usize, data: &[u8], - flash: &mut F, + dfu_flash: &mut F, block_size: usize, ) -> Result<(), FirmwareUpdaterError> { assert!(data.len() >= F::ERASE_SIZE); - flash - .erase( - (self.dfu.from + offset) as u32, - (self.dfu.from + offset + data.len()) as u32, - ) + self.dfu + .erase(dfu_flash, offset as u32, (offset + data.len()) as u32) .await?; - trace!( - "Erased from {} to {}", - self.dfu.from + offset, - self.dfu.from + offset + data.len() - ); - FirmwareWriter(self.dfu) - .write_block(offset, data, flash, block_size) + .write_block(offset, data, dfu_flash, block_size) .await?; Ok(()) @@ -297,11 +265,9 @@ impl FirmwareUpdater { /// exchange for added complexity. pub async fn prepare_update( &mut self, - flash: &mut F, + dfu_flash: &mut F, ) -> Result { - flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32).await?; - - trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); + self.dfu.wipe(dfu_flash).await?; Ok(FirmwareWriter(self.dfu)) } @@ -317,10 +283,10 @@ impl FirmwareUpdater { /// `mark_booted`. pub fn get_state_blocking( &mut self, - flash: &mut F, + state_flash: &mut F, aligned: &mut [u8], ) -> Result { - flash.read(self.state.from as u32, aligned)?; + self.state.read_blocking(state_flash, 0, aligned)?; if !aligned.iter().any(|&b| b != SWAP_MAGIC) { Ok(State::Swap) @@ -348,7 +314,7 @@ impl FirmwareUpdater { #[cfg(feature = "_verify")] pub fn verify_and_mark_updated_blocking( &mut self, - _flash: &mut F, + _state_and_dfu_flash: &mut F, _public_key: &[u8], _signature: &[u8], _update_len: usize, @@ -370,21 +336,10 @@ impl FirmwareUpdater { let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; let mut digest = Sha512::new(); - - let mut offset = self.dfu.from; - let last_offset = _end / _read_size * _read_size; - - while offset < last_offset { - _flash.read(offset as u32, _aligned)?; - digest.update(&_aligned); - offset += _read_size; - } - - let remaining = _end % _read_size; - - if remaining > 0 { - _flash.read(last_offset as u32, _aligned)?; - digest.update(&_aligned[0..remaining]); + for offset in (0.._update_len).step_by(_aligned.len()) { + self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?; + let len = core::cmp::min(_update_len - offset, _aligned.len()); + digest.update(&_aligned[..len]); } public_key @@ -406,21 +361,10 @@ impl FirmwareUpdater { let signature = Signature::try_from(&signature).map_err(into_signature_error)?; let mut digest = Sha512::new(); - - let mut offset = self.dfu.from; - let last_offset = _end / _read_size * _read_size; - - while offset < last_offset { - _flash.read(offset as u32, _aligned)?; - digest.update(&_aligned); - offset += _read_size; - } - - let remaining = _end % _read_size; - - if remaining > 0 { - _flash.read(last_offset as u32, _aligned)?; - digest.update(&_aligned[0..remaining]); + for offset in (0.._update_len).step_by(_aligned.len()) { + self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?; + let len = core::cmp::min(_update_len - offset, _aligned.len()); + digest.update(&_aligned[..len]); } let message = digest.finalize(); @@ -435,7 +379,7 @@ impl FirmwareUpdater { r.map_err(into_signature_error)? } - self.set_magic_blocking(_aligned, SWAP_MAGIC, _flash) + self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) } /// Mark to trigger firmware swap on next boot. @@ -446,11 +390,11 @@ impl FirmwareUpdater { #[cfg(not(feature = "_verify"))] pub fn mark_updated_blocking( &mut self, - flash: &mut F, + state_flash: &mut F, aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { assert_eq!(aligned.len(), F::WRITE_SIZE); - self.set_magic_blocking(aligned, SWAP_MAGIC, flash) + self.set_magic_blocking(aligned, SWAP_MAGIC, state_flash) } /// Mark firmware boot successful and stop rollback on reset. @@ -460,29 +404,29 @@ impl FirmwareUpdater { /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. pub fn mark_booted_blocking( &mut self, - flash: &mut F, + state_flash: &mut F, aligned: &mut [u8], ) -> Result<(), FirmwareUpdaterError> { assert_eq!(aligned.len(), F::WRITE_SIZE); - self.set_magic_blocking(aligned, BOOT_MAGIC, flash) + self.set_magic_blocking(aligned, BOOT_MAGIC, state_flash) } fn set_magic_blocking( &mut self, aligned: &mut [u8], magic: u8, - flash: &mut F, + state_flash: &mut F, ) -> Result<(), FirmwareUpdaterError> { - flash.read(self.state.from as u32, aligned)?; + self.state.read_blocking(state_flash, 0, aligned)?; if aligned.iter().any(|&b| b != magic) { aligned.fill(0); - flash.write(self.state.from as u32, aligned)?; - flash.erase(self.state.from as u32, self.state.to as u32)?; + self.state.write_blocking(state_flash, 0, aligned)?; + self.state.wipe_blocking(state_flash)?; aligned.fill(magic); - flash.write(self.state.from as u32, aligned)?; + self.state.write_blocking(state_flash, 0, aligned)?; } Ok(()) } @@ -498,23 +442,15 @@ impl FirmwareUpdater { &mut self, offset: usize, data: &[u8], - flash: &mut F, + dfu_flash: &mut F, block_size: usize, ) -> Result<(), FirmwareUpdaterError> { assert!(data.len() >= F::ERASE_SIZE); - flash.erase( - (self.dfu.from + offset) as u32, - (self.dfu.from + offset + data.len()) as u32, - )?; + self.dfu + .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?; - trace!( - "Erased from {} to {}", - self.dfu.from + offset, - self.dfu.from + offset + data.len() - ); - - FirmwareWriter(self.dfu).write_block_blocking(offset, data, flash, block_size)?; + FirmwareWriter(self.dfu).write_block_blocking(offset, data, dfu_flash, block_size)?; Ok(()) } @@ -528,9 +464,7 @@ impl FirmwareUpdater { &mut self, flash: &mut F, ) -> Result { - flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32)?; - - trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); + self.dfu.wipe_blocking(flash)?; Ok(FirmwareWriter(self.dfu)) } diff --git a/embassy-boot/boot/src/firmware_writer.rs b/embassy-boot/boot/src/firmware_writer.rs index f992021b..46079e73 100644 --- a/embassy-boot/boot/src/firmware_writer.rs +++ b/embassy-boot/boot/src/firmware_writer.rs @@ -21,32 +21,11 @@ impl FirmwareWriter { flash: &mut F, block_size: usize, ) -> Result<(), F::Error> { - trace!( - "Writing firmware at offset 0x{:x} len {}", - self.0.from + offset, - data.len() - ); - - let mut write_offset = self.0.from + offset; + let mut offset = offset as u32; for chunk in data.chunks(block_size) { - trace!("Wrote chunk at {}: {:?}", write_offset, chunk); - flash.write(write_offset as u32, chunk).await?; - write_offset += chunk.len(); + self.0.write(flash, offset, chunk).await?; + offset += chunk.len() as u32; } - /* - trace!("Wrote data, reading back for verification"); - - let mut buf: [u8; 4096] = [0; 4096]; - let mut data_offset = 0; - let mut read_offset = self.dfu.from + offset; - for chunk in buf.chunks_mut(block_size) { - flash.read(read_offset as u32, chunk).await?; - trace!("Read chunk at {}: {:?}", read_offset, chunk); - assert_eq!(&data[data_offset..data_offset + block_size], chunk); - read_offset += chunk.len(); - data_offset += chunk.len(); - } - */ Ok(()) } @@ -65,32 +44,11 @@ impl FirmwareWriter { flash: &mut F, block_size: usize, ) -> Result<(), F::Error> { - trace!( - "Writing firmware at offset 0x{:x} len {}", - self.0.from + offset, - data.len() - ); - - let mut write_offset = self.0.from + offset; + let mut offset = offset as u32; for chunk in data.chunks(block_size) { - trace!("Wrote chunk at {}: {:?}", write_offset, chunk); - flash.write(write_offset as u32, chunk)?; - write_offset += chunk.len(); + self.0.write_blocking(flash, offset, chunk)?; + offset += chunk.len() as u32; } - /* - trace!("Wrote data, reading back for verification"); - - let mut buf: [u8; 4096] = [0; 4096]; - let mut data_offset = 0; - let mut read_offset = self.dfu.from + offset; - for chunk in buf.chunks_mut(block_size) { - flash.read(read_offset as u32, chunk).await?; - trace!("Read chunk at {}: {:?}", read_offset, chunk); - assert_eq!(&data[data_offset..data_offset + block_size], chunk); - read_offset += chunk.len(); - data_offset += chunk.len(); - } - */ Ok(()) } diff --git a/embassy-boot/boot/src/partition.rs b/embassy-boot/boot/src/partition.rs index 46f80a23..9918fb83 100644 --- a/embassy-boot/boot/src/partition.rs +++ b/embassy-boot/boot/src/partition.rs @@ -1,10 +1,13 @@ +use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; +use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; + /// A region in flash used by the bootloader. #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Partition { - /// Start of the flash region. + /// The offset into the flash where the partition starts. pub from: usize, - /// End of the flash region. + /// The offset into the flash where the partition ends. pub to: usize, } @@ -14,9 +17,88 @@ impl Partition { Self { from, to } } - /// Return the length of the partition + /// Return the size of the partition #[allow(clippy::len_without_is_empty)] pub const fn len(&self) -> usize { self.to - self.from } + + /// Read from the partition on the provided flash + pub(crate) async fn read( + &self, + flash: &mut F, + offset: u32, + bytes: &mut [u8], + ) -> Result<(), F::Error> { + let offset = self.from as u32 + offset; + flash.read(offset, bytes).await + } + + /// Write to the partition on the provided flash + pub(crate) async fn write( + &self, + flash: &mut F, + offset: u32, + bytes: &[u8], + ) -> Result<(), F::Error> { + let offset = self.from as u32 + offset; + flash.write(offset, bytes).await?; + trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); + Ok(()) + } + + /// Erase part of the partition on the provided flash + pub(crate) async fn erase(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { + let from = self.from as u32 + from; + let to = self.from as u32 + to; + flash.erase(from, to).await?; + trace!("Erased from 0x{:x} to 0x{:x}", from, to); + Ok(()) + } + + /// Erase the entire partition + pub(crate) async fn wipe(&self, flash: &mut F) -> Result<(), F::Error> { + let from = self.from as u32; + let to = self.to as u32; + flash.erase(from, to).await?; + trace!("Wiped from 0x{:x} to 0x{:x}", from, to); + Ok(()) + } + + /// Read from the partition on the provided flash + pub(crate) fn read_blocking( + &self, + flash: &mut F, + offset: u32, + bytes: &mut [u8], + ) -> Result<(), F::Error> { + let offset = self.from as u32 + offset; + flash.read(offset, bytes) + } + + /// Write to the partition on the provided flash + pub(crate) fn write_blocking(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> { + let offset = self.from as u32 + offset; + flash.write(offset, bytes)?; + trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); + Ok(()) + } + + /// Erase part of the partition on the provided flash + pub(crate) fn erase_blocking(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { + let from = self.from as u32 + from; + let to = self.from as u32 + to; + flash.erase(from, to)?; + trace!("Erased from 0x{:x} to 0x{:x}", from, to); + Ok(()) + } + + /// Erase the entire partition + pub(crate) fn wipe_blocking(&self, flash: &mut F) -> Result<(), F::Error> { + let from = self.from as u32; + let to = self.to as u32; + flash.erase(from, to)?; + trace!("Wiped from 0x{:x} to 0x{:x}", from, to); + Ok(()) + } } From d9d6fd6d70f3f9971c6db65b6962199f9da7913c Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Fri, 31 Mar 2023 10:28:47 +0200 Subject: [PATCH 2/2] Add erase and wipe tests --- embassy-boot/boot/src/lib.rs | 3 +- embassy-boot/boot/src/partition.rs | 46 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index a2259411..4c28d7aa 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 diff --git a/embassy-boot/boot/src/partition.rs b/embassy-boot/boot/src/partition.rs index 9918fb83..3ccd4dd7 100644 --- a/embassy-boot/boot/src/partition.rs +++ b/embassy-boot/boot/src/partition.rs @@ -102,3 +102,49 @@ impl Partition { Ok(()) } } + +#[cfg(test)] +mod tests { + use crate::tests::MemFlash; + use crate::Partition; + + #[test] + fn can_erase() { + let mut flash = MemFlash::<1024, 64, 4>([0x00; 1024]); + let partition = Partition::new(256, 512); + + partition.erase_blocking(&mut flash, 64, 192).unwrap(); + + for (index, byte) in flash.0.iter().copied().enumerate().take(256 + 64) { + assert_eq!(0x00, byte, "Index {}", index); + } + + for (index, byte) in flash.0.iter().copied().enumerate().skip(256 + 64).take(128) { + assert_eq!(0xFF, byte, "Index {}", index); + } + + for (index, byte) in flash.0.iter().copied().enumerate().skip(256 + 64 + 128) { + assert_eq!(0x00, byte, "Index {}", index); + } + } + + #[test] + fn can_wipe() { + let mut flash = MemFlash::<1024, 64, 4>([0x00; 1024]); + let partition = Partition::new(256, 512); + + partition.wipe_blocking(&mut flash).unwrap(); + + for (index, byte) in flash.0.iter().copied().enumerate().take(256) { + assert_eq!(0x00, byte, "Index {}", index); + } + + for (index, byte) in flash.0.iter().copied().enumerate().skip(256).take(256) { + assert_eq!(0xFF, byte, "Index {}", index); + } + + for (index, byte) in flash.0.iter().copied().enumerate().skip(512) { + assert_eq!(0x00, byte, "Index {}", index); + } + } +}