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.rs101
-rw-r--r--embassy-boot/boot/src/firmware_updater.rs17
-rw-r--r--embassy-boot/boot/src/lib.rs60
-rw-r--r--embassy-boot/boot/src/mem_flash.rs17
-rw-r--r--embassy-boot/boot/src/partition.rs9
5 files changed, 93 insertions, 111 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 2b5cc72fa..93d4a4c12 100644
--- a/embassy-boot/boot/src/firmware_updater.rs
+++ b/embassy-boot/boot/src/firmware_updater.rs
@@ -49,14 +49,14 @@ impl Default for FirmwareUpdater {
49 49
50 let dfu = unsafe { 50 let dfu = unsafe {
51 Partition::new( 51 Partition::new(
52 &__bootloader_dfu_start as *const u32 as usize, 52 &__bootloader_dfu_start as *const u32 as u32,
53 &__bootloader_dfu_end as *const u32 as usize, 53 &__bootloader_dfu_end as *const u32 as u32,
54 ) 54 )
55 }; 55 };
56 let state = unsafe { 56 let state = unsafe {
57 Partition::new( 57 Partition::new(
58 &__bootloader_state_start as *const u32 as usize, 58 &__bootloader_state_start as *const u32 as u32,
59 &__bootloader_state_end as *const u32 as usize, 59 &__bootloader_state_end as *const u32 as u32,
60 ) 60 )
61 }; 61 };
62 62
@@ -121,10 +121,8 @@ impl FirmwareUpdater {
121 _update_len: usize, 121 _update_len: usize,
122 _aligned: &mut [u8], 122 _aligned: &mut [u8],
123 ) -> Result<(), FirmwareUpdaterError> { 123 ) -> Result<(), FirmwareUpdaterError> {
124 let _read_size = _aligned.len();
125
126 assert_eq!(_aligned.len(), F::WRITE_SIZE); 124 assert_eq!(_aligned.len(), F::WRITE_SIZE);
127 assert!(_update_len <= self.dfu.len()); 125 assert!(_update_len as u32 <= self.dfu.size());
128 126
129 #[cfg(feature = "ed25519-dalek")] 127 #[cfg(feature = "ed25519-dalek")]
130 { 128 {
@@ -330,11 +328,8 @@ impl FirmwareUpdater {
330 _update_len: usize, 328 _update_len: usize,
331 _aligned: &mut [u8], 329 _aligned: &mut [u8],
332 ) -> Result<(), FirmwareUpdaterError> { 330 ) -> Result<(), FirmwareUpdaterError> {
333 let _end = self.dfu.from + _update_len;
334 let _read_size = _aligned.len();
335
336 assert_eq!(_aligned.len(), F::WRITE_SIZE); 331 assert_eq!(_aligned.len(), F::WRITE_SIZE);
337 assert!(_end <= self.dfu.to); 332 assert!(_update_len as u32 <= self.dfu.size());
338 333
339 #[cfg(feature = "ed25519-dalek")] 334 #[cfg(feature = "ed25519-dalek")]
340 { 335 {
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 3109f2b47..8b94b6bdc 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -89,13 +89,11 @@ mod tests {
89 const DFU: Partition = Partition::new(61440, 122880); 89 const DFU: Partition = Partition::new(61440, 122880);
90 let mut flash = MemFlash::<131072, 4096, 4>::random(); 90 let mut flash = MemFlash::<131072, 4096, 4>::random();
91 91
92 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 92 let original = [rand::random::<u8>(); ACTIVE.size() as usize];
93 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 93 let update = [rand::random::<u8>(); ACTIVE.size() as usize];
94 let mut aligned = [0; 4]; 94 let mut aligned = [0; 4];
95 95
96 for i in ACTIVE.from..ACTIVE.to { 96 flash.program(ACTIVE.from, &original).unwrap();
97 flash.mem[i] = original[i - ACTIVE.from];
98 }
99 97
100 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 98 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
101 let mut updater = FirmwareUpdater::new(DFU, STATE); 99 let mut updater = FirmwareUpdater::new(DFU, STATE);
@@ -110,14 +108,9 @@ mod tests {
110 .unwrap() 108 .unwrap()
111 ); 109 );
112 110
113 for i in ACTIVE.from..ACTIVE.to { 111 flash.assert_eq(ACTIVE.from, &update);
114 assert_eq!(flash.mem[i], update[i - ACTIVE.from], "Index {}", i);
115 }
116
117 // First DFU page is untouched 112 // First DFU page is untouched
118 for i in DFU.from + 4096..DFU.to { 113 flash.assert_eq(DFU.from + 4096, &original);
119 assert_eq!(flash.mem[i], original[i - DFU.from - 4096], "Index {}", i);
120 }
121 114
122 // Running again should cause a revert 115 // Running again should cause a revert
123 assert_eq!( 116 assert_eq!(
@@ -127,14 +120,9 @@ mod tests {
127 .unwrap() 120 .unwrap()
128 ); 121 );
129 122
130 for i in ACTIVE.from..ACTIVE.to { 123 flash.assert_eq(ACTIVE.from, &original);
131 assert_eq!(flash.mem[i], original[i - ACTIVE.from], "Index {}", i);
132 }
133
134 // Last page is untouched 124 // Last page is untouched
135 for i in DFU.from..DFU.to - 4096 { 125 flash.assert_eq(DFU.from, &update);
136 assert_eq!(flash.mem[i], update[i - DFU.from], "Index {}", i);
137 }
138 126
139 // Mark as booted 127 // Mark as booted
140 block_on(updater.mark_booted(&mut flash, &mut aligned)).unwrap(); 128 block_on(updater.mark_booted(&mut flash, &mut aligned)).unwrap();
@@ -158,12 +146,10 @@ mod tests {
158 let mut state = MemFlash::<4096, 128, 4>::random(); 146 let mut state = MemFlash::<4096, 128, 4>::random();
159 let mut aligned = [0; 4]; 147 let mut aligned = [0; 4];
160 148
161 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 149 let original = [rand::random::<u8>(); ACTIVE.size() as usize];
162 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 150 let update = [rand::random::<u8>(); ACTIVE.size() as usize];
163 151
164 for i in ACTIVE.from..ACTIVE.to { 152 active.program(ACTIVE.from, &original).unwrap();
165 active.mem[i] = original[i - ACTIVE.from];
166 }
167 153
168 let mut updater = FirmwareUpdater::new(DFU, STATE); 154 let mut updater = FirmwareUpdater::new(DFU, STATE);
169 155
@@ -180,14 +166,9 @@ mod tests {
180 .unwrap() 166 .unwrap()
181 ); 167 );
182 168
183 for i in ACTIVE.from..ACTIVE.to { 169 active.assert_eq(ACTIVE.from, &update);
184 assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i);
185 }
186
187 // First DFU page is untouched 170 // First DFU page is untouched
188 for i in DFU.from + 4096..DFU.to { 171 dfu.assert_eq(DFU.from + 4096, &original);
189 assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i);
190 }
191 } 172 }
192 173
193 #[test] 174 #[test]
@@ -202,12 +183,10 @@ mod tests {
202 let mut dfu = MemFlash::<16384, 4096, 8>::random(); 183 let mut dfu = MemFlash::<16384, 4096, 8>::random();
203 let mut state = MemFlash::<4096, 128, 4>::random(); 184 let mut state = MemFlash::<4096, 128, 4>::random();
204 185
205 let original: [u8; ACTIVE.len()] = [rand::random::<u8>(); ACTIVE.len()]; 186 let original = [rand::random::<u8>(); ACTIVE.size() as usize];
206 let update: [u8; DFU.len()] = [rand::random::<u8>(); DFU.len()]; 187 let update = [rand::random::<u8>(); ACTIVE.size() as usize];
207 188
208 for i in ACTIVE.from..ACTIVE.to { 189 active.program(ACTIVE.from, &original).unwrap();
209 active.mem[i] = original[i - ACTIVE.from];
210 }
211 190
212 let mut updater = FirmwareUpdater::new(DFU, STATE); 191 let mut updater = FirmwareUpdater::new(DFU, STATE);
213 192
@@ -226,14 +205,9 @@ mod tests {
226 .unwrap() 205 .unwrap()
227 ); 206 );
228 207
229 for i in ACTIVE.from..ACTIVE.to { 208 active.assert_eq(ACTIVE.from, &update);
230 assert_eq!(active.mem[i], update[i - ACTIVE.from], "Index {}", i);
231 }
232
233 // First DFU page is untouched 209 // First DFU page is untouched
234 for i in DFU.from + 4096..DFU.to { 210 dfu.assert_eq(DFU.from + 4096, &original);
235 assert_eq!(dfu.mem[i], original[i - DFU.from - 4096], "Index {}", i);
236 }
237 } 211 }
238 212
239 #[test] 213 #[test]
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