Refactored swap/scratch to state

This commit is contained in:
Wouter Geraedts 2022-07-11 17:05:02 +02:00
parent 01fe251f1f
commit e2d1ce797b
7 changed files with 136 additions and 135 deletions

View file

@ -1,8 +1,7 @@
use crate::{ use crate::{
hardware::processor::Processor, hardware::processor::Processor,
hardware::{Bank, Config}, hardware::{Bank, Config},
state::{ExchangeProgress, ExchangeStep, State, Update, UpdateError}, state::{Exchange, ExchangeProgress, ExchangeStep, MemoryError, State, Update, UpdateError},
swap::{MemoryError, Swap},
}; };
use embedded_storage::Storage; use embedded_storage::Storage;
@ -15,47 +14,47 @@ use defmt::Format;
/// Use this from your bootloader application and call boot() to do the magic, reading the current /// Use this from your bootloader application and call boot() to do the magic, reading the current
/// state via the State type and then jumping to the new image using the Jumper specified /// state via the State type and then jumping to the new image using the Jumper specified
pub struct MoonbootBoot< pub struct MoonbootBoot<
InternalMemory: Storage, STORAGE: Storage,
HardwareState: State, STATE: State,
CPU: Processor, // TODO: Wrap these into a context struct like rubble? PROCESSOR: Processor, // TODO: Wrap these into a context struct like rubble?
PageSwap: Swap, EXCHANGE: Exchange,
const INTERNAL_PAGE_SIZE: usize, const INTERNAL_PAGE_SIZE: usize,
> { > {
config: Config, config: Config,
internal_memory: InternalMemory, storage: STORAGE,
state: HardwareState, state: STATE,
processor: CPU, processor: PROCESSOR,
swap: PageSwap, exchange: EXCHANGE,
} }
impl< impl<
InternalMemory: Storage, STORAGE: Storage,
HardwareState: State, STATE: State,
CPU: Processor, PROCESSOR: Processor,
PageSwap: Swap, EXCHANGE: Exchange,
const INTERNAL_PAGE_SIZE: usize, const INTERNAL_PAGE_SIZE: usize,
> MoonbootBoot<InternalMemory, HardwareState, CPU, PageSwap, INTERNAL_PAGE_SIZE> > MoonbootBoot<STORAGE, STATE, PROCESSOR, EXCHANGE, INTERNAL_PAGE_SIZE>
{ {
/// create a new instance of the bootloader /// create a new instance of the bootloader
pub fn new( pub fn new(
config: Config, config: Config,
internal_memory: InternalMemory, storage: STORAGE,
state: HardwareState, state: STATE,
processor: CPU, processor: PROCESSOR,
swap: PageSwap, exchange: EXCHANGE,
) -> MoonbootBoot<InternalMemory, HardwareState, CPU, PageSwap, INTERNAL_PAGE_SIZE> { ) -> MoonbootBoot<STORAGE, STATE, PROCESSOR, EXCHANGE, INTERNAL_PAGE_SIZE> {
Self { Self {
config, config,
internal_memory, storage,
state, state,
processor, processor,
swap, exchange,
} }
} }
/// Destroy this instance of the bootloader and return access to the hardware peripheral /// Destroy this instance of the bootloader and return access to the hardware peripheral
pub fn destroy(self) -> (InternalMemory, HardwareState, CPU) { pub fn destroy(self) -> (STORAGE, STATE, PROCESSOR) {
(self.internal_memory, self.state, self.processor) (self.storage, self.state, self.processor)
} }
/// Execute the update and boot logic of the bootloader /// Execute the update and boot logic of the bootloader
@ -124,9 +123,9 @@ impl<
); );
let exchange_result = self let exchange_result = self
.swap .exchange
.exchange::<InternalMemory, HardwareState, INTERNAL_PAGE_SIZE>( .exchange::<STORAGE, STATE, INTERNAL_PAGE_SIZE>(
&mut self.internal_memory, &mut self.storage,
&mut self.state, &mut self.state,
progress, progress,
); );
@ -165,7 +164,7 @@ impl<
old.location, old.location,
old.size / 1024, old.size / 1024,
new.location, new.location,
new.size / 1024, new.size / 1024
); );
// Try to exchange the firmware images // Try to exchange the firmware images
@ -195,9 +194,9 @@ impl<
} }
fn exchange_banks(&mut self, a: Bank, b: Bank) -> Result<(), MemoryError> { fn exchange_banks(&mut self, a: Bank, b: Bank) -> Result<(), MemoryError> {
self.swap self.exchange
.exchange::<InternalMemory, HardwareState, INTERNAL_PAGE_SIZE>( .exchange::<STORAGE, STATE, INTERNAL_PAGE_SIZE>(
&mut self.internal_memory, &mut self.storage,
&mut self.state, &mut self.state,
ExchangeProgress { ExchangeProgress {
a, a,

View file

@ -29,7 +29,7 @@ pub mod cortex_m {
fn do_jump(&mut self, address: super::Address) -> ! { fn do_jump(&mut self, address: super::Address) -> ! {
unsafe { unsafe {
// Set Vector Table to new vector table (unsafe but okay here) // Set Vector Table to new vector table (unsafe but okay here)
(*cortex_m::peripheral::SCB::ptr()).vtor.write(address); (*cortex_m::peripheral::SCB::PTR).vtor.write(address);
cortex_m::asm::bootload(address as *const u32); cortex_m::asm::bootload(address as *const u32);
} }
@ -40,4 +40,3 @@ pub mod cortex_m {
} }
} }
} }

View file

@ -24,8 +24,6 @@ pub use manager::MoonbootManager;
pub mod hardware; pub mod hardware;
/// Shared state management between firmware and bootloader /// Shared state management between firmware and bootloader
pub mod state; pub mod state;
/// Abstractions on the method of flash page swapping.
pub mod swap;
pub use embedded_storage; pub use embedded_storage;

View file

@ -1,10 +1,37 @@
#[cfg(feature = "ram-state")]
pub mod ram;
#[cfg(feature = "scratch-state")]
pub mod scratch;
use embedded_storage::Storage;
/// Error occured during memory access
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[derive(Debug)]
pub enum MemoryError {
BankSizeNotEqual,
BankSizeZero,
ReadFailure,
WriteFailure,
}
/// Abstraction for the exchange operation of the current state.
pub trait Exchange {
fn exchange<STORAGE: Storage, STATE: State, const INTERNAL_PAGE_SIZE: usize>(
&mut self,
internal_memory: &mut STORAGE,
state: &mut STATE,
progress: ExchangeProgress,
) -> Result<(), MemoryError>;
}
use crate::hardware::Bank; use crate::hardware::Bank;
use crate::log;
use crc::{Crc, CRC_32_CKSUM}; use crc::{Crc, CRC_32_CKSUM};
#[cfg(feature = "defmt")] #[cfg(feature = "defmt")]
use defmt::Format; use defmt::Format;
#[cfg(feature = "ram-state")] #[cfg(any(feature = "ram-state", feature = "scratch-state"))]
use desse::{Desse, DesseSized}; use desse::{Desse, DesseSized};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -14,7 +41,10 @@ use serde::{Deserialize, Serialize};
// exchanged via software updates easily // exchanged via software updates easily
#[cfg_attr(feature = "use-defmt", derive(Format))] #[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))] #[cfg_attr(
any(feature = "ram-state", feature = "scratch-state"),
derive(Desse, DesseSized)
)]
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum Update { pub enum Update {
// No update requested, just jump to the application // No update requested, just jump to the application
@ -33,7 +63,10 @@ pub enum Update {
#[cfg_attr(feature = "use-defmt", derive(Format))] #[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))] #[cfg_attr(
any(feature = "ram-state", feature = "scratch-state"),
derive(Desse, DesseSized)
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// Errors that can occur during update /// Errors that can occur during update
pub enum UpdateError { pub enum UpdateError {
@ -50,7 +83,10 @@ pub enum UpdateError {
/// Upcoming operation of the exchange process for a given page index. /// Upcoming operation of the exchange process for a given page index.
#[cfg_attr(feature = "use-defmt", derive(Format))] #[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))] #[cfg_attr(
any(feature = "ram-state", feature = "scratch-state"),
derive(Desse, DesseSized)
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExchangeStep { pub enum ExchangeStep {
/// Copy page A to the scratch page. /// Copy page A to the scratch page.
@ -64,7 +100,10 @@ pub enum ExchangeStep {
/// Store the progress of the current exchange operation /// Store the progress of the current exchange operation
#[cfg_attr(feature = "use-defmt", derive(Format))] #[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))] #[cfg_attr(
any(feature = "ram-state", feature = "scratch-state"),
derive(Desse, DesseSized)
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ExchangeProgress { pub struct ExchangeProgress {
/// Bank the update is coming from /// Bank the update is coming from
@ -82,7 +121,10 @@ pub struct ExchangeProgress {
/// Struct used to store the state of the bootloader situation in NVM /// Struct used to store the state of the bootloader situation in NVM
#[cfg_attr(feature = "use-defmt", derive(Format))] #[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))] #[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))] #[cfg_attr(
any(feature = "ram-state", feature = "scratch-state"),
derive(Desse, DesseSized)
)]
#[derive(Debug)] #[derive(Debug)]
pub struct MoonbootState { pub struct MoonbootState {
/// If set Request, an Update is requested. This will exchange the two images, set the update /// If set Request, an Update is requested. This will exchange the two images, set the update
@ -112,63 +154,3 @@ const CRC: Crc<StateCrcType> = Crc::<StateCrcType>::new(&CRC_32_CKSUM);
fn checksum(bytes: &[u8]) -> StateCrcType { fn checksum(bytes: &[u8]) -> StateCrcType {
CRC.checksum(bytes) CRC.checksum(bytes)
} }
/// State stored in the RAM
/// TODO: Move to hardware folder together with state trait?
#[cfg(feature = "ram-state")]
pub mod ram {
use super::*;
/// State read and written to RAM. This assumes the device is never powered off / the ram is never
/// reset!
pub struct RamState;
extern "C" {
static mut _moonboot_state_crc_start: StateCrcType;
static mut _moonboot_state_data_start: [u8; STATE_SERIALIZED_MAX_SIZE];
// TODO: Move these as normal variables to linker sections via #[link] macro?
}
impl State for RamState {
fn read(&mut self) -> MoonbootState {
let crc = unsafe { _moonboot_state_crc_start };
log::info!(
"Reading data with len: {}, CRC: {}",
STATE_SERIALIZED_MAX_SIZE,
crc
);
let checksum = checksum(unsafe { &_moonboot_state_data_start });
if crc == checksum {
let data = MoonbootState::deserialize_from(unsafe { &_moonboot_state_data_start });
log::trace!("CRC Match! {}: {:?}", crc, data);
return data;
} else {
log::trace!("CRC Mismatch! {} vs {}", crc, checksum);
}
MoonbootState {
update: Update::None,
}
}
fn write(&mut self, data: &MoonbootState) -> Result<(), ()> {
log::trace!("Writing data {:?}", data);
unsafe { _moonboot_state_data_start = data.serialize() };
log::trace!("Written data: {:?}", unsafe { &_moonboot_state_data_start });
unsafe {
_moonboot_state_crc_start = checksum(&_moonboot_state_data_start);
}
log::info!(
"Written len: {}, checksum: {}",
STATE_SERIALIZED_MAX_SIZE,
unsafe { _moonboot_state_crc_start }
);
Ok(())
}
}
}

View file

@ -1,15 +1,63 @@
use embedded_storage::Storage; use embedded_storage::Storage;
use crate::{ use crate::{log, Address};
log,
state::{ExchangeProgress, State, Update},
swap::{MemoryError, Swap},
Address,
};
pub struct Ram; use super::*;
impl Swap for Ram { /// State read and written to RAM. This assumes the device is never powered off / the ram is never
/// reset!
pub struct RamState;
extern "C" {
static mut _moonboot_state_crc_start: StateCrcType;
static mut _moonboot_state_data_start: [u8; STATE_SERIALIZED_MAX_SIZE];
// TODO: Move these as normal variables to linker sections via #[link] macro?
}
impl State for RamState {
fn read(&mut self) -> MoonbootState {
let crc = unsafe { _moonboot_state_crc_start };
log::info!(
"Reading data with len: {}, CRC: {}",
STATE_SERIALIZED_MAX_SIZE,
crc
);
let checksum = checksum(unsafe { &_moonboot_state_data_start });
if crc == checksum {
let data = MoonbootState::deserialize_from(unsafe { &_moonboot_state_data_start });
log::trace!("CRC Match! {}: {:?}", crc, data);
return data;
} else {
log::trace!("CRC Mismatch! {} vs {}", crc, checksum);
}
MoonbootState {
update: Update::None,
}
}
fn write(&mut self, data: &MoonbootState) -> Result<(), ()> {
log::trace!("Writing data {:?}", data);
unsafe { _moonboot_state_data_start = data.serialize() };
log::trace!("Written data: {:?}", unsafe { &_moonboot_state_data_start });
unsafe {
_moonboot_state_crc_start = checksum(&_moonboot_state_data_start);
}
log::info!(
"Written len: {}, checksum: {}",
STATE_SERIALIZED_MAX_SIZE,
unsafe { _moonboot_state_crc_start }
);
Ok(())
}
}
impl Exchange for RamState {
fn exchange<InternalMemory: Storage, HardwareState: State, const INTERNAL_PAGE_SIZE: usize>( fn exchange<InternalMemory: Storage, HardwareState: State, const INTERNAL_PAGE_SIZE: usize>(
&mut self, &mut self,
internal_memory: &mut InternalMemory, internal_memory: &mut InternalMemory,

View file

@ -1,25 +0,0 @@
pub mod ram;
pub mod scratch;
use embedded_storage::Storage;
use crate::state::{ExchangeProgress, State};
/// Error occured during memory access
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[derive(Debug)]
pub enum MemoryError {
BankSizeNotEqual,
BankSizeZero,
ReadFailure,
WriteFailure,
}
pub trait Swap {
fn exchange<InternalMemory: Storage, HardwareState: State, const INTERNAL_PAGE_SIZE: usize>(
&mut self,
internal_memory: &mut InternalMemory,
state: &mut HardwareState,
exchange: ExchangeProgress,
) -> Result<(), MemoryError>;
}