aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2022-04-26 18:33:09 +0200
committerUlf Lilleengen <[email protected]>2022-04-27 15:17:18 +0200
commitda61611f8f57410a87106961efd24d80e6a8f63e (patch)
tree81bf5f96a052be8cc74fa4f513592adf1f4bb1db /embassy-boot
parent484e0acc638c27366e19275c32db9c8487ea8fba (diff)
Add bootloader to CI
Diffstat (limited to 'embassy-boot')
-rw-r--r--embassy-boot/boot/Cargo.toml5
-rw-r--r--embassy-boot/boot/src/lib.rs57
-rw-r--r--embassy-boot/nrf/Cargo.toml2
-rw-r--r--embassy-boot/nrf/src/lib.rs2
-rw-r--r--embassy-boot/nrf/src/main.rs5
-rw-r--r--embassy-boot/stm32/Cargo.toml4
-rw-r--r--embassy-boot/stm32/memory.x12
-rw-r--r--embassy-boot/stm32/src/lib.rs8
-rw-r--r--embassy-boot/stm32/src/main.rs18
9 files changed, 40 insertions, 73 deletions
diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml
index 04deab30b..0a3006ffc 100644
--- a/embassy-boot/boot/Cargo.toml
+++ b/embassy-boot/boot/Cargo.toml
@@ -21,8 +21,3 @@ log = "0.4"
21env_logger = "0.9" 21env_logger = "0.9"
22rand = "0.8" 22rand = "0.8"
23futures = { version = "0.3", features = ["executor"] } 23futures = { version = "0.3", features = ["executor"] }
24
25[features]
26write-4 = []
27write-8 = []
28invert-erase = []
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 080ea2426..554709250 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -1,5 +1,7 @@
1#![feature(type_alias_impl_trait)] 1#![feature(type_alias_impl_trait)]
2#![feature(generic_associated_types)] 2#![feature(generic_associated_types)]
3#![feature(generic_const_exprs)]
4#![allow(incomplete_features)]
3#![no_std] 5#![no_std]
4///! embassy-boot is a bootloader and firmware updater for embedded devices with flash 6///! embassy-boot is a bootloader and firmware updater for embedded devices with flash
5///! storage implemented using embedded-storage 7///! storage implemented using embedded-storage
@@ -17,24 +19,9 @@ mod fmt;
17use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 19use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
18use embedded_storage_async::nor_flash::AsyncNorFlash; 20use embedded_storage_async::nor_flash::AsyncNorFlash;
19 21
20#[cfg(not(any(feature = "write-4", feature = "write-8",)))]
21compile_error!("No write size/alignment specified. Must specify exactly one of the following features: write-4, write-8");
22
23const BOOT_MAGIC: u8 = 0xD0; 22const BOOT_MAGIC: u8 = 0xD0;
24const SWAP_MAGIC: u8 = 0xF0; 23const SWAP_MAGIC: u8 = 0xF0;
25 24
26#[cfg(feature = "write-4")]
27const WRITE_SIZE: usize = 4;
28
29#[cfg(feature = "write-8")]
30const WRITE_SIZE: usize = 8;
31
32#[cfg(feature = "invert-erase")]
33const ERASE_VALUE: u8 = 0x00;
34
35#[cfg(not(feature = "invert-erase"))]
36const ERASE_VALUE: u8 = 0xFF;
37
38#[derive(Copy, Clone, Debug)] 25#[derive(Copy, Clone, Debug)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))] 26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub struct Partition { 27pub struct Partition {
@@ -96,7 +83,7 @@ pub trait FlashProvider {
96 83
97/// BootLoader works with any flash implementing embedded_storage and can also work with 84/// BootLoader works with any flash implementing embedded_storage and can also work with
98/// different page sizes and flash write sizes. 85/// different page sizes and flash write sizes.
99pub struct BootLoader<const PAGE_SIZE: usize> { 86pub struct BootLoader<const PAGE_SIZE: usize, const WRITE_SIZE: usize, const ERASE_VALUE: u8> {
100 // Page with current state of bootloader. The state partition has the following format: 87 // Page with current state of bootloader. The state partition has the following format:
101 // | Range | Description | 88 // | Range | Description |
102 // | 0 - WRITE_SIZE | Magic indicating bootloader state. BOOT_MAGIC means boot, SWAP_MAGIC means swap. | 89 // | 0 - WRITE_SIZE | Magic indicating bootloader state. BOOT_MAGIC means boot, SWAP_MAGIC means swap. |
@@ -108,7 +95,9 @@ pub struct BootLoader<const PAGE_SIZE: usize> {
108 dfu: Partition, 95 dfu: Partition,
109} 96}
110 97
111impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> { 98impl<const PAGE_SIZE: usize, const WRITE_SIZE: usize, const ERASE_VALUE: u8>
99 BootLoader<PAGE_SIZE, WRITE_SIZE, ERASE_VALUE>
100{
112 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self { 101 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
113 assert_eq!(active.len() % PAGE_SIZE, 0); 102 assert_eq!(active.len() % PAGE_SIZE, 0);
114 assert_eq!(dfu.len() % PAGE_SIZE, 0); 103 assert_eq!(dfu.len() % PAGE_SIZE, 0);
@@ -352,8 +341,6 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
352 self.copy_page_once_to_active(page * 2 + 1, dfu_page, active_page, p)?; 341 self.copy_page_once_to_active(page * 2 + 1, dfu_page, active_page, p)?;
353 } 342 }
354 343
355 info!("DONE COPYING");
356
357 Ok(()) 344 Ok(())
358 } 345 }
359 346
@@ -379,7 +366,6 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
379 let flash = p.flash(); 366 let flash = p.flash();
380 flash.read(self.state.from as u32, &mut magic)?; 367 flash.read(self.state.from as u32, &mut magic)?;
381 368
382 info!("Read magic: {:x}", magic);
383 if magic == [SWAP_MAGIC; WRITE_SIZE] { 369 if magic == [SWAP_MAGIC; WRITE_SIZE] {
384 Ok(State::Swap) 370 Ok(State::Swap)
385 } else { 371 } else {
@@ -451,13 +437,9 @@ pub struct FirmwareUpdater {
451 dfu: Partition, 437 dfu: Partition,
452} 438}
453 439
454#[cfg(feature = "write-4")] 440// NOTE: Aligned to the largest write size supported by flash
455#[repr(align(4))] 441#[repr(align(32))]
456pub struct Aligned([u8; 4]); 442pub struct Aligned<const N: usize>([u8; N]);
457
458#[cfg(feature = "write-8")]
459#[repr(align(8))]
460pub struct Aligned([u8; 8]);
461 443
462impl Default for FirmwareUpdater { 444impl Default for FirmwareUpdater {
463 fn default() -> Self { 445 fn default() -> Self {
@@ -480,6 +462,9 @@ impl Default for FirmwareUpdater {
480 &__bootloader_state_end as *const u32 as usize, 462 &__bootloader_state_end as *const u32 as usize,
481 ) 463 )
482 }; 464 };
465
466 trace!("DFU: 0x{:x} - 0x{:x}", dfu.from, dfu.to);
467 trace!("STATE: 0x{:x} - 0x{:x}", state.from, state.to);
483 FirmwareUpdater::new(dfu, state) 468 FirmwareUpdater::new(dfu, state)
484 } 469 }
485} 470}
@@ -496,14 +481,20 @@ impl FirmwareUpdater {
496 481
497 /// Instruct bootloader that DFU should commence at next boot. 482 /// Instruct bootloader that DFU should commence at next boot.
498 /// Must be provided with an aligned buffer to use for reading and writing magic; 483 /// Must be provided with an aligned buffer to use for reading and writing magic;
499 pub async fn mark_update<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<(), F::Error> { 484 pub async fn mark_update<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<(), F::Error>
500 let mut aligned = Aligned([0; WRITE_SIZE]); 485 where
486 [(); F::WRITE_SIZE]:,
487 {
488 let mut aligned = Aligned([0; { F::WRITE_SIZE }]);
501 self.set_magic(&mut aligned.0, SWAP_MAGIC, flash).await 489 self.set_magic(&mut aligned.0, SWAP_MAGIC, flash).await
502 } 490 }
503 491
504 /// Mark firmware boot successfully 492 /// Mark firmware boot successfully
505 pub async fn mark_booted<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<(), F::Error> { 493 pub async fn mark_booted<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<(), F::Error>
506 let mut aligned = Aligned([0; WRITE_SIZE]); 494 where
495 [(); F::WRITE_SIZE]:,
496 {
497 let mut aligned = Aligned([0; { F::WRITE_SIZE }]);
507 self.set_magic(&mut aligned.0, BOOT_MAGIC, flash).await 498 self.set_magic(&mut aligned.0, BOOT_MAGIC, flash).await
508 } 499 }
509 500
@@ -626,7 +617,7 @@ mod tests {
626 flash.0[0..4].copy_from_slice(&[BOOT_MAGIC; 4]); 617 flash.0[0..4].copy_from_slice(&[BOOT_MAGIC; 4]);
627 let mut flash = SingleFlashProvider::new(&mut flash); 618 let mut flash = SingleFlashProvider::new(&mut flash);
628 619
629 let mut bootloader = BootLoader::<4096>::new(ACTIVE, DFU, STATE); 620 let mut bootloader = BootLoader::<4096, 4, 0xFF>::new(ACTIVE, DFU, STATE);
630 621
631 assert_eq!(State::Boot, bootloader.prepare_boot(&mut flash).unwrap()); 622 assert_eq!(State::Boot, bootloader.prepare_boot(&mut flash).unwrap());
632 } 623 }
@@ -643,7 +634,7 @@ mod tests {
643 flash.0[i] = original[i - ACTIVE.from]; 634 flash.0[i] = original[i - ACTIVE.from];
644 } 635 }
645 636
646 let mut bootloader = BootLoader::<4096>::new(ACTIVE, DFU, STATE); 637 let mut bootloader = BootLoader::<4096, 4, 0xFF>::new(ACTIVE, DFU, STATE);
647 let mut updater = FirmwareUpdater::new(DFU, STATE); 638 let mut updater = FirmwareUpdater::new(DFU, STATE);
648 let mut offset = 0; 639 let mut offset = 0;
649 for chunk in update.chunks(4096) { 640 for chunk in update.chunks(4096) {
diff --git a/embassy-boot/nrf/Cargo.toml b/embassy-boot/nrf/Cargo.toml
index 78157d246..97207ac29 100644
--- a/embassy-boot/nrf/Cargo.toml
+++ b/embassy-boot/nrf/Cargo.toml
@@ -13,7 +13,7 @@ defmt-rtt = { version = "0.3", optional = true }
13 13
14embassy = { path = "../../embassy", default-features = false } 14embassy = { path = "../../embassy", default-features = false }
15embassy-nrf = { path = "../../embassy-nrf", default-features = false, features = ["nightly"] } 15embassy-nrf = { path = "../../embassy-nrf", default-features = false, features = ["nightly"] }
16embassy-boot = { path = "../boot", default-features = false, features = ["write-4"] } 16embassy-boot = { path = "../boot", default-features = false }
17cortex-m = { version = "0.7" } 17cortex-m = { version = "0.7" }
18cortex-m-rt = { version = "0.7" } 18cortex-m-rt = { version = "0.7" }
19embedded-storage = "0.3.0" 19embedded-storage = "0.3.0"
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs
index 500cae500..c12899d77 100644
--- a/embassy-boot/nrf/src/lib.rs
+++ b/embassy-boot/nrf/src/lib.rs
@@ -13,7 +13,7 @@ use embassy_nrf::{
13use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; 13use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
14 14
15pub struct BootLoader { 15pub struct BootLoader {
16 boot: embassy_boot::BootLoader<PAGE_SIZE>, 16 boot: embassy_boot::BootLoader<PAGE_SIZE, 4, 0xFF>,
17} 17}
18 18
19impl BootLoader { 19impl BootLoader {
diff --git a/embassy-boot/nrf/src/main.rs b/embassy-boot/nrf/src/main.rs
index 63de7c869..0ccd3774d 100644
--- a/embassy-boot/nrf/src/main.rs
+++ b/embassy-boot/nrf/src/main.rs
@@ -46,8 +46,5 @@ unsafe fn DefaultHandler(_: i16) -> ! {
46 46
47#[panic_handler] 47#[panic_handler]
48fn panic(_info: &core::panic::PanicInfo) -> ! { 48fn panic(_info: &core::panic::PanicInfo) -> ! {
49 unsafe { 49 cortex_m::asm::udf();
50 cortex_m::asm::udf();
51 core::hint::unreachable_unchecked();
52 }
53} 50}
diff --git a/embassy-boot/stm32/Cargo.toml b/embassy-boot/stm32/Cargo.toml
index 76bc480bf..a706e4c06 100644
--- a/embassy-boot/stm32/Cargo.toml
+++ b/embassy-boot/stm32/Cargo.toml
@@ -27,10 +27,6 @@ defmt = [
27 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
28] 28]
29debug = ["defmt-rtt"] 29debug = ["defmt-rtt"]
30flash-2k = ["embassy-boot/write-8"]
31flash-128 = ["embassy-boot/write-4"]
32flash-256 = ["embassy-boot/write-4"]
33invert-erase = ["embassy-boot/invert-erase"]
34thumbv6 = [] 30thumbv6 = []
35 31
36[profile.dev] 32[profile.dev]
diff --git a/embassy-boot/stm32/memory.x b/embassy-boot/stm32/memory.x
index c5356ed37..110c23259 100644
--- a/embassy-boot/stm32/memory.x
+++ b/embassy-boot/stm32/memory.x
@@ -8,11 +8,11 @@ MEMORY
8 RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K 8 RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
9} 9}
10 10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); 11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH);
12__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE); 12__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH);
13 13
14__bootloader_active_start = ORIGIN(ACTIVE); 14__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH);
15__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE); 15__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH);
16 16
17__bootloader_dfu_start = ORIGIN(DFU); 17__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(FLASH);
18__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU); 18__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(FLASH);
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs
index d1754a310..68220780c 100644
--- a/embassy-boot/stm32/src/lib.rs
+++ b/embassy-boot/stm32/src/lib.rs
@@ -5,12 +5,13 @@
5mod fmt; 5mod fmt;
6 6
7pub use embassy_boot::{FirmwareUpdater, FlashProvider, Partition, SingleFlashProvider, State}; 7pub use embassy_boot::{FirmwareUpdater, FlashProvider, Partition, SingleFlashProvider, State};
8use embassy_stm32::flash::{ERASE_SIZE, ERASE_VALUE, WRITE_SIZE};
8 9
9pub struct BootLoader<const PAGE_SIZE: usize> { 10pub struct BootLoader {
10 boot: embassy_boot::BootLoader<PAGE_SIZE>, 11 boot: embassy_boot::BootLoader<ERASE_SIZE, WRITE_SIZE, ERASE_VALUE>,
11} 12}
12 13
13impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> { 14impl BootLoader {
14 /// Create a new bootloader instance using parameters from linker script 15 /// Create a new bootloader instance using parameters from linker script
15 pub fn default() -> Self { 16 pub fn default() -> Self {
16 extern "C" { 17 extern "C" {
@@ -65,6 +66,7 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
65 66
66 pub unsafe fn load(&mut self, start: usize) -> ! { 67 pub unsafe fn load(&mut self, start: usize) -> ! {
67 trace!("Loading app at 0x{:x}", start); 68 trace!("Loading app at 0x{:x}", start);
69 #[allow(unused_mut)]
68 let mut p = cortex_m::Peripherals::steal(); 70 let mut p = cortex_m::Peripherals::steal();
69 #[cfg(not(feature = "thumbv6"))] 71 #[cfg(not(feature = "thumbv6"))]
70 p.SCB.invalidate_icache(); 72 p.SCB.invalidate_icache();
diff --git a/embassy-boot/stm32/src/main.rs b/embassy-boot/stm32/src/main.rs
index 6fe0fb66d..563bc55d3 100644
--- a/embassy-boot/stm32/src/main.rs
+++ b/embassy-boot/stm32/src/main.rs
@@ -9,9 +9,6 @@ use defmt_rtt as _;
9use embassy_boot_stm32::*; 9use embassy_boot_stm32::*;
10use embassy_stm32::flash::Flash; 10use embassy_stm32::flash::Flash;
11 11
12#[cfg(not(any(feature = "flash-2k", feature = "flash-256", feature = "flash-128")))]
13compile_error!("No flash size specified. Must specify exactly one of the following features: flash-2k, flash-256, flash-128");
14
15#[entry] 12#[entry]
16fn main() -> ! { 13fn main() -> ! {
17 let p = embassy_stm32::init(Default::default()); 14 let p = embassy_stm32::init(Default::default());
@@ -24,15 +21,7 @@ fn main() -> ! {
24 } 21 }
25 */ 22 */
26 23
27 #[cfg(feature = "flash-2k")] 24 let mut bl = BootLoader::default();
28 let mut bl: BootLoader<2048> = BootLoader::default();
29
30 #[cfg(feature = "flash-256")]
31 let mut bl: BootLoader<256> = BootLoader::default();
32
33 #[cfg(feature = "flash-128")]
34 let mut bl: BootLoader<128> = BootLoader::default();
35
36 let mut flash = Flash::unlock(p.FLASH); 25 let mut flash = Flash::unlock(p.FLASH);
37 let start = bl.prepare(&mut SingleFlashProvider::new(&mut flash)); 26 let start = bl.prepare(&mut SingleFlashProvider::new(&mut flash));
38 core::mem::drop(flash); 27 core::mem::drop(flash);
@@ -55,8 +44,5 @@ unsafe fn DefaultHandler(_: i16) -> ! {
55 44
56#[panic_handler] 45#[panic_handler]
57fn panic(_info: &core::panic::PanicInfo) -> ! { 46fn panic(_info: &core::panic::PanicInfo) -> ! {
58 unsafe { 47 cortex_m::asm::udf();
59 cortex_m::asm::udf();
60 core::hint::unreachable_unchecked();
61 }
62} 48}