aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-04-11 06:17:00 +0000
committerGitHub <[email protected]>2023-04-11 06:17:00 +0000
commit636a3d05c2ac129e2fa85cf6e7fb5afff2d8126b (patch)
tree91c7bec35c40932932569c889654986a52d30ee7
parent1f25d2ba8335300368b32f9ceedf163376dfdb6f (diff)
parentd3ce64254aecb24feded2408119855daf7380e80 (diff)
Merge #1331
1331: Let bootloader partition be u32 r=rmja a=rmja This is probably controversial but hear me out:) The idea about changing from usize to u32 is to enable support for 16 bit mcu's with large flash, e.g. MSP430F5529. Its usize is only 16 bit, but its flash is larger than 64k. Hence, to address its entire flash, it needs the flash address space to be u32. Missing from the PR is `update_len` in the verification methods. There is currently [a different PR](https://github.com/embassy-rs/embassy/pull/1323) that contains changes in those methods, and I will align depending on the merge order of the two. The general distinction between u32 and usize is: * If it is a size or address that only ever lives in flash, then it is u32. * If the offset or size is ever representable in memory, then usize. Co-authored-by: Rasmus Melchior Jacobsen <[email protected]>
-rw-r--r--embassy-boot/boot/src/boot_loader.rs101
-rw-r--r--embassy-boot/boot/src/firmware_updater.rs29
-rw-r--r--embassy-boot/boot/src/lib.rs62
-rw-r--r--embassy-boot/boot/src/mem_flash.rs17
-rw-r--r--embassy-boot/boot/src/partition.rs9
-rw-r--r--embassy-boot/nrf/src/lib.rs12
-rw-r--r--embassy-boot/rp/src/lib.rs12
-rw-r--r--embassy-boot/stm32/src/lib.rs12
8 files changed, 117 insertions, 137 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs
index 2412427c0..b959de2c4 100644
--- a/embassy-boot/boot/src/boot_loader.rs
+++ b/embassy-boot/boot/src/boot_loader.rs
@@ -50,13 +50,13 @@ pub trait FlashConfig {
50} 50}
51 51
52trait FlashConfigEx { 52trait FlashConfigEx {
53 fn page_size() -> usize; 53 fn page_size() -> u32;
54} 54}
55 55
56impl<T: FlashConfig> FlashConfigEx for T { 56impl<T: FlashConfig> FlashConfigEx for T {
57 /// Get the page size which is the "unit of operation" within the bootloader. 57 /// Get the page size which is the "unit of operation" within the bootloader.
58 fn page_size() -> usize { 58 fn page_size() -> u32 {
59 core::cmp::max(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE) 59 core::cmp::max(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE) as u32
60 } 60 }
61} 61}
62 62
@@ -86,7 +86,7 @@ impl BootLoader {
86 86
87 /// Return the offset of the active partition into the active flash. 87 /// Return the offset of the active partition into the active flash.
88 pub fn boot_address(&self) -> usize { 88 pub fn boot_address(&self) -> usize {
89 self.active.from 89 self.active.from as usize
90 } 90 }
91 91
92 /// Perform necessary boot preparations like swapping images. 92 /// Perform necessary boot preparations like swapping images.
@@ -177,11 +177,11 @@ impl BootLoader {
177 /// 177 ///
178 pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> { 178 pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> {
179 // Ensure we have enough progress pages to store copy progress 179 // Ensure we have enough progress pages to store copy progress
180 assert_eq!(0, P::page_size() % aligned_buf.len()); 180 assert_eq!(0, P::page_size() % aligned_buf.len() as u32);
181 assert_eq!(0, P::page_size() % P::ACTIVE::WRITE_SIZE); 181 assert_eq!(0, P::page_size() % P::ACTIVE::WRITE_SIZE as u32);
182 assert_eq!(0, P::page_size() % P::ACTIVE::ERASE_SIZE); 182 assert_eq!(0, P::page_size() % P::ACTIVE::ERASE_SIZE as u32);
183 assert_eq!(0, P::page_size() % P::DFU::WRITE_SIZE); 183 assert_eq!(0, P::page_size() % P::DFU::WRITE_SIZE as u32);
184 assert_eq!(0, P::page_size() % P::DFU::ERASE_SIZE); 184 assert_eq!(0, P::page_size() % P::DFU::ERASE_SIZE as u32);
185 assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE); 185 assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE);
186 assert_eq!(0, aligned_buf.len() % P::ACTIVE::WRITE_SIZE); 186 assert_eq!(0, aligned_buf.len() % P::ACTIVE::WRITE_SIZE);
187 assert_eq!(0, aligned_buf.len() % P::DFU::WRITE_SIZE); 187 assert_eq!(0, aligned_buf.len() % P::DFU::WRITE_SIZE);
@@ -222,30 +222,27 @@ impl BootLoader {
222 } 222 }
223 223
224 fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<bool, BootError> { 224 fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<bool, BootError> {
225 let page_count = self.active.len() / P::page_size(); 225 let page_count = (self.active.size() / P::page_size()) as usize;
226 let progress = self.current_progress(p, aligned_buf)?; 226 let progress = self.current_progress(p, aligned_buf)?;
227 227
228 Ok(progress >= page_count * 2) 228 Ok(progress >= page_count * 2)
229 } 229 }
230 230
231 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<usize, BootError> { 231 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<usize, BootError> {
232 let max_index = ((self.state.len() - P::STATE::WRITE_SIZE) / P::STATE::WRITE_SIZE) - 2; 232 let write_size = P::STATE::WRITE_SIZE as u32;
233 let max_index = (((self.state.size() - write_size) / write_size) - 2) as usize;
233 let state_flash = config.state(); 234 let state_flash = config.state();
234 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE]; 235 let state_word = &mut aligned_buf[..write_size as usize];
235 236
236 self.state 237 self.state.read_blocking(state_flash, write_size, state_word)?;
237 .read_blocking(state_flash, P::STATE::WRITE_SIZE as u32, state_word)?;
238 if state_word.iter().any(|&b| b != P::STATE_ERASE_VALUE) { 238 if state_word.iter().any(|&b| b != P::STATE_ERASE_VALUE) {
239 // Progress is invalid 239 // Progress is invalid
240 return Ok(max_index); 240 return Ok(max_index);
241 } 241 }
242 242
243 for index in 0..max_index { 243 for index in 0..max_index {
244 self.state.read_blocking( 244 self.state
245 state_flash, 245 .read_blocking(state_flash, (2 + index) as u32 * write_size, state_word)?;
246 (2 + index) as u32 * P::STATE::WRITE_SIZE as u32,
247 state_word,
248 )?;
249 246
250 if state_word.iter().any(|&b| b == P::STATE_ERASE_VALUE) { 247 if state_word.iter().any(|&b| b == P::STATE_ERASE_VALUE) {
251 return Ok(index); 248 return Ok(index);
@@ -256,26 +253,29 @@ impl BootLoader {
256 253
257 fn update_progress<P: FlashConfig>( 254 fn update_progress<P: FlashConfig>(
258 &mut self, 255 &mut self,
259 index: usize, 256 progress_index: usize,
260 p: &mut P, 257 p: &mut P,
261 aligned_buf: &mut [u8], 258 aligned_buf: &mut [u8],
262 ) -> Result<(), BootError> { 259 ) -> Result<(), BootError> {
263 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE]; 260 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
264 state_word.fill(!P::STATE_ERASE_VALUE); 261 state_word.fill(!P::STATE_ERASE_VALUE);
265 self.state 262 self.state.write_blocking(
266 .write_blocking(p.state(), (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, state_word)?; 263 p.state(),
264 (2 + progress_index) as u32 * P::STATE::WRITE_SIZE as u32,
265 state_word,
266 )?;
267 Ok(()) 267 Ok(())
268 } 268 }
269 269
270 fn copy_page_once_to_active<P: FlashConfig>( 270 fn copy_page_once_to_active<P: FlashConfig>(
271 &mut self, 271 &mut self,
272 idx: usize, 272 progress_index: usize,
273 from_offset: u32, 273 from_offset: u32,
274 to_offset: u32, 274 to_offset: u32,
275 p: &mut P, 275 p: &mut P,
276 aligned_buf: &mut [u8], 276 aligned_buf: &mut [u8],
277 ) -> Result<(), BootError> { 277 ) -> Result<(), BootError> {
278 if self.current_progress(p, aligned_buf)? <= idx { 278 if self.current_progress(p, aligned_buf)? <= progress_index {
279 let page_size = P::page_size() as u32; 279 let page_size = P::page_size() as u32;
280 280
281 self.active 281 self.active
@@ -288,20 +288,20 @@ impl BootLoader {
288 .write_blocking(p.active(), to_offset + offset_in_page as u32, aligned_buf)?; 288 .write_blocking(p.active(), to_offset + offset_in_page as u32, aligned_buf)?;
289 } 289 }
290 290
291 self.update_progress(idx, p, aligned_buf)?; 291 self.update_progress(progress_index, p, aligned_buf)?;
292 } 292 }
293 Ok(()) 293 Ok(())
294 } 294 }
295 295
296 fn copy_page_once_to_dfu<P: FlashConfig>( 296 fn copy_page_once_to_dfu<P: FlashConfig>(
297 &mut self, 297 &mut self,
298 idx: usize, 298 progress_index: usize,
299 from_offset: u32, 299 from_offset: u32,
300 to_offset: u32, 300 to_offset: u32,
301 p: &mut P, 301 p: &mut P,
302 aligned_buf: &mut [u8], 302 aligned_buf: &mut [u8],
303 ) -> Result<(), BootError> { 303 ) -> Result<(), BootError> {
304 if self.current_progress(p, aligned_buf)? <= idx { 304 if self.current_progress(p, aligned_buf)? <= progress_index {
305 let page_size = P::page_size() as u32; 305 let page_size = P::page_size() as u32;
306 306
307 self.dfu 307 self.dfu
@@ -314,31 +314,28 @@ impl BootLoader {
314 .write_blocking(p.dfu(), to_offset + offset_in_page as u32, aligned_buf)?; 314 .write_blocking(p.dfu(), to_offset + offset_in_page as u32, aligned_buf)?;
315 } 315 }
316 316
317 self.update_progress(idx, p, aligned_buf)?; 317 self.update_progress(progress_index, p, aligned_buf)?;
318 } 318 }
319 Ok(()) 319 Ok(())
320 } 320 }
321 321
322 fn swap<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> { 322 fn swap<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> {
323 let page_size = P::page_size(); 323 let page_size = P::page_size();
324 let page_count = self.active.len() / page_size; 324 let page_count = self.active.size() / page_size;
325 trace!("Page count: {}", page_count);
326 for page_num in 0..page_count { 325 for page_num in 0..page_count {
327 trace!("COPY PAGE {}", page_num); 326 let progress_index = (page_num * 2) as usize;
328
329 let idx = page_num * 2;
330 327
331 // Copy active page to the 'next' DFU page. 328 // Copy active page to the 'next' DFU page.
332 let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32; 329 let active_from_offset = (page_count - 1 - page_num) * page_size;
333 let dfu_to_offset = ((page_count - page_num) * page_size) as u32; 330 let dfu_to_offset = (page_count - page_num) * page_size;
334 //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); 331 //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset);
335 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, aligned_buf)?; 332 self.copy_page_once_to_dfu(progress_index, active_from_offset, dfu_to_offset, p, aligned_buf)?;
336 333
337 // Copy DFU page to the active page 334 // Copy DFU page to the active page
338 let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32; 335 let active_to_offset = (page_count - 1 - page_num) * page_size;
339 let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32; 336 let dfu_from_offset = (page_count - 1 - page_num) * page_size;
340 //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); 337 //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset);
341 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?; 338 self.copy_page_once_to_active(progress_index + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?;
342 } 339 }
343 340
344 Ok(()) 341 Ok(())
@@ -346,19 +343,19 @@ impl BootLoader {
346 343
347 fn revert<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> { 344 fn revert<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> {
348 let page_size = P::page_size(); 345 let page_size = P::page_size();
349 let page_count = self.active.len() / page_size; 346 let page_count = self.active.size() / page_size;
350 for page_num in 0..page_count { 347 for page_num in 0..page_count {
351 let idx = page_count * 2 + page_num * 2; 348 let progress_index = (page_count * 2 + page_num * 2) as usize;
352 349
353 // Copy the bad active page to the DFU page 350 // Copy the bad active page to the DFU page
354 let active_from_offset = (page_num * page_size) as u32; 351 let active_from_offset = page_num * page_size;
355 let dfu_to_offset = (page_num * page_size) as u32; 352 let dfu_to_offset = page_num * page_size;
356 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, aligned_buf)?; 353 self.copy_page_once_to_dfu(progress_index, active_from_offset, dfu_to_offset, p, aligned_buf)?;
357 354
358 // Copy the DFU page back to the active page 355 // Copy the DFU page back to the active page
359 let active_to_offset = (page_num * page_size) as u32; 356 let active_to_offset = page_num * page_size;
360 let dfu_from_offset = ((page_num + 1) * page_size) as u32; 357 let dfu_from_offset = (page_num + 1) * page_size;
361 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?; 358 self.copy_page_once_to_active(progress_index + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?;
362 } 359 }
363 360
364 Ok(()) 361 Ok(())
@@ -376,11 +373,11 @@ impl BootLoader {
376 } 373 }
377} 374}
378 375
379fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_size: usize, write_size: usize) { 376fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_size: u32, state_write_size: usize) {
380 assert_eq!(active.len() % page_size, 0); 377 assert_eq!(active.size() % page_size, 0);
381 assert_eq!(dfu.len() % page_size, 0); 378 assert_eq!(dfu.size() % page_size, 0);
382 assert!(dfu.len() - active.len() >= page_size); 379 assert!(dfu.size() - active.size() >= page_size);
383 assert!(2 + 2 * (active.len() / page_size) <= state.len() / write_size); 380 assert!(2 + 2 * (active.size() / page_size) <= state.size() / state_write_size as u32);
384} 381}
385 382
386/// A flash wrapper implementing the Flash and embedded_storage traits. 383/// A flash wrapper implementing the Flash and embedded_storage traits.
diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs
index 48e15024e..a2f822f4a 100644
--- a/embassy-boot/boot/src/firmware_updater.rs
+++ b/embassy-boot/boot/src/firmware_updater.rs
@@ -50,14 +50,14 @@ impl Default for FirmwareUpdater {
50 50
51 let dfu = unsafe { 51 let dfu = unsafe {
52 Partition::new( 52 Partition::new(
53 &__bootloader_dfu_start as *const u32 as usize, 53 &__bootloader_dfu_start as *const u32 as u32,
54 &__bootloader_dfu_end as *const u32 as usize, 54 &__bootloader_dfu_end as *const u32 as u32,
55 ) 55 )
56 }; 56 };
57 let state = unsafe { 57 let state = unsafe {
58 Partition::new( 58 Partition::new(
59 &__bootloader_state_start as *const u32 as usize, 59 &__bootloader_state_start as *const u32 as u32,
60 &__bootloader_state_end as *const u32 as usize, 60 &__bootloader_state_end as *const u32 as u32,
61 ) 61 )
62 }; 62 };
63 63
@@ -73,11 +73,6 @@ impl FirmwareUpdater {
73 Self { dfu, state } 73 Self { dfu, state }
74 } 74 }
75 75
76 /// Return the length of the DFU area
77 pub fn firmware_len(&self) -> usize {
78 self.dfu.len()
79 }
80
81 /// Obtain the current state. 76 /// Obtain the current state.
82 /// 77 ///
83 /// This is useful to check if the bootloader has just done a swap, in order 78 /// This is useful to check if the bootloader has just done a swap, in order
@@ -119,11 +114,11 @@ impl FirmwareUpdater {
119 _state_and_dfu_flash: &mut F, 114 _state_and_dfu_flash: &mut F,
120 _public_key: &[u8], 115 _public_key: &[u8],
121 _signature: &[u8], 116 _signature: &[u8],
122 _update_len: usize, 117 _update_len: u32,
123 _aligned: &mut [u8], 118 _aligned: &mut [u8],
124 ) -> Result<(), FirmwareUpdaterError> { 119 ) -> Result<(), FirmwareUpdaterError> {
125 assert_eq!(_aligned.len(), F::WRITE_SIZE); 120 assert_eq!(_aligned.len(), F::WRITE_SIZE);
126 assert!(_update_len <= self.dfu.len()); 121 assert!(_update_len <= self.dfu.size());
127 122
128 #[cfg(feature = "ed25519-dalek")] 123 #[cfg(feature = "ed25519-dalek")]
129 { 124 {
@@ -180,11 +175,10 @@ impl FirmwareUpdater {
180 pub async fn hash<F: AsyncNorFlash, D: Digest>( 175 pub async fn hash<F: AsyncNorFlash, D: Digest>(
181 &mut self, 176 &mut self,
182 dfu_flash: &mut F, 177 dfu_flash: &mut F,
183 update_len: usize, 178 update_len: u32,
184 chunk_buf: &mut [u8], 179 chunk_buf: &mut [u8],
185 output: &mut [u8], 180 output: &mut [u8],
186 ) -> Result<(), FirmwareUpdaterError> { 181 ) -> Result<(), FirmwareUpdaterError> {
187 let update_len = update_len as u32;
188 let mut digest = D::new(); 182 let mut digest = D::new();
189 for offset in (0..update_len).step_by(chunk_buf.len()) { 183 for offset in (0..update_len).step_by(chunk_buf.len()) {
190 self.dfu.read(dfu_flash, offset, chunk_buf).await?; 184 self.dfu.read(dfu_flash, offset, chunk_buf).await?;
@@ -340,11 +334,11 @@ impl FirmwareUpdater {
340 _state_and_dfu_flash: &mut F, 334 _state_and_dfu_flash: &mut F,
341 _public_key: &[u8], 335 _public_key: &[u8],
342 _signature: &[u8], 336 _signature: &[u8],
343 _update_len: usize, 337 _update_len: u32,
344 _aligned: &mut [u8], 338 _aligned: &mut [u8],
345 ) -> Result<(), FirmwareUpdaterError> { 339 ) -> Result<(), FirmwareUpdaterError> {
346 assert_eq!(_aligned.len(), F::WRITE_SIZE); 340 assert_eq!(_aligned.len(), F::WRITE_SIZE);
347 assert!(_update_len <= self.dfu.len()); 341 assert!(_update_len <= self.dfu.size());
348 342
349 #[cfg(feature = "ed25519-dalek")] 343 #[cfg(feature = "ed25519-dalek")]
350 { 344 {
@@ -399,11 +393,10 @@ impl FirmwareUpdater {
399 pub fn hash_blocking<F: NorFlash, D: Digest>( 393 pub fn hash_blocking<F: NorFlash, D: Digest>(
400 &mut self, 394 &mut self,
401 dfu_flash: &mut F, 395 dfu_flash: &mut F,
402 update_len: usize, 396 update_len: u32,
403 chunk_buf: &mut [u8], 397 chunk_buf: &mut [u8],
404 output: &mut [u8], 398 output: &mut [u8],
405 ) -> Result<(), FirmwareUpdaterError> { 399 ) -> Result<(), FirmwareUpdaterError> {
406 let update_len = update_len as u32;
407 let mut digest = D::new(); 400 let mut digest = D::new();
408 for offset in (0..update_len).step_by(chunk_buf.len()) { 401 for offset in (0..update_len).step_by(chunk_buf.len()) {
409 self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; 402 self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?;
@@ -534,7 +527,7 @@ mod tests {
534 block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap(); 527 block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap();
535 let mut chunk_buf = [0; 2]; 528 let mut chunk_buf = [0; 2];
536 let mut hash = [0; 20]; 529 let mut hash = [0; 20];
537 block_on(updater.hash::<_, Sha1>(&mut flash, update.len(), &mut chunk_buf, &mut hash)).unwrap(); 530 block_on(updater.hash::<_, Sha1>(&mut flash, update.len() as u32, &mut chunk_buf, &mut hash)).unwrap();
538 531
539 assert_eq!(Sha1::digest(update).as_slice(), hash); 532 assert_eq!(Sha1::digest(update).as_slice(), hash);
540 } 533 }
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index acd90996f..87457b173 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -90,13 +90,11 @@ mod tests {
90 const DFU: Partition = Partition::new(61440, 122880); 90 const DFU: Partition = Partition::new(61440, 122880);
91 let mut flash = MemFlash::<131072, 4096, 4>::random(); 91 let mut flash = MemFlash::<131072, 4096, 4>::random();
92 92
93 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 93 let original = [rand::random::<u8>(); ACTIVE.size() as usize];
94 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 94 let update = [rand::random::<u8>(); ACTIVE.size() as usize];
95 let mut aligned = [0; 4]; 95 let mut aligned = [0; 4];
96 96
97 for i in ACTIVE.from..ACTIVE.to { 97 flash.program(ACTIVE.from, &original).unwrap();
98 flash.mem[i] = original[i - ACTIVE.from];
99 }
100 98
101 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 99 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
102 let mut updater = FirmwareUpdater::new(DFU, STATE); 100 let mut updater = FirmwareUpdater::new(DFU, STATE);
@@ -111,14 +109,9 @@ mod tests {
111 .unwrap() 109 .unwrap()
112 ); 110 );
113 111
114 for i in ACTIVE.from..ACTIVE.to { 112 flash.assert_eq(ACTIVE.from, &update);
115 assert_eq!(flash.mem[i], update[i - ACTIVE.from], "Index {}", i);
116 }
117
118 // First DFU page is untouched 113 // First DFU page is untouched
119 for i in DFU.from + 4096..DFU.to { 114 flash.assert_eq(DFU.from + 4096, &original);
120 assert_eq!(flash.mem[i], original[i - DFU.from - 4096], "Index {}", i);
121 }
122 115
123 // Running again should cause a revert 116 // Running again should cause a revert
124 assert_eq!( 117 assert_eq!(
@@ -128,14 +121,9 @@ mod tests {
128 .unwrap() 121 .unwrap()
129 ); 122 );
130 123
131 for i in ACTIVE.from..ACTIVE.to { 124 flash.assert_eq(ACTIVE.from, &original);
132 assert_eq!(flash.mem[i], original[i - ACTIVE.from], "Index {}", i);
133 }
134
135 // Last page is untouched 125 // Last page is untouched
136 for i in DFU.from..DFU.to - 4096 { 126 flash.assert_eq(DFU.from, &update);
137 assert_eq!(flash.mem[i], update[i - DFU.from], "Index {}", i);
138 }
139 127
140 // Mark as booted 128 // Mark as booted
141 block_on(updater.mark_booted(&mut flash, &mut aligned)).unwrap(); 129 block_on(updater.mark_booted(&mut flash, &mut aligned)).unwrap();
@@ -159,12 +147,10 @@ mod tests {
159 let mut state = MemFlash::<4096, 128, 4>::random(); 147 let mut state = MemFlash::<4096, 128, 4>::random();
160 let mut aligned = [0; 4]; 148 let mut aligned = [0; 4];
161 149
162 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 150 let original = [rand::random::<u8>(); ACTIVE.size() as usize];
163 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 151 let update = [rand::random::<u8>(); ACTIVE.size() as usize];
164 152
165 for i in ACTIVE.from..ACTIVE.to { 153 active.program(ACTIVE.from, &original).unwrap();
166 active.mem[i] = original[i - ACTIVE.from];
167 }
168 154
169 let mut updater = FirmwareUpdater::new(DFU, STATE); 155 let mut updater = FirmwareUpdater::new(DFU, STATE);
170 156
@@ -181,14 +167,9 @@ mod tests {
181 .unwrap() 167 .unwrap()
182 ); 168 );
183 169
184 for i in ACTIVE.from..ACTIVE.to { 170 active.assert_eq(ACTIVE.from, &update);
185 assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i);
186 }
187
188 // First DFU page is untouched 171 // First DFU page is untouched
189 for i in DFU.from + 4096..DFU.to { 172 dfu.assert_eq(DFU.from + 4096, &original);
190 assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i);
191 }
192 } 173 }
193 174
194 #[test] 175 #[test]
@@ -203,12 +184,10 @@ mod tests {
203 let mut dfu = MemFlash::<16384, 4096, 8>::random(); 184 let mut dfu = MemFlash::<16384, 4096, 8>::random();
204 let mut state = MemFlash::<4096, 128, 4>::random(); 185 let mut state = MemFlash::<4096, 128, 4>::random();
205 186
206 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 187 let original = [rand::random::<u8>(); ACTIVE.size() as usize];
207 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 188 let update = [rand::random::<u8>(); ACTIVE.size() as usize];
208 189
209 for i in ACTIVE.from..ACTIVE.to { 190 active.program(ACTIVE.from, &original).unwrap();
210 active.mem[i] = original[i - ACTIVE.from];
211 }
212 191
213 let mut updater = FirmwareUpdater::new(DFU, STATE); 192 let mut updater = FirmwareUpdater::new(DFU, STATE);
214 193
@@ -227,14 +206,9 @@ mod tests {
227 .unwrap() 206 .unwrap()
228 ); 207 );
229 208
230 for i in ACTIVE.from..ACTIVE.to { 209 active.assert_eq(ACTIVE.from, &update);
231 assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i);
232 }
233
234 // First DFU page is untouched 210 // First DFU page is untouched
235 for i in DFU.from + 4096..DFU.to { 211 dfu.assert_eq(DFU.from + 4096, &original);
236 assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i);
237 }
238 } 212 }
239 213
240 #[test] 214 #[test]
@@ -281,7 +255,7 @@ mod tests {
281 &mut flash, 255 &mut flash,
282 &public_key.to_bytes(), 256 &public_key.to_bytes(),
283 &signature.to_bytes(), 257 &signature.to_bytes(),
284 firmware_len, 258 firmware_len as u32,
285 &mut aligned, 259 &mut aligned,
286 )) 260 ))
287 .is_ok()); 261 .is_ok());
diff --git a/embassy-boot/boot/src/mem_flash.rs b/embassy-boot/boot/src/mem_flash.rs
index dd85405c8..c62379b24 100644
--- a/embassy-boot/boot/src/mem_flash.rs
+++ b/embassy-boot/boot/src/mem_flash.rs
@@ -32,6 +32,23 @@ impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> MemFla
32 pending_write_successes: None, 32 pending_write_successes: None,
33 } 33 }
34 } 34 }
35
36 pub fn program(&mut self, offset: u32, bytes: &[u8]) -> Result<(), MemFlashError> {
37 let offset = offset as usize;
38 assert!(bytes.len() % WRITE_SIZE == 0);
39 assert!(offset % WRITE_SIZE == 0);
40 assert!(offset + bytes.len() <= SIZE);
41
42 self.mem[offset..offset + bytes.len()].copy_from_slice(bytes);
43
44 Ok(())
45 }
46
47 pub fn assert_eq(&self, offset: u32, expectation: &[u8]) {
48 for i in 0..expectation.len() {
49 assert_eq!(self.mem[offset as usize + i], expectation[i], "Index {}", i);
50 }
51 }
35} 52}
36 53
37impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> Default 54impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> Default
diff --git a/embassy-boot/boot/src/partition.rs b/embassy-boot/boot/src/partition.rs
index ac6b0ed0f..7529059b6 100644
--- a/embassy-boot/boot/src/partition.rs
+++ b/embassy-boot/boot/src/partition.rs
@@ -6,20 +6,19 @@ use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash
6#[cfg_attr(feature = "defmt", derive(defmt::Format))] 6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub struct Partition { 7pub struct Partition {
8 /// The offset into the flash where the partition starts. 8 /// The offset into the flash where the partition starts.
9 pub from: usize, 9 pub from: u32,
10 /// The offset into the flash where the partition ends. 10 /// The offset into the flash where the partition ends.
11 pub to: usize, 11 pub to: u32,
12} 12}
13 13
14impl Partition { 14impl Partition {
15 /// Create a new partition with the provided range 15 /// Create a new partition with the provided range
16 pub const fn new(from: usize, to: usize) -> Self { 16 pub const fn new(from: u32, to: u32) -> Self {
17 Self { from, to } 17 Self { from, to }
18 } 18 }
19 19
20 /// Return the size of the partition 20 /// Return the size of the partition
21 #[allow(clippy::len_without_is_empty)] 21 pub const fn size(&self) -> u32 {
22 pub const fn len(&self) -> usize {
23 self.to - self.from 22 self.to - self.from
24 } 23 }
25 24
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs
index a2176f609..d46ed9f36 100644
--- a/embassy-boot/nrf/src/lib.rs
+++ b/embassy-boot/nrf/src/lib.rs
@@ -30,20 +30,20 @@ impl Default for BootLoader<PAGE_SIZE> {
30 30
31 let active = unsafe { 31 let active = unsafe {
32 Partition::new( 32 Partition::new(
33 &__bootloader_active_start as *const u32 as usize, 33 &__bootloader_active_start as *const u32 as u32,
34 &__bootloader_active_end as *const u32 as usize, 34 &__bootloader_active_end as *const u32 as u32,
35 ) 35 )
36 }; 36 };
37 let dfu = unsafe { 37 let dfu = unsafe {
38 Partition::new( 38 Partition::new(
39 &__bootloader_dfu_start as *const u32 as usize, 39 &__bootloader_dfu_start as *const u32 as u32,
40 &__bootloader_dfu_end as *const u32 as usize, 40 &__bootloader_dfu_end as *const u32 as u32,
41 ) 41 )
42 }; 42 };
43 let state = unsafe { 43 let state = unsafe {
44 Partition::new( 44 Partition::new(
45 &__bootloader_state_start as *const u32 as usize, 45 &__bootloader_state_start as *const u32 as u32,
46 &__bootloader_state_end as *const u32 as usize, 46 &__bootloader_state_end as *const u32 as u32,
47 ) 47 )
48 }; 48 };
49 49
diff --git a/embassy-boot/rp/src/lib.rs b/embassy-boot/rp/src/lib.rs
index 0031efa63..c3cb22299 100644
--- a/embassy-boot/rp/src/lib.rs
+++ b/embassy-boot/rp/src/lib.rs
@@ -66,20 +66,20 @@ impl Default for BootLoader<ERASE_SIZE> {
66 66
67 let active = unsafe { 67 let active = unsafe {
68 Partition::new( 68 Partition::new(
69 &__bootloader_active_start as *const u32 as usize, 69 &__bootloader_active_start as *const u32 as u32,
70 &__bootloader_active_end as *const u32 as usize, 70 &__bootloader_active_end as *const u32 as u32,
71 ) 71 )
72 }; 72 };
73 let dfu = unsafe { 73 let dfu = unsafe {
74 Partition::new( 74 Partition::new(
75 &__bootloader_dfu_start as *const u32 as usize, 75 &__bootloader_dfu_start as *const u32 as u32,
76 &__bootloader_dfu_end as *const u32 as usize, 76 &__bootloader_dfu_end as *const u32 as u32,
77 ) 77 )
78 }; 78 };
79 let state = unsafe { 79 let state = unsafe {
80 Partition::new( 80 Partition::new(
81 &__bootloader_state_start as *const u32 as usize, 81 &__bootloader_state_start as *const u32 as u32,
82 &__bootloader_state_end as *const u32 as usize, 82 &__bootloader_state_end as *const u32 as u32,
83 ) 83 )
84 }; 84 };
85 85
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs
index 1f63fcd63..94404697f 100644
--- a/embassy-boot/stm32/src/lib.rs
+++ b/embassy-boot/stm32/src/lib.rs
@@ -61,20 +61,20 @@ impl<const BUFFER_SIZE: usize> Default for BootLoader<BUFFER_SIZE> {
61 61
62 let active = unsafe { 62 let active = unsafe {
63 Partition::new( 63 Partition::new(
64 &__bootloader_active_start as *const u32 as usize, 64 &__bootloader_active_start as *const u32 as u32,
65 &__bootloader_active_end as *const u32 as usize, 65 &__bootloader_active_end as *const u32 as u32,
66 ) 66 )
67 }; 67 };
68 let dfu = unsafe { 68 let dfu = unsafe {
69 Partition::new( 69 Partition::new(
70 &__bootloader_dfu_start as *const u32 as usize, 70 &__bootloader_dfu_start as *const u32 as u32,
71 &__bootloader_dfu_end as *const u32 as usize, 71 &__bootloader_dfu_end as *const u32 as u32,
72 ) 72 )
73 }; 73 };
74 let state = unsafe { 74 let state = unsafe {
75 Partition::new( 75 Partition::new(
76 &__bootloader_state_start as *const u32 as usize, 76 &__bootloader_state_start as *const u32 as u32,
77 &__bootloader_state_end as *const u32 as usize, 77 &__bootloader_state_end as *const u32 as u32,
78 ) 78 )
79 }; 79 };
80 80