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

View file

@ -29,7 +29,7 @@ pub mod cortex_m {
fn do_jump(&mut self, address: super::Address) -> ! {
unsafe {
// 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);
}
@ -40,4 +40,3 @@ pub mod cortex_m {
}
}
}

View file

@ -24,8 +24,6 @@ pub use manager::MoonbootManager;
pub mod hardware;
/// Shared state management between firmware and bootloader
pub mod state;
/// Abstractions on the method of flash page swapping.
pub mod swap;
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::log;
use crc::{Crc, CRC_32_CKSUM};
#[cfg(feature = "defmt")]
use defmt::Format;
#[cfg(feature = "ram-state")]
#[cfg(any(feature = "ram-state", feature = "scratch-state"))]
use desse::{Desse, DesseSized};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@ -14,7 +41,10 @@ use serde::{Deserialize, Serialize};
// exchanged via software updates easily
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[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)]
pub enum Update {
// 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 = "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)]
/// Errors that can occur during update
pub enum UpdateError {
@ -50,7 +83,10 @@ pub enum UpdateError {
/// Upcoming operation of the exchange process for a given page index.
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[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)]
pub enum ExchangeStep {
/// Copy page A to the scratch page.
@ -64,7 +100,10 @@ pub enum ExchangeStep {
/// Store the progress of the current exchange operation
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[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)]
pub struct ExchangeProgress {
/// 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
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[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)]
pub struct MoonbootState {
/// 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 {
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 crate::{
log,
state::{ExchangeProgress, State, Update},
swap::{MemoryError, Swap},
Address,
};
use crate::{log, 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>(
&mut self,
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>;
}