diff options
Diffstat (limited to 'embassy-boot')
| -rw-r--r-- | embassy-boot/boot/src/firmware_updater.rs | 137 | ||||
| -rw-r--r-- | embassy-boot/boot/src/partition.rs | 51 | ||||
| -rw-r--r-- | embassy-boot/nrf/Cargo.toml | 6 |
3 files changed, 99 insertions, 95 deletions
diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs index f3d76a56c..1f2a6d24e 100644 --- a/embassy-boot/boot/src/firmware_updater.rs +++ b/embassy-boot/boot/src/firmware_updater.rs | |||
| @@ -74,21 +74,18 @@ impl FirmwareUpdater { | |||
| 74 | Self { dfu, state } | 74 | Self { dfu, state } |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | // | ||
| 78 | // Blocking API | ||
| 79 | // | ||
| 80 | |||
| 81 | /// Obtain the current state. | 77 | /// Obtain the current state. |
| 82 | /// | 78 | /// |
| 83 | /// This is useful to check if the bootloader has just done a swap, in order | 79 | /// This is useful to check if the bootloader has just done a swap, in order |
| 84 | /// to do verifications and self-tests of the new image before calling | 80 | /// to do verifications and self-tests of the new image before calling |
| 85 | /// `mark_booted`. | 81 | /// `mark_booted`. |
| 86 | pub fn get_state_blocking<F: NorFlash>( | 82 | #[cfg(feature = "nightly")] |
| 83 | pub async fn get_state<F: AsyncNorFlash>( | ||
| 87 | &mut self, | 84 | &mut self, |
| 88 | state_flash: &mut F, | 85 | state_flash: &mut F, |
| 89 | aligned: &mut [u8], | 86 | aligned: &mut [u8], |
| 90 | ) -> Result<State, FirmwareUpdaterError> { | 87 | ) -> Result<State, FirmwareUpdaterError> { |
| 91 | self.state.read_blocking(state_flash, 0, aligned)?; | 88 | self.state.read(state_flash, 0, aligned).await?; |
| 92 | 89 | ||
| 93 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | 90 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { |
| 94 | Ok(State::Swap) | 91 | Ok(State::Swap) |
| @@ -113,8 +110,8 @@ impl FirmwareUpdater { | |||
| 113 | /// | 110 | /// |
| 114 | /// The `_aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being read from | 111 | /// The `_aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being read from |
| 115 | /// and written to. | 112 | /// and written to. |
| 116 | #[cfg(feature = "_verify")] | 113 | #[cfg(all(feature = "_verify", feature = "nightly"))] |
| 117 | pub fn verify_and_mark_updated_blocking<F: NorFlash>( | 114 | pub async fn verify_and_mark_updated<F: AsyncNorFlash>( |
| 118 | &mut self, | 115 | &mut self, |
| 119 | _state_and_dfu_flash: &mut F, | 116 | _state_and_dfu_flash: &mut F, |
| 120 | _public_key: &[u8], | 117 | _public_key: &[u8], |
| @@ -137,7 +134,8 @@ impl FirmwareUpdater { | |||
| 137 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; | 134 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; |
| 138 | 135 | ||
| 139 | let mut message = [0; 64]; | 136 | let mut message = [0; 64]; |
| 140 | self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; | 137 | self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) |
| 138 | .await?; | ||
| 141 | 139 | ||
| 142 | public_key.verify(&message, &signature).map_err(into_signature_error)? | 140 | public_key.verify(&message, &signature).map_err(into_signature_error)? |
| 143 | } | 141 | } |
| @@ -158,7 +156,8 @@ impl FirmwareUpdater { | |||
| 158 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; | 156 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; |
| 159 | 157 | ||
| 160 | let mut message = [0; 64]; | 158 | let mut message = [0; 64]; |
| 161 | self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; | 159 | self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) |
| 160 | .await?; | ||
| 162 | 161 | ||
| 163 | let r = public_key.verify(&message, &signature); | 162 | let r = public_key.verify(&message, &signature); |
| 164 | trace!( | 163 | trace!( |
| @@ -171,11 +170,12 @@ impl FirmwareUpdater { | |||
| 171 | r.map_err(into_signature_error)? | 170 | r.map_err(into_signature_error)? |
| 172 | } | 171 | } |
| 173 | 172 | ||
| 174 | self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) | 173 | self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await |
| 175 | } | 174 | } |
| 176 | 175 | ||
| 177 | /// Verify the update in DFU with any digest. | 176 | /// Verify the update in DFU with any digest. |
| 178 | pub fn hash_blocking<F: NorFlash, D: Digest>( | 177 | #[cfg(feature = "nightly")] |
| 178 | pub async fn hash<F: AsyncNorFlash, D: Digest>( | ||
| 179 | &mut self, | 179 | &mut self, |
| 180 | dfu_flash: &mut F, | 180 | dfu_flash: &mut F, |
| 181 | update_len: u32, | 181 | update_len: u32, |
| @@ -184,7 +184,7 @@ impl FirmwareUpdater { | |||
| 184 | ) -> Result<(), FirmwareUpdaterError> { | 184 | ) -> Result<(), FirmwareUpdaterError> { |
| 185 | let mut digest = D::new(); | 185 | let mut digest = D::new(); |
| 186 | for offset in (0..update_len).step_by(chunk_buf.len()) { | 186 | for offset in (0..update_len).step_by(chunk_buf.len()) { |
| 187 | self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; | 187 | self.dfu.read(dfu_flash, offset, chunk_buf).await?; |
| 188 | let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); | 188 | let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); |
| 189 | digest.update(&chunk_buf[..len]); | 189 | digest.update(&chunk_buf[..len]); |
| 190 | } | 190 | } |
| @@ -197,14 +197,14 @@ impl FirmwareUpdater { | |||
| 197 | /// # Safety | 197 | /// # Safety |
| 198 | /// | 198 | /// |
| 199 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | 199 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. |
| 200 | #[cfg(not(feature = "_verify"))] | 200 | #[cfg(all(feature = "nightly", not(feature = "_verify")))] |
| 201 | pub fn mark_updated_blocking<F: NorFlash>( | 201 | pub async fn mark_updated<F: AsyncNorFlash>( |
| 202 | &mut self, | 202 | &mut self, |
| 203 | state_flash: &mut F, | 203 | state_flash: &mut F, |
| 204 | aligned: &mut [u8], | 204 | aligned: &mut [u8], |
| 205 | ) -> Result<(), FirmwareUpdaterError> { | 205 | ) -> Result<(), FirmwareUpdaterError> { |
| 206 | assert_eq!(aligned.len(), F::WRITE_SIZE); | 206 | assert_eq!(aligned.len(), F::WRITE_SIZE); |
| 207 | self.set_magic_blocking(aligned, SWAP_MAGIC, state_flash) | 207 | self.set_magic(aligned, SWAP_MAGIC, state_flash).await |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | /// Mark firmware boot successful and stop rollback on reset. | 210 | /// Mark firmware boot successful and stop rollback on reset. |
| @@ -212,26 +212,28 @@ impl FirmwareUpdater { | |||
| 212 | /// # Safety | 212 | /// # Safety |
| 213 | /// | 213 | /// |
| 214 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | 214 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. |
| 215 | pub fn mark_booted_blocking<F: NorFlash>( | 215 | #[cfg(feature = "nightly")] |
| 216 | pub async fn mark_booted<F: AsyncNorFlash>( | ||
| 216 | &mut self, | 217 | &mut self, |
| 217 | state_flash: &mut F, | 218 | state_flash: &mut F, |
| 218 | aligned: &mut [u8], | 219 | aligned: &mut [u8], |
| 219 | ) -> Result<(), FirmwareUpdaterError> { | 220 | ) -> Result<(), FirmwareUpdaterError> { |
| 220 | assert_eq!(aligned.len(), F::WRITE_SIZE); | 221 | assert_eq!(aligned.len(), F::WRITE_SIZE); |
| 221 | self.set_magic_blocking(aligned, BOOT_MAGIC, state_flash) | 222 | self.set_magic(aligned, BOOT_MAGIC, state_flash).await |
| 222 | } | 223 | } |
| 223 | 224 | ||
| 224 | fn set_magic_blocking<F: NorFlash>( | 225 | #[cfg(feature = "nightly")] |
| 226 | async fn set_magic<F: AsyncNorFlash>( | ||
| 225 | &mut self, | 227 | &mut self, |
| 226 | aligned: &mut [u8], | 228 | aligned: &mut [u8], |
| 227 | magic: u8, | 229 | magic: u8, |
| 228 | state_flash: &mut F, | 230 | state_flash: &mut F, |
| 229 | ) -> Result<(), FirmwareUpdaterError> { | 231 | ) -> Result<(), FirmwareUpdaterError> { |
| 230 | self.state.read_blocking(state_flash, 0, aligned)?; | 232 | self.state.read(state_flash, 0, aligned).await?; |
| 231 | 233 | ||
| 232 | if aligned.iter().any(|&b| b != magic) { | 234 | if aligned.iter().any(|&b| b != magic) { |
| 233 | // Read progress validity | 235 | // Read progress validity |
| 234 | self.state.read_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?; | 236 | self.state.read(state_flash, F::WRITE_SIZE as u32, aligned).await?; |
| 235 | 237 | ||
| 236 | // FIXME: Do not make this assumption. | 238 | // FIXME: Do not make this assumption. |
| 237 | const STATE_ERASE_VALUE: u8 = 0xFF; | 239 | const STATE_ERASE_VALUE: u8 = 0xFF; |
| @@ -241,15 +243,15 @@ impl FirmwareUpdater { | |||
| 241 | } else { | 243 | } else { |
| 242 | // Invalidate progress | 244 | // Invalidate progress |
| 243 | aligned.fill(!STATE_ERASE_VALUE); | 245 | aligned.fill(!STATE_ERASE_VALUE); |
| 244 | self.state.write_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?; | 246 | self.state.write(state_flash, F::WRITE_SIZE as u32, aligned).await?; |
| 245 | } | 247 | } |
| 246 | 248 | ||
| 247 | // Clear magic and progress | 249 | // Clear magic and progress |
| 248 | self.state.wipe_blocking(state_flash)?; | 250 | self.state.wipe(state_flash).await?; |
| 249 | 251 | ||
| 250 | // Set magic | 252 | // Set magic |
| 251 | aligned.fill(magic); | 253 | aligned.fill(magic); |
| 252 | self.state.write_blocking(state_flash, 0, aligned)?; | 254 | self.state.write(state_flash, 0, aligned).await?; |
| 253 | } | 255 | } |
| 254 | Ok(()) | 256 | Ok(()) |
| 255 | } | 257 | } |
| @@ -261,7 +263,8 @@ impl FirmwareUpdater { | |||
| 261 | /// # Safety | 263 | /// # Safety |
| 262 | /// | 264 | /// |
| 263 | /// Failing to meet alignment and size requirements may result in a panic. | 265 | /// Failing to meet alignment and size requirements may result in a panic. |
| 264 | pub fn write_firmware_blocking<F: NorFlash>( | 266 | #[cfg(feature = "nightly")] |
| 267 | pub async fn write_firmware<F: AsyncNorFlash>( | ||
| 265 | &mut self, | 268 | &mut self, |
| 266 | offset: usize, | 269 | offset: usize, |
| 267 | data: &[u8], | 270 | data: &[u8], |
| @@ -270,9 +273,10 @@ impl FirmwareUpdater { | |||
| 270 | assert!(data.len() >= F::ERASE_SIZE); | 273 | assert!(data.len() >= F::ERASE_SIZE); |
| 271 | 274 | ||
| 272 | self.dfu | 275 | self.dfu |
| 273 | .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?; | 276 | .erase(dfu_flash, offset as u32, (offset + data.len()) as u32) |
| 277 | .await?; | ||
| 274 | 278 | ||
| 275 | self.dfu.write_blocking(dfu_flash, offset as u32, data)?; | 279 | self.dfu.write(dfu_flash, offset as u32, data).await?; |
| 276 | 280 | ||
| 277 | Ok(()) | 281 | Ok(()) |
| 278 | } | 282 | } |
| @@ -280,29 +284,33 @@ impl FirmwareUpdater { | |||
| 280 | /// Prepare for an incoming DFU update by erasing the entire DFU area and | 284 | /// Prepare for an incoming DFU update by erasing the entire DFU area and |
| 281 | /// returning its `Partition`. | 285 | /// returning its `Partition`. |
| 282 | /// | 286 | /// |
| 283 | /// Using this instead of `write_firmware_blocking` allows for an optimized | 287 | /// Using this instead of `write_firmware` allows for an optimized API in |
| 284 | /// API in exchange for added complexity. | 288 | /// exchange for added complexity. |
| 285 | pub fn prepare_update_blocking<F: NorFlash>(&mut self, flash: &mut F) -> Result<Partition, FirmwareUpdaterError> { | 289 | #[cfg(feature = "nightly")] |
| 286 | self.dfu.wipe_blocking(flash)?; | 290 | pub async fn prepare_update<F: AsyncNorFlash>( |
| 291 | &mut self, | ||
| 292 | dfu_flash: &mut F, | ||
| 293 | ) -> Result<Partition, FirmwareUpdaterError> { | ||
| 294 | self.dfu.wipe(dfu_flash).await?; | ||
| 287 | 295 | ||
| 288 | Ok(self.dfu) | 296 | Ok(self.dfu) |
| 289 | } | 297 | } |
| 290 | } | ||
| 291 | 298 | ||
| 292 | // Async API | 299 | // |
| 293 | #[cfg(feature = "nightly")] | 300 | // Blocking API |
| 294 | impl FirmwareUpdater { | 301 | // |
| 302 | |||
| 295 | /// Obtain the current state. | 303 | /// Obtain the current state. |
| 296 | /// | 304 | /// |
| 297 | /// This is useful to check if the bootloader has just done a swap, in order | 305 | /// This is useful to check if the bootloader has just done a swap, in order |
| 298 | /// to do verifications and self-tests of the new image before calling | 306 | /// to do verifications and self-tests of the new image before calling |
| 299 | /// `mark_booted`. | 307 | /// `mark_booted`. |
| 300 | pub async fn get_state<F: AsyncNorFlash>( | 308 | pub fn get_state_blocking<F: NorFlash>( |
| 301 | &mut self, | 309 | &mut self, |
| 302 | state_flash: &mut F, | 310 | state_flash: &mut F, |
| 303 | aligned: &mut [u8], | 311 | aligned: &mut [u8], |
| 304 | ) -> Result<State, FirmwareUpdaterError> { | 312 | ) -> Result<State, FirmwareUpdaterError> { |
| 305 | self.state.read(state_flash, 0, aligned).await?; | 313 | self.state.read_blocking(state_flash, 0, aligned)?; |
| 306 | 314 | ||
| 307 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | 315 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { |
| 308 | Ok(State::Swap) | 316 | Ok(State::Swap) |
| @@ -328,7 +336,7 @@ impl FirmwareUpdater { | |||
| 328 | /// The `_aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being read from | 336 | /// The `_aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being read from |
| 329 | /// and written to. | 337 | /// and written to. |
| 330 | #[cfg(feature = "_verify")] | 338 | #[cfg(feature = "_verify")] |
| 331 | pub async fn verify_and_mark_updated<F: AsyncNorFlash>( | 339 | pub fn verify_and_mark_updated_blocking<F: NorFlash>( |
| 332 | &mut self, | 340 | &mut self, |
| 333 | _state_and_dfu_flash: &mut F, | 341 | _state_and_dfu_flash: &mut F, |
| 334 | _public_key: &[u8], | 342 | _public_key: &[u8], |
| @@ -351,8 +359,7 @@ impl FirmwareUpdater { | |||
| 351 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; | 359 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; |
| 352 | 360 | ||
| 353 | let mut message = [0; 64]; | 361 | let mut message = [0; 64]; |
| 354 | self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) | 362 | self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; |
| 355 | .await?; | ||
| 356 | 363 | ||
| 357 | public_key.verify(&message, &signature).map_err(into_signature_error)? | 364 | public_key.verify(&message, &signature).map_err(into_signature_error)? |
| 358 | } | 365 | } |
| @@ -373,8 +380,7 @@ impl FirmwareUpdater { | |||
| 373 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; | 380 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; |
| 374 | 381 | ||
| 375 | let mut message = [0; 64]; | 382 | let mut message = [0; 64]; |
| 376 | self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) | 383 | self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; |
| 377 | .await?; | ||
| 378 | 384 | ||
| 379 | let r = public_key.verify(&message, &signature); | 385 | let r = public_key.verify(&message, &signature); |
| 380 | trace!( | 386 | trace!( |
| @@ -387,11 +393,11 @@ impl FirmwareUpdater { | |||
| 387 | r.map_err(into_signature_error)? | 393 | r.map_err(into_signature_error)? |
| 388 | } | 394 | } |
| 389 | 395 | ||
| 390 | self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await | 396 | self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) |
| 391 | } | 397 | } |
| 392 | 398 | ||
| 393 | /// Verify the update in DFU with any digest. | 399 | /// Verify the update in DFU with any digest. |
| 394 | pub async fn hash<F: AsyncNorFlash, D: Digest>( | 400 | pub fn hash_blocking<F: NorFlash, D: Digest>( |
| 395 | &mut self, | 401 | &mut self, |
| 396 | dfu_flash: &mut F, | 402 | dfu_flash: &mut F, |
| 397 | update_len: u32, | 403 | update_len: u32, |
| @@ -400,7 +406,7 @@ impl FirmwareUpdater { | |||
| 400 | ) -> Result<(), FirmwareUpdaterError> { | 406 | ) -> Result<(), FirmwareUpdaterError> { |
| 401 | let mut digest = D::new(); | 407 | let mut digest = D::new(); |
| 402 | for offset in (0..update_len).step_by(chunk_buf.len()) { | 408 | for offset in (0..update_len).step_by(chunk_buf.len()) { |
| 403 | self.dfu.read(dfu_flash, offset, chunk_buf).await?; | 409 | self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; |
| 404 | let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); | 410 | let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); |
| 405 | digest.update(&chunk_buf[..len]); | 411 | digest.update(&chunk_buf[..len]); |
| 406 | } | 412 | } |
| @@ -414,13 +420,13 @@ impl FirmwareUpdater { | |||
| 414 | /// | 420 | /// |
| 415 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | 421 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. |
| 416 | #[cfg(not(feature = "_verify"))] | 422 | #[cfg(not(feature = "_verify"))] |
| 417 | pub async fn mark_updated<F: AsyncNorFlash>( | 423 | pub fn mark_updated_blocking<F: NorFlash>( |
| 418 | &mut self, | 424 | &mut self, |
| 419 | state_flash: &mut F, | 425 | state_flash: &mut F, |
| 420 | aligned: &mut [u8], | 426 | aligned: &mut [u8], |
| 421 | ) -> Result<(), FirmwareUpdaterError> { | 427 | ) -> Result<(), FirmwareUpdaterError> { |
| 422 | assert_eq!(aligned.len(), F::WRITE_SIZE); | 428 | assert_eq!(aligned.len(), F::WRITE_SIZE); |
| 423 | self.set_magic(aligned, SWAP_MAGIC, state_flash).await | 429 | self.set_magic_blocking(aligned, SWAP_MAGIC, state_flash) |
| 424 | } | 430 | } |
| 425 | 431 | ||
| 426 | /// Mark firmware boot successful and stop rollback on reset. | 432 | /// Mark firmware boot successful and stop rollback on reset. |
| @@ -428,26 +434,26 @@ impl FirmwareUpdater { | |||
| 428 | /// # Safety | 434 | /// # Safety |
| 429 | /// | 435 | /// |
| 430 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | 436 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. |
| 431 | pub async fn mark_booted<F: AsyncNorFlash>( | 437 | pub fn mark_booted_blocking<F: NorFlash>( |
| 432 | &mut self, | 438 | &mut self, |
| 433 | state_flash: &mut F, | 439 | state_flash: &mut F, |
| 434 | aligned: &mut [u8], | 440 | aligned: &mut [u8], |
| 435 | ) -> Result<(), FirmwareUpdaterError> { | 441 | ) -> Result<(), FirmwareUpdaterError> { |
| 436 | assert_eq!(aligned.len(), F::WRITE_SIZE); | 442 | assert_eq!(aligned.len(), F::WRITE_SIZE); |
| 437 | self.set_magic(aligned, BOOT_MAGIC, state_flash).await | 443 | self.set_magic_blocking(aligned, BOOT_MAGIC, state_flash) |
| 438 | } | 444 | } |
| 439 | 445 | ||
| 440 | async fn set_magic<F: AsyncNorFlash>( | 446 | fn set_magic_blocking<F: NorFlash>( |
| 441 | &mut self, | 447 | &mut self, |
| 442 | aligned: &mut [u8], | 448 | aligned: &mut [u8], |
| 443 | magic: u8, | 449 | magic: u8, |
| 444 | state_flash: &mut F, | 450 | state_flash: &mut F, |
| 445 | ) -> Result<(), FirmwareUpdaterError> { | 451 | ) -> Result<(), FirmwareUpdaterError> { |
| 446 | self.state.read(state_flash, 0, aligned).await?; | 452 | self.state.read_blocking(state_flash, 0, aligned)?; |
| 447 | 453 | ||
| 448 | if aligned.iter().any(|&b| b != magic) { | 454 | if aligned.iter().any(|&b| b != magic) { |
| 449 | // Read progress validity | 455 | // Read progress validity |
| 450 | self.state.read(state_flash, F::WRITE_SIZE as u32, aligned).await?; | 456 | self.state.read_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?; |
| 451 | 457 | ||
| 452 | // FIXME: Do not make this assumption. | 458 | // FIXME: Do not make this assumption. |
| 453 | const STATE_ERASE_VALUE: u8 = 0xFF; | 459 | const STATE_ERASE_VALUE: u8 = 0xFF; |
| @@ -457,15 +463,15 @@ impl FirmwareUpdater { | |||
| 457 | } else { | 463 | } else { |
| 458 | // Invalidate progress | 464 | // Invalidate progress |
| 459 | aligned.fill(!STATE_ERASE_VALUE); | 465 | aligned.fill(!STATE_ERASE_VALUE); |
| 460 | self.state.write(state_flash, F::WRITE_SIZE as u32, aligned).await?; | 466 | self.state.write_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?; |
| 461 | } | 467 | } |
| 462 | 468 | ||
| 463 | // Clear magic and progress | 469 | // Clear magic and progress |
| 464 | self.state.wipe(state_flash).await?; | 470 | self.state.wipe_blocking(state_flash)?; |
| 465 | 471 | ||
| 466 | // Set magic | 472 | // Set magic |
| 467 | aligned.fill(magic); | 473 | aligned.fill(magic); |
| 468 | self.state.write(state_flash, 0, aligned).await?; | 474 | self.state.write_blocking(state_flash, 0, aligned)?; |
| 469 | } | 475 | } |
| 470 | Ok(()) | 476 | Ok(()) |
| 471 | } | 477 | } |
| @@ -477,7 +483,7 @@ impl FirmwareUpdater { | |||
| 477 | /// # Safety | 483 | /// # Safety |
| 478 | /// | 484 | /// |
| 479 | /// Failing to meet alignment and size requirements may result in a panic. | 485 | /// Failing to meet alignment and size requirements may result in a panic. |
| 480 | pub async fn write_firmware<F: AsyncNorFlash>( | 486 | pub fn write_firmware_blocking<F: NorFlash>( |
| 481 | &mut self, | 487 | &mut self, |
| 482 | offset: usize, | 488 | offset: usize, |
| 483 | data: &[u8], | 489 | data: &[u8], |
| @@ -486,10 +492,9 @@ impl FirmwareUpdater { | |||
| 486 | assert!(data.len() >= F::ERASE_SIZE); | 492 | assert!(data.len() >= F::ERASE_SIZE); |
| 487 | 493 | ||
| 488 | self.dfu | 494 | self.dfu |
| 489 | .erase(dfu_flash, offset as u32, (offset + data.len()) as u32) | 495 | .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?; |
| 490 | .await?; | ||
| 491 | 496 | ||
| 492 | self.dfu.write(dfu_flash, offset as u32, data).await?; | 497 | self.dfu.write_blocking(dfu_flash, offset as u32, data)?; |
| 493 | 498 | ||
| 494 | Ok(()) | 499 | Ok(()) |
| 495 | } | 500 | } |
| @@ -497,20 +502,16 @@ impl FirmwareUpdater { | |||
| 497 | /// Prepare for an incoming DFU update by erasing the entire DFU area and | 502 | /// Prepare for an incoming DFU update by erasing the entire DFU area and |
| 498 | /// returning its `Partition`. | 503 | /// returning its `Partition`. |
| 499 | /// | 504 | /// |
| 500 | /// Using this instead of `write_firmware` allows for an optimized API in | 505 | /// Using this instead of `write_firmware_blocking` allows for an optimized |
| 501 | /// exchange for added complexity. | 506 | /// API in exchange for added complexity. |
| 502 | pub async fn prepare_update<F: AsyncNorFlash>( | 507 | pub fn prepare_update_blocking<F: NorFlash>(&mut self, flash: &mut F) -> Result<Partition, FirmwareUpdaterError> { |
| 503 | &mut self, | 508 | self.dfu.wipe_blocking(flash)?; |
| 504 | dfu_flash: &mut F, | ||
| 505 | ) -> Result<Partition, FirmwareUpdaterError> { | ||
| 506 | self.dfu.wipe(dfu_flash).await?; | ||
| 507 | 509 | ||
| 508 | Ok(self.dfu) | 510 | Ok(self.dfu) |
| 509 | } | 511 | } |
| 510 | } | 512 | } |
| 511 | 513 | ||
| 512 | 514 | #[cfg(test)] | |
| 513 | #[cfg(test)] | ||
| 514 | mod tests { | 515 | mod tests { |
| 515 | use futures::executor::block_on; | 516 | use futures::executor::block_on; |
| 516 | use sha1::{Digest, Sha1}; | 517 | use sha1::{Digest, Sha1}; |
diff --git a/embassy-boot/boot/src/partition.rs b/embassy-boot/boot/src/partition.rs index 67bd7abba..7b56a8240 100644 --- a/embassy-boot/boot/src/partition.rs +++ b/embassy-boot/boot/src/partition.rs | |||
| @@ -24,75 +24,74 @@ impl Partition { | |||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | /// Read from the partition on the provided flash | 26 | /// Read from the partition on the provided flash |
| 27 | pub fn read_blocking<F: ReadNorFlash>(&self, flash: &mut F, offset: u32, bytes: &mut [u8]) -> Result<(), F::Error> { | 27 | #[cfg(feature = "nightly")] |
| 28 | pub async fn read<F: AsyncReadNorFlash>( | ||
| 29 | &self, | ||
| 30 | flash: &mut F, | ||
| 31 | offset: u32, | ||
| 32 | bytes: &mut [u8], | ||
| 33 | ) -> Result<(), F::Error> { | ||
| 28 | let offset = self.from as u32 + offset; | 34 | let offset = self.from as u32 + offset; |
| 29 | flash.read(offset, bytes) | 35 | flash.read(offset, bytes).await |
| 30 | } | 36 | } |
| 31 | 37 | ||
| 32 | /// Write to the partition on the provided flash | 38 | /// Write to the partition on the provided flash |
| 33 | pub fn write_blocking<F: NorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> { | 39 | #[cfg(feature = "nightly")] |
| 40 | pub async fn write<F: AsyncNorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> { | ||
| 34 | let offset = self.from as u32 + offset; | 41 | let offset = self.from as u32 + offset; |
| 35 | flash.write(offset, bytes)?; | 42 | flash.write(offset, bytes).await?; |
| 36 | trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); | 43 | trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); |
| 37 | Ok(()) | 44 | Ok(()) |
| 38 | } | 45 | } |
| 39 | 46 | ||
| 40 | /// Erase part of the partition on the provided flash | 47 | /// Erase part of the partition on the provided flash |
| 41 | pub fn erase_blocking<F: NorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { | 48 | #[cfg(feature = "nightly")] |
| 49 | pub async fn erase<F: AsyncNorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { | ||
| 42 | let from = self.from as u32 + from; | 50 | let from = self.from as u32 + from; |
| 43 | let to = self.from as u32 + to; | 51 | let to = self.from as u32 + to; |
| 44 | flash.erase(from, to)?; | 52 | flash.erase(from, to).await?; |
| 45 | trace!("Erased from 0x{:x} to 0x{:x}", from, to); | 53 | trace!("Erased from 0x{:x} to 0x{:x}", from, to); |
| 46 | Ok(()) | 54 | Ok(()) |
| 47 | } | 55 | } |
| 48 | 56 | ||
| 49 | /// Erase the entire partition | 57 | /// Erase the entire partition |
| 50 | pub(crate) fn wipe_blocking<F: NorFlash>(&self, flash: &mut F) -> Result<(), F::Error> { | 58 | #[cfg(feature = "nightly")] |
| 59 | pub(crate) async fn wipe<F: AsyncNorFlash>(&self, flash: &mut F) -> Result<(), F::Error> { | ||
| 51 | let from = self.from as u32; | 60 | let from = self.from as u32; |
| 52 | let to = self.to as u32; | 61 | let to = self.to as u32; |
| 53 | flash.erase(from, to)?; | 62 | flash.erase(from, to).await?; |
| 54 | trace!("Wiped from 0x{:x} to 0x{:x}", from, to); | 63 | trace!("Wiped from 0x{:x} to 0x{:x}", from, to); |
| 55 | Ok(()) | 64 | Ok(()) |
| 56 | } | 65 | } |
| 57 | } | ||
| 58 | |||
| 59 | // Async API | ||
| 60 | #[cfg(feature = "nightly")] | ||
| 61 | impl Partition { | ||
| 62 | 66 | ||
| 63 | /// Read from the partition on the provided flash | 67 | /// Read from the partition on the provided flash |
| 64 | pub async fn read<F: AsyncReadNorFlash>( | 68 | pub fn read_blocking<F: ReadNorFlash>(&self, flash: &mut F, offset: u32, bytes: &mut [u8]) -> Result<(), F::Error> { |
| 65 | &self, | ||
| 66 | flash: &mut F, | ||
| 67 | offset: u32, | ||
| 68 | bytes: &mut [u8], | ||
| 69 | ) -> Result<(), F::Error> { | ||
| 70 | let offset = self.from as u32 + offset; | 69 | let offset = self.from as u32 + offset; |
| 71 | flash.read(offset, bytes).await | 70 | flash.read(offset, bytes) |
| 72 | } | 71 | } |
| 73 | 72 | ||
| 74 | /// Write to the partition on the provided flash | 73 | /// Write to the partition on the provided flash |
| 75 | pub async fn write<F: AsyncNorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> { | 74 | pub fn write_blocking<F: NorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> { |
| 76 | let offset = self.from as u32 + offset; | 75 | let offset = self.from as u32 + offset; |
| 77 | flash.write(offset, bytes).await?; | 76 | flash.write(offset, bytes)?; |
| 78 | trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); | 77 | trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); |
| 79 | Ok(()) | 78 | Ok(()) |
| 80 | } | 79 | } |
| 81 | 80 | ||
| 82 | /// Erase part of the partition on the provided flash | 81 | /// Erase part of the partition on the provided flash |
| 83 | pub async fn erase<F: AsyncNorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { | 82 | pub fn erase_blocking<F: NorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { |
| 84 | let from = self.from as u32 + from; | 83 | let from = self.from as u32 + from; |
| 85 | let to = self.from as u32 + to; | 84 | let to = self.from as u32 + to; |
| 86 | flash.erase(from, to).await?; | 85 | flash.erase(from, to)?; |
| 87 | trace!("Erased from 0x{:x} to 0x{:x}", from, to); | 86 | trace!("Erased from 0x{:x} to 0x{:x}", from, to); |
| 88 | Ok(()) | 87 | Ok(()) |
| 89 | } | 88 | } |
| 90 | 89 | ||
| 91 | /// Erase the entire partition | 90 | /// Erase the entire partition |
| 92 | pub(crate) async fn wipe<F: AsyncNorFlash>(&self, flash: &mut F) -> Result<(), F::Error> { | 91 | pub(crate) fn wipe_blocking<F: NorFlash>(&self, flash: &mut F) -> Result<(), F::Error> { |
| 93 | let from = self.from as u32; | 92 | let from = self.from as u32; |
| 94 | let to = self.to as u32; | 93 | let to = self.to as u32; |
| 95 | flash.erase(from, to).await?; | 94 | flash.erase(from, to)?; |
| 96 | trace!("Wiped from 0x{:x} to 0x{:x}", from, to); | 95 | trace!("Wiped from 0x{:x} to 0x{:x}", from, to); |
| 97 | Ok(()) | 96 | Ok(()) |
| 98 | } | 97 | } |
diff --git a/embassy-boot/nrf/Cargo.toml b/embassy-boot/nrf/Cargo.toml index 90a36d014..05ab87896 100644 --- a/embassy-boot/nrf/Cargo.toml +++ b/embassy-boot/nrf/Cargo.toml | |||
| @@ -37,4 +37,8 @@ defmt = [ | |||
| 37 | softdevice = [ | 37 | softdevice = [ |
| 38 | "nrf-softdevice-mbr", | 38 | "nrf-softdevice-mbr", |
| 39 | ] | 39 | ] |
| 40 | nightly = ["dep:embedded-storage-async", "embassy-boot/nightly", "embassy-nrf/nightly"] | 40 | nightly = [ |
| 41 | "dep:embedded-storage-async", | ||
| 42 | "embassy-boot/nightly", | ||
| 43 | "embassy-nrf/nightly" | ||
| 44 | ] | ||
