aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2024-09-19 07:24:33 +0000
committerGitHub <[email protected]>2024-09-19 07:24:33 +0000
commitcdb44f1272e9264324cc866ee2d141301e968e10 (patch)
tree3c453373e1c443121ee4e18e3d2c482e41c3b971
parent45cbcb513dc0bbf3e12c102df0db8c15643cc78b (diff)
parent4e1efd93fd4dc8dd692daf419d901ae22413e091 (diff)
Merge pull request #3349 from embassy-rs/e-b-introduce-reverted-magic
Add revert state in embassy-boot
-rw-r--r--embassy-boot/src/boot_loader.rs6
-rw-r--r--embassy-boot/src/firmware_updater/asynch.rs10
-rw-r--r--embassy-boot/src/firmware_updater/blocking.rs12
-rw-r--r--embassy-boot/src/lib.rs24
-rw-r--r--examples/boot/application/nrf/build.rs3
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs11
6 files changed, 48 insertions, 18 deletions
diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs
index 61d61b96e..5bffdc5ea 100644
--- a/embassy-boot/src/boot_loader.rs
+++ b/embassy-boot/src/boot_loader.rs
@@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
5use embassy_sync::blocking_mutex::Mutex; 5use embassy_sync::blocking_mutex::Mutex;
6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; 6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
7 7
8use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; 8use crate::{State, DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
9 9
10/// Errors returned by bootloader 10/// Errors returned by bootloader
11#[derive(PartialEq, Eq, Debug)] 11#[derive(PartialEq, Eq, Debug)]
@@ -276,7 +276,7 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
276 self.state.erase(0, self.state.capacity() as u32)?; 276 self.state.erase(0, self.state.capacity() as u32)?;
277 277
278 // Set magic 278 // Set magic
279 state_word.fill(BOOT_MAGIC); 279 state_word.fill(REVERT_MAGIC);
280 self.state.write(0, state_word)?; 280 self.state.write(0, state_word)?;
281 } 281 }
282 } 282 }
@@ -411,6 +411,8 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
411 Ok(State::Swap) 411 Ok(State::Swap)
412 } else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) { 412 } else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) {
413 Ok(State::DfuDetach) 413 Ok(State::DfuDetach)
414 } else if !state_word.iter().any(|&b| b != REVERT_MAGIC) {
415 Ok(State::Revert)
414 } else { 416 } else {
415 Ok(State::Boot) 417 Ok(State::Boot)
416 } 418 }
diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs
index 86b441592..d9d15b004 100644
--- a/embassy-boot/src/firmware_updater/asynch.rs
+++ b/embassy-boot/src/firmware_updater/asynch.rs
@@ -289,7 +289,8 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
289 289
290 // Make sure we are running a booted firmware to avoid reverting to a bad state. 290 // Make sure we are running a booted firmware to avoid reverting to a bad state.
291 async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 291 async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
292 if self.get_state().await? == State::Boot { 292 let state = self.get_state().await?;
293 if state == State::Boot || state == State::DfuDetach || state == State::Revert {
293 Ok(()) 294 Ok(())
294 } else { 295 } else {
295 Err(FirmwareUpdaterError::BadState) 296 Err(FirmwareUpdaterError::BadState)
@@ -303,12 +304,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
303 /// `mark_booted`. 304 /// `mark_booted`.
304 pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> { 305 pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
305 self.state.read(0, &mut self.aligned).await?; 306 self.state.read(0, &mut self.aligned).await?;
306 307 Ok(State::from(&self.aligned))
307 if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) {
308 Ok(State::Swap)
309 } else {
310 Ok(State::Boot)
311 }
312 } 308 }
313 309
314 /// Mark to trigger firmware swap on next boot. 310 /// Mark to trigger firmware swap on next boot.
diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs
index d3c723456..08062b0d0 100644
--- a/embassy-boot/src/firmware_updater/blocking.rs
+++ b/embassy-boot/src/firmware_updater/blocking.rs
@@ -324,7 +324,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
324 324
325 // Make sure we are running a booted firmware to avoid reverting to a bad state. 325 // Make sure we are running a booted firmware to avoid reverting to a bad state.
326 fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 326 fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
327 if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach { 327 let state = self.get_state()?;
328 if state == State::Boot || state == State::DfuDetach || state == State::Revert {
328 Ok(()) 329 Ok(())
329 } else { 330 } else {
330 Err(FirmwareUpdaterError::BadState) 331 Err(FirmwareUpdaterError::BadState)
@@ -338,14 +339,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
338 /// `mark_booted`. 339 /// `mark_booted`.
339 pub fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> { 340 pub fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
340 self.state.read(0, &mut self.aligned)?; 341 self.state.read(0, &mut self.aligned)?;
341 342 Ok(State::from(&self.aligned))
342 if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) {
343 Ok(State::Swap)
344 } else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) {
345 Ok(State::DfuDetach)
346 } else {
347 Ok(State::Boot)
348 }
349 } 343 }
350 344
351 /// Mark to trigger firmware swap on next boot. 345 /// Mark to trigger firmware swap on next boot.
diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs
index 8849055e8..e2c4cf771 100644
--- a/embassy-boot/src/lib.rs
+++ b/embassy-boot/src/lib.rs
@@ -25,6 +25,7 @@ pub use firmware_updater::{
25 FirmwareUpdaterError, 25 FirmwareUpdaterError,
26}; 26};
27 27
28pub(crate) const REVERT_MAGIC: u8 = 0xC0;
28pub(crate) const BOOT_MAGIC: u8 = 0xD0; 29pub(crate) const BOOT_MAGIC: u8 = 0xD0;
29pub(crate) const SWAP_MAGIC: u8 = 0xF0; 30pub(crate) const SWAP_MAGIC: u8 = 0xF0;
30pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0; 31pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0;
@@ -37,10 +38,30 @@ pub enum State {
37 Boot, 38 Boot,
38 /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. 39 /// Bootloader has swapped the active partition with the dfu partition and will attempt boot.
39 Swap, 40 Swap,
41 /// Bootloader has reverted the active partition with the dfu partition and will attempt boot.
42 Revert,
40 /// Application has received a request to reboot into DFU mode to apply an update. 43 /// Application has received a request to reboot into DFU mode to apply an update.
41 DfuDetach, 44 DfuDetach,
42} 45}
43 46
47impl<T> From<T> for State
48where
49 T: AsRef<[u8]>,
50{
51 fn from(magic: T) -> State {
52 let magic = magic.as_ref();
53 if !magic.iter().any(|&b| b != SWAP_MAGIC) {
54 State::Swap
55 } else if !magic.iter().any(|&b| b != REVERT_MAGIC) {
56 State::Revert
57 } else if !magic.iter().any(|&b| b != DFU_DETACH_MAGIC) {
58 State::DfuDetach
59 } else {
60 State::Boot
61 }
62 }
63}
64
44/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. 65/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot.
45#[repr(align(32))] 66#[repr(align(32))]
46pub struct AlignedBuffer<const N: usize>(pub [u8; N]); 67pub struct AlignedBuffer<const N: usize>(pub [u8; N]);
@@ -157,6 +178,9 @@ mod tests {
157 // Running again should cause a revert 178 // Running again should cause a revert
158 assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); 179 assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
159 180
181 // Next time we know it was reverted
182 assert_eq!(State::Revert, bootloader.prepare_boot(&mut page).unwrap());
183
160 let mut read_buf = [0; FIRMWARE_SIZE]; 184 let mut read_buf = [0; FIRMWARE_SIZE];
161 flash.active().read(0, &mut read_buf).unwrap(); 185 flash.active().read(0, &mut read_buf).unwrap();
162 assert_eq!(ORIGINAL, read_buf); 186 assert_eq!(ORIGINAL, read_buf);
diff --git a/examples/boot/application/nrf/build.rs b/examples/boot/application/nrf/build.rs
index cd1a264c4..e1da69328 100644
--- a/examples/boot/application/nrf/build.rs
+++ b/examples/boot/application/nrf/build.rs
@@ -31,4 +31,7 @@ fn main() {
31 31
32 println!("cargo:rustc-link-arg-bins=--nmagic"); 32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x"); 33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
35 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
36 }
34} 37}
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index 851a3d721..2c1d1a7bb 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -2,6 +2,9 @@
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4 4
5#[cfg(feature = "defmt")]
6use defmt_rtt as _;
7use embassy_boot::State;
5use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
6use embassy_embedded_hal::adapter::BlockingAsync; 9use embassy_embedded_hal::adapter::BlockingAsync;
7use embassy_executor::Spawner; 10use embassy_executor::Spawner;
@@ -22,6 +25,7 @@ async fn main(_spawner: Spawner) {
22 25
23 let mut button = Input::new(p.P0_11, Pull::Up); 26 let mut button = Input::new(p.P0_11, Pull::Up);
24 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); 27 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
28 let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard);
25 29
26 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); 30 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
27 //let mut button = Input::new(p.P1_02, Pull::Up); 31 //let mut button = Input::new(p.P1_02, Pull::Up);
@@ -53,6 +57,13 @@ async fn main(_spawner: Spawner) {
53 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); 57 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc);
54 let mut magic = [0; 4]; 58 let mut magic = [0; 4];
55 let mut updater = FirmwareUpdater::new(config, &mut magic); 59 let mut updater = FirmwareUpdater::new(config, &mut magic);
60 let state = updater.get_state().await.unwrap();
61 if state == State::Revert {
62 led_reverted.set_low();
63 } else {
64 led_reverted.set_high();
65 }
66
56 loop { 67 loop {
57 led.set_low(); 68 led.set_low();
58 button.wait_for_any_edge().await; 69 button.wait_for_any_edge().await;