aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-05-30 13:38:00 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-05-30 13:38:00 +0200
commitc5ec453ec1e87c2f5c5047bf357ae99298aa6d12 (patch)
tree11fa79cefd51e40f1ee719eac585f1b02412ad7d /embassy-boot/boot
parent5205b5b09588d6e0006e5479764ee94b113b03b9 (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.rs136
-rw-r--r--embassy-boot/boot/src/lib.rs2
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 @@
1use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 1use core::cell::RefCell;
2 2
3use crate::{State, BOOT_MAGIC, SWAP_MAGIC}; 3use embassy_embedded_hal::flash::partition::BlockingPartition;
4use embassy_sync::blocking_mutex::raw::NoopRawMutex;
5use embassy_sync::blocking_mutex::Mutex;
6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
4 7
5const STATE_ERASE_VALUE: u8 = 0xFF; 8use 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.
43pub 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
52impl<'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.
36pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> { 98pub 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.
344pub struct BootFlash<F>
345where
346 F: NorFlash,
347{
348 flash: F,
349}
350
351impl<F> BootFlash<F>
352where
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
361impl<F> ErrorType for BootFlash<F>
362where
363 F: NorFlash,
364{
365 type Error = F::Error;
366}
367
368impl<F> NorFlash for BootFlash<F>
369where
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
384impl<F> ReadNorFlash for BootFlash<F>
385where
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)]
400mod tests { 406mod 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;
10mod mem_flash; 10mod mem_flash;
11mod partition; 11mod partition;
12 12
13pub use boot_loader::{BootError, BootFlash, BootLoader, FlashConfig, MultiFlashConfig, SingleFlashConfig};
14pub use partition::Partition; 13pub use partition::Partition;
14pub use boot_loader::{BootError, BootLoader, BootLoaderConfig};
15#[cfg(feature = "nightly")] 15#[cfg(feature = "nightly")]
16pub use firmware_updater::FirmwareUpdater; 16pub use firmware_updater::FirmwareUpdater;
17pub use firmware_updater::{BlockingFirmwareUpdater, FirmwareUpdaterConfig, FirmwareUpdaterError}; 17pub use firmware_updater::{BlockingFirmwareUpdater, FirmwareUpdaterConfig, FirmwareUpdaterError};