aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-boot/boot')
-rw-r--r--embassy-boot/boot/src/boot_loader.rs102
-rw-r--r--embassy-boot/boot/src/firmware_updater.rs174
-rw-r--r--embassy-boot/boot/src/firmware_writer.rs54
-rw-r--r--embassy-boot/boot/src/lib.rs3
-rw-r--r--embassy-boot/boot/src/partition.rs134
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 @@
1use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
2use 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))]
4pub struct Partition { 7pub 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)]
107mod 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}