diff options
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. |
