diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2023-04-11 06:17:00 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-04-11 06:17:00 +0000 |
| commit | 636a3d05c2ac129e2fa85cf6e7fb5afff2d8126b (patch) | |
| tree | 91c7bec35c40932932569c889654986a52d30ee7 /embassy-boot/boot/src/boot_loader.rs | |
| parent | 1f25d2ba8335300368b32f9ceedf163376dfdb6f (diff) | |
| parent | d3ce64254aecb24feded2408119855daf7380e80 (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.rs | 101 |
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 | ||
| 52 | trait FlashConfigEx { | 52 | trait FlashConfigEx { |
| 53 | fn page_size() -> usize; | 53 | fn page_size() -> u32; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | impl<T: FlashConfig> FlashConfigEx for T { | 56 | impl<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 | ||
| 379 | fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_size: usize, write_size: usize) { | 376 | fn 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. |
