mirror of
https://github.com/jhbruhn/moonboot.git
synced 2025-03-15 01:55:50 +00:00
Refactored swap/scratch to state
This commit is contained in:
parent
01fe251f1f
commit
e2d1ce797b
7 changed files with 136 additions and 135 deletions
|
@ -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,
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
|
@ -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>;
|
||||
}
|
Loading…
Reference in a new issue