aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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