aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot/src/boot_loader.rs
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 /embassy-boot/boot/src/boot_loader.rs
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]>
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.