diff options
| author | Rasmus Melchior Jacobsen <[email protected]> | 2023-05-30 13:38:00 +0200 |
|---|---|---|
| committer | Rasmus Melchior Jacobsen <[email protected]> | 2023-05-30 13:38:00 +0200 |
| commit | c5ec453ec1e87c2f5c5047bf357ae99298aa6d12 (patch) | |
| tree | 11fa79cefd51e40f1ee719eac585f1b02412ad7d /embassy-boot/boot | |
| parent | 5205b5b09588d6e0006e5479764ee94b113b03b9 (diff) | |
Add bootloader helper for creating config from linkerfile symbols
Diffstat (limited to 'embassy-boot/boot')
| -rw-r--r-- | embassy-boot/boot/src/boot_loader.rs | 136 | ||||
| -rw-r--r-- | embassy-boot/boot/src/lib.rs | 2 |
2 files changed, 72 insertions, 66 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index 50eb5e668..bdf7bd7fd 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs | |||
| @@ -1,8 +1,11 @@ | |||
| 1 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | 1 | use core::cell::RefCell; |
| 2 | 2 | ||
| 3 | use crate::{State, BOOT_MAGIC, SWAP_MAGIC}; | 3 | use embassy_embedded_hal::flash::partition::BlockingPartition; |
| 4 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 5 | use embassy_sync::blocking_mutex::Mutex; | ||
| 6 | use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; | ||
| 4 | 7 | ||
| 5 | const STATE_ERASE_VALUE: u8 = 0xFF; | 8 | use crate::{State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; |
| 6 | 9 | ||
| 7 | /// Errors returned by bootloader | 10 | /// Errors returned by bootloader |
| 8 | #[derive(PartialEq, Eq, Debug)] | 11 | #[derive(PartialEq, Eq, Debug)] |
| @@ -32,14 +35,69 @@ where | |||
| 32 | } | 35 | } |
| 33 | } | 36 | } |
| 34 | 37 | ||
| 38 | /// Bootloader flash configuration holding the three flashes used by the bootloader | ||
| 39 | /// | ||
| 40 | /// If only a single flash is actually used, then that flash should be partitioned into three partitions before use. | ||
| 41 | /// The easiest way to do this is to use [`BootLoaderConfig::from_linkerfile_blocking`] which will partition | ||
| 42 | /// the provided flash according to symbols defined in the linkerfile. | ||
| 43 | pub struct BootLoaderConfig<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> { | ||
| 44 | /// Flash type used for the active partition - the partition which will be booted from. | ||
| 45 | pub active: ACTIVE, | ||
| 46 | /// Flash type used for the dfu partition - the partition which will be swapped in when requested. | ||
| 47 | pub dfu: DFU, | ||
| 48 | /// Flash type used for the state partition. | ||
| 49 | pub state: STATE, | ||
| 50 | } | ||
| 51 | |||
| 52 | impl<'a, FLASH: NorFlash> | ||
| 53 | BootLoaderConfig< | ||
| 54 | BlockingPartition<'a, NoopRawMutex, FLASH>, | ||
| 55 | BlockingPartition<'a, NoopRawMutex, FLASH>, | ||
| 56 | BlockingPartition<'a, NoopRawMutex, FLASH>, | ||
| 57 | > | ||
| 58 | { | ||
| 59 | /// Create a bootloader config from the flash and address symbols defined in the linkerfile | ||
| 60 | // #[cfg(target_os = "none")] | ||
| 61 | pub fn from_linkerfile_blocking(flash: &'a Mutex<NoopRawMutex, RefCell<FLASH>>) -> Self { | ||
| 62 | extern "C" { | ||
| 63 | static __bootloader_state_start: u32; | ||
| 64 | static __bootloader_state_end: u32; | ||
| 65 | static __bootloader_active_start: u32; | ||
| 66 | static __bootloader_active_end: u32; | ||
| 67 | static __bootloader_dfu_start: u32; | ||
| 68 | static __bootloader_dfu_end: u32; | ||
| 69 | } | ||
| 70 | |||
| 71 | let active = unsafe { | ||
| 72 | let start = &__bootloader_active_start as *const u32 as u32; | ||
| 73 | let end = &__bootloader_active_end as *const u32 as u32; | ||
| 74 | trace!("ACTIVE: 0x{:x} - 0x{:x}", start, end); | ||
| 75 | |||
| 76 | BlockingPartition::new(flash, start, end - start) | ||
| 77 | }; | ||
| 78 | let dfu = unsafe { | ||
| 79 | let start = &__bootloader_dfu_start as *const u32 as u32; | ||
| 80 | let end = &__bootloader_dfu_end as *const u32 as u32; | ||
| 81 | trace!("DFU: 0x{:x} - 0x{:x}", start, end); | ||
| 82 | |||
| 83 | BlockingPartition::new(flash, start, end - start) | ||
| 84 | }; | ||
| 85 | let state = unsafe { | ||
| 86 | let start = &__bootloader_state_start as *const u32 as u32; | ||
| 87 | let end = &__bootloader_state_end as *const u32 as u32; | ||
| 88 | trace!("STATE: 0x{:x} - 0x{:x}", start, end); | ||
| 89 | |||
| 90 | BlockingPartition::new(flash, start, end - start) | ||
| 91 | }; | ||
| 92 | |||
| 93 | Self { active, dfu, state } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 35 | /// BootLoader works with any flash implementing embedded_storage. | 97 | /// BootLoader works with any flash implementing embedded_storage. |
| 36 | pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> { | 98 | pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> { |
| 37 | /// Flash type used for the active partition - the partition which will be booted from. | ||
| 38 | active: ACTIVE, | 99 | active: ACTIVE, |
| 39 | /// Flash type used for the dfu partition - he partition which will be swapped in when requested. | ||
| 40 | dfu: DFU, | 100 | dfu: DFU, |
| 41 | /// Flash type used for the state partition. | ||
| 42 | /// | ||
| 43 | /// The state partition has the following format: | 101 | /// The state partition has the following format: |
| 44 | /// All ranges are in multiples of WRITE_SIZE bytes. | 102 | /// All ranges are in multiples of WRITE_SIZE bytes. |
| 45 | /// | Range | Description | | 103 | /// | Range | Description | |
| @@ -61,8 +119,12 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S | |||
| 61 | /// | 119 | /// |
| 62 | /// - All partitions must be aligned with the PAGE_SIZE const generic parameter. | 120 | /// - All partitions must be aligned with the PAGE_SIZE const generic parameter. |
| 63 | /// - The dfu partition must be at least PAGE_SIZE bigger than the active partition. | 121 | /// - The dfu partition must be at least PAGE_SIZE bigger than the active partition. |
| 64 | pub fn new(active: ACTIVE, dfu: DFU, state: STATE) -> Self { | 122 | pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self { |
| 65 | Self { active, dfu, state } | 123 | Self { |
| 124 | active: config.active, | ||
| 125 | dfu: config.dfu, | ||
| 126 | state: config.state, | ||
| 127 | } | ||
| 66 | } | 128 | } |
| 67 | 129 | ||
| 68 | /// Perform necessary boot preparations like swapping images. | 130 | /// Perform necessary boot preparations like swapping images. |
| @@ -340,62 +402,6 @@ fn assert_partitions<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>( | |||
| 340 | assert!(2 + 2 * (active.capacity() as u32 / page_size) <= state.capacity() as u32 / STATE::WRITE_SIZE as u32); | 402 | assert!(2 + 2 * (active.capacity() as u32 / page_size) <= state.capacity() as u32 / STATE::WRITE_SIZE as u32); |
| 341 | } | 403 | } |
| 342 | 404 | ||
| 343 | /// A flash wrapper implementing the Flash and embedded_storage traits. | ||
| 344 | pub struct BootFlash<F> | ||
| 345 | where | ||
| 346 | F: NorFlash, | ||
| 347 | { | ||
| 348 | flash: F, | ||
| 349 | } | ||
| 350 | |||
| 351 | impl<F> BootFlash<F> | ||
| 352 | where | ||
| 353 | F: NorFlash, | ||
| 354 | { | ||
| 355 | /// Create a new instance of a bootable flash | ||
| 356 | pub fn new(flash: F) -> Self { | ||
| 357 | Self { flash } | ||
| 358 | } | ||
| 359 | } | ||
| 360 | |||
| 361 | impl<F> ErrorType for BootFlash<F> | ||
| 362 | where | ||
| 363 | F: NorFlash, | ||
| 364 | { | ||
| 365 | type Error = F::Error; | ||
| 366 | } | ||
| 367 | |||
| 368 | impl<F> NorFlash for BootFlash<F> | ||
| 369 | where | ||
| 370 | F: NorFlash, | ||
| 371 | { | ||
| 372 | const WRITE_SIZE: usize = F::WRITE_SIZE; | ||
| 373 | const ERASE_SIZE: usize = F::ERASE_SIZE; | ||
| 374 | |||
| 375 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 376 | F::erase(&mut self.flash, from, to) | ||
| 377 | } | ||
| 378 | |||
| 379 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 380 | F::write(&mut self.flash, offset, bytes) | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | impl<F> ReadNorFlash for BootFlash<F> | ||
| 385 | where | ||
| 386 | F: NorFlash, | ||
| 387 | { | ||
| 388 | const READ_SIZE: usize = F::READ_SIZE; | ||
| 389 | |||
| 390 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 391 | F::read(&mut self.flash, offset, bytes) | ||
| 392 | } | ||
| 393 | |||
| 394 | fn capacity(&self) -> usize { | ||
| 395 | F::capacity(&self.flash) | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | #[cfg(test)] | 405 | #[cfg(test)] |
| 400 | mod tests { | 406 | mod tests { |
| 401 | use super::*; | 407 | use super::*; |
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index af2d3ce02..f2034fa8a 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs | |||
| @@ -10,8 +10,8 @@ mod firmware_updater; | |||
| 10 | mod mem_flash; | 10 | mod mem_flash; |
| 11 | mod partition; | 11 | mod partition; |
| 12 | 12 | ||
| 13 | pub use boot_loader::{BootError, BootFlash, BootLoader, FlashConfig, MultiFlashConfig, SingleFlashConfig}; | ||
| 14 | pub use partition::Partition; | 13 | pub use partition::Partition; |
| 14 | pub use boot_loader::{BootError, BootLoader, BootLoaderConfig}; | ||
| 15 | #[cfg(feature = "nightly")] | 15 | #[cfg(feature = "nightly")] |
| 16 | pub use firmware_updater::FirmwareUpdater; | 16 | pub use firmware_updater::FirmwareUpdater; |
| 17 | pub use firmware_updater::{BlockingFirmwareUpdater, FirmwareUpdaterConfig, FirmwareUpdaterError}; | 17 | pub use firmware_updater::{BlockingFirmwareUpdater, FirmwareUpdaterConfig, FirmwareUpdaterError}; |
