diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2023-04-03 11:49:44 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-04-03 11:49:44 +0000 |
| commit | 0909a6cd3ff6fb953aa2d83fb5da37384ad7dae2 (patch) | |
| tree | a040bd60916068140f86a773ff952a0d128c12ed | |
| parent | 08f911d25e83266b03bd1ebd37eee50cf2c53dd4 (diff) | |
| parent | d9d6fd6d70f3f9971c6db65b6962199f9da7913c (diff) | |
Merge #1312
1312: Let bootloader partition have read/write/erase operations r=Dirbaio a=rmja
This change should not have any breaking changes.
Co-authored-by: Rasmus Melchior Jacobsen <[email protected]>
| -rw-r--r-- | embassy-boot/boot/src/boot_loader.rs | 102 | ||||
| -rw-r--r-- | embassy-boot/boot/src/firmware_updater.rs | 174 | ||||
| -rw-r--r-- | embassy-boot/boot/src/firmware_writer.rs | 54 | ||||
| -rw-r--r-- | embassy-boot/boot/src/lib.rs | 3 | ||||
| -rw-r--r-- | embassy-boot/boot/src/partition.rs | 134 |
5 files changed, 243 insertions, 224 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index ad6735112..e2e361e3c 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs | |||
| @@ -79,7 +79,7 @@ impl BootLoader { | |||
| 79 | Self { active, dfu, state } | 79 | Self { active, dfu, state } |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | /// Return the boot address for the active partition. | 82 | /// Return the offset of the active partition into the active flash. |
| 83 | pub fn boot_address(&self) -> usize { | 83 | pub fn boot_address(&self) -> usize { |
| 84 | self.active.from | 84 | self.active.from |
| 85 | } | 85 | } |
| @@ -193,13 +193,13 @@ impl BootLoader { | |||
| 193 | self.revert(p, magic, page)?; | 193 | self.revert(p, magic, page)?; |
| 194 | 194 | ||
| 195 | // Overwrite magic and reset progress | 195 | // Overwrite magic and reset progress |
| 196 | let fstate = p.state(); | 196 | let state_flash = p.state(); |
| 197 | magic.fill(!P::STATE::ERASE_VALUE); | 197 | magic.fill(!P::STATE::ERASE_VALUE); |
| 198 | fstate.write(self.state.from as u32, magic)?; | 198 | self.state.write_blocking(state_flash, 0, magic)?; |
| 199 | fstate.erase(self.state.from as u32, self.state.to as u32)?; | 199 | self.state.wipe_blocking(state_flash)?; |
| 200 | 200 | ||
| 201 | magic.fill(BOOT_MAGIC); | 201 | magic.fill(BOOT_MAGIC); |
| 202 | fstate.write(self.state.from as u32, magic)?; | 202 | self.state.write_blocking(state_flash, 0, magic)?; |
| 203 | } | 203 | } |
| 204 | } | 204 | } |
| 205 | Ok(state) | 205 | Ok(state) |
| @@ -218,9 +218,10 @@ impl BootLoader { | |||
| 218 | let max_index = ((self.state.len() - write_size) / write_size) - 1; | 218 | let max_index = ((self.state.len() - write_size) / write_size) - 1; |
| 219 | aligned.fill(!P::STATE::ERASE_VALUE); | 219 | aligned.fill(!P::STATE::ERASE_VALUE); |
| 220 | 220 | ||
| 221 | let flash = config.state(); | 221 | let state_flash = config.state(); |
| 222 | for i in 0..max_index { | 222 | for i in 0..max_index { |
| 223 | flash.read((self.state.from + write_size + i * write_size) as u32, aligned)?; | 223 | self.state |
| 224 | .read_blocking(state_flash, (write_size + i * write_size) as u32, aligned)?; | ||
| 224 | 225 | ||
| 225 | if aligned.iter().any(|&b| b == P::STATE::ERASE_VALUE) { | 226 | if aligned.iter().any(|&b| b == P::STATE::ERASE_VALUE) { |
| 226 | return Ok(i); | 227 | return Ok(i); |
| @@ -230,47 +231,39 @@ impl BootLoader { | |||
| 230 | } | 231 | } |
| 231 | 232 | ||
| 232 | fn update_progress<P: FlashConfig>(&mut self, idx: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> { | 233 | fn update_progress<P: FlashConfig>(&mut self, idx: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> { |
| 233 | let flash = p.state(); | ||
| 234 | let write_size = magic.len(); | 234 | let write_size = magic.len(); |
| 235 | let w = self.state.from + write_size + idx * write_size; | ||
| 236 | 235 | ||
| 237 | let aligned = magic; | 236 | let aligned = magic; |
| 238 | aligned.fill(!P::STATE::ERASE_VALUE); | 237 | aligned.fill(!P::STATE::ERASE_VALUE); |
| 239 | flash.write(w as u32, aligned)?; | 238 | self.state |
| 239 | .write_blocking(p.state(), (write_size + idx * write_size) as u32, aligned)?; | ||
| 240 | Ok(()) | 240 | Ok(()) |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | fn active_addr(&self, n: usize, page_size: usize) -> usize { | ||
| 244 | self.active.from + n * page_size | ||
| 245 | } | ||
| 246 | |||
| 247 | fn dfu_addr(&self, n: usize, page_size: usize) -> usize { | ||
| 248 | self.dfu.from + n * page_size | ||
| 249 | } | ||
| 250 | |||
| 251 | fn copy_page_once_to_active<P: FlashConfig>( | 243 | fn copy_page_once_to_active<P: FlashConfig>( |
| 252 | &mut self, | 244 | &mut self, |
| 253 | idx: usize, | 245 | idx: usize, |
| 254 | from_page: usize, | 246 | from_offset: u32, |
| 255 | to_page: usize, | 247 | to_offset: u32, |
| 256 | p: &mut P, | 248 | p: &mut P, |
| 257 | magic: &mut [u8], | 249 | magic: &mut [u8], |
| 258 | page: &mut [u8], | 250 | page: &mut [u8], |
| 259 | ) -> Result<(), BootError> { | 251 | ) -> Result<(), BootError> { |
| 260 | let buf = page; | 252 | let buf = page; |
| 261 | if self.current_progress(p, magic)? <= idx { | 253 | if self.current_progress(p, magic)? <= idx { |
| 262 | let mut offset = from_page; | 254 | let mut offset = from_offset; |
| 263 | for chunk in buf.chunks_mut(P::DFU::BLOCK_SIZE) { | 255 | for chunk in buf.chunks_mut(P::DFU::BLOCK_SIZE) { |
| 264 | p.dfu().read(offset as u32, chunk)?; | 256 | self.dfu.read_blocking(p.dfu(), offset, chunk)?; |
| 265 | offset += chunk.len(); | 257 | offset += chunk.len() as u32; |
| 266 | } | 258 | } |
| 267 | 259 | ||
| 268 | p.active().erase(to_page as u32, (to_page + buf.len()) as u32)?; | 260 | self.active |
| 261 | .erase_blocking(p.active(), to_offset, to_offset + buf.len() as u32)?; | ||
| 269 | 262 | ||
| 270 | let mut offset = to_page; | 263 | let mut offset = to_offset; |
| 271 | for chunk in buf.chunks(P::ACTIVE::BLOCK_SIZE) { | 264 | for chunk in buf.chunks(P::ACTIVE::BLOCK_SIZE) { |
| 272 | p.active().write(offset as u32, chunk)?; | 265 | self.active.write_blocking(p.active(), offset, chunk)?; |
| 273 | offset += chunk.len(); | 266 | offset += chunk.len() as u32; |
| 274 | } | 267 | } |
| 275 | self.update_progress(idx, p, magic)?; | 268 | self.update_progress(idx, p, magic)?; |
| 276 | } | 269 | } |
| @@ -280,26 +273,27 @@ impl BootLoader { | |||
| 280 | fn copy_page_once_to_dfu<P: FlashConfig>( | 273 | fn copy_page_once_to_dfu<P: FlashConfig>( |
| 281 | &mut self, | 274 | &mut self, |
| 282 | idx: usize, | 275 | idx: usize, |
| 283 | from_page: usize, | 276 | from_offset: u32, |
| 284 | to_page: usize, | 277 | to_offset: u32, |
| 285 | p: &mut P, | 278 | p: &mut P, |
| 286 | magic: &mut [u8], | 279 | magic: &mut [u8], |
| 287 | page: &mut [u8], | 280 | page: &mut [u8], |
| 288 | ) -> Result<(), BootError> { | 281 | ) -> Result<(), BootError> { |
| 289 | let buf = page; | 282 | let buf = page; |
| 290 | if self.current_progress(p, magic)? <= idx { | 283 | if self.current_progress(p, magic)? <= idx { |
| 291 | let mut offset = from_page; | 284 | let mut offset = from_offset; |
| 292 | for chunk in buf.chunks_mut(P::ACTIVE::BLOCK_SIZE) { | 285 | for chunk in buf.chunks_mut(P::ACTIVE::BLOCK_SIZE) { |
| 293 | p.active().read(offset as u32, chunk)?; | 286 | self.active.read_blocking(p.active(), offset, chunk)?; |
| 294 | offset += chunk.len(); | 287 | offset += chunk.len() as u32; |
| 295 | } | 288 | } |
| 296 | 289 | ||
| 297 | p.dfu().erase(to_page as u32, (to_page + buf.len()) as u32)?; | 290 | self.dfu |
| 291 | .erase_blocking(p.dfu(), to_offset as u32, to_offset + buf.len() as u32)?; | ||
| 298 | 292 | ||
| 299 | let mut offset = to_page; | 293 | let mut offset = to_offset; |
| 300 | for chunk in buf.chunks(P::DFU::BLOCK_SIZE) { | 294 | for chunk in buf.chunks(P::DFU::BLOCK_SIZE) { |
| 301 | p.dfu().write(offset as u32, chunk)?; | 295 | self.dfu.write_blocking(p.dfu(), offset, chunk)?; |
| 302 | offset += chunk.len(); | 296 | offset += chunk.len() as u32; |
| 303 | } | 297 | } |
| 304 | self.update_progress(idx, p, magic)?; | 298 | self.update_progress(idx, p, magic)?; |
| 305 | } | 299 | } |
| @@ -312,17 +306,20 @@ impl BootLoader { | |||
| 312 | trace!("Page count: {}", page_count); | 306 | trace!("Page count: {}", page_count); |
| 313 | for page_num in 0..page_count { | 307 | for page_num in 0..page_count { |
| 314 | trace!("COPY PAGE {}", page_num); | 308 | trace!("COPY PAGE {}", page_num); |
| 309 | |||
| 310 | let idx = page_num * 2; | ||
| 311 | |||
| 315 | // Copy active page to the 'next' DFU page. | 312 | // Copy active page to the 'next' DFU page. |
| 316 | let active_page = self.active_addr(page_count - 1 - page_num, page_size); | 313 | let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32; |
| 317 | let dfu_page = self.dfu_addr(page_count - page_num, page_size); | 314 | let dfu_to_offset = ((page_count - page_num) * page_size) as u32; |
| 318 | //trace!("Copy active {} to dfu {}", active_page, dfu_page); | 315 | //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); |
| 319 | self.copy_page_once_to_dfu(page_num * 2, active_page, dfu_page, p, magic, page)?; | 316 | self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; |
| 320 | 317 | ||
| 321 | // Copy DFU page to the active page | 318 | // Copy DFU page to the active page |
| 322 | let active_page = self.active_addr(page_count - 1 - page_num, page_size); | 319 | let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32; |
| 323 | let dfu_page = self.dfu_addr(page_count - 1 - page_num, page_size); | 320 | let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32; |
| 324 | //trace!("Copy dfy {} to active {}", dfu_page, active_page); | 321 | //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); |
| 325 | self.copy_page_once_to_active(page_num * 2 + 1, dfu_page, active_page, p, magic, page)?; | 322 | self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; |
| 326 | } | 323 | } |
| 327 | 324 | ||
| 328 | Ok(()) | 325 | Ok(()) |
| @@ -332,23 +329,24 @@ impl BootLoader { | |||
| 332 | let page_size = page.len(); | 329 | let page_size = page.len(); |
| 333 | let page_count = self.active.len() / page_size; | 330 | let page_count = self.active.len() / page_size; |
| 334 | for page_num in 0..page_count { | 331 | for page_num in 0..page_count { |
| 332 | let idx = page_count * 2 + page_num * 2; | ||
| 333 | |||
| 335 | // Copy the bad active page to the DFU page | 334 | // Copy the bad active page to the DFU page |
| 336 | let active_page = self.active_addr(page_num, page_size); | 335 | let active_from_offset = (page_num * page_size) as u32; |
| 337 | let dfu_page = self.dfu_addr(page_num, page_size); | 336 | let dfu_to_offset = (page_num * page_size) as u32; |
| 338 | self.copy_page_once_to_dfu(page_count * 2 + page_num * 2, active_page, dfu_page, p, magic, page)?; | 337 | self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; |
| 339 | 338 | ||
| 340 | // Copy the DFU page back to the active page | 339 | // Copy the DFU page back to the active page |
| 341 | let active_page = self.active_addr(page_num, page_size); | 340 | let active_to_offset = (page_num * page_size) as u32; |
| 342 | let dfu_page = self.dfu_addr(page_num + 1, page_size); | 341 | let dfu_from_offset = ((page_num + 1) * page_size) as u32; |
| 343 | self.copy_page_once_to_active(page_count * 2 + page_num * 2 + 1, dfu_page, active_page, p, magic, page)?; | 342 | self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; |
| 344 | } | 343 | } |
| 345 | 344 | ||
| 346 | Ok(()) | 345 | Ok(()) |
| 347 | } | 346 | } |
| 348 | 347 | ||
| 349 | fn read_state<P: FlashConfig>(&mut self, config: &mut P, magic: &mut [u8]) -> Result<State, BootError> { | 348 | fn read_state<P: FlashConfig>(&mut self, config: &mut P, magic: &mut [u8]) -> Result<State, BootError> { |
| 350 | let flash = config.state(); | 349 | self.state.read_blocking(config.state(), 0, magic)?; |
| 351 | flash.read(self.state.from as u32, magic)?; | ||
| 352 | 350 | ||
| 353 | if !magic.iter().any(|&b| b != SWAP_MAGIC) { | 351 | if !magic.iter().any(|&b| b != SWAP_MAGIC) { |
| 354 | Ok(State::Swap) | 352 | Ok(State::Swap) |
diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs index 2d8712277..af1ba114a 100644 --- a/embassy-boot/boot/src/firmware_updater.rs +++ b/embassy-boot/boot/src/firmware_updater.rs | |||
| @@ -84,10 +84,10 @@ impl FirmwareUpdater { | |||
| 84 | /// `mark_booted`. | 84 | /// `mark_booted`. |
| 85 | pub async fn get_state<F: AsyncNorFlash>( | 85 | pub async fn get_state<F: AsyncNorFlash>( |
| 86 | &mut self, | 86 | &mut self, |
| 87 | flash: &mut F, | 87 | state_flash: &mut F, |
| 88 | aligned: &mut [u8], | 88 | aligned: &mut [u8], |
| 89 | ) -> Result<State, FirmwareUpdaterError> { | 89 | ) -> Result<State, FirmwareUpdaterError> { |
| 90 | flash.read(self.state.from as u32, aligned).await?; | 90 | self.state.read(state_flash, 0, aligned).await?; |
| 91 | 91 | ||
| 92 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | 92 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { |
| 93 | Ok(State::Swap) | 93 | Ok(State::Swap) |
| @@ -115,17 +115,16 @@ impl FirmwareUpdater { | |||
| 115 | #[cfg(feature = "_verify")] | 115 | #[cfg(feature = "_verify")] |
| 116 | pub async fn verify_and_mark_updated<F: AsyncNorFlash>( | 116 | pub async fn verify_and_mark_updated<F: AsyncNorFlash>( |
| 117 | &mut self, | 117 | &mut self, |
| 118 | _flash: &mut F, | 118 | _state_and_dfu_flash: &mut F, |
| 119 | _public_key: &[u8], | 119 | _public_key: &[u8], |
| 120 | _signature: &[u8], | 120 | _signature: &[u8], |
| 121 | _update_len: usize, | 121 | _update_len: usize, |
| 122 | _aligned: &mut [u8], | 122 | _aligned: &mut [u8], |
| 123 | ) -> Result<(), FirmwareUpdaterError> { | 123 | ) -> Result<(), FirmwareUpdaterError> { |
| 124 | let _end = self.dfu.from + _update_len; | ||
| 125 | let _read_size = _aligned.len(); | 124 | let _read_size = _aligned.len(); |
| 126 | 125 | ||
| 127 | assert_eq!(_aligned.len(), F::WRITE_SIZE); | 126 | assert_eq!(_aligned.len(), F::WRITE_SIZE); |
| 128 | assert!(_end <= self.dfu.to); | 127 | assert!(_update_len <= self.dfu.len()); |
| 129 | 128 | ||
| 130 | #[cfg(feature = "ed25519-dalek")] | 129 | #[cfg(feature = "ed25519-dalek")] |
| 131 | { | 130 | { |
| @@ -137,21 +136,10 @@ impl FirmwareUpdater { | |||
| 137 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; | 136 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; |
| 138 | 137 | ||
| 139 | let mut digest = Sha512::new(); | 138 | let mut digest = Sha512::new(); |
| 140 | 139 | for offset in (0.._update_len).step_by(_aligned.len()) { | |
| 141 | let mut offset = self.dfu.from; | 140 | self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; |
| 142 | let last_offset = _end / _read_size * _read_size; | 141 | let len = core::cmp::min(_update_len - offset, _aligned.len()); |
| 143 | 142 | digest.update(&_aligned[..len]); | |
| 144 | while offset < last_offset { | ||
| 145 | _flash.read(offset as u32, _aligned).await?; | ||
| 146 | digest.update(&_aligned); | ||
| 147 | offset += _read_size; | ||
| 148 | } | ||
| 149 | |||
| 150 | let remaining = _end % _read_size; | ||
| 151 | |||
| 152 | if remaining > 0 { | ||
| 153 | _flash.read(last_offset as u32, _aligned).await?; | ||
| 154 | digest.update(&_aligned[0..remaining]); | ||
| 155 | } | 143 | } |
| 156 | 144 | ||
| 157 | public_key | 145 | public_key |
| @@ -173,21 +161,10 @@ impl FirmwareUpdater { | |||
| 173 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; | 161 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; |
| 174 | 162 | ||
| 175 | let mut digest = Sha512::new(); | 163 | let mut digest = Sha512::new(); |
| 176 | 164 | for offset in (0.._update_len).step_by(_aligned.len()) { | |
| 177 | let mut offset = self.dfu.from; | 165 | self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; |
| 178 | let last_offset = _end / _read_size * _read_size; | 166 | let len = core::cmp::min(_update_len - offset, _aligned.len()); |
| 179 | 167 | digest.update(&_aligned[..len]); | |
| 180 | while offset < last_offset { | ||
| 181 | _flash.read(offset as u32, _aligned).await?; | ||
| 182 | digest.update(&_aligned); | ||
| 183 | offset += _read_size; | ||
| 184 | } | ||
| 185 | |||
| 186 | let remaining = _end % _read_size; | ||
| 187 | |||
| 188 | if remaining > 0 { | ||
| 189 | _flash.read(last_offset as u32, _aligned).await?; | ||
| 190 | digest.update(&_aligned[0..remaining]); | ||
| 191 | } | 168 | } |
| 192 | 169 | ||
| 193 | let message = digest.finalize(); | 170 | let message = digest.finalize(); |
| @@ -202,7 +179,7 @@ impl FirmwareUpdater { | |||
| 202 | r.map_err(into_signature_error)? | 179 | r.map_err(into_signature_error)? |
| 203 | } | 180 | } |
| 204 | 181 | ||
| 205 | self.set_magic(_aligned, SWAP_MAGIC, _flash).await | 182 | self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await |
| 206 | } | 183 | } |
| 207 | 184 | ||
| 208 | /// Mark to trigger firmware swap on next boot. | 185 | /// Mark to trigger firmware swap on next boot. |
| @@ -213,11 +190,11 @@ impl FirmwareUpdater { | |||
| 213 | #[cfg(not(feature = "_verify"))] | 190 | #[cfg(not(feature = "_verify"))] |
| 214 | pub async fn mark_updated<F: AsyncNorFlash>( | 191 | pub async fn mark_updated<F: AsyncNorFlash>( |
| 215 | &mut self, | 192 | &mut self, |
| 216 | flash: &mut F, | 193 | state_flash: &mut F, |
| 217 | aligned: &mut [u8], | 194 | aligned: &mut [u8], |
| 218 | ) -> Result<(), FirmwareUpdaterError> { | 195 | ) -> Result<(), FirmwareUpdaterError> { |
| 219 | assert_eq!(aligned.len(), F::WRITE_SIZE); | 196 | assert_eq!(aligned.len(), F::WRITE_SIZE); |
| 220 | self.set_magic(aligned, SWAP_MAGIC, flash).await | 197 | self.set_magic(aligned, SWAP_MAGIC, state_flash).await |
| 221 | } | 198 | } |
| 222 | 199 | ||
| 223 | /// Mark firmware boot successful and stop rollback on reset. | 200 | /// Mark firmware boot successful and stop rollback on reset. |
| @@ -227,29 +204,29 @@ impl FirmwareUpdater { | |||
| 227 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | 204 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. |
| 228 | pub async fn mark_booted<F: AsyncNorFlash>( | 205 | pub async fn mark_booted<F: AsyncNorFlash>( |
| 229 | &mut self, | 206 | &mut self, |
| 230 | flash: &mut F, | 207 | state_flash: &mut F, |
| 231 | aligned: &mut [u8], | 208 | aligned: &mut [u8], |
| 232 | ) -> Result<(), FirmwareUpdaterError> { | 209 | ) -> Result<(), FirmwareUpdaterError> { |
| 233 | assert_eq!(aligned.len(), F::WRITE_SIZE); | 210 | assert_eq!(aligned.len(), F::WRITE_SIZE); |
| 234 | self.set_magic(aligned, BOOT_MAGIC, flash).await | 211 | self.set_magic(aligned, BOOT_MAGIC, state_flash).await |
| 235 | } | 212 | } |
| 236 | 213 | ||
| 237 | async fn set_magic<F: AsyncNorFlash>( | 214 | async fn set_magic<F: AsyncNorFlash>( |
| 238 | &mut self, | 215 | &mut self, |
| 239 | aligned: &mut [u8], | 216 | aligned: &mut [u8], |
| 240 | magic: u8, | 217 | magic: u8, |
| 241 | flash: &mut F, | 218 | state_flash: &mut F, |
| 242 | ) -> Result<(), FirmwareUpdaterError> { | 219 | ) -> Result<(), FirmwareUpdaterError> { |
| 243 | flash.read(self.state.from as u32, aligned).await?; | 220 | self.state.read(state_flash, 0, aligned).await?; |
| 244 | 221 | ||
| 245 | if aligned.iter().any(|&b| b != magic) { | 222 | if aligned.iter().any(|&b| b != magic) { |
| 246 | aligned.fill(0); | 223 | aligned.fill(0); |
| 247 | 224 | ||
| 248 | flash.write(self.state.from as u32, aligned).await?; | 225 | self.state.write(state_flash, 0, aligned).await?; |
| 249 | flash.erase(self.state.from as u32, self.state.to as u32).await?; | 226 | self.state.wipe(state_flash).await?; |
| 250 | 227 | ||
| 251 | aligned.fill(magic); | 228 | aligned.fill(magic); |
| 252 | flash.write(self.state.from as u32, aligned).await?; | 229 | self.state.write(state_flash, 0, aligned).await?; |
| 253 | } | 230 | } |
| 254 | Ok(()) | 231 | Ok(()) |
| 255 | } | 232 | } |
| @@ -265,26 +242,17 @@ impl FirmwareUpdater { | |||
| 265 | &mut self, | 242 | &mut self, |
| 266 | offset: usize, | 243 | offset: usize, |
| 267 | data: &[u8], | 244 | data: &[u8], |
| 268 | flash: &mut F, | 245 | dfu_flash: &mut F, |
| 269 | block_size: usize, | 246 | block_size: usize, |
| 270 | ) -> Result<(), FirmwareUpdaterError> { | 247 | ) -> Result<(), FirmwareUpdaterError> { |
| 271 | assert!(data.len() >= F::ERASE_SIZE); | 248 | assert!(data.len() >= F::ERASE_SIZE); |
| 272 | 249 | ||
| 273 | flash | 250 | self.dfu |
| 274 | .erase( | 251 | .erase(dfu_flash, offset as u32, (offset + data.len()) as u32) |
| 275 | (self.dfu.from + offset) as u32, | ||
| 276 | (self.dfu.from + offset + data.len()) as u32, | ||
| 277 | ) | ||
| 278 | .await?; | 252 | .await?; |
| 279 | 253 | ||
| 280 | trace!( | ||
| 281 | "Erased from {} to {}", | ||
| 282 | self.dfu.from + offset, | ||
| 283 | self.dfu.from + offset + data.len() | ||
| 284 | ); | ||
| 285 | |||
| 286 | FirmwareWriter(self.dfu) | 254 | FirmwareWriter(self.dfu) |
| 287 | .write_block(offset, data, flash, block_size) | 255 | .write_block(offset, data, dfu_flash, block_size) |
| 288 | .await?; | 256 | .await?; |
| 289 | 257 | ||
| 290 | Ok(()) | 258 | Ok(()) |
| @@ -297,11 +265,9 @@ impl FirmwareUpdater { | |||
| 297 | /// exchange for added complexity. | 265 | /// exchange for added complexity. |
| 298 | pub async fn prepare_update<F: AsyncNorFlash>( | 266 | pub async fn prepare_update<F: AsyncNorFlash>( |
| 299 | &mut self, | 267 | &mut self, |
| 300 | flash: &mut F, | 268 | dfu_flash: &mut F, |
| 301 | ) -> Result<FirmwareWriter, FirmwareUpdaterError> { | 269 | ) -> Result<FirmwareWriter, FirmwareUpdaterError> { |
| 302 | flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32).await?; | 270 | self.dfu.wipe(dfu_flash).await?; |
| 303 | |||
| 304 | trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); | ||
| 305 | 271 | ||
| 306 | Ok(FirmwareWriter(self.dfu)) | 272 | Ok(FirmwareWriter(self.dfu)) |
| 307 | } | 273 | } |
| @@ -317,10 +283,10 @@ impl FirmwareUpdater { | |||
| 317 | /// `mark_booted`. | 283 | /// `mark_booted`. |
| 318 | pub fn get_state_blocking<F: NorFlash>( | 284 | pub fn get_state_blocking<F: NorFlash>( |
| 319 | &mut self, | 285 | &mut self, |
| 320 | flash: &mut F, | 286 | state_flash: &mut F, |
| 321 | aligned: &mut [u8], | 287 | aligned: &mut [u8], |
| 322 | ) -> Result<State, FirmwareUpdaterError> { | 288 | ) -> Result<State, FirmwareUpdaterError> { |
| 323 | flash.read(self.state.from as u32, aligned)?; | 289 | self.state.read_blocking(state_flash, 0, aligned)?; |
| 324 | 290 | ||
| 325 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | 291 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { |
| 326 | Ok(State::Swap) | 292 | Ok(State::Swap) |
| @@ -348,7 +314,7 @@ impl FirmwareUpdater { | |||
| 348 | #[cfg(feature = "_verify")] | 314 | #[cfg(feature = "_verify")] |
| 349 | pub fn verify_and_mark_updated_blocking<F: NorFlash>( | 315 | pub fn verify_and_mark_updated_blocking<F: NorFlash>( |
| 350 | &mut self, | 316 | &mut self, |
| 351 | _flash: &mut F, | 317 | _state_and_dfu_flash: &mut F, |
| 352 | _public_key: &[u8], | 318 | _public_key: &[u8], |
| 353 | _signature: &[u8], | 319 | _signature: &[u8], |
| 354 | _update_len: usize, | 320 | _update_len: usize, |
| @@ -370,21 +336,10 @@ impl FirmwareUpdater { | |||
| 370 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; | 336 | let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; |
| 371 | 337 | ||
| 372 | let mut digest = Sha512::new(); | 338 | let mut digest = Sha512::new(); |
| 373 | 339 | for offset in (0.._update_len).step_by(_aligned.len()) { | |
| 374 | let mut offset = self.dfu.from; | 340 | self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?; |
| 375 | let last_offset = _end / _read_size * _read_size; | 341 | let len = core::cmp::min(_update_len - offset, _aligned.len()); |
| 376 | 342 | digest.update(&_aligned[..len]); | |
| 377 | while offset < last_offset { | ||
| 378 | _flash.read(offset as u32, _aligned)?; | ||
| 379 | digest.update(&_aligned); | ||
| 380 | offset += _read_size; | ||
| 381 | } | ||
| 382 | |||
| 383 | let remaining = _end % _read_size; | ||
| 384 | |||
| 385 | if remaining > 0 { | ||
| 386 | _flash.read(last_offset as u32, _aligned)?; | ||
| 387 | digest.update(&_aligned[0..remaining]); | ||
| 388 | } | 343 | } |
| 389 | 344 | ||
| 390 | public_key | 345 | public_key |
| @@ -406,21 +361,10 @@ impl FirmwareUpdater { | |||
| 406 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; | 361 | let signature = Signature::try_from(&signature).map_err(into_signature_error)?; |
| 407 | 362 | ||
| 408 | let mut digest = Sha512::new(); | 363 | let mut digest = Sha512::new(); |
| 409 | 364 | for offset in (0.._update_len).step_by(_aligned.len()) { | |
| 410 | let mut offset = self.dfu.from; | 365 | self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?; |
| 411 | let last_offset = _end / _read_size * _read_size; | 366 | let len = core::cmp::min(_update_len - offset, _aligned.len()); |
| 412 | 367 | digest.update(&_aligned[..len]); | |
| 413 | while offset < last_offset { | ||
| 414 | _flash.read(offset as u32, _aligned)?; | ||
| 415 | digest.update(&_aligned); | ||
| 416 | offset += _read_size; | ||
| 417 | } | ||
| 418 | |||
| 419 | let remaining = _end % _read_size; | ||
| 420 | |||
| 421 | if remaining > 0 { | ||
| 422 | _flash.read(last_offset as u32, _aligned)?; | ||
| 423 | digest.update(&_aligned[0..remaining]); | ||
| 424 | } | 368 | } |
| 425 | 369 | ||
| 426 | let message = digest.finalize(); | 370 | let message = digest.finalize(); |
| @@ -435,7 +379,7 @@ impl FirmwareUpdater { | |||
| 435 | r.map_err(into_signature_error)? | 379 | r.map_err(into_signature_error)? |
| 436 | } | 380 | } |
| 437 | 381 | ||
| 438 | self.set_magic_blocking(_aligned, SWAP_MAGIC, _flash) | 382 | self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) |
| 439 | } | 383 | } |
| 440 | 384 | ||
| 441 | /// Mark to trigger firmware swap on next boot. | 385 | /// Mark to trigger firmware swap on next boot. |
| @@ -446,11 +390,11 @@ impl FirmwareUpdater { | |||
| 446 | #[cfg(not(feature = "_verify"))] | 390 | #[cfg(not(feature = "_verify"))] |
| 447 | pub fn mark_updated_blocking<F: NorFlash>( | 391 | pub fn mark_updated_blocking<F: NorFlash>( |
| 448 | &mut self, | 392 | &mut self, |
| 449 | flash: &mut F, | 393 | state_flash: &mut F, |
| 450 | aligned: &mut [u8], | 394 | aligned: &mut [u8], |
| 451 | ) -> Result<(), FirmwareUpdaterError> { | 395 | ) -> Result<(), FirmwareUpdaterError> { |
| 452 | assert_eq!(aligned.len(), F::WRITE_SIZE); | 396 | assert_eq!(aligned.len(), F::WRITE_SIZE); |
| 453 | self.set_magic_blocking(aligned, SWAP_MAGIC, flash) | 397 | self.set_magic_blocking(aligned, SWAP_MAGIC, state_flash) |
| 454 | } | 398 | } |
| 455 | 399 | ||
| 456 | /// Mark firmware boot successful and stop rollback on reset. | 400 | /// Mark firmware boot successful and stop rollback on reset. |
| @@ -460,29 +404,29 @@ impl FirmwareUpdater { | |||
| 460 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | 404 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. |
| 461 | pub fn mark_booted_blocking<F: NorFlash>( | 405 | pub fn mark_booted_blocking<F: NorFlash>( |
| 462 | &mut self, | 406 | &mut self, |
| 463 | flash: &mut F, | 407 | state_flash: &mut F, |
| 464 | aligned: &mut [u8], | 408 | aligned: &mut [u8], |
| 465 | ) -> Result<(), FirmwareUpdaterError> { | 409 | ) -> Result<(), FirmwareUpdaterError> { |
| 466 | assert_eq!(aligned.len(), F::WRITE_SIZE); | 410 | assert_eq!(aligned.len(), F::WRITE_SIZE); |
| 467 | self.set_magic_blocking(aligned, BOOT_MAGIC, flash) | 411 | self.set_magic_blocking(aligned, BOOT_MAGIC, state_flash) |
| 468 | } | 412 | } |
| 469 | 413 | ||
| 470 | fn set_magic_blocking<F: NorFlash>( | 414 | fn set_magic_blocking<F: NorFlash>( |
| 471 | &mut self, | 415 | &mut self, |
| 472 | aligned: &mut [u8], | 416 | aligned: &mut [u8], |
| 473 | magic: u8, | 417 | magic: u8, |
| 474 | flash: &mut F, | 418 | state_flash: &mut F, |
| 475 | ) -> Result<(), FirmwareUpdaterError> { | 419 | ) -> Result<(), FirmwareUpdaterError> { |
| 476 | flash.read(self.state.from as u32, aligned)?; | 420 | self.state.read_blocking(state_flash, 0, aligned)?; |
| 477 | 421 | ||
| 478 | if aligned.iter().any(|&b| b != magic) { | 422 | if aligned.iter().any(|&b| b != magic) { |
| 479 | aligned.fill(0); | 423 | aligned.fill(0); |
| 480 | 424 | ||
| 481 | flash.write(self.state.from as u32, aligned)?; | 425 | self.state.write_blocking(state_flash, 0, aligned)?; |
| 482 | flash.erase(self.state.from as u32, self.state.to as u32)?; | 426 | self.state.wipe_blocking(state_flash)?; |
| 483 | 427 | ||
| 484 | aligned.fill(magic); | 428 | aligned.fill(magic); |
| 485 | flash.write(self.state.from as u32, aligned)?; | 429 | self.state.write_blocking(state_flash, 0, aligned)?; |
| 486 | } | 430 | } |
| 487 | Ok(()) | 431 | Ok(()) |
| 488 | } | 432 | } |
| @@ -498,23 +442,15 @@ impl FirmwareUpdater { | |||
| 498 | &mut self, | 442 | &mut self, |
| 499 | offset: usize, | 443 | offset: usize, |
| 500 | data: &[u8], | 444 | data: &[u8], |
| 501 | flash: &mut F, | 445 | dfu_flash: &mut F, |
| 502 | block_size: usize, | 446 | block_size: usize, |
| 503 | ) -> Result<(), FirmwareUpdaterError> { | 447 | ) -> Result<(), FirmwareUpdaterError> { |
| 504 | assert!(data.len() >= F::ERASE_SIZE); | 448 | assert!(data.len() >= F::ERASE_SIZE); |
| 505 | 449 | ||
| 506 | flash.erase( | 450 | self.dfu |
| 507 | (self.dfu.from + offset) as u32, | 451 | .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?; |
| 508 | (self.dfu.from + offset + data.len()) as u32, | ||
| 509 | )?; | ||
| 510 | 452 | ||
| 511 | trace!( | 453 | FirmwareWriter(self.dfu).write_block_blocking(offset, data, dfu_flash, block_size)?; |
| 512 | "Erased from {} to {}", | ||
| 513 | self.dfu.from + offset, | ||
| 514 | self.dfu.from + offset + data.len() | ||
| 515 | ); | ||
| 516 | |||
| 517 | FirmwareWriter(self.dfu).write_block_blocking(offset, data, flash, block_size)?; | ||
| 518 | 454 | ||
| 519 | Ok(()) | 455 | Ok(()) |
| 520 | } | 456 | } |
| @@ -528,9 +464,7 @@ impl FirmwareUpdater { | |||
| 528 | &mut self, | 464 | &mut self, |
| 529 | flash: &mut F, | 465 | flash: &mut F, |
| 530 | ) -> Result<FirmwareWriter, FirmwareUpdaterError> { | 466 | ) -> Result<FirmwareWriter, FirmwareUpdaterError> { |
| 531 | flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32)?; | 467 | self.dfu.wipe_blocking(flash)?; |
| 532 | |||
| 533 | trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); | ||
| 534 | 468 | ||
| 535 | Ok(FirmwareWriter(self.dfu)) | 469 | Ok(FirmwareWriter(self.dfu)) |
| 536 | } | 470 | } |
diff --git a/embassy-boot/boot/src/firmware_writer.rs b/embassy-boot/boot/src/firmware_writer.rs index f992021bb..46079e731 100644 --- a/embassy-boot/boot/src/firmware_writer.rs +++ b/embassy-boot/boot/src/firmware_writer.rs | |||
| @@ -21,32 +21,11 @@ impl FirmwareWriter { | |||
| 21 | flash: &mut F, | 21 | flash: &mut F, |
| 22 | block_size: usize, | 22 | block_size: usize, |
| 23 | ) -> Result<(), F::Error> { | 23 | ) -> Result<(), F::Error> { |
| 24 | trace!( | 24 | let mut offset = offset as u32; |
| 25 | "Writing firmware at offset 0x{:x} len {}", | ||
| 26 | self.0.from + offset, | ||
| 27 | data.len() | ||
| 28 | ); | ||
| 29 | |||
| 30 | let mut write_offset = self.0.from + offset; | ||
| 31 | for chunk in data.chunks(block_size) { | 25 | for chunk in data.chunks(block_size) { |
| 32 | trace!("Wrote chunk at {}: {:?}", write_offset, chunk); | 26 | self.0.write(flash, offset, chunk).await?; |
| 33 | flash.write(write_offset as u32, chunk).await?; | 27 | offset += chunk.len() as u32; |
| 34 | write_offset += chunk.len(); | ||
| 35 | } | ||
| 36 | /* | ||
| 37 | trace!("Wrote data, reading back for verification"); | ||
| 38 | |||
| 39 | let mut buf: [u8; 4096] = [0; 4096]; | ||
| 40 | let mut data_offset = 0; | ||
| 41 | let mut read_offset = self.dfu.from + offset; | ||
| 42 | for chunk in buf.chunks_mut(block_size) { | ||
| 43 | flash.read(read_offset as u32, chunk).await?; | ||
| 44 | trace!("Read chunk at {}: {:?}", read_offset, chunk); | ||
| 45 | assert_eq!(&data[data_offset..data_offset + block_size], chunk); | ||
| 46 | read_offset += chunk.len(); | ||
| 47 | data_offset += chunk.len(); | ||
| 48 | } | 28 | } |
| 49 | */ | ||
| 50 | 29 | ||
| 51 | Ok(()) | 30 | Ok(()) |
| 52 | } | 31 | } |
| @@ -65,32 +44,11 @@ impl FirmwareWriter { | |||
| 65 | flash: &mut F, | 44 | flash: &mut F, |
| 66 | block_size: usize, | 45 | block_size: usize, |
| 67 | ) -> Result<(), F::Error> { | 46 | ) -> Result<(), F::Error> { |
| 68 | trace!( | 47 | let mut offset = offset as u32; |
| 69 | "Writing firmware at offset 0x{:x} len {}", | ||
| 70 | self.0.from + offset, | ||
| 71 | data.len() | ||
| 72 | ); | ||
| 73 | |||
| 74 | let mut write_offset = self.0.from + offset; | ||
| 75 | for chunk in data.chunks(block_size) { | 48 | for chunk in data.chunks(block_size) { |
| 76 | trace!("Wrote chunk at {}: {:?}", write_offset, chunk); | 49 | self.0.write_blocking(flash, offset, chunk)?; |
| 77 | flash.write(write_offset as u32, chunk)?; | 50 | offset += chunk.len() as u32; |
| 78 | write_offset += chunk.len(); | ||
| 79 | } | ||
| 80 | /* | ||
| 81 | trace!("Wrote data, reading back for verification"); | ||
| 82 | |||
| 83 | let mut buf: [u8; 4096] = [0; 4096]; | ||
| 84 | let mut data_offset = 0; | ||
| 85 | let mut read_offset = self.dfu.from + offset; | ||
| 86 | for chunk in buf.chunks_mut(block_size) { | ||
| 87 | flash.read(read_offset as u32, chunk).await?; | ||
| 88 | trace!("Read chunk at {}: {:?}", read_offset, chunk); | ||
| 89 | assert_eq!(&data[data_offset..data_offset + block_size], chunk); | ||
| 90 | read_offset += chunk.len(); | ||
| 91 | data_offset += chunk.len(); | ||
| 92 | } | 51 | } |
| 93 | */ | ||
| 94 | 52 | ||
| 95 | Ok(()) | 53 | Ok(()) |
| 96 | } | 54 | } |
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index a2259411f..4c28d7aa4 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs | |||
| @@ -313,7 +313,8 @@ mod tests { | |||
| 313 | )) | 313 | )) |
| 314 | .is_ok()); | 314 | .is_ok()); |
| 315 | } | 315 | } |
| 316 | struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize>([u8; SIZE]); | 316 | |
| 317 | pub struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize>(pub [u8; SIZE]); | ||
| 317 | 318 | ||
| 318 | impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> NorFlash | 319 | impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> NorFlash |
| 319 | for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE> | 320 | for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE> |
diff --git a/embassy-boot/boot/src/partition.rs b/embassy-boot/boot/src/partition.rs index 46f80a23c..3ccd4dd76 100644 --- a/embassy-boot/boot/src/partition.rs +++ b/embassy-boot/boot/src/partition.rs | |||
| @@ -1,10 +1,13 @@ | |||
| 1 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 2 | use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; | ||
| 3 | |||
| 1 | /// A region in flash used by the bootloader. | 4 | /// A region in flash used by the bootloader. |
| 2 | #[derive(Copy, Clone, Debug)] | 5 | #[derive(Copy, Clone, Debug)] |
| 3 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 6 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 4 | pub struct Partition { | 7 | pub struct Partition { |
| 5 | /// Start of the flash region. | 8 | /// The offset into the flash where the partition starts. |
| 6 | pub from: usize, | 9 | pub from: usize, |
| 7 | /// End of the flash region. | 10 | /// The offset into the flash where the partition ends. |
| 8 | pub to: usize, | 11 | pub to: usize, |
| 9 | } | 12 | } |
| 10 | 13 | ||
| @@ -14,9 +17,134 @@ impl Partition { | |||
| 14 | Self { from, to } | 17 | Self { from, to } |
| 15 | } | 18 | } |
| 16 | 19 | ||
| 17 | /// Return the length of the partition | 20 | /// Return the size of the partition |
| 18 | #[allow(clippy::len_without_is_empty)] | 21 | #[allow(clippy::len_without_is_empty)] |
| 19 | pub const fn len(&self) -> usize { | 22 | pub const fn len(&self) -> usize { |
| 20 | self.to - self.from | 23 | self.to - self.from |
| 21 | } | 24 | } |
| 25 | |||
| 26 | /// Read from the partition on the provided flash | ||
| 27 | pub(crate) async fn read<F: AsyncReadNorFlash>( | ||
| 28 | &self, | ||
| 29 | flash: &mut F, | ||
| 30 | offset: u32, | ||
| 31 | bytes: &mut [u8], | ||
| 32 | ) -> Result<(), F::Error> { | ||
| 33 | let offset = self.from as u32 + offset; | ||
| 34 | flash.read(offset, bytes).await | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Write to the partition on the provided flash | ||
| 38 | pub(crate) async fn write<F: AsyncNorFlash>( | ||
| 39 | &self, | ||
| 40 | flash: &mut F, | ||
| 41 | offset: u32, | ||
| 42 | bytes: &[u8], | ||
| 43 | ) -> Result<(), F::Error> { | ||
| 44 | let offset = self.from as u32 + offset; | ||
| 45 | flash.write(offset, bytes).await?; | ||
| 46 | trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); | ||
| 47 | Ok(()) | ||
| 48 | } | ||
| 49 | |||
| 50 | /// Erase part of the partition on the provided flash | ||
| 51 | pub(crate) async fn erase<F: AsyncNorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { | ||
| 52 | let from = self.from as u32 + from; | ||
| 53 | let to = self.from as u32 + to; | ||
| 54 | flash.erase(from, to).await?; | ||
| 55 | trace!("Erased from 0x{:x} to 0x{:x}", from, to); | ||
| 56 | Ok(()) | ||
| 57 | } | ||
| 58 | |||
| 59 | /// Erase the entire partition | ||
| 60 | pub(crate) async fn wipe<F: AsyncNorFlash>(&self, flash: &mut F) -> Result<(), F::Error> { | ||
| 61 | let from = self.from as u32; | ||
| 62 | let to = self.to as u32; | ||
| 63 | flash.erase(from, to).await?; | ||
| 64 | trace!("Wiped from 0x{:x} to 0x{:x}", from, to); | ||
| 65 | Ok(()) | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Read from the partition on the provided flash | ||
| 69 | pub(crate) fn read_blocking<F: ReadNorFlash>( | ||
| 70 | &self, | ||
| 71 | flash: &mut F, | ||
| 72 | offset: u32, | ||
| 73 | bytes: &mut [u8], | ||
| 74 | ) -> Result<(), F::Error> { | ||
| 75 | let offset = self.from as u32 + offset; | ||
| 76 | flash.read(offset, bytes) | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Write to the partition on the provided flash | ||
| 80 | pub(crate) fn write_blocking<F: NorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> { | ||
| 81 | let offset = self.from as u32 + offset; | ||
| 82 | flash.write(offset, bytes)?; | ||
| 83 | trace!("Wrote from 0x{:x} len {}", offset, bytes.len()); | ||
| 84 | Ok(()) | ||
| 85 | } | ||
| 86 | |||
| 87 | /// Erase part of the partition on the provided flash | ||
| 88 | pub(crate) fn erase_blocking<F: NorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> { | ||
| 89 | let from = self.from as u32 + from; | ||
| 90 | let to = self.from as u32 + to; | ||
| 91 | flash.erase(from, to)?; | ||
| 92 | trace!("Erased from 0x{:x} to 0x{:x}", from, to); | ||
| 93 | Ok(()) | ||
| 94 | } | ||
| 95 | |||
| 96 | /// Erase the entire partition | ||
| 97 | pub(crate) fn wipe_blocking<F: NorFlash>(&self, flash: &mut F) -> Result<(), F::Error> { | ||
| 98 | let from = self.from as u32; | ||
| 99 | let to = self.to as u32; | ||
| 100 | flash.erase(from, to)?; | ||
| 101 | trace!("Wiped from 0x{:x} to 0x{:x}", from, to); | ||
| 102 | Ok(()) | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | #[cfg(test)] | ||
| 107 | mod tests { | ||
| 108 | use crate::tests::MemFlash; | ||
| 109 | use crate::Partition; | ||
| 110 | |||
| 111 | #[test] | ||
| 112 | fn can_erase() { | ||
| 113 | let mut flash = MemFlash::<1024, 64, 4>([0x00; 1024]); | ||
| 114 | let partition = Partition::new(256, 512); | ||
| 115 | |||
| 116 | partition.erase_blocking(&mut flash, 64, 192).unwrap(); | ||
| 117 | |||
| 118 | for (index, byte) in flash.0.iter().copied().enumerate().take(256 + 64) { | ||
| 119 | assert_eq!(0x00, byte, "Index {}", index); | ||
| 120 | } | ||
| 121 | |||
| 122 | for (index, byte) in flash.0.iter().copied().enumerate().skip(256 + 64).take(128) { | ||
| 123 | assert_eq!(0xFF, byte, "Index {}", index); | ||
| 124 | } | ||
| 125 | |||
| 126 | for (index, byte) in flash.0.iter().copied().enumerate().skip(256 + 64 + 128) { | ||
| 127 | assert_eq!(0x00, byte, "Index {}", index); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | #[test] | ||
| 132 | fn can_wipe() { | ||
| 133 | let mut flash = MemFlash::<1024, 64, 4>([0x00; 1024]); | ||
| 134 | let partition = Partition::new(256, 512); | ||
| 135 | |||
| 136 | partition.wipe_blocking(&mut flash).unwrap(); | ||
| 137 | |||
| 138 | for (index, byte) in flash.0.iter().copied().enumerate().take(256) { | ||
| 139 | assert_eq!(0x00, byte, "Index {}", index); | ||
| 140 | } | ||
| 141 | |||
| 142 | for (index, byte) in flash.0.iter().copied().enumerate().skip(256).take(256) { | ||
| 143 | assert_eq!(0xFF, byte, "Index {}", index); | ||
| 144 | } | ||
| 145 | |||
| 146 | for (index, byte) in flash.0.iter().copied().enumerate().skip(512) { | ||
| 147 | assert_eq!(0x00, byte, "Index {}", index); | ||
| 148 | } | ||
| 149 | } | ||
| 22 | } | 150 | } |
