Add revert state in embassy-boot

The revert state signals that a firmware revert has taken place,
allowing the application to know if a firmware update attempt was
reverted.
This commit is contained in:
Ulf Lilleengen 2024-09-18 16:14:53 +02:00
parent 45cbcb513d
commit b1897c58fa
4 changed files with 14 additions and 4 deletions

View File

@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::blocking_mutex::Mutex; use embassy_sync::blocking_mutex::Mutex;
use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; use crate::{State, DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
/// Errors returned by bootloader /// Errors returned by bootloader
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
@ -276,7 +276,7 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
self.state.erase(0, self.state.capacity() as u32)?; self.state.erase(0, self.state.capacity() as u32)?;
// Set magic // Set magic
state_word.fill(BOOT_MAGIC); state_word.fill(REVERT_MAGIC);
self.state.write(0, state_word)?; self.state.write(0, state_word)?;
} }
} }
@ -411,6 +411,8 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
Ok(State::Swap) Ok(State::Swap)
} else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) { } else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) {
Ok(State::DfuDetach) Ok(State::DfuDetach)
} else if !state_word.iter().any(|&b| b != REVERT_MAGIC) {
Ok(State::Revert)
} else { } else {
Ok(State::Boot) Ok(State::Boot)
} }

View File

@ -289,7 +289,8 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
// Make sure we are running a booted firmware to avoid reverting to a bad state. // Make sure we are running a booted firmware to avoid reverting to a bad state.
async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
if self.get_state().await? == State::Boot { let state = self.get_state().await?;
if state == State::Boot || state == State::DfuDetach || state == State::Revert {
Ok(()) Ok(())
} else { } else {
Err(FirmwareUpdaterError::BadState) Err(FirmwareUpdaterError::BadState)

View File

@ -324,7 +324,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
// Make sure we are running a booted firmware to avoid reverting to a bad state. // Make sure we are running a booted firmware to avoid reverting to a bad state.
fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach { let state = self.get_state()?;
if state == State::Boot || state == State::DfuDetach || state == State::Revert {
Ok(()) Ok(())
} else { } else {
Err(FirmwareUpdaterError::BadState) Err(FirmwareUpdaterError::BadState)

View File

@ -25,6 +25,7 @@ pub use firmware_updater::{
FirmwareUpdaterError, FirmwareUpdaterError,
}; };
pub(crate) const REVERT_MAGIC: u8 = 0xC0;
pub(crate) const BOOT_MAGIC: u8 = 0xD0; pub(crate) const BOOT_MAGIC: u8 = 0xD0;
pub(crate) const SWAP_MAGIC: u8 = 0xF0; pub(crate) const SWAP_MAGIC: u8 = 0xF0;
pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0; pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0;
@ -37,6 +38,8 @@ pub enum State {
Boot, Boot,
/// Bootloader has swapped the active partition with the dfu partition and will attempt boot. /// Bootloader has swapped the active partition with the dfu partition and will attempt boot.
Swap, Swap,
/// Bootloader has reverted the active partition with the dfu partition and will attempt boot.
Revert,
/// Application has received a request to reboot into DFU mode to apply an update. /// Application has received a request to reboot into DFU mode to apply an update.
DfuDetach, DfuDetach,
} }
@ -157,6 +160,9 @@ mod tests {
// Running again should cause a revert // Running again should cause a revert
assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
// Next time we know it was reverted
assert_eq!(State::Revert, bootloader.prepare_boot(&mut page).unwrap());
let mut read_buf = [0; FIRMWARE_SIZE]; let mut read_buf = [0; FIRMWARE_SIZE];
flash.active().read(0, &mut read_buf).unwrap(); flash.active().read(0, &mut read_buf).unwrap();
assert_eq!(ORIGINAL, read_buf); assert_eq!(ORIGINAL, read_buf);