aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot/src/boot_loader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-boot/boot/src/boot_loader.rs')
-rw-r--r--embassy-boot/boot/src/boot_loader.rs101
1 files changed, 49 insertions, 52 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.