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