diff options
Diffstat (limited to 'embassy-boot')
| -rw-r--r-- | embassy-boot/boot/src/firmware_updater/asynch.rs | 188 | ||||
| -rw-r--r-- | embassy-boot/boot/src/firmware_updater/blocking.rs | 196 | ||||
| -rw-r--r-- | embassy-boot/boot/src/firmware_updater/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-boot/boot/src/lib.rs | 79 | ||||
| -rw-r--r-- | embassy-boot/nrf/src/lib.rs | 6 | ||||
| -rw-r--r-- | embassy-boot/rp/src/lib.rs | 6 | ||||
| -rw-r--r-- | embassy-boot/stm32/src/lib.rs | 6 |
7 files changed, 268 insertions, 217 deletions
diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs index 20731ee0a..ae713bb6f 100644 --- a/embassy-boot/boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/boot/src/firmware_updater/asynch.rs | |||
| @@ -10,9 +10,9 @@ use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAG | |||
| 10 | 10 | ||
| 11 | /// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to | 11 | /// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to |
| 12 | /// 'mess up' the internal bootloader state | 12 | /// 'mess up' the internal bootloader state |
| 13 | pub struct FirmwareUpdater<DFU: NorFlash, STATE: NorFlash> { | 13 | pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { |
| 14 | dfu: DFU, | 14 | dfu: DFU, |
| 15 | state: STATE, | 15 | state: FirmwareState<'d, STATE>, |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | #[cfg(target_os = "none")] | 18 | #[cfg(target_os = "none")] |
| @@ -47,22 +47,12 @@ impl<'a, FLASH: NorFlash> | |||
| 47 | } | 47 | } |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | 50 | impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { |
| 51 | /// Create a firmware updater instance with partition ranges for the update and state partitions. | 51 | /// Create a firmware updater instance with partition ranges for the update and state partitions. |
| 52 | pub fn new(config: FirmwareUpdaterConfig<DFU, STATE>) -> Self { | 52 | pub fn new(config: FirmwareUpdaterConfig<DFU, STATE>, aligned: &'d mut [u8]) -> Self { |
| 53 | Self { | 53 | Self { |
| 54 | dfu: config.dfu, | 54 | dfu: config.dfu, |
| 55 | state: config.state, | 55 | state: FirmwareState::new(config.state, aligned), |
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | // Make sure we are running a booted firmware to avoid reverting to a bad state. | ||
| 60 | async fn verify_booted(&mut self, aligned: &mut [u8]) -> Result<(), FirmwareUpdaterError> { | ||
| 61 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | ||
| 62 | if self.get_state(aligned).await? == State::Boot { | ||
| 63 | Ok(()) | ||
| 64 | } else { | ||
| 65 | Err(FirmwareUpdaterError::BadState) | ||
| 66 | } | 56 | } |
| 67 | } | 57 | } |
| 68 | 58 | ||
| @@ -71,14 +61,8 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | |||
| 71 | /// This is useful to check if the bootloader has just done a swap, in order | 61 | /// This is useful to check if the bootloader has just done a swap, in order |
| 72 | /// to do verifications and self-tests of the new image before calling | 62 | /// to do verifications and self-tests of the new image before calling |
| 73 | /// `mark_booted`. | 63 | /// `mark_booted`. |
| 74 | pub async fn get_state(&mut self, aligned: &mut [u8]) -> Result<State, FirmwareUpdaterError> { | 64 | pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> { |
| 75 | self.state.read(0, aligned).await?; | 65 | self.state.get_state().await |
| 76 | |||
| 77 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | ||
| 78 | Ok(State::Swap) | ||
| 79 | } else { | ||
| 80 | Ok(State::Boot) | ||
| 81 | } | ||
| 82 | } | 66 | } |
| 83 | 67 | ||
| 84 | /// Verify the DFU given a public key. If there is an error then DO NOT | 68 | /// Verify the DFU given a public key. If there is an error then DO NOT |
| @@ -92,23 +76,16 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | |||
| 92 | /// | 76 | /// |
| 93 | /// If no signature feature is set then this method will always return a | 77 | /// If no signature feature is set then this method will always return a |
| 94 | /// signature error. | 78 | /// signature error. |
| 95 | /// | ||
| 96 | /// # Safety | ||
| 97 | /// | ||
| 98 | /// The `_aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from | ||
| 99 | /// and written to. | ||
| 100 | #[cfg(feature = "_verify")] | 79 | #[cfg(feature = "_verify")] |
| 101 | pub async fn verify_and_mark_updated( | 80 | pub async fn verify_and_mark_updated( |
| 102 | &mut self, | 81 | &mut self, |
| 103 | _public_key: &[u8], | 82 | _public_key: &[u8], |
| 104 | _signature: &[u8], | 83 | _signature: &[u8], |
| 105 | _update_len: u32, | 84 | _update_len: u32, |
| 106 | _aligned: &mut [u8], | ||
| 107 | ) -> Result<(), FirmwareUpdaterError> { | 85 | ) -> Result<(), FirmwareUpdaterError> { |
| 108 | assert_eq!(_aligned.len(), STATE::WRITE_SIZE); | ||
| 109 | assert!(_update_len <= self.dfu.capacity() as u32); | 86 | assert!(_update_len <= self.dfu.capacity() as u32); |
| 110 | 87 | ||
| 111 | self.verify_booted(_aligned).await?; | 88 | self.state.verify_booted().await?; |
| 112 | 89 | ||
| 113 | #[cfg(feature = "ed25519-dalek")] | 90 | #[cfg(feature = "ed25519-dalek")] |
| 114 | { | 91 | { |
| @@ -121,8 +98,9 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | |||
| 121 | let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; | 98 | let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; |
| 122 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; | 99 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; |
| 123 | 100 | ||
| 101 | let mut chunk_buf = [0; 2]; | ||
| 124 | let mut message = [0; 64]; | 102 | let mut message = [0; 64]; |
| 125 | self.hash::<Sha512>(_update_len, _aligned, &mut message).await?; | 103 | self.hash::<Sha512>(_update_len, &mut chunk_buf, &mut message).await?; |
| 126 | 104 | ||
| 127 | public_key.verify(&message, &signature).map_err(into_signature_error)? | 105 | public_key.verify(&message, &signature).map_err(into_signature_error)? |
| 128 | } | 106 | } |
| @@ -143,7 +121,8 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | |||
| 143 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; | 121 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; |
| 144 | 122 | ||
| 145 | let mut message = [0; 64]; | 123 | let mut message = [0; 64]; |
| 146 | self.hash::<Sha512>(_update_len, _aligned, &mut message).await?; | 124 | let mut chunk_buf = [0; 2]; |
| 125 | self.hash::<Sha512>(_update_len, &mut chunk_buf, &mut message).await?; | ||
| 147 | 126 | ||
| 148 | let r = public_key.verify(&message, &signature); | 127 | let r = public_key.verify(&message, &signature); |
| 149 | trace!( | 128 | trace!( |
| @@ -156,7 +135,7 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | |||
| 156 | r.map_err(into_signature_error)? | 135 | r.map_err(into_signature_error)? |
| 157 | } | 136 | } |
| 158 | 137 | ||
| 159 | self.set_magic(_aligned, SWAP_MAGIC).await | 138 | self.state.mark_updated().await |
| 160 | } | 139 | } |
| 161 | 140 | ||
| 162 | /// Verify the update in DFU with any digest. | 141 | /// Verify the update in DFU with any digest. |
| @@ -177,49 +156,14 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | |||
| 177 | } | 156 | } |
| 178 | 157 | ||
| 179 | /// Mark to trigger firmware swap on next boot. | 158 | /// Mark to trigger firmware swap on next boot. |
| 180 | /// | ||
| 181 | /// # Safety | ||
| 182 | /// | ||
| 183 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being written to. | ||
| 184 | #[cfg(not(feature = "_verify"))] | 159 | #[cfg(not(feature = "_verify"))] |
| 185 | pub async fn mark_updated(&mut self, aligned: &mut [u8]) -> Result<(), FirmwareUpdaterError> { | 160 | pub async fn mark_updated(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 186 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | 161 | self.state.mark_updated().await |
| 187 | self.set_magic(aligned, SWAP_MAGIC).await | ||
| 188 | } | 162 | } |
| 189 | 163 | ||
| 190 | /// Mark firmware boot successful and stop rollback on reset. | 164 | /// Mark firmware boot successful and stop rollback on reset. |
| 191 | /// | 165 | pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 192 | /// # Safety | 166 | self.state.mark_booted().await |
| 193 | /// | ||
| 194 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being written to. | ||
| 195 | pub async fn mark_booted(&mut self, aligned: &mut [u8]) -> Result<(), FirmwareUpdaterError> { | ||
| 196 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | ||
| 197 | self.set_magic(aligned, BOOT_MAGIC).await | ||
| 198 | } | ||
| 199 | |||
| 200 | async fn set_magic(&mut self, aligned: &mut [u8], magic: u8) -> Result<(), FirmwareUpdaterError> { | ||
| 201 | self.state.read(0, aligned).await?; | ||
| 202 | |||
| 203 | if aligned.iter().any(|&b| b != magic) { | ||
| 204 | // Read progress validity | ||
| 205 | self.state.read(STATE::WRITE_SIZE as u32, aligned).await?; | ||
| 206 | |||
| 207 | if aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { | ||
| 208 | // The current progress validity marker is invalid | ||
| 209 | } else { | ||
| 210 | // Invalidate progress | ||
| 211 | aligned.fill(!STATE_ERASE_VALUE); | ||
| 212 | self.state.write(STATE::WRITE_SIZE as u32, aligned).await?; | ||
| 213 | } | ||
| 214 | |||
| 215 | // Clear magic and progress | ||
| 216 | self.state.erase(0, self.state.capacity() as u32).await?; | ||
| 217 | |||
| 218 | // Set magic | ||
| 219 | aligned.fill(magic); | ||
| 220 | self.state.write(0, aligned).await?; | ||
| 221 | } | ||
| 222 | Ok(()) | ||
| 223 | } | 167 | } |
| 224 | 168 | ||
| 225 | /// Write data to a flash page. | 169 | /// Write data to a flash page. |
| @@ -229,16 +173,10 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | |||
| 229 | /// # Safety | 173 | /// # Safety |
| 230 | /// | 174 | /// |
| 231 | /// Failing to meet alignment and size requirements may result in a panic. | 175 | /// Failing to meet alignment and size requirements may result in a panic. |
| 232 | pub async fn write_firmware( | 176 | pub async fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { |
| 233 | &mut self, | ||
| 234 | aligned: &mut [u8], | ||
| 235 | offset: usize, | ||
| 236 | data: &[u8], | ||
| 237 | ) -> Result<(), FirmwareUpdaterError> { | ||
| 238 | assert!(data.len() >= DFU::ERASE_SIZE); | 177 | assert!(data.len() >= DFU::ERASE_SIZE); |
| 239 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | ||
| 240 | 178 | ||
| 241 | self.verify_booted(aligned).await?; | 179 | self.state.verify_booted().await?; |
| 242 | 180 | ||
| 243 | self.dfu.erase(offset as u32, (offset + data.len()) as u32).await?; | 181 | self.dfu.erase(offset as u32, (offset + data.len()) as u32).await?; |
| 244 | 182 | ||
| @@ -252,17 +190,91 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> { | |||
| 252 | /// | 190 | /// |
| 253 | /// Using this instead of `write_firmware` allows for an optimized API in | 191 | /// Using this instead of `write_firmware` allows for an optimized API in |
| 254 | /// exchange for added complexity. | 192 | /// exchange for added complexity. |
| 193 | pub async fn prepare_update(&mut self) -> Result<&mut DFU, FirmwareUpdaterError> { | ||
| 194 | self.state.verify_booted().await?; | ||
| 195 | self.dfu.erase(0, self.dfu.capacity() as u32).await?; | ||
| 196 | |||
| 197 | Ok(&mut self.dfu) | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | /// Manages the state partition of the firmware update. | ||
| 202 | /// | ||
| 203 | /// Can be used standalone for more fine grained control, or as part of the updater. | ||
| 204 | pub struct FirmwareState<'d, STATE> { | ||
| 205 | state: STATE, | ||
| 206 | aligned: &'d mut [u8], | ||
| 207 | } | ||
| 208 | |||
| 209 | impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { | ||
| 210 | /// Create a firmware state instance with a buffer for magic content and state partition. | ||
| 255 | /// | 211 | /// |
| 256 | /// # Safety | 212 | /// # Safety |
| 257 | /// | 213 | /// |
| 258 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being written to. | 214 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from |
| 259 | pub async fn prepare_update(&mut self, aligned: &mut [u8]) -> Result<&mut DFU, FirmwareUpdaterError> { | 215 | /// and written to. |
| 216 | pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { | ||
| 260 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | 217 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); |
| 261 | self.verify_booted(aligned).await?; | 218 | Self { state, aligned } |
| 219 | } | ||
| 262 | 220 | ||
| 263 | self.dfu.erase(0, self.dfu.capacity() as u32).await?; | 221 | // Make sure we are running a booted firmware to avoid reverting to a bad state. |
| 222 | async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 223 | if self.get_state().await? == State::Boot { | ||
| 224 | Ok(()) | ||
| 225 | } else { | ||
| 226 | Err(FirmwareUpdaterError::BadState) | ||
| 227 | } | ||
| 228 | } | ||
| 264 | 229 | ||
| 265 | Ok(&mut self.dfu) | 230 | /// Obtain the current state. |
| 231 | /// | ||
| 232 | /// This is useful to check if the bootloader has just done a swap, in order | ||
| 233 | /// to do verifications and self-tests of the new image before calling | ||
| 234 | /// `mark_booted`. | ||
| 235 | pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> { | ||
| 236 | self.state.read(0, &mut self.aligned).await?; | ||
| 237 | |||
| 238 | if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { | ||
| 239 | Ok(State::Swap) | ||
| 240 | } else { | ||
| 241 | Ok(State::Boot) | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | /// Mark to trigger firmware swap on next boot. | ||
| 246 | pub async fn mark_updated(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 247 | self.set_magic(SWAP_MAGIC).await | ||
| 248 | } | ||
| 249 | |||
| 250 | /// Mark firmware boot successful and stop rollback on reset. | ||
| 251 | pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 252 | self.set_magic(BOOT_MAGIC).await | ||
| 253 | } | ||
| 254 | |||
| 255 | async fn set_magic(&mut self, magic: u8) -> Result<(), FirmwareUpdaterError> { | ||
| 256 | self.state.read(0, &mut self.aligned).await?; | ||
| 257 | |||
| 258 | if self.aligned.iter().any(|&b| b != magic) { | ||
| 259 | // Read progress validity | ||
| 260 | self.state.read(STATE::WRITE_SIZE as u32, &mut self.aligned).await?; | ||
| 261 | |||
| 262 | if self.aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { | ||
| 263 | // The current progress validity marker is invalid | ||
| 264 | } else { | ||
| 265 | // Invalidate progress | ||
| 266 | self.aligned.fill(!STATE_ERASE_VALUE); | ||
| 267 | self.state.write(STATE::WRITE_SIZE as u32, &self.aligned).await?; | ||
| 268 | } | ||
| 269 | |||
| 270 | // Clear magic and progress | ||
| 271 | self.state.erase(0, self.state.capacity() as u32).await?; | ||
| 272 | |||
| 273 | // Set magic | ||
| 274 | self.aligned.fill(magic); | ||
| 275 | self.state.write(0, &self.aligned).await?; | ||
| 276 | } | ||
| 277 | Ok(()) | ||
| 266 | } | 278 | } |
| 267 | } | 279 | } |
| 268 | 280 | ||
| @@ -288,8 +300,8 @@ mod tests { | |||
| 288 | let mut to_write = [0; 4096]; | 300 | let mut to_write = [0; 4096]; |
| 289 | to_write[..7].copy_from_slice(update.as_slice()); | 301 | to_write[..7].copy_from_slice(update.as_slice()); |
| 290 | 302 | ||
| 291 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }); | 303 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned); |
| 292 | block_on(updater.write_firmware(&mut aligned, 0, to_write.as_slice())).unwrap(); | 304 | block_on(updater.write_firmware(0, to_write.as_slice())).unwrap(); |
| 293 | let mut chunk_buf = [0; 2]; | 305 | let mut chunk_buf = [0; 2]; |
| 294 | let mut hash = [0; 20]; | 306 | let mut hash = [0; 20]; |
| 295 | block_on(updater.hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); | 307 | block_on(updater.hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); |
diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs index f03f53e4d..76e4264a0 100644 --- a/embassy-boot/boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/boot/src/firmware_updater/blocking.rs | |||
| @@ -10,9 +10,9 @@ use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAG | |||
| 10 | 10 | ||
| 11 | /// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to | 11 | /// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to |
| 12 | /// 'mess up' the internal bootloader state | 12 | /// 'mess up' the internal bootloader state |
| 13 | pub struct BlockingFirmwareUpdater<DFU: NorFlash, STATE: NorFlash> { | 13 | pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { |
| 14 | dfu: DFU, | 14 | dfu: DFU, |
| 15 | state: STATE, | 15 | state: BlockingFirmwareState<'d, STATE>, |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | #[cfg(target_os = "none")] | 18 | #[cfg(target_os = "none")] |
| @@ -49,22 +49,17 @@ impl<'a, FLASH: NorFlash> | |||
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | 52 | impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> { |
| 53 | /// Create a firmware updater instance with partition ranges for the update and state partitions. | 53 | /// Create a firmware updater instance with partition ranges for the update and state partitions. |
| 54 | pub fn new(config: FirmwareUpdaterConfig<DFU, STATE>) -> Self { | 54 | /// |
| 55 | /// # Safety | ||
| 56 | /// | ||
| 57 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from | ||
| 58 | /// and written to. | ||
| 59 | pub fn new(config: FirmwareUpdaterConfig<DFU, STATE>, aligned: &'d mut [u8]) -> Self { | ||
| 55 | Self { | 60 | Self { |
| 56 | dfu: config.dfu, | 61 | dfu: config.dfu, |
| 57 | state: config.state, | 62 | state: BlockingFirmwareState::new(config.state, aligned), |
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | // Make sure we are running a booted firmware to avoid reverting to a bad state. | ||
| 62 | fn verify_booted(&mut self, aligned: &mut [u8]) -> Result<(), FirmwareUpdaterError> { | ||
| 63 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | ||
| 64 | if self.get_state(aligned)? == State::Boot { | ||
| 65 | Ok(()) | ||
| 66 | } else { | ||
| 67 | Err(FirmwareUpdaterError::BadState) | ||
| 68 | } | 63 | } |
| 69 | } | 64 | } |
| 70 | 65 | ||
| @@ -73,14 +68,8 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | |||
| 73 | /// This is useful to check if the bootloader has just done a swap, in order | 68 | /// This is useful to check if the bootloader has just done a swap, in order |
| 74 | /// to do verifications and self-tests of the new image before calling | 69 | /// to do verifications and self-tests of the new image before calling |
| 75 | /// `mark_booted`. | 70 | /// `mark_booted`. |
| 76 | pub fn get_state(&mut self, aligned: &mut [u8]) -> Result<State, FirmwareUpdaterError> { | 71 | pub fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> { |
| 77 | self.state.read(0, aligned)?; | 72 | self.state.get_state() |
| 78 | |||
| 79 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | ||
| 80 | Ok(State::Swap) | ||
| 81 | } else { | ||
| 82 | Ok(State::Boot) | ||
| 83 | } | ||
| 84 | } | 73 | } |
| 85 | 74 | ||
| 86 | /// Verify the DFU given a public key. If there is an error then DO NOT | 75 | /// Verify the DFU given a public key. If there is an error then DO NOT |
| @@ -94,23 +83,16 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | |||
| 94 | /// | 83 | /// |
| 95 | /// If no signature feature is set then this method will always return a | 84 | /// If no signature feature is set then this method will always return a |
| 96 | /// signature error. | 85 | /// signature error. |
| 97 | /// | ||
| 98 | /// # Safety | ||
| 99 | /// | ||
| 100 | /// The `_aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from | ||
| 101 | /// and written to. | ||
| 102 | #[cfg(feature = "_verify")] | 86 | #[cfg(feature = "_verify")] |
| 103 | pub fn verify_and_mark_updated( | 87 | pub fn verify_and_mark_updated( |
| 104 | &mut self, | 88 | &mut self, |
| 105 | _public_key: &[u8], | 89 | _public_key: &[u8], |
| 106 | _signature: &[u8], | 90 | _signature: &[u8], |
| 107 | _update_len: u32, | 91 | _update_len: u32, |
| 108 | _aligned: &mut [u8], | ||
| 109 | ) -> Result<(), FirmwareUpdaterError> { | 92 | ) -> Result<(), FirmwareUpdaterError> { |
| 110 | assert_eq!(_aligned.len(), STATE::WRITE_SIZE); | ||
| 111 | assert!(_update_len <= self.dfu.capacity() as u32); | 93 | assert!(_update_len <= self.dfu.capacity() as u32); |
| 112 | 94 | ||
| 113 | self.verify_booted(_aligned)?; | 95 | self.state.verify_booted()?; |
| 114 | 96 | ||
| 115 | #[cfg(feature = "ed25519-dalek")] | 97 | #[cfg(feature = "ed25519-dalek")] |
| 116 | { | 98 | { |
| @@ -124,7 +106,8 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | |||
| 124 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; | 106 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; |
| 125 | 107 | ||
| 126 | let mut message = [0; 64]; | 108 | let mut message = [0; 64]; |
| 127 | self.hash::<Sha512>(_update_len, _aligned, &mut message)?; | 109 | let mut chunk_buf = [0; 2]; |
| 110 | self.hash::<Sha512>(_update_len, &mut chunk_buf, &mut message)?; | ||
| 128 | 111 | ||
| 129 | public_key.verify(&message, &signature).map_err(into_signature_error)? | 112 | public_key.verify(&message, &signature).map_err(into_signature_error)? |
| 130 | } | 113 | } |
| @@ -145,7 +128,8 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | |||
| 145 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; | 128 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; |
| 146 | 129 | ||
| 147 | let mut message = [0; 64]; | 130 | let mut message = [0; 64]; |
| 148 | self.hash::<Sha512>(_update_len, _aligned, &mut message)?; | 131 | let mut chunk_buf = [0; 2]; |
| 132 | self.hash::<Sha512>(_update_len, &mut chunk_buf, &mut message)?; | ||
| 149 | 133 | ||
| 150 | let r = public_key.verify(&message, &signature); | 134 | let r = public_key.verify(&message, &signature); |
| 151 | trace!( | 135 | trace!( |
| @@ -158,7 +142,7 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | |||
| 158 | r.map_err(into_signature_error)? | 142 | r.map_err(into_signature_error)? |
| 159 | } | 143 | } |
| 160 | 144 | ||
| 161 | self.set_magic(_aligned, SWAP_MAGIC) | 145 | self.state.mark_updated() |
| 162 | } | 146 | } |
| 163 | 147 | ||
| 164 | /// Verify the update in DFU with any digest. | 148 | /// Verify the update in DFU with any digest. |
| @@ -179,49 +163,14 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | |||
| 179 | } | 163 | } |
| 180 | 164 | ||
| 181 | /// Mark to trigger firmware swap on next boot. | 165 | /// Mark to trigger firmware swap on next boot. |
| 182 | /// | ||
| 183 | /// # Safety | ||
| 184 | /// | ||
| 185 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being written to. | ||
| 186 | #[cfg(not(feature = "_verify"))] | 166 | #[cfg(not(feature = "_verify"))] |
| 187 | pub fn mark_updated(&mut self, aligned: &mut [u8]) -> Result<(), FirmwareUpdaterError> { | 167 | pub fn mark_updated(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 188 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | 168 | self.state.mark_updated() |
| 189 | self.set_magic(aligned, SWAP_MAGIC) | ||
| 190 | } | 169 | } |
| 191 | 170 | ||
| 192 | /// Mark firmware boot successful and stop rollback on reset. | 171 | /// Mark firmware boot successful and stop rollback on reset. |
| 193 | /// | 172 | pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 194 | /// # Safety | 173 | self.state.mark_booted() |
| 195 | /// | ||
| 196 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being written to. | ||
| 197 | pub fn mark_booted(&mut self, aligned: &mut [u8]) -> Result<(), FirmwareUpdaterError> { | ||
| 198 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | ||
| 199 | self.set_magic(aligned, BOOT_MAGIC) | ||
| 200 | } | ||
| 201 | |||
| 202 | fn set_magic(&mut self, aligned: &mut [u8], magic: u8) -> Result<(), FirmwareUpdaterError> { | ||
| 203 | self.state.read(0, aligned)?; | ||
| 204 | |||
| 205 | if aligned.iter().any(|&b| b != magic) { | ||
| 206 | // Read progress validity | ||
| 207 | self.state.read(STATE::WRITE_SIZE as u32, aligned)?; | ||
| 208 | |||
| 209 | if aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { | ||
| 210 | // The current progress validity marker is invalid | ||
| 211 | } else { | ||
| 212 | // Invalidate progress | ||
| 213 | aligned.fill(!STATE_ERASE_VALUE); | ||
| 214 | self.state.write(STATE::WRITE_SIZE as u32, aligned)?; | ||
| 215 | } | ||
| 216 | |||
| 217 | // Clear magic and progress | ||
| 218 | self.state.erase(0, self.state.capacity() as u32)?; | ||
| 219 | |||
| 220 | // Set magic | ||
| 221 | aligned.fill(magic); | ||
| 222 | self.state.write(0, aligned)?; | ||
| 223 | } | ||
| 224 | Ok(()) | ||
| 225 | } | 174 | } |
| 226 | 175 | ||
| 227 | /// Write data to a flash page. | 176 | /// Write data to a flash page. |
| @@ -231,15 +180,9 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | |||
| 231 | /// # Safety | 180 | /// # Safety |
| 232 | /// | 181 | /// |
| 233 | /// Failing to meet alignment and size requirements may result in a panic. | 182 | /// Failing to meet alignment and size requirements may result in a panic. |
| 234 | pub fn write_firmware( | 183 | pub fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { |
| 235 | &mut self, | ||
| 236 | aligned: &mut [u8], | ||
| 237 | offset: usize, | ||
| 238 | data: &[u8], | ||
| 239 | ) -> Result<(), FirmwareUpdaterError> { | ||
| 240 | assert!(data.len() >= DFU::ERASE_SIZE); | 184 | assert!(data.len() >= DFU::ERASE_SIZE); |
| 241 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | 185 | self.state.verify_booted()?; |
| 242 | self.verify_booted(aligned)?; | ||
| 243 | 186 | ||
| 244 | self.dfu.erase(offset as u32, (offset + data.len()) as u32)?; | 187 | self.dfu.erase(offset as u32, (offset + data.len()) as u32)?; |
| 245 | 188 | ||
| @@ -253,16 +196,91 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> { | |||
| 253 | /// | 196 | /// |
| 254 | /// Using this instead of `write_firmware` allows for an optimized API in | 197 | /// Using this instead of `write_firmware` allows for an optimized API in |
| 255 | /// exchange for added complexity. | 198 | /// exchange for added complexity. |
| 199 | pub fn prepare_update(&mut self) -> Result<&mut DFU, FirmwareUpdaterError> { | ||
| 200 | self.state.verify_booted()?; | ||
| 201 | self.dfu.erase(0, self.dfu.capacity() as u32)?; | ||
| 202 | |||
| 203 | Ok(&mut self.dfu) | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | /// Manages the state partition of the firmware update. | ||
| 208 | /// | ||
| 209 | /// Can be used standalone for more fine grained control, or as part of the updater. | ||
| 210 | pub struct BlockingFirmwareState<'d, STATE> { | ||
| 211 | state: STATE, | ||
| 212 | aligned: &'d mut [u8], | ||
| 213 | } | ||
| 214 | |||
| 215 | impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { | ||
| 216 | /// Create a firmware state instance with a buffer for magic content and state partition. | ||
| 256 | /// | 217 | /// |
| 257 | /// # Safety | 218 | /// # Safety |
| 258 | /// | 219 | /// |
| 259 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being written to. | 220 | /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from |
| 260 | pub fn prepare_update(&mut self, aligned: &mut [u8]) -> Result<&mut DFU, FirmwareUpdaterError> { | 221 | /// and written to. |
| 222 | pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { | ||
| 261 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | 223 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); |
| 262 | self.verify_booted(aligned)?; | 224 | Self { state, aligned } |
| 263 | self.dfu.erase(0, self.dfu.capacity() as u32)?; | 225 | } |
| 264 | 226 | ||
| 265 | Ok(&mut self.dfu) | 227 | // Make sure we are running a booted firmware to avoid reverting to a bad state. |
| 228 | fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 229 | if self.get_state()? == State::Boot { | ||
| 230 | Ok(()) | ||
| 231 | } else { | ||
| 232 | Err(FirmwareUpdaterError::BadState) | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | /// Obtain the current state. | ||
| 237 | /// | ||
| 238 | /// This is useful to check if the bootloader has just done a swap, in order | ||
| 239 | /// to do verifications and self-tests of the new image before calling | ||
| 240 | /// `mark_booted`. | ||
| 241 | pub fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> { | ||
| 242 | self.state.read(0, &mut self.aligned)?; | ||
| 243 | |||
| 244 | if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { | ||
| 245 | Ok(State::Swap) | ||
| 246 | } else { | ||
| 247 | Ok(State::Boot) | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | /// Mark to trigger firmware swap on next boot. | ||
| 252 | pub fn mark_updated(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 253 | self.set_magic(SWAP_MAGIC) | ||
| 254 | } | ||
| 255 | |||
| 256 | /// Mark firmware boot successful and stop rollback on reset. | ||
| 257 | pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 258 | self.set_magic(BOOT_MAGIC) | ||
| 259 | } | ||
| 260 | |||
| 261 | fn set_magic(&mut self, magic: u8) -> Result<(), FirmwareUpdaterError> { | ||
| 262 | self.state.read(0, &mut self.aligned)?; | ||
| 263 | |||
| 264 | if self.aligned.iter().any(|&b| b != magic) { | ||
| 265 | // Read progress validity | ||
| 266 | self.state.read(STATE::WRITE_SIZE as u32, &mut self.aligned)?; | ||
| 267 | |||
| 268 | if self.aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { | ||
| 269 | // The current progress validity marker is invalid | ||
| 270 | } else { | ||
| 271 | // Invalidate progress | ||
| 272 | self.aligned.fill(!STATE_ERASE_VALUE); | ||
| 273 | self.state.write(STATE::WRITE_SIZE as u32, &self.aligned)?; | ||
| 274 | } | ||
| 275 | |||
| 276 | // Clear magic and progress | ||
| 277 | self.state.erase(0, self.state.capacity() as u32)?; | ||
| 278 | |||
| 279 | // Set magic | ||
| 280 | self.aligned.fill(magic); | ||
| 281 | self.state.write(0, &self.aligned)?; | ||
| 282 | } | ||
| 283 | Ok(()) | ||
| 266 | } | 284 | } |
| 267 | } | 285 | } |
| 268 | 286 | ||
| @@ -283,14 +301,14 @@ mod tests { | |||
| 283 | let flash = Mutex::<NoopRawMutex, _>::new(RefCell::new(MemFlash::<131072, 4096, 8>::default())); | 301 | let flash = Mutex::<NoopRawMutex, _>::new(RefCell::new(MemFlash::<131072, 4096, 8>::default())); |
| 284 | let state = BlockingPartition::new(&flash, 0, 4096); | 302 | let state = BlockingPartition::new(&flash, 0, 4096); |
| 285 | let dfu = BlockingPartition::new(&flash, 65536, 65536); | 303 | let dfu = BlockingPartition::new(&flash, 65536, 65536); |
| 304 | let mut aligned = [0; 8]; | ||
| 286 | 305 | ||
| 287 | let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; | 306 | let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; |
| 288 | let mut to_write = [0; 4096]; | 307 | let mut to_write = [0; 4096]; |
| 289 | to_write[..7].copy_from_slice(update.as_slice()); | 308 | to_write[..7].copy_from_slice(update.as_slice()); |
| 290 | 309 | ||
| 291 | let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }); | 310 | let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned); |
| 292 | let mut aligned = [0; 8]; | 311 | updater.write_firmware(0, to_write.as_slice()).unwrap(); |
| 293 | updater.write_firmware(&mut aligned, 0, to_write.as_slice()).unwrap(); | ||
| 294 | let mut chunk_buf = [0; 2]; | 312 | let mut chunk_buf = [0; 2]; |
| 295 | let mut hash = [0; 20]; | 313 | let mut hash = [0; 20]; |
| 296 | updater | 314 | updater |
diff --git a/embassy-boot/boot/src/firmware_updater/mod.rs b/embassy-boot/boot/src/firmware_updater/mod.rs index 55ce8f363..937ddcc69 100644 --- a/embassy-boot/boot/src/firmware_updater/mod.rs +++ b/embassy-boot/boot/src/firmware_updater/mod.rs | |||
| @@ -3,8 +3,8 @@ mod asynch; | |||
| 3 | mod blocking; | 3 | mod blocking; |
| 4 | 4 | ||
| 5 | #[cfg(feature = "nightly")] | 5 | #[cfg(feature = "nightly")] |
| 6 | pub use asynch::FirmwareUpdater; | 6 | pub use asynch::{FirmwareState, FirmwareUpdater}; |
| 7 | pub use blocking::BlockingFirmwareUpdater; | 7 | pub use blocking::{BlockingFirmwareState, BlockingFirmwareUpdater}; |
| 8 | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; | 8 | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; |
| 9 | 9 | ||
| 10 | /// Firmware updater flash configuration holding the two flashes used by the updater | 10 | /// Firmware updater flash configuration holding the two flashes used by the updater |
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 016362b86..47f7c1797 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs | |||
| @@ -16,9 +16,11 @@ mod test_flash; | |||
| 16 | // TODO: Use the value provided by NorFlash when available | 16 | // TODO: Use the value provided by NorFlash when available |
| 17 | pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF; | 17 | pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF; |
| 18 | pub use boot_loader::{BootError, BootLoader, BootLoaderConfig}; | 18 | pub use boot_loader::{BootError, BootLoader, BootLoaderConfig}; |
| 19 | pub use firmware_updater::{ | ||
| 20 | BlockingFirmwareState, BlockingFirmwareUpdater, FirmwareUpdaterConfig, FirmwareUpdaterError, | ||
| 21 | }; | ||
| 19 | #[cfg(feature = "nightly")] | 22 | #[cfg(feature = "nightly")] |
| 20 | pub use firmware_updater::FirmwareUpdater; | 23 | pub use firmware_updater::{FirmwareState, FirmwareUpdater}; |
| 21 | pub use firmware_updater::{BlockingFirmwareUpdater, FirmwareUpdaterConfig, FirmwareUpdaterError}; | ||
| 22 | 24 | ||
| 23 | pub(crate) const BOOT_MAGIC: u8 = 0xD0; | 25 | pub(crate) const BOOT_MAGIC: u8 = 0xD0; |
| 24 | pub(crate) const SWAP_MAGIC: u8 = 0xF0; | 26 | pub(crate) const SWAP_MAGIC: u8 = 0xF0; |
| @@ -118,15 +120,18 @@ mod tests { | |||
| 118 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); | 120 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); |
| 119 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); | 121 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); |
| 120 | 122 | ||
| 121 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { | 123 | let mut updater = FirmwareUpdater::new( |
| 122 | dfu: flash.dfu(), | 124 | FirmwareUpdaterConfig { |
| 123 | state: flash.state(), | 125 | dfu: flash.dfu(), |
| 124 | }); | 126 | state: flash.state(), |
| 125 | block_on(updater.write_firmware(&mut aligned, 0, &UPDATE)).unwrap(); | 127 | }, |
| 126 | block_on(updater.mark_updated(&mut aligned)).unwrap(); | 128 | &mut aligned, |
| 129 | ); | ||
| 130 | block_on(updater.write_firmware(0, &UPDATE)).unwrap(); | ||
| 131 | block_on(updater.mark_updated()).unwrap(); | ||
| 127 | 132 | ||
| 128 | // Writing after marking updated is not allowed until marked as booted. | 133 | // Writing after marking updated is not allowed until marked as booted. |
| 129 | let res: Result<(), FirmwareUpdaterError> = block_on(updater.write_firmware(&mut aligned, 0, &UPDATE)); | 134 | let res: Result<(), FirmwareUpdaterError> = block_on(updater.write_firmware(0, &UPDATE)); |
| 130 | assert!(matches!(res, Err::<(), _>(FirmwareUpdaterError::BadState))); | 135 | assert!(matches!(res, Err::<(), _>(FirmwareUpdaterError::BadState))); |
| 131 | 136 | ||
| 132 | let flash = flash.into_blocking(); | 137 | let flash = flash.into_blocking(); |
| @@ -158,11 +163,14 @@ mod tests { | |||
| 158 | 163 | ||
| 159 | // Mark as booted | 164 | // Mark as booted |
| 160 | let flash = flash.into_async(); | 165 | let flash = flash.into_async(); |
| 161 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { | 166 | let mut updater = FirmwareUpdater::new( |
| 162 | dfu: flash.dfu(), | 167 | FirmwareUpdaterConfig { |
| 163 | state: flash.state(), | 168 | dfu: flash.dfu(), |
| 164 | }); | 169 | state: flash.state(), |
| 165 | block_on(updater.mark_booted(&mut aligned)).unwrap(); | 170 | }, |
| 171 | &mut aligned, | ||
| 172 | ); | ||
| 173 | block_on(updater.mark_booted()).unwrap(); | ||
| 166 | 174 | ||
| 167 | let flash = flash.into_blocking(); | 175 | let flash = flash.into_blocking(); |
| 168 | let mut bootloader = BootLoader::new(BootLoaderConfig { | 176 | let mut bootloader = BootLoader::new(BootLoaderConfig { |
| @@ -190,12 +198,15 @@ mod tests { | |||
| 190 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); | 198 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); |
| 191 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); | 199 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); |
| 192 | 200 | ||
| 193 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { | 201 | let mut updater = FirmwareUpdater::new( |
| 194 | dfu: flash.dfu(), | 202 | FirmwareUpdaterConfig { |
| 195 | state: flash.state(), | 203 | dfu: flash.dfu(), |
| 196 | }); | 204 | state: flash.state(), |
| 197 | block_on(updater.write_firmware(&mut aligned, 0, &UPDATE)).unwrap(); | 205 | }, |
| 198 | block_on(updater.mark_updated(&mut aligned)).unwrap(); | 206 | &mut aligned, |
| 207 | ); | ||
| 208 | block_on(updater.write_firmware(0, &UPDATE)).unwrap(); | ||
| 209 | block_on(updater.mark_updated()).unwrap(); | ||
| 199 | 210 | ||
| 200 | let flash = flash.into_blocking(); | 211 | let flash = flash.into_blocking(); |
| 201 | let mut bootloader = BootLoader::new(BootLoaderConfig { | 212 | let mut bootloader = BootLoader::new(BootLoaderConfig { |
| @@ -232,12 +243,15 @@ mod tests { | |||
| 232 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); | 243 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); |
| 233 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); | 244 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); |
| 234 | 245 | ||
| 235 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { | 246 | let mut updater = FirmwareUpdater::new( |
| 236 | dfu: flash.dfu(), | 247 | FirmwareUpdaterConfig { |
| 237 | state: flash.state(), | 248 | dfu: flash.dfu(), |
| 238 | }); | 249 | state: flash.state(), |
| 239 | block_on(updater.write_firmware(&mut aligned, 0, &UPDATE)).unwrap(); | 250 | }, |
| 240 | block_on(updater.mark_updated(&mut aligned)).unwrap(); | 251 | &mut aligned, |
| 252 | ); | ||
| 253 | block_on(updater.write_firmware(0, &UPDATE)).unwrap(); | ||
| 254 | block_on(updater.mark_updated()).unwrap(); | ||
| 241 | 255 | ||
| 242 | let flash = flash.into_blocking(); | 256 | let flash = flash.into_blocking(); |
| 243 | let mut bootloader = BootLoader::new(BootLoaderConfig { | 257 | let mut bootloader = BootLoader::new(BootLoaderConfig { |
| @@ -293,18 +307,19 @@ mod tests { | |||
| 293 | 307 | ||
| 294 | // On with the test | 308 | // On with the test |
| 295 | let flash = flash.into_async(); | 309 | let flash = flash.into_async(); |
| 296 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { | ||
| 297 | dfu: flash.dfu(), | ||
| 298 | state: flash.state(), | ||
| 299 | }); | ||
| 300 | |||
| 301 | let mut aligned = [0; 4]; | 310 | let mut aligned = [0; 4]; |
| 311 | let mut updater = FirmwareUpdater::new( | ||
| 312 | FirmwareUpdaterConfig { | ||
| 313 | dfu: flash.dfu(), | ||
| 314 | state: flash.state(), | ||
| 315 | }, | ||
| 316 | &mut aligned, | ||
| 317 | ); | ||
| 302 | 318 | ||
| 303 | assert!(block_on(updater.verify_and_mark_updated( | 319 | assert!(block_on(updater.verify_and_mark_updated( |
| 304 | &public_key.to_bytes(), | 320 | &public_key.to_bytes(), |
| 305 | &signature.to_bytes(), | 321 | &signature.to_bytes(), |
| 306 | firmware_len as u32, | 322 | firmware_len as u32, |
| 307 | &mut aligned, | ||
| 308 | )) | 323 | )) |
| 309 | .is_ok()); | 324 | .is_ok()); |
| 310 | } | 325 | } |
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs index 65f57fcd1..df94819fc 100644 --- a/embassy-boot/nrf/src/lib.rs +++ b/embassy-boot/nrf/src/lib.rs | |||
| @@ -3,9 +3,11 @@ | |||
| 3 | #![doc = include_str!("../README.md")] | 3 | #![doc = include_str!("../README.md")] |
| 4 | mod fmt; | 4 | mod fmt; |
| 5 | 5 | ||
| 6 | pub use embassy_boot::{ | ||
| 7 | AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareUpdaterConfig, | ||
| 8 | }; | ||
| 6 | #[cfg(feature = "nightly")] | 9 | #[cfg(feature = "nightly")] |
| 7 | pub use embassy_boot::FirmwareUpdater; | 10 | pub use embassy_boot::{FirmwareState, FirmwareUpdater}; |
| 8 | pub use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareUpdaterConfig}; | ||
| 9 | use embassy_nrf::nvmc::PAGE_SIZE; | 11 | use embassy_nrf::nvmc::PAGE_SIZE; |
| 10 | use embassy_nrf::peripherals::WDT; | 12 | use embassy_nrf::peripherals::WDT; |
| 11 | use embassy_nrf::wdt; | 13 | use embassy_nrf::wdt; |
diff --git a/embassy-boot/rp/src/lib.rs b/embassy-boot/rp/src/lib.rs index 35fc104ec..f5aefa416 100644 --- a/embassy-boot/rp/src/lib.rs +++ b/embassy-boot/rp/src/lib.rs | |||
| @@ -3,9 +3,11 @@ | |||
| 3 | #![doc = include_str!("../README.md")] | 3 | #![doc = include_str!("../README.md")] |
| 4 | mod fmt; | 4 | mod fmt; |
| 5 | 5 | ||
| 6 | pub use embassy_boot::{ | ||
| 7 | AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareUpdaterConfig, State, | ||
| 8 | }; | ||
| 6 | #[cfg(feature = "nightly")] | 9 | #[cfg(feature = "nightly")] |
| 7 | pub use embassy_boot::FirmwareUpdater; | 10 | pub use embassy_boot::{FirmwareState, FirmwareUpdater}; |
| 8 | pub use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareUpdaterConfig, State}; | ||
| 9 | use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE}; | 11 | use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE}; |
| 10 | use embassy_rp::peripherals::{FLASH, WATCHDOG}; | 12 | use embassy_rp::peripherals::{FLASH, WATCHDOG}; |
| 11 | use embassy_rp::watchdog::Watchdog; | 13 | use embassy_rp::watchdog::Watchdog; |
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs index 069de0d1a..25f029423 100644 --- a/embassy-boot/stm32/src/lib.rs +++ b/embassy-boot/stm32/src/lib.rs | |||
| @@ -3,9 +3,11 @@ | |||
| 3 | #![doc = include_str!("../README.md")] | 3 | #![doc = include_str!("../README.md")] |
| 4 | mod fmt; | 4 | mod fmt; |
| 5 | 5 | ||
| 6 | pub use embassy_boot::{ | ||
| 7 | AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareUpdaterConfig, State, | ||
| 8 | }; | ||
| 6 | #[cfg(feature = "nightly")] | 9 | #[cfg(feature = "nightly")] |
| 7 | pub use embassy_boot::FirmwareUpdater; | 10 | pub use embassy_boot::{FirmwareState, FirmwareUpdater}; |
| 8 | pub use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareUpdaterConfig, State}; | ||
| 9 | use embedded_storage::nor_flash::NorFlash; | 11 | use embedded_storage::nor_flash::NorFlash; |
| 10 | 12 | ||
| 11 | /// A bootloader for STM32 devices. | 13 | /// A bootloader for STM32 devices. |
