diff options
| -rw-r--r-- | embassy-boot/boot/src/boot_loader.rs | 101 | ||||
| -rw-r--r-- | embassy-boot/boot/src/firmware_updater.rs | 29 | ||||
| -rw-r--r-- | embassy-boot/boot/src/lib.rs | 62 | ||||
| -rw-r--r-- | embassy-boot/boot/src/mem_flash.rs | 17 | ||||
| -rw-r--r-- | embassy-boot/boot/src/partition.rs | 9 | ||||
| -rw-r--r-- | embassy-boot/nrf/src/lib.rs | 12 | ||||
| -rw-r--r-- | embassy-boot/rp/src/lib.rs | 12 | ||||
| -rw-r--r-- | embassy-boot/stm32/src/lib.rs | 12 |
8 files changed, 117 insertions, 137 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index 2412427c0..b959de2c4 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs | |||
| @@ -50,13 +50,13 @@ pub trait FlashConfig { | |||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | trait FlashConfigEx { | 52 | trait FlashConfigEx { |
| 53 | fn page_size() -> usize; | 53 | fn page_size() -> u32; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | impl<T: FlashConfig> FlashConfigEx for T { | 56 | impl<T: FlashConfig> FlashConfigEx for T { |
| 57 | /// Get the page size which is the "unit of operation" within the bootloader. | 57 | /// Get the page size which is the "unit of operation" within the bootloader. |
| 58 | fn page_size() -> usize { | 58 | fn page_size() -> u32 { |
| 59 | core::cmp::max(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE) | 59 | core::cmp::max(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE) as u32 |
| 60 | } | 60 | } |
| 61 | } | 61 | } |
| 62 | 62 | ||
| @@ -86,7 +86,7 @@ impl BootLoader { | |||
| 86 | 86 | ||
| 87 | /// Return the offset of the active partition into the active flash. | 87 | /// Return the offset of the active partition into the active flash. |
| 88 | pub fn boot_address(&self) -> usize { | 88 | pub fn boot_address(&self) -> usize { |
| 89 | self.active.from | 89 | self.active.from as usize |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | /// Perform necessary boot preparations like swapping images. | 92 | /// Perform necessary boot preparations like swapping images. |
| @@ -177,11 +177,11 @@ impl BootLoader { | |||
| 177 | /// | 177 | /// |
| 178 | pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> { | 178 | pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> { |
| 179 | // Ensure we have enough progress pages to store copy progress | 179 | // Ensure we have enough progress pages to store copy progress |
| 180 | assert_eq!(0, P::page_size() % aligned_buf.len()); | 180 | assert_eq!(0, P::page_size() % aligned_buf.len() as u32); |
| 181 | assert_eq!(0, P::page_size() % P::ACTIVE::WRITE_SIZE); | 181 | assert_eq!(0, P::page_size() % P::ACTIVE::WRITE_SIZE as u32); |
| 182 | assert_eq!(0, P::page_size() % P::ACTIVE::ERASE_SIZE); | 182 | assert_eq!(0, P::page_size() % P::ACTIVE::ERASE_SIZE as u32); |
| 183 | assert_eq!(0, P::page_size() % P::DFU::WRITE_SIZE); | 183 | assert_eq!(0, P::page_size() % P::DFU::WRITE_SIZE as u32); |
| 184 | assert_eq!(0, P::page_size() % P::DFU::ERASE_SIZE); | 184 | assert_eq!(0, P::page_size() % P::DFU::ERASE_SIZE as u32); |
| 185 | assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE); | 185 | assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE); |
| 186 | assert_eq!(0, aligned_buf.len() % P::ACTIVE::WRITE_SIZE); | 186 | assert_eq!(0, aligned_buf.len() % P::ACTIVE::WRITE_SIZE); |
| 187 | assert_eq!(0, aligned_buf.len() % P::DFU::WRITE_SIZE); | 187 | assert_eq!(0, aligned_buf.len() % P::DFU::WRITE_SIZE); |
| @@ -222,30 +222,27 @@ impl BootLoader { | |||
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<bool, BootError> { | 224 | fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<bool, BootError> { |
| 225 | let page_count = self.active.len() / P::page_size(); | 225 | let page_count = (self.active.size() / P::page_size()) as usize; |
| 226 | let progress = self.current_progress(p, aligned_buf)?; | 226 | let progress = self.current_progress(p, aligned_buf)?; |
| 227 | 227 | ||
| 228 | Ok(progress >= page_count * 2) | 228 | Ok(progress >= page_count * 2) |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<usize, BootError> { | 231 | fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<usize, BootError> { |
| 232 | let max_index = ((self.state.len() - P::STATE::WRITE_SIZE) / P::STATE::WRITE_SIZE) - 2; | 232 | let write_size = P::STATE::WRITE_SIZE as u32; |
| 233 | let max_index = (((self.state.size() - write_size) / write_size) - 2) as usize; | ||
| 233 | let state_flash = config.state(); | 234 | let state_flash = config.state(); |
| 234 | let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE]; | 235 | let state_word = &mut aligned_buf[..write_size as usize]; |
| 235 | 236 | ||
| 236 | self.state | 237 | self.state.read_blocking(state_flash, write_size, state_word)?; |
| 237 | .read_blocking(state_flash, P::STATE::WRITE_SIZE as u32, state_word)?; | ||
| 238 | if state_word.iter().any(|&b| b != P::STATE_ERASE_VALUE) { | 238 | if state_word.iter().any(|&b| b != P::STATE_ERASE_VALUE) { |
| 239 | // Progress is invalid | 239 | // Progress is invalid |
| 240 | return Ok(max_index); | 240 | return Ok(max_index); |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | for index in 0..max_index { | 243 | for index in 0..max_index { |
| 244 | self.state.read_blocking( | 244 | self.state |
| 245 | state_flash, | 245 | .read_blocking(state_flash, (2 + index) as u32 * write_size, state_word)?; |
| 246 | (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, | ||
| 247 | state_word, | ||
| 248 | )?; | ||
| 249 | 246 | ||
| 250 | if state_word.iter().any(|&b| b == P::STATE_ERASE_VALUE) { | 247 | if state_word.iter().any(|&b| b == P::STATE_ERASE_VALUE) { |
| 251 | return Ok(index); | 248 | return Ok(index); |
| @@ -256,26 +253,29 @@ impl BootLoader { | |||
| 256 | 253 | ||
| 257 | fn update_progress<P: FlashConfig>( | 254 | fn update_progress<P: FlashConfig>( |
| 258 | &mut self, | 255 | &mut self, |
| 259 | index: usize, | 256 | progress_index: usize, |
| 260 | p: &mut P, | 257 | p: &mut P, |
| 261 | aligned_buf: &mut [u8], | 258 | aligned_buf: &mut [u8], |
| 262 | ) -> Result<(), BootError> { | 259 | ) -> Result<(), BootError> { |
| 263 | let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE]; | 260 | let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE]; |
| 264 | state_word.fill(!P::STATE_ERASE_VALUE); | 261 | state_word.fill(!P::STATE_ERASE_VALUE); |
| 265 | self.state | 262 | self.state.write_blocking( |
| 266 | .write_blocking(p.state(), (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, state_word)?; | 263 | p.state(), |
| 264 | (2 + progress_index) as u32 * P::STATE::WRITE_SIZE as u32, | ||
| 265 | state_word, | ||
| 266 | )?; | ||
| 267 | Ok(()) | 267 | Ok(()) |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | fn copy_page_once_to_active<P: FlashConfig>( | 270 | fn copy_page_once_to_active<P: FlashConfig>( |
| 271 | &mut self, | 271 | &mut self, |
| 272 | idx: usize, | 272 | progress_index: usize, |
| 273 | from_offset: u32, | 273 | from_offset: u32, |
| 274 | to_offset: u32, | 274 | to_offset: u32, |
| 275 | p: &mut P, | 275 | p: &mut P, |
| 276 | aligned_buf: &mut [u8], | 276 | aligned_buf: &mut [u8], |
| 277 | ) -> Result<(), BootError> { | 277 | ) -> Result<(), BootError> { |
| 278 | if self.current_progress(p, aligned_buf)? <= idx { | 278 | if self.current_progress(p, aligned_buf)? <= progress_index { |
| 279 | let page_size = P::page_size() as u32; | 279 | let page_size = P::page_size() as u32; |
| 280 | 280 | ||
| 281 | self.active | 281 | self.active |
| @@ -288,20 +288,20 @@ impl BootLoader { | |||
| 288 | .write_blocking(p.active(), to_offset + offset_in_page as u32, aligned_buf)?; | 288 | .write_blocking(p.active(), to_offset + offset_in_page as u32, aligned_buf)?; |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | self.update_progress(idx, p, aligned_buf)?; | 291 | self.update_progress(progress_index, p, aligned_buf)?; |
| 292 | } | 292 | } |
| 293 | Ok(()) | 293 | Ok(()) |
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | fn copy_page_once_to_dfu<P: FlashConfig>( | 296 | fn copy_page_once_to_dfu<P: FlashConfig>( |
| 297 | &mut self, | 297 | &mut self, |
| 298 | idx: usize, | 298 | progress_index: usize, |
| 299 | from_offset: u32, | 299 | from_offset: u32, |
| 300 | to_offset: u32, | 300 | to_offset: u32, |
| 301 | p: &mut P, | 301 | p: &mut P, |
| 302 | aligned_buf: &mut [u8], | 302 | aligned_buf: &mut [u8], |
| 303 | ) -> Result<(), BootError> { | 303 | ) -> Result<(), BootError> { |
| 304 | if self.current_progress(p, aligned_buf)? <= idx { | 304 | if self.current_progress(p, aligned_buf)? <= progress_index { |
| 305 | let page_size = P::page_size() as u32; | 305 | let page_size = P::page_size() as u32; |
| 306 | 306 | ||
| 307 | self.dfu | 307 | self.dfu |
| @@ -314,31 +314,28 @@ impl BootLoader { | |||
| 314 | .write_blocking(p.dfu(), to_offset + offset_in_page as u32, aligned_buf)?; | 314 | .write_blocking(p.dfu(), to_offset + offset_in_page as u32, aligned_buf)?; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | self.update_progress(idx, p, aligned_buf)?; | 317 | self.update_progress(progress_index, p, aligned_buf)?; |
| 318 | } | 318 | } |
| 319 | Ok(()) | 319 | Ok(()) |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | fn swap<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> { | 322 | fn swap<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> { |
| 323 | let page_size = P::page_size(); | 323 | let page_size = P::page_size(); |
| 324 | let page_count = self.active.len() / page_size; | 324 | let page_count = self.active.size() / page_size; |
| 325 | trace!("Page count: {}", page_count); | ||
| 326 | for page_num in 0..page_count { | 325 | for page_num in 0..page_count { |
| 327 | trace!("COPY PAGE {}", page_num); | 326 | let progress_index = (page_num * 2) as usize; |
| 328 | |||
| 329 | let idx = page_num * 2; | ||
| 330 | 327 | ||
| 331 | // Copy active page to the 'next' DFU page. | 328 | // Copy active page to the 'next' DFU page. |
| 332 | let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32; | 329 | let active_from_offset = (page_count - 1 - page_num) * page_size; |
| 333 | let dfu_to_offset = ((page_count - page_num) * page_size) as u32; | 330 | let dfu_to_offset = (page_count - page_num) * page_size; |
| 334 | //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); | 331 | //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); |
| 335 | self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, aligned_buf)?; | 332 | self.copy_page_once_to_dfu(progress_index, active_from_offset, dfu_to_offset, p, aligned_buf)?; |
| 336 | 333 | ||
| 337 | // Copy DFU page to the active page | 334 | // Copy DFU page to the active page |
| 338 | let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32; | 335 | let active_to_offset = (page_count - 1 - page_num) * page_size; |
| 339 | let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32; | 336 | let dfu_from_offset = (page_count - 1 - page_num) * page_size; |
| 340 | //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); | 337 | //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); |
| 341 | self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?; | 338 | self.copy_page_once_to_active(progress_index + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?; |
| 342 | } | 339 | } |
| 343 | 340 | ||
| 344 | Ok(()) | 341 | Ok(()) |
| @@ -346,19 +343,19 @@ impl BootLoader { | |||
| 346 | 343 | ||
| 347 | fn revert<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> { | 344 | fn revert<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> { |
| 348 | let page_size = P::page_size(); | 345 | let page_size = P::page_size(); |
| 349 | let page_count = self.active.len() / page_size; | 346 | let page_count = self.active.size() / page_size; |
| 350 | for page_num in 0..page_count { | 347 | for page_num in 0..page_count { |
| 351 | let idx = page_count * 2 + page_num * 2; | 348 | let progress_index = (page_count * 2 + page_num * 2) as usize; |
| 352 | 349 | ||
| 353 | // Copy the bad active page to the DFU page | 350 | // Copy the bad active page to the DFU page |
| 354 | let active_from_offset = (page_num * page_size) as u32; | 351 | let active_from_offset = page_num * page_size; |
| 355 | let dfu_to_offset = (page_num * page_size) as u32; | 352 | let dfu_to_offset = page_num * page_size; |
| 356 | self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, aligned_buf)?; | 353 | self.copy_page_once_to_dfu(progress_index, active_from_offset, dfu_to_offset, p, aligned_buf)?; |
| 357 | 354 | ||
| 358 | // Copy the DFU page back to the active page | 355 | // Copy the DFU page back to the active page |
| 359 | let active_to_offset = (page_num * page_size) as u32; | 356 | let active_to_offset = page_num * page_size; |
| 360 | let dfu_from_offset = ((page_num + 1) * page_size) as u32; | 357 | let dfu_from_offset = (page_num + 1) * page_size; |
| 361 | self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?; | 358 | self.copy_page_once_to_active(progress_index + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?; |
| 362 | } | 359 | } |
| 363 | 360 | ||
| 364 | Ok(()) | 361 | Ok(()) |
| @@ -376,11 +373,11 @@ impl BootLoader { | |||
| 376 | } | 373 | } |
| 377 | } | 374 | } |
| 378 | 375 | ||
| 379 | fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_size: usize, write_size: usize) { | 376 | fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_size: u32, state_write_size: usize) { |
| 380 | assert_eq!(active.len() % page_size, 0); | 377 | assert_eq!(active.size() % page_size, 0); |
| 381 | assert_eq!(dfu.len() % page_size, 0); | 378 | assert_eq!(dfu.size() % page_size, 0); |
| 382 | assert!(dfu.len() - active.len() >= page_size); | 379 | assert!(dfu.size() - active.size() >= page_size); |
| 383 | assert!(2 + 2 * (active.len() / page_size) <= state.len() / write_size); | 380 | assert!(2 + 2 * (active.size() / page_size) <= state.size() / state_write_size as u32); |
| 384 | } | 381 | } |
| 385 | 382 | ||
| 386 | /// A flash wrapper implementing the Flash and embedded_storage traits. | 383 | /// A flash wrapper implementing the Flash and embedded_storage traits. |
diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs index 48e15024e..a2f822f4a 100644 --- a/embassy-boot/boot/src/firmware_updater.rs +++ b/embassy-boot/boot/src/firmware_updater.rs | |||
| @@ -50,14 +50,14 @@ impl Default for FirmwareUpdater { | |||
| 50 | 50 | ||
| 51 | let dfu = unsafe { | 51 | let dfu = unsafe { |
| 52 | Partition::new( | 52 | Partition::new( |
| 53 | &__bootloader_dfu_start as *const u32 as usize, | 53 | &__bootloader_dfu_start as *const u32 as u32, |
| 54 | &__bootloader_dfu_end as *const u32 as usize, | 54 | &__bootloader_dfu_end as *const u32 as u32, |
| 55 | ) | 55 | ) |
| 56 | }; | 56 | }; |
| 57 | let state = unsafe { | 57 | let state = unsafe { |
| 58 | Partition::new( | 58 | Partition::new( |
| 59 | &__bootloader_state_start as *const u32 as usize, | 59 | &__bootloader_state_start as *const u32 as u32, |
| 60 | &__bootloader_state_end as *const u32 as usize, | 60 | &__bootloader_state_end as *const u32 as u32, |
| 61 | ) | 61 | ) |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| @@ -73,11 +73,6 @@ impl FirmwareUpdater { | |||
| 73 | Self { dfu, state } | 73 | Self { dfu, state } |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | /// Return the length of the DFU area | ||
| 77 | pub fn firmware_len(&self) -> usize { | ||
| 78 | self.dfu.len() | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Obtain the current state. | 76 | /// Obtain the current state. |
| 82 | /// | 77 | /// |
| 83 | /// This is useful to check if the bootloader has just done a swap, in order | 78 | /// This is useful to check if the bootloader has just done a swap, in order |
| @@ -119,11 +114,11 @@ impl FirmwareUpdater { | |||
| 119 | _state_and_dfu_flash: &mut F, | 114 | _state_and_dfu_flash: &mut F, |
| 120 | _public_key: &[u8], | 115 | _public_key: &[u8], |
| 121 | _signature: &[u8], | 116 | _signature: &[u8], |
| 122 | _update_len: usize, | 117 | _update_len: u32, |
| 123 | _aligned: &mut [u8], | 118 | _aligned: &mut [u8], |
| 124 | ) -> Result<(), FirmwareUpdaterError> { | 119 | ) -> Result<(), FirmwareUpdaterError> { |
| 125 | assert_eq!(_aligned.len(), F::WRITE_SIZE); | 120 | assert_eq!(_aligned.len(), F::WRITE_SIZE); |
| 126 | assert!(_update_len <= self.dfu.len()); | 121 | assert!(_update_len <= self.dfu.size()); |
| 127 | 122 | ||
| 128 | #[cfg(feature = "ed25519-dalek")] | 123 | #[cfg(feature = "ed25519-dalek")] |
| 129 | { | 124 | { |
| @@ -180,11 +175,10 @@ impl FirmwareUpdater { | |||
| 180 | pub async fn hash<F: AsyncNorFlash, D: Digest>( | 175 | pub async fn hash<F: AsyncNorFlash, D: Digest>( |
| 181 | &mut self, | 176 | &mut self, |
| 182 | dfu_flash: &mut F, | 177 | dfu_flash: &mut F, |
| 183 | update_len: usize, | 178 | update_len: u32, |
| 184 | chunk_buf: &mut [u8], | 179 | chunk_buf: &mut [u8], |
| 185 | output: &mut [u8], | 180 | output: &mut [u8], |
| 186 | ) -> Result<(), FirmwareUpdaterError> { | 181 | ) -> Result<(), FirmwareUpdaterError> { |
| 187 | let update_len = update_len as u32; | ||
| 188 | let mut digest = D::new(); | 182 | let mut digest = D::new(); |
| 189 | for offset in (0..update_len).step_by(chunk_buf.len()) { | 183 | for offset in (0..update_len).step_by(chunk_buf.len()) { |
| 190 | self.dfu.read(dfu_flash, offset, chunk_buf).await?; | 184 | self.dfu.read(dfu_flash, offset, chunk_buf).await?; |
| @@ -340,11 +334,11 @@ impl FirmwareUpdater { | |||
| 340 | _state_and_dfu_flash: &mut F, | 334 | _state_and_dfu_flash: &mut F, |
| 341 | _public_key: &[u8], | 335 | _public_key: &[u8], |
| 342 | _signature: &[u8], | 336 | _signature: &[u8], |
| 343 | _update_len: usize, | 337 | _update_len: u32, |
| 344 | _aligned: &mut [u8], | 338 | _aligned: &mut [u8], |
| 345 | ) -> Result<(), FirmwareUpdaterError> { | 339 | ) -> Result<(), FirmwareUpdaterError> { |
| 346 | assert_eq!(_aligned.len(), F::WRITE_SIZE); | 340 | assert_eq!(_aligned.len(), F::WRITE_SIZE); |
| 347 | assert!(_update_len <= self.dfu.len()); | 341 | assert!(_update_len <= self.dfu.size()); |
| 348 | 342 | ||
| 349 | #[cfg(feature = "ed25519-dalek")] | 343 | #[cfg(feature = "ed25519-dalek")] |
| 350 | { | 344 | { |
| @@ -399,11 +393,10 @@ impl FirmwareUpdater { | |||
| 399 | pub fn hash_blocking<F: NorFlash, D: Digest>( | 393 | pub fn hash_blocking<F: NorFlash, D: Digest>( |
| 400 | &mut self, | 394 | &mut self, |
| 401 | dfu_flash: &mut F, | 395 | dfu_flash: &mut F, |
| 402 | update_len: usize, | 396 | update_len: u32, |
| 403 | chunk_buf: &mut [u8], | 397 | chunk_buf: &mut [u8], |
| 404 | output: &mut [u8], | 398 | output: &mut [u8], |
| 405 | ) -> Result<(), FirmwareUpdaterError> { | 399 | ) -> Result<(), FirmwareUpdaterError> { |
| 406 | let update_len = update_len as u32; | ||
| 407 | let mut digest = D::new(); | 400 | let mut digest = D::new(); |
| 408 | for offset in (0..update_len).step_by(chunk_buf.len()) { | 401 | for offset in (0..update_len).step_by(chunk_buf.len()) { |
| 409 | self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; | 402 | self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; |
| @@ -534,7 +527,7 @@ mod tests { | |||
| 534 | block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap(); | 527 | block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap(); |
| 535 | let mut chunk_buf = [0; 2]; | 528 | let mut chunk_buf = [0; 2]; |
| 536 | let mut hash = [0; 20]; | 529 | let mut hash = [0; 20]; |
| 537 | block_on(updater.hash::<_, Sha1>(&mut flash, update.len(), &mut chunk_buf, &mut hash)).unwrap(); | 530 | block_on(updater.hash::<_, Sha1>(&mut flash, update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); |
| 538 | 531 | ||
| 539 | assert_eq!(Sha1::digest(update).as_slice(), hash); | 532 | assert_eq!(Sha1::digest(update).as_slice(), hash); |
| 540 | } | 533 | } |
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index acd90996f..87457b173 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs | |||
| @@ -90,13 +90,11 @@ mod tests { | |||
| 90 | const DFU: Partition = Partition::new(61440, 122880); | 90 | const DFU: Partition = Partition::new(61440, 122880); |
| 91 | let mut flash = MemFlash::<131072, 4096, 4>::random(); | 91 | let mut flash = MemFlash::<131072, 4096, 4>::random(); |
| 92 | 92 | ||
| 93 | let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; | 93 | let original = [rand::random::<u8>(); ACTIVE.size() as usize]; |
| 94 | let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; | 94 | let update = [rand::random::<u8>(); ACTIVE.size() as usize]; |
| 95 | let mut aligned = [0; 4]; | 95 | let mut aligned = [0; 4]; |
| 96 | 96 | ||
| 97 | for i in ACTIVE.from..ACTIVE.to { | 97 | flash.program(ACTIVE.from, &original).unwrap(); |
| 98 | flash.mem[i] = original[i - ACTIVE.from]; | ||
| 99 | } | ||
| 100 | 98 | ||
| 101 | let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); | 99 | let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); |
| 102 | let mut updater = FirmwareUpdater::new(DFU, STATE); | 100 | let mut updater = FirmwareUpdater::new(DFU, STATE); |
| @@ -111,14 +109,9 @@ mod tests { | |||
| 111 | .unwrap() | 109 | .unwrap() |
| 112 | ); | 110 | ); |
| 113 | 111 | ||
| 114 | for i in ACTIVE.from..ACTIVE.to { | 112 | flash.assert_eq(ACTIVE.from, &update); |
| 115 | assert_eq!(flash.mem[i], update[i - ACTIVE.from], "Index {}", i); | ||
| 116 | } | ||
| 117 | |||
| 118 | // First DFU page is untouched | 113 | // First DFU page is untouched |
| 119 | for i in DFU.from + 4096..DFU.to { | 114 | flash.assert_eq(DFU.from + 4096, &original); |
| 120 | assert_eq!(flash.mem[i], original[i - DFU.from - 4096], "Index {}", i); | ||
| 121 | } | ||
| 122 | 115 | ||
| 123 | // Running again should cause a revert | 116 | // Running again should cause a revert |
| 124 | assert_eq!( | 117 | assert_eq!( |
| @@ -128,14 +121,9 @@ mod tests { | |||
| 128 | .unwrap() | 121 | .unwrap() |
| 129 | ); | 122 | ); |
| 130 | 123 | ||
| 131 | for i in ACTIVE.from..ACTIVE.to { | 124 | flash.assert_eq(ACTIVE.from, &original); |
| 132 | assert_eq!(flash.mem[i], original[i - ACTIVE.from], "Index {}", i); | ||
| 133 | } | ||
| 134 | |||
| 135 | // Last page is untouched | 125 | // Last page is untouched |
| 136 | for i in DFU.from..DFU.to - 4096 { | 126 | flash.assert_eq(DFU.from, &update); |
| 137 | assert_eq!(flash.mem[i], update[i - DFU.from], "Index {}", i); | ||
| 138 | } | ||
| 139 | 127 | ||
| 140 | // Mark as booted | 128 | // Mark as booted |
| 141 | block_on(updater.mark_booted(&mut flash, &mut aligned)).unwrap(); | 129 | block_on(updater.mark_booted(&mut flash, &mut aligned)).unwrap(); |
| @@ -159,12 +147,10 @@ mod tests { | |||
| 159 | let mut state = MemFlash::<4096, 128, 4>::random(); | 147 | let mut state = MemFlash::<4096, 128, 4>::random(); |
| 160 | let mut aligned = [0; 4]; | 148 | let mut aligned = [0; 4]; |
| 161 | 149 | ||
| 162 | let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; | 150 | let original = [rand::random::<u8>(); ACTIVE.size() as usize]; |
| 163 | let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; | 151 | let update = [rand::random::<u8>(); ACTIVE.size() as usize]; |
| 164 | 152 | ||
| 165 | for i in ACTIVE.from..ACTIVE.to { | 153 | active.program(ACTIVE.from, &original).unwrap(); |
| 166 | active.mem[i] = original[i - ACTIVE.from]; | ||
| 167 | } | ||
| 168 | 154 | ||
| 169 | let mut updater = FirmwareUpdater::new(DFU, STATE); | 155 | let mut updater = FirmwareUpdater::new(DFU, STATE); |
| 170 | 156 | ||
| @@ -181,14 +167,9 @@ mod tests { | |||
| 181 | .unwrap() | 167 | .unwrap() |
| 182 | ); | 168 | ); |
| 183 | 169 | ||
| 184 | for i in ACTIVE.from..ACTIVE.to { | 170 | active.assert_eq(ACTIVE.from, &update); |
| 185 | assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i); | ||
| 186 | } | ||
| 187 | |||
| 188 | // First DFU page is untouched | 171 | // First DFU page is untouched |
| 189 | for i in DFU.from + 4096..DFU.to { | 172 | dfu.assert_eq(DFU.from + 4096, &original); |
| 190 | assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i); | ||
| 191 | } | ||
| 192 | } | 173 | } |
| 193 | 174 | ||
| 194 | #[test] | 175 | #[test] |
| @@ -203,12 +184,10 @@ mod tests { | |||
| 203 | let mut dfu = MemFlash::<16384, 4096, 8>::random(); | 184 | let mut dfu = MemFlash::<16384, 4096, 8>::random(); |
| 204 | let mut state = MemFlash::<4096, 128, 4>::random(); | 185 | let mut state = MemFlash::<4096, 128, 4>::random(); |
| 205 | 186 | ||
| 206 | let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; | 187 | let original = [rand::random::<u8>(); ACTIVE.size() as usize]; |
| 207 | let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; | 188 | let update = [rand::random::<u8>(); ACTIVE.size() as usize]; |
| 208 | 189 | ||
| 209 | for i in ACTIVE.from..ACTIVE.to { | 190 | active.program(ACTIVE.from, &original).unwrap(); |
| 210 | active.mem[i] = original[i - ACTIVE.from]; | ||
| 211 | } | ||
| 212 | 191 | ||
| 213 | let mut updater = FirmwareUpdater::new(DFU, STATE); | 192 | let mut updater = FirmwareUpdater::new(DFU, STATE); |
| 214 | 193 | ||
| @@ -227,14 +206,9 @@ mod tests { | |||
| 227 | .unwrap() | 206 | .unwrap() |
| 228 | ); | 207 | ); |
| 229 | 208 | ||
| 230 | for i in ACTIVE.from..ACTIVE.to { | 209 | active.assert_eq(ACTIVE.from, &update); |
| 231 | assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i); | ||
| 232 | } | ||
| 233 | |||
| 234 | // First DFU page is untouched | 210 | // First DFU page is untouched |
| 235 | for i in DFU.from + 4096..DFU.to { | 211 | dfu.assert_eq(DFU.from + 4096, &original); |
| 236 | assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i); | ||
| 237 | } | ||
| 238 | } | 212 | } |
| 239 | 213 | ||
| 240 | #[test] | 214 | #[test] |
| @@ -281,7 +255,7 @@ mod tests { | |||
| 281 | &mut flash, | 255 | &mut flash, |
| 282 | &public_key.to_bytes(), | 256 | &public_key.to_bytes(), |
| 283 | &signature.to_bytes(), | 257 | &signature.to_bytes(), |
| 284 | firmware_len, | 258 | firmware_len as u32, |
| 285 | &mut aligned, | 259 | &mut aligned, |
| 286 | )) | 260 | )) |
| 287 | .is_ok()); | 261 | .is_ok()); |
diff --git a/embassy-boot/boot/src/mem_flash.rs b/embassy-boot/boot/src/mem_flash.rs index dd85405c8..c62379b24 100644 --- a/embassy-boot/boot/src/mem_flash.rs +++ b/embassy-boot/boot/src/mem_flash.rs | |||
| @@ -32,6 +32,23 @@ impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> MemFla | |||
| 32 | pending_write_successes: None, | 32 | pending_write_successes: None, |
| 33 | } | 33 | } |
| 34 | } | 34 | } |
| 35 | |||
| 36 | pub fn program(&mut self, offset: u32, bytes: &[u8]) -> Result<(), MemFlashError> { | ||
| 37 | let offset = offset as usize; | ||
| 38 | assert!(bytes.len() % WRITE_SIZE == 0); | ||
| 39 | assert!(offset % WRITE_SIZE == 0); | ||
| 40 | assert!(offset + bytes.len() <= SIZE); | ||
| 41 | |||
| 42 | self.mem[offset..offset + bytes.len()].copy_from_slice(bytes); | ||
| 43 | |||
| 44 | Ok(()) | ||
| 45 | } | ||
| 46 | |||
| 47 | pub fn assert_eq(&self, offset: u32, expectation: &[u8]) { | ||
| 48 | for i in 0..expectation.len() { | ||
| 49 | assert_eq!(self.mem[offset as usize + i], expectation[i], "Index {}", i); | ||
| 50 | } | ||
| 51 | } | ||
| 35 | } | 52 | } |
| 36 | 53 | ||
| 37 | impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> Default | 54 | impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> Default |
diff --git a/embassy-boot/boot/src/partition.rs b/embassy-boot/boot/src/partition.rs index ac6b0ed0f..7529059b6 100644 --- a/embassy-boot/boot/src/partition.rs +++ b/embassy-boot/boot/src/partition.rs | |||
| @@ -6,20 +6,19 @@ use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash | |||
| 6 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 6 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 7 | pub struct Partition { | 7 | pub struct Partition { |
| 8 | /// The offset into the flash where the partition starts. | 8 | /// The offset into the flash where the partition starts. |
| 9 | pub from: usize, | 9 | pub from: u32, |
| 10 | /// The offset into the flash where the partition ends. | 10 | /// The offset into the flash where the partition ends. |
| 11 | pub to: usize, | 11 | pub to: u32, |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | impl Partition { | 14 | impl Partition { |
| 15 | /// Create a new partition with the provided range | 15 | /// Create a new partition with the provided range |
| 16 | pub const fn new(from: usize, to: usize) -> Self { | 16 | pub const fn new(from: u32, to: u32) -> Self { |
| 17 | Self { from, to } | 17 | Self { from, to } |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | /// Return the size of the partition | 20 | /// Return the size of the partition |
| 21 | #[allow(clippy::len_without_is_empty)] | 21 | pub const fn size(&self) -> u32 { |
| 22 | pub const fn len(&self) -> usize { | ||
| 23 | self.to - self.from | 22 | self.to - self.from |
| 24 | } | 23 | } |
| 25 | 24 | ||
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs index a2176f609..d46ed9f36 100644 --- a/embassy-boot/nrf/src/lib.rs +++ b/embassy-boot/nrf/src/lib.rs | |||
| @@ -30,20 +30,20 @@ impl Default for BootLoader<PAGE_SIZE> { | |||
| 30 | 30 | ||
| 31 | let active = unsafe { | 31 | let active = unsafe { |
| 32 | Partition::new( | 32 | Partition::new( |
| 33 | &__bootloader_active_start as *const u32 as usize, | 33 | &__bootloader_active_start as *const u32 as u32, |
| 34 | &__bootloader_active_end as *const u32 as usize, | 34 | &__bootloader_active_end as *const u32 as u32, |
| 35 | ) | 35 | ) |
| 36 | }; | 36 | }; |
| 37 | let dfu = unsafe { | 37 | let dfu = unsafe { |
| 38 | Partition::new( | 38 | Partition::new( |
| 39 | &__bootloader_dfu_start as *const u32 as usize, | 39 | &__bootloader_dfu_start as *const u32 as u32, |
| 40 | &__bootloader_dfu_end as *const u32 as usize, | 40 | &__bootloader_dfu_end as *const u32 as u32, |
| 41 | ) | 41 | ) |
| 42 | }; | 42 | }; |
| 43 | let state = unsafe { | 43 | let state = unsafe { |
| 44 | Partition::new( | 44 | Partition::new( |
| 45 | &__bootloader_state_start as *const u32 as usize, | 45 | &__bootloader_state_start as *const u32 as u32, |
| 46 | &__bootloader_state_end as *const u32 as usize, | 46 | &__bootloader_state_end as *const u32 as u32, |
| 47 | ) | 47 | ) |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
diff --git a/embassy-boot/rp/src/lib.rs b/embassy-boot/rp/src/lib.rs index 0031efa63..c3cb22299 100644 --- a/embassy-boot/rp/src/lib.rs +++ b/embassy-boot/rp/src/lib.rs | |||
| @@ -66,20 +66,20 @@ impl Default for BootLoader<ERASE_SIZE> { | |||
| 66 | 66 | ||
| 67 | let active = unsafe { | 67 | let active = unsafe { |
| 68 | Partition::new( | 68 | Partition::new( |
| 69 | &__bootloader_active_start as *const u32 as usize, | 69 | &__bootloader_active_start as *const u32 as u32, |
| 70 | &__bootloader_active_end as *const u32 as usize, | 70 | &__bootloader_active_end as *const u32 as u32, |
| 71 | ) | 71 | ) |
| 72 | }; | 72 | }; |
| 73 | let dfu = unsafe { | 73 | let dfu = unsafe { |
| 74 | Partition::new( | 74 | Partition::new( |
| 75 | &__bootloader_dfu_start as *const u32 as usize, | 75 | &__bootloader_dfu_start as *const u32 as u32, |
| 76 | &__bootloader_dfu_end as *const u32 as usize, | 76 | &__bootloader_dfu_end as *const u32 as u32, |
| 77 | ) | 77 | ) |
| 78 | }; | 78 | }; |
| 79 | let state = unsafe { | 79 | let state = unsafe { |
| 80 | Partition::new( | 80 | Partition::new( |
| 81 | &__bootloader_state_start as *const u32 as usize, | 81 | &__bootloader_state_start as *const u32 as u32, |
| 82 | &__bootloader_state_end as *const u32 as usize, | 82 | &__bootloader_state_end as *const u32 as u32, |
| 83 | ) | 83 | ) |
| 84 | }; | 84 | }; |
| 85 | 85 | ||
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs index 1f63fcd63..94404697f 100644 --- a/embassy-boot/stm32/src/lib.rs +++ b/embassy-boot/stm32/src/lib.rs | |||
| @@ -61,20 +61,20 @@ impl<const BUFFER_SIZE: usize> Default for BootLoader<BUFFER_SIZE> { | |||
| 61 | 61 | ||
| 62 | let active = unsafe { | 62 | let active = unsafe { |
| 63 | Partition::new( | 63 | Partition::new( |
| 64 | &__bootloader_active_start as *const u32 as usize, | 64 | &__bootloader_active_start as *const u32 as u32, |
| 65 | &__bootloader_active_end as *const u32 as usize, | 65 | &__bootloader_active_end as *const u32 as u32, |
| 66 | ) | 66 | ) |
| 67 | }; | 67 | }; |
| 68 | let dfu = unsafe { | 68 | let dfu = unsafe { |
| 69 | Partition::new( | 69 | Partition::new( |
| 70 | &__bootloader_dfu_start as *const u32 as usize, | 70 | &__bootloader_dfu_start as *const u32 as u32, |
| 71 | &__bootloader_dfu_end as *const u32 as usize, | 71 | &__bootloader_dfu_end as *const u32 as u32, |
| 72 | ) | 72 | ) |
| 73 | }; | 73 | }; |
| 74 | let state = unsafe { | 74 | let state = unsafe { |
| 75 | Partition::new( | 75 | Partition::new( |
| 76 | &__bootloader_state_start as *const u32 as usize, | 76 | &__bootloader_state_start as *const u32 as u32, |
| 77 | &__bootloader_state_end as *const u32 as usize, | 77 | &__bootloader_state_end as *const u32 as u32, |
| 78 | ) | 78 | ) |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
