Let bootloader partition have read/write/erase operations
This change should not have any breaking changes.
This commit is contained in:
		| @@ -79,7 +79,7 @@ impl BootLoader { | |||||||
|         Self { active, dfu, state } |         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 { |     pub fn boot_address(&self) -> usize { | ||||||
|         self.active.from |         self.active.from | ||||||
|     } |     } | ||||||
| @@ -193,13 +193,13 @@ impl BootLoader { | |||||||
|                 self.revert(p, magic, page)?; |                 self.revert(p, magic, page)?; | ||||||
|  |  | ||||||
|                 // Overwrite magic and reset progress |                 // Overwrite magic and reset progress | ||||||
|                 let fstate = p.state(); |                 let state_flash = p.state(); | ||||||
|                 magic.fill(!P::STATE::ERASE_VALUE); |                 magic.fill(!P::STATE::ERASE_VALUE); | ||||||
|                 fstate.write(self.state.from as u32, magic)?; |                 self.state.write_blocking(state_flash, 0, magic)?; | ||||||
|                 fstate.erase(self.state.from as u32, self.state.to as u32)?; |                 self.state.wipe_blocking(state_flash)?; | ||||||
|  |  | ||||||
|                 magic.fill(BOOT_MAGIC); |                 magic.fill(BOOT_MAGIC); | ||||||
|                 fstate.write(self.state.from as u32, magic)?; |                 self.state.write_blocking(state_flash, 0, magic)?; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Ok(state) |         Ok(state) | ||||||
| @@ -218,9 +218,10 @@ impl BootLoader { | |||||||
|         let max_index = ((self.state.len() - write_size) / write_size) - 1; |         let max_index = ((self.state.len() - write_size) / write_size) - 1; | ||||||
|         aligned.fill(!P::STATE::ERASE_VALUE); |         aligned.fill(!P::STATE::ERASE_VALUE); | ||||||
|  |  | ||||||
|         let flash = config.state(); |         let state_flash = config.state(); | ||||||
|         for i in 0..max_index { |         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) { |             if aligned.iter().any(|&b| b == P::STATE::ERASE_VALUE) { | ||||||
|                 return Ok(i); |                 return Ok(i); | ||||||
| @@ -230,47 +231,39 @@ impl BootLoader { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn update_progress<P: FlashConfig>(&mut self, idx: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> { |     fn update_progress<P: FlashConfig>(&mut self, idx: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> { | ||||||
|         let flash = p.state(); |  | ||||||
|         let write_size = magic.len(); |         let write_size = magic.len(); | ||||||
|         let w = self.state.from + write_size + idx * write_size; |  | ||||||
|  |  | ||||||
|         let aligned = magic; |         let aligned = magic; | ||||||
|         aligned.fill(!P::STATE::ERASE_VALUE); |         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(()) |         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<P: FlashConfig>( |     fn copy_page_once_to_active<P: FlashConfig>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         idx: usize, |         idx: usize, | ||||||
|         from_page: usize, |         from_offset: u32, | ||||||
|         to_page: usize, |         to_offset: u32, | ||||||
|         p: &mut P, |         p: &mut P, | ||||||
|         magic: &mut [u8], |         magic: &mut [u8], | ||||||
|         page: &mut [u8], |         page: &mut [u8], | ||||||
|     ) -> Result<(), BootError> { |     ) -> Result<(), BootError> { | ||||||
|         let buf = page; |         let buf = page; | ||||||
|         if self.current_progress(p, magic)? <= idx { |         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) { |             for chunk in buf.chunks_mut(P::DFU::BLOCK_SIZE) { | ||||||
|                 p.dfu().read(offset as u32, chunk)?; |                 self.dfu.read_blocking(p.dfu(), offset, chunk)?; | ||||||
|                 offset += chunk.len(); |                 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) { |             for chunk in buf.chunks(P::ACTIVE::BLOCK_SIZE) { | ||||||
|                 p.active().write(offset as u32, chunk)?; |                 self.active.write_blocking(p.active(), offset, chunk)?; | ||||||
|                 offset += chunk.len(); |                 offset += chunk.len() as u32; | ||||||
|             } |             } | ||||||
|             self.update_progress(idx, p, magic)?; |             self.update_progress(idx, p, magic)?; | ||||||
|         } |         } | ||||||
| @@ -280,26 +273,27 @@ impl BootLoader { | |||||||
|     fn copy_page_once_to_dfu<P: FlashConfig>( |     fn copy_page_once_to_dfu<P: FlashConfig>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         idx: usize, |         idx: usize, | ||||||
|         from_page: usize, |         from_offset: u32, | ||||||
|         to_page: usize, |         to_offset: u32, | ||||||
|         p: &mut P, |         p: &mut P, | ||||||
|         magic: &mut [u8], |         magic: &mut [u8], | ||||||
|         page: &mut [u8], |         page: &mut [u8], | ||||||
|     ) -> Result<(), BootError> { |     ) -> Result<(), BootError> { | ||||||
|         let buf = page; |         let buf = page; | ||||||
|         if self.current_progress(p, magic)? <= idx { |         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) { |             for chunk in buf.chunks_mut(P::ACTIVE::BLOCK_SIZE) { | ||||||
|                 p.active().read(offset as u32, chunk)?; |                 self.active.read_blocking(p.active(), offset, chunk)?; | ||||||
|                 offset += chunk.len(); |                 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) { |             for chunk in buf.chunks(P::DFU::BLOCK_SIZE) { | ||||||
|                 p.dfu().write(offset as u32, chunk)?; |                 self.dfu.write_blocking(p.dfu(), offset, chunk)?; | ||||||
|                 offset += chunk.len(); |                 offset += chunk.len() as u32; | ||||||
|             } |             } | ||||||
|             self.update_progress(idx, p, magic)?; |             self.update_progress(idx, p, magic)?; | ||||||
|         } |         } | ||||||
| @@ -312,17 +306,20 @@ impl BootLoader { | |||||||
|         trace!("Page count: {}", page_count); |         trace!("Page count: {}", page_count); | ||||||
|         for page_num in 0..page_count { |         for page_num in 0..page_count { | ||||||
|             trace!("COPY PAGE {}", page_num); |             trace!("COPY PAGE {}", page_num); | ||||||
|  |  | ||||||
|  |             let idx = page_num * 2; | ||||||
|  |  | ||||||
|             // Copy active page to the 'next' DFU page. |             // Copy active page to the 'next' DFU page. | ||||||
|             let active_page = self.active_addr(page_count - 1 - page_num, page_size); |             let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32; | ||||||
|             let dfu_page = self.dfu_addr(page_count - page_num, page_size); |             let dfu_to_offset = ((page_count - page_num) * page_size) as u32; | ||||||
|             //trace!("Copy active {} to dfu {}", active_page, dfu_page); |             //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); | ||||||
|             self.copy_page_once_to_dfu(page_num * 2, active_page, dfu_page, p, magic, page)?; |             self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; | ||||||
|  |  | ||||||
|             // Copy DFU page to the active page |             // Copy DFU page to the active page | ||||||
|             let active_page = self.active_addr(page_count - 1 - page_num, page_size); |             let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32; | ||||||
|             let dfu_page = self.dfu_addr(page_count - 1 - page_num, page_size); |             let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32; | ||||||
|             //trace!("Copy dfy {} to active {}", dfu_page, active_page); |             //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); | ||||||
|             self.copy_page_once_to_active(page_num * 2 + 1, dfu_page, active_page, p, magic, page)?; |             self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
| @@ -332,23 +329,24 @@ impl BootLoader { | |||||||
|         let page_size = page.len(); |         let page_size = page.len(); | ||||||
|         let page_count = self.active.len() / page_size; |         let page_count = self.active.len() / page_size; | ||||||
|         for page_num in 0..page_count { |         for page_num in 0..page_count { | ||||||
|  |             let idx = page_count * 2 + page_num * 2; | ||||||
|  |  | ||||||
|             // Copy the bad active page to the DFU page |             // Copy the bad active page to the DFU page | ||||||
|             let active_page = self.active_addr(page_num, page_size); |             let active_from_offset = (page_num * page_size) as u32; | ||||||
|             let dfu_page = self.dfu_addr(page_num, page_size); |             let dfu_to_offset = (page_num * page_size) as u32; | ||||||
|             self.copy_page_once_to_dfu(page_count * 2 + page_num * 2, active_page, dfu_page, p, magic, page)?; |             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 |             // Copy the DFU page back to the active page | ||||||
|             let active_page = self.active_addr(page_num, page_size); |             let active_to_offset = (page_num * page_size) as u32; | ||||||
|             let dfu_page = self.dfu_addr(page_num + 1, page_size); |             let dfu_from_offset = ((page_num + 1) * page_size) as u32; | ||||||
|             self.copy_page_once_to_active(page_count * 2 + page_num * 2 + 1, dfu_page, active_page, p, magic, page)?; |             self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn read_state<P: FlashConfig>(&mut self, config: &mut P, magic: &mut [u8]) -> Result<State, BootError> { |     fn read_state<P: FlashConfig>(&mut self, config: &mut P, magic: &mut [u8]) -> Result<State, BootError> { | ||||||
|         let flash = config.state(); |         self.state.read_blocking(config.state(), 0, magic)?; | ||||||
|         flash.read(self.state.from as u32, magic)?; |  | ||||||
|  |  | ||||||
|         if !magic.iter().any(|&b| b != SWAP_MAGIC) { |         if !magic.iter().any(|&b| b != SWAP_MAGIC) { | ||||||
|             Ok(State::Swap) |             Ok(State::Swap) | ||||||
|   | |||||||
| @@ -84,10 +84,10 @@ impl FirmwareUpdater { | |||||||
|     /// `mark_booted`. |     /// `mark_booted`. | ||||||
|     pub async fn get_state<F: AsyncNorFlash>( |     pub async fn get_state<F: AsyncNorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         flash: &mut F, |         state_flash: &mut F, | ||||||
|         aligned: &mut [u8], |         aligned: &mut [u8], | ||||||
|     ) -> Result<State, FirmwareUpdaterError> { |     ) -> Result<State, FirmwareUpdaterError> { | ||||||
|         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) { |         if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | ||||||
|             Ok(State::Swap) |             Ok(State::Swap) | ||||||
| @@ -115,17 +115,16 @@ impl FirmwareUpdater { | |||||||
|     #[cfg(feature = "_verify")] |     #[cfg(feature = "_verify")] | ||||||
|     pub async fn verify_and_mark_updated<F: AsyncNorFlash>( |     pub async fn verify_and_mark_updated<F: AsyncNorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         _flash: &mut F, |         _state_and_dfu_flash: &mut F, | ||||||
|         _public_key: &[u8], |         _public_key: &[u8], | ||||||
|         _signature: &[u8], |         _signature: &[u8], | ||||||
|         _update_len: usize, |         _update_len: usize, | ||||||
|         _aligned: &mut [u8], |         _aligned: &mut [u8], | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> Result<(), FirmwareUpdaterError> { | ||||||
|         let _end = self.dfu.from + _update_len; |  | ||||||
|         let _read_size = _aligned.len(); |         let _read_size = _aligned.len(); | ||||||
|  |  | ||||||
|         assert_eq!(_aligned.len(), F::WRITE_SIZE); |         assert_eq!(_aligned.len(), F::WRITE_SIZE); | ||||||
|         assert!(_end <= self.dfu.to); |         assert!(_update_len <= self.dfu.len()); | ||||||
|  |  | ||||||
|         #[cfg(feature = "ed25519-dalek")] |         #[cfg(feature = "ed25519-dalek")] | ||||||
|         { |         { | ||||||
| @@ -137,21 +136,10 @@ impl FirmwareUpdater { | |||||||
|             let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; |             let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; | ||||||
|  |  | ||||||
|             let mut digest = Sha512::new(); |             let mut digest = Sha512::new(); | ||||||
|  |             for offset in (0.._update_len).step_by(_aligned.len()) { | ||||||
|             let mut offset = self.dfu.from; |                 self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; | ||||||
|             let last_offset = _end / _read_size * _read_size; |                 let len = core::cmp::min(_update_len - offset, _aligned.len()); | ||||||
|  |                 digest.update(&_aligned[..len]); | ||||||
|             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]); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             public_key |             public_key | ||||||
| @@ -173,21 +161,10 @@ impl FirmwareUpdater { | |||||||
|             let signature = Signature::try_from(&signature).map_err(into_signature_error)?; |             let signature = Signature::try_from(&signature).map_err(into_signature_error)?; | ||||||
|  |  | ||||||
|             let mut digest = Sha512::new(); |             let mut digest = Sha512::new(); | ||||||
|  |             for offset in (0.._update_len).step_by(_aligned.len()) { | ||||||
|             let mut offset = self.dfu.from; |                 self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; | ||||||
|             let last_offset = _end / _read_size * _read_size; |                 let len = core::cmp::min(_update_len - offset, _aligned.len()); | ||||||
|  |                 digest.update(&_aligned[..len]); | ||||||
|             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]); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             let message = digest.finalize(); |             let message = digest.finalize(); | ||||||
| @@ -202,7 +179,7 @@ impl FirmwareUpdater { | |||||||
|             r.map_err(into_signature_error)? |             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. |     /// Mark to trigger firmware swap on next boot. | ||||||
| @@ -213,11 +190,11 @@ impl FirmwareUpdater { | |||||||
|     #[cfg(not(feature = "_verify"))] |     #[cfg(not(feature = "_verify"))] | ||||||
|     pub async fn mark_updated<F: AsyncNorFlash>( |     pub async fn mark_updated<F: AsyncNorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         flash: &mut F, |         state_flash: &mut F, | ||||||
|         aligned: &mut [u8], |         aligned: &mut [u8], | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> Result<(), FirmwareUpdaterError> { | ||||||
|         assert_eq!(aligned.len(), F::WRITE_SIZE); |         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. |     /// 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. |     /// 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<F: AsyncNorFlash>( |     pub async fn mark_booted<F: AsyncNorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         flash: &mut F, |         state_flash: &mut F, | ||||||
|         aligned: &mut [u8], |         aligned: &mut [u8], | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> Result<(), FirmwareUpdaterError> { | ||||||
|         assert_eq!(aligned.len(), F::WRITE_SIZE); |         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<F: AsyncNorFlash>( |     async fn set_magic<F: AsyncNorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         aligned: &mut [u8], |         aligned: &mut [u8], | ||||||
|         magic: u8, |         magic: u8, | ||||||
|         flash: &mut F, |         state_flash: &mut F, | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> 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) { |         if aligned.iter().any(|&b| b != magic) { | ||||||
|             aligned.fill(0); |             aligned.fill(0); | ||||||
|  |  | ||||||
|             flash.write(self.state.from as u32, aligned).await?; |             self.state.write(state_flash, 0, aligned).await?; | ||||||
|             flash.erase(self.state.from as u32, self.state.to as u32).await?; |             self.state.wipe(state_flash).await?; | ||||||
|  |  | ||||||
|             aligned.fill(magic); |             aligned.fill(magic); | ||||||
|             flash.write(self.state.from as u32, aligned).await?; |             self.state.write(state_flash, 0, aligned).await?; | ||||||
|         } |         } | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @@ -265,26 +242,17 @@ impl FirmwareUpdater { | |||||||
|         &mut self, |         &mut self, | ||||||
|         offset: usize, |         offset: usize, | ||||||
|         data: &[u8], |         data: &[u8], | ||||||
|         flash: &mut F, |         dfu_flash: &mut F, | ||||||
|         block_size: usize, |         block_size: usize, | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> Result<(), FirmwareUpdaterError> { | ||||||
|         assert!(data.len() >= F::ERASE_SIZE); |         assert!(data.len() >= F::ERASE_SIZE); | ||||||
|  |  | ||||||
|         flash |         self.dfu | ||||||
|             .erase( |             .erase(dfu_flash, offset as u32, (offset + data.len()) as u32) | ||||||
|                 (self.dfu.from + offset) as u32, |  | ||||||
|                 (self.dfu.from + offset + data.len()) as u32, |  | ||||||
|             ) |  | ||||||
|             .await?; |             .await?; | ||||||
|  |  | ||||||
|         trace!( |  | ||||||
|             "Erased from {} to {}", |  | ||||||
|             self.dfu.from + offset, |  | ||||||
|             self.dfu.from + offset + data.len() |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         FirmwareWriter(self.dfu) |         FirmwareWriter(self.dfu) | ||||||
|             .write_block(offset, data, flash, block_size) |             .write_block(offset, data, dfu_flash, block_size) | ||||||
|             .await?; |             .await?; | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
| @@ -297,11 +265,9 @@ impl FirmwareUpdater { | |||||||
|     /// exchange for added complexity. |     /// exchange for added complexity. | ||||||
|     pub async fn prepare_update<F: AsyncNorFlash>( |     pub async fn prepare_update<F: AsyncNorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         flash: &mut F, |         dfu_flash: &mut F, | ||||||
|     ) -> Result<FirmwareWriter, FirmwareUpdaterError> { |     ) -> Result<FirmwareWriter, FirmwareUpdaterError> { | ||||||
|         flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32).await?; |         self.dfu.wipe(dfu_flash).await?; | ||||||
|  |  | ||||||
|         trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); |  | ||||||
|  |  | ||||||
|         Ok(FirmwareWriter(self.dfu)) |         Ok(FirmwareWriter(self.dfu)) | ||||||
|     } |     } | ||||||
| @@ -317,10 +283,10 @@ impl FirmwareUpdater { | |||||||
|     /// `mark_booted`. |     /// `mark_booted`. | ||||||
|     pub fn get_state_blocking<F: NorFlash>( |     pub fn get_state_blocking<F: NorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         flash: &mut F, |         state_flash: &mut F, | ||||||
|         aligned: &mut [u8], |         aligned: &mut [u8], | ||||||
|     ) -> Result<State, FirmwareUpdaterError> { |     ) -> Result<State, FirmwareUpdaterError> { | ||||||
|         flash.read(self.state.from as u32, aligned)?; |         self.state.read_blocking(state_flash, 0, aligned)?; | ||||||
|  |  | ||||||
|         if !aligned.iter().any(|&b| b != SWAP_MAGIC) { |         if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | ||||||
|             Ok(State::Swap) |             Ok(State::Swap) | ||||||
| @@ -348,7 +314,7 @@ impl FirmwareUpdater { | |||||||
|     #[cfg(feature = "_verify")] |     #[cfg(feature = "_verify")] | ||||||
|     pub fn verify_and_mark_updated_blocking<F: NorFlash>( |     pub fn verify_and_mark_updated_blocking<F: NorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         _flash: &mut F, |         _state_and_dfu_flash: &mut F, | ||||||
|         _public_key: &[u8], |         _public_key: &[u8], | ||||||
|         _signature: &[u8], |         _signature: &[u8], | ||||||
|         _update_len: usize, |         _update_len: usize, | ||||||
| @@ -370,21 +336,10 @@ impl FirmwareUpdater { | |||||||
|             let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; |             let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; | ||||||
|  |  | ||||||
|             let mut digest = Sha512::new(); |             let mut digest = Sha512::new(); | ||||||
|  |             for offset in (0.._update_len).step_by(_aligned.len()) { | ||||||
|             let mut offset = self.dfu.from; |                 self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?; | ||||||
|             let last_offset = _end / _read_size * _read_size; |                 let len = core::cmp::min(_update_len - offset, _aligned.len()); | ||||||
|  |                 digest.update(&_aligned[..len]); | ||||||
|             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]); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             public_key |             public_key | ||||||
| @@ -406,21 +361,10 @@ impl FirmwareUpdater { | |||||||
|             let signature = Signature::try_from(&signature).map_err(into_signature_error)?; |             let signature = Signature::try_from(&signature).map_err(into_signature_error)?; | ||||||
|  |  | ||||||
|             let mut digest = Sha512::new(); |             let mut digest = Sha512::new(); | ||||||
|  |             for offset in (0.._update_len).step_by(_aligned.len()) { | ||||||
|             let mut offset = self.dfu.from; |                 self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?; | ||||||
|             let last_offset = _end / _read_size * _read_size; |                 let len = core::cmp::min(_update_len - offset, _aligned.len()); | ||||||
|  |                 digest.update(&_aligned[..len]); | ||||||
|             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]); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             let message = digest.finalize(); |             let message = digest.finalize(); | ||||||
| @@ -435,7 +379,7 @@ impl FirmwareUpdater { | |||||||
|             r.map_err(into_signature_error)? |             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. |     /// Mark to trigger firmware swap on next boot. | ||||||
| @@ -446,11 +390,11 @@ impl FirmwareUpdater { | |||||||
|     #[cfg(not(feature = "_verify"))] |     #[cfg(not(feature = "_verify"))] | ||||||
|     pub fn mark_updated_blocking<F: NorFlash>( |     pub fn mark_updated_blocking<F: NorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         flash: &mut F, |         state_flash: &mut F, | ||||||
|         aligned: &mut [u8], |         aligned: &mut [u8], | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> Result<(), FirmwareUpdaterError> { | ||||||
|         assert_eq!(aligned.len(), F::WRITE_SIZE); |         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. |     /// 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. |     /// 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<F: NorFlash>( |     pub fn mark_booted_blocking<F: NorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         flash: &mut F, |         state_flash: &mut F, | ||||||
|         aligned: &mut [u8], |         aligned: &mut [u8], | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> Result<(), FirmwareUpdaterError> { | ||||||
|         assert_eq!(aligned.len(), F::WRITE_SIZE); |         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<F: NorFlash>( |     fn set_magic_blocking<F: NorFlash>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         aligned: &mut [u8], |         aligned: &mut [u8], | ||||||
|         magic: u8, |         magic: u8, | ||||||
|         flash: &mut F, |         state_flash: &mut F, | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> 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) { |         if aligned.iter().any(|&b| b != magic) { | ||||||
|             aligned.fill(0); |             aligned.fill(0); | ||||||
|  |  | ||||||
|             flash.write(self.state.from as u32, aligned)?; |             self.state.write_blocking(state_flash, 0, aligned)?; | ||||||
|             flash.erase(self.state.from as u32, self.state.to as u32)?; |             self.state.wipe_blocking(state_flash)?; | ||||||
|  |  | ||||||
|             aligned.fill(magic); |             aligned.fill(magic); | ||||||
|             flash.write(self.state.from as u32, aligned)?; |             self.state.write_blocking(state_flash, 0, aligned)?; | ||||||
|         } |         } | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @@ -498,23 +442,15 @@ impl FirmwareUpdater { | |||||||
|         &mut self, |         &mut self, | ||||||
|         offset: usize, |         offset: usize, | ||||||
|         data: &[u8], |         data: &[u8], | ||||||
|         flash: &mut F, |         dfu_flash: &mut F, | ||||||
|         block_size: usize, |         block_size: usize, | ||||||
|     ) -> Result<(), FirmwareUpdaterError> { |     ) -> Result<(), FirmwareUpdaterError> { | ||||||
|         assert!(data.len() >= F::ERASE_SIZE); |         assert!(data.len() >= F::ERASE_SIZE); | ||||||
|  |  | ||||||
|         flash.erase( |         self.dfu | ||||||
|             (self.dfu.from + offset) as u32, |             .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?; | ||||||
|             (self.dfu.from + offset + data.len()) as u32, |  | ||||||
|         )?; |  | ||||||
|  |  | ||||||
|         trace!( |         FirmwareWriter(self.dfu).write_block_blocking(offset, data, dfu_flash, block_size)?; | ||||||
|             "Erased from {} to {}", |  | ||||||
|             self.dfu.from + offset, |  | ||||||
|             self.dfu.from + offset + data.len() |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         FirmwareWriter(self.dfu).write_block_blocking(offset, data, flash, block_size)?; |  | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @@ -528,9 +464,7 @@ impl FirmwareUpdater { | |||||||
|         &mut self, |         &mut self, | ||||||
|         flash: &mut F, |         flash: &mut F, | ||||||
|     ) -> Result<FirmwareWriter, FirmwareUpdaterError> { |     ) -> Result<FirmwareWriter, FirmwareUpdaterError> { | ||||||
|         flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32)?; |         self.dfu.wipe_blocking(flash)?; | ||||||
|  |  | ||||||
|         trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); |  | ||||||
|  |  | ||||||
|         Ok(FirmwareWriter(self.dfu)) |         Ok(FirmwareWriter(self.dfu)) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -21,32 +21,11 @@ impl FirmwareWriter { | |||||||
|         flash: &mut F, |         flash: &mut F, | ||||||
|         block_size: usize, |         block_size: usize, | ||||||
|     ) -> Result<(), F::Error> { |     ) -> Result<(), F::Error> { | ||||||
|         trace!( |         let mut offset = offset as u32; | ||||||
|             "Writing firmware at offset 0x{:x} len {}", |  | ||||||
|             self.0.from + offset, |  | ||||||
|             data.len() |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         let mut write_offset = self.0.from + offset; |  | ||||||
|         for chunk in data.chunks(block_size) { |         for chunk in data.chunks(block_size) { | ||||||
|             trace!("Wrote chunk at {}: {:?}", write_offset, chunk); |             self.0.write(flash, offset, chunk).await?; | ||||||
|             flash.write(write_offset as u32, chunk).await?; |             offset += chunk.len() as u32; | ||||||
|             write_offset += chunk.len(); |  | ||||||
|         } |         } | ||||||
|         /* |  | ||||||
|         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(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @@ -65,32 +44,11 @@ impl FirmwareWriter { | |||||||
|         flash: &mut F, |         flash: &mut F, | ||||||
|         block_size: usize, |         block_size: usize, | ||||||
|     ) -> Result<(), F::Error> { |     ) -> Result<(), F::Error> { | ||||||
|         trace!( |         let mut offset = offset as u32; | ||||||
|             "Writing firmware at offset 0x{:x} len {}", |  | ||||||
|             self.0.from + offset, |  | ||||||
|             data.len() |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         let mut write_offset = self.0.from + offset; |  | ||||||
|         for chunk in data.chunks(block_size) { |         for chunk in data.chunks(block_size) { | ||||||
|             trace!("Wrote chunk at {}: {:?}", write_offset, chunk); |             self.0.write_blocking(flash, offset, chunk)?; | ||||||
|             flash.write(write_offset as u32, chunk)?; |             offset += chunk.len() as u32; | ||||||
|             write_offset += chunk.len(); |  | ||||||
|         } |         } | ||||||
|         /* |  | ||||||
|         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(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -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. | /// A region in flash used by the bootloader. | ||||||
| #[derive(Copy, Clone, Debug)] | #[derive(Copy, Clone, Debug)] | ||||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
| pub struct Partition { | pub struct Partition { | ||||||
|     /// Start of the flash region. |     /// The offset into the flash where the partition starts. | ||||||
|     pub from: usize, |     pub from: usize, | ||||||
|     /// End of the flash region. |     /// The offset into the flash where the partition ends. | ||||||
|     pub to: usize, |     pub to: usize, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -14,9 +17,88 @@ impl Partition { | |||||||
|         Self { from, to } |         Self { from, to } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Return the length of the partition |     /// Return the size of the partition | ||||||
|     #[allow(clippy::len_without_is_empty)] |     #[allow(clippy::len_without_is_empty)] | ||||||
|     pub const fn len(&self) -> usize { |     pub const fn len(&self) -> usize { | ||||||
|         self.to - self.from |         self.to - self.from | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Read from the partition on the provided flash | ||||||
|  |     pub(crate) async fn read<F: AsyncReadNorFlash>( | ||||||
|  |         &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<F: AsyncNorFlash>( | ||||||
|  |         &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<F: AsyncNorFlash>(&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<F: AsyncNorFlash>(&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<F: ReadNorFlash>( | ||||||
|  |         &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<F: NorFlash>(&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<F: NorFlash>(&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<F: NorFlash>(&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(()) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user