Moved exchange back into separate module

This commit is contained in:
Wouter Geraedts 2022-07-12 08:57:14 +02:00
parent 34e6326482
commit 1e1c174f32
7 changed files with 153 additions and 139 deletions

View file

@ -1,7 +1,8 @@
use crate::{
exchange::Exchange,
hardware::processor::Processor,
hardware::{Bank, Config},
state::{Exchange, ExchangeProgress, ExchangeStep, State, Update, UpdateError},
state::{ExchangeProgress, ExchangeStep, State, Update, UpdateError},
Context,
};

18
src/exchange/mod.rs Normal file
View file

@ -0,0 +1,18 @@
pub mod ram;
pub mod scratch;
use crate::state::{ExchangeProgress, State};
use embedded_storage::Storage;
/// Abstraction for the exchange operation of the current state.
pub trait Exchange<STORAGE: Storage, STATE: State> {
type Error: core::fmt::Debug;
fn exchange<const INTERNAL_PAGE_SIZE: usize>(
&mut self,
storage: &mut STORAGE,
state: &mut STATE,
progress: ExchangeProgress,
) -> Result<(), Self::Error>;
}

127
src/exchange/ram.rs Normal file
View file

@ -0,0 +1,127 @@
use embedded_storage::Storage;
use crate::{
exchange::Exchange,
log,
state::{ExchangeProgress, State, Update},
Address,
};
pub struct Ram;
pub enum ExchangeError<STORAGE, STATE> {
Storage(STORAGE),
State(STATE),
}
impl<STORAGE, STATE> core::fmt::Debug for ExchangeError<STORAGE, STATE>
where
STORAGE: core::fmt::Debug,
STATE: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Storage(arg0) => f.debug_tuple("Storage").field(arg0).finish(),
Self::State(arg0) => f.debug_tuple("State").field(arg0).finish(),
}
}
}
impl<STORAGE: Storage, STATE: State> Exchange<STORAGE, STATE> for Ram
where
STORAGE::Error: core::fmt::Debug,
STATE::Error: core::fmt::Debug,
{
type Error = ExchangeError<STORAGE::Error, STATE::Error>;
fn exchange<const INTERNAL_PAGE_SIZE: usize>(
&mut self,
storage: &mut STORAGE,
state: &mut STATE,
progress: ExchangeProgress,
) -> Result<(), Self::Error> {
let ExchangeProgress {
a,
b,
page_index,
step,
..
} = progress;
assert_eq!(a.size, b.size);
assert_ne!(a.size, 0);
assert_ne!(b.size, 0);
let size = a.size; // Both are equal
let full_pages = size / INTERNAL_PAGE_SIZE as Address;
let remaining_page_length = size as usize % INTERNAL_PAGE_SIZE;
let mut page_a_buf = [0_u8; INTERNAL_PAGE_SIZE];
let mut page_b_buf = [0_u8; INTERNAL_PAGE_SIZE];
let mut last_state = state.read().map_err(ExchangeError::State)?;
// Set this in the exchanging part to know whether we are in a recovery process from a
// failed update or on the initial update
let recovering = matches!(last_state.update, Update::Revert(_));
for page_index in page_index..full_pages {
let offset = page_index * INTERNAL_PAGE_SIZE as u32;
let a_location = a.location + offset;
let b_location = b.location + offset;
log::trace!(
"Exchange: Page {}, from a ({}) to b ({})",
page_index,
a_location,
b_location
);
storage
.read(a_location, &mut page_a_buf)
.map_err(ExchangeError::Storage)?;
storage
.read(b_location, &mut page_b_buf)
.map_err(ExchangeError::Storage)?;
storage
.write(a_location, &page_b_buf)
.map_err(ExchangeError::Storage)?;
storage
.write(b_location, &page_a_buf)
.map_err(ExchangeError::Storage)?;
// Store the exchange progress
last_state.update = Update::Exchanging(ExchangeProgress {
a,
b,
recovering,
page_index,
step,
});
state.write(&last_state).map_err(ExchangeError::State)?;
}
// TODO: Fit this into the while loop
if remaining_page_length > 0 {
let offset = full_pages * INTERNAL_PAGE_SIZE as u32;
let a_location = a.location + offset;
let b_location = b.location + offset;
storage
.read(a_location, &mut page_a_buf[0..remaining_page_length])
.map_err(ExchangeError::Storage)?;
storage
.read(b_location, &mut page_b_buf[0..remaining_page_length])
.map_err(ExchangeError::Storage)?;
storage
.write(a_location, &page_a_buf[0..remaining_page_length])
.map_err(ExchangeError::Storage)?;
storage
.write(b_location + offset, &page_b_buf[0..remaining_page_length])
.map_err(ExchangeError::Storage)?;
}
Ok(())
}
}

View file

@ -3,8 +3,9 @@ use core::{fmt::Debug, ops::Range};
use embedded_storage::Storage;
use crate::{
exchange::Exchange,
log,
state::{Exchange, ExchangeProgress, ExchangeStep, State, Update},
state::{ExchangeProgress, ExchangeStep, State, Update},
Address,
};

View file

@ -20,6 +20,8 @@ mod manager;
/// Implementations for use in the firmware
pub use manager::MoonbootManager;
/// Various processes for exchanging pages
pub mod exchange;
/// Common hardware abstractions and associated implementations
pub mod hardware;
/// Shared state management between firmware and bootloader
@ -49,7 +51,7 @@ pub trait Context {
type Storage: embedded_storage::Storage;
type State: state::State;
type Processor: hardware::processor::Processor;
type Exchange: state::Exchange<Self::Storage, Self::State>;
type Exchange: exchange::Exchange<Self::Storage, Self::State>;
}
#[cfg(not(any(feature = "use-log", feature = "use-defmt")))]

View file

@ -1,13 +1,9 @@
#[cfg(feature = "ram-state")]
pub mod ram;
#[cfg(feature = "scratch-state")]
pub mod scratch;
use crate::hardware::Bank;
use core::fmt::Debug;
use embedded_storage::Storage;
use crc::{Crc, CRC_32_CKSUM};
#[cfg(feature = "defmt")]
@ -17,18 +13,6 @@ use desse::{Desse, DesseSized};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
/// Abstraction for the exchange operation of the current state.
pub trait Exchange<STORAGE: Storage, STATE: State> {
type Error: Debug;
fn exchange<const INTERNAL_PAGE_SIZE: usize>(
&mut self,
storage: &mut STORAGE,
state: &mut STATE,
progress: ExchangeProgress,
) -> Result<(), Self::Error>;
}
/// Decision making states for the bootloader
// TODO: Hash + Signature? Should be done on download I think! This way, the algorithms can be
// exchanged via software updates easily

View file

@ -1,6 +1,4 @@
use embedded_storage::Storage;
use crate::{log, Address};
use crate::log;
use super::*;
@ -57,120 +55,3 @@ impl State for RamState {
Ok(())
}
}
pub enum ExchangeError<STORAGE, STATE> {
Storage(STORAGE),
State(STATE),
}
impl<STORAGE, STATE> Debug for ExchangeError<STORAGE, STATE>
where
STORAGE: Debug,
STATE: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Storage(arg0) => f.debug_tuple("Storage").field(arg0).finish(),
Self::State(arg0) => f.debug_tuple("State").field(arg0).finish(),
}
}
}
impl<STORAGE: Storage, STATE: State> Exchange<STORAGE, STATE> for RamState
where
STORAGE::Error: Debug,
STATE::Error: Debug,
{
type Error = ExchangeError<STORAGE::Error, STATE::Error>;
fn exchange<const INTERNAL_PAGE_SIZE: usize>(
&mut self,
storage: &mut STORAGE,
state: &mut STATE,
progress: ExchangeProgress,
) -> Result<(), Self::Error> {
let ExchangeProgress {
a,
b,
page_index,
step,
..
} = progress;
assert_eq!(a.size, b.size);
assert_ne!(a.size, 0);
assert_ne!(b.size, 0);
let size = a.size; // Both are equal
let full_pages = size / INTERNAL_PAGE_SIZE as Address;
let remaining_page_length = size as usize % INTERNAL_PAGE_SIZE;
let mut page_a_buf = [0_u8; INTERNAL_PAGE_SIZE];
let mut page_b_buf = [0_u8; INTERNAL_PAGE_SIZE];
let mut last_state = state.read().map_err(ExchangeError::State)?;
// Set this in the exchanging part to know whether we are in a recovery process from a
// failed update or on the initial update
let recovering = matches!(last_state.update, Update::Revert(_));
for page_index in page_index..full_pages {
let offset = page_index * INTERNAL_PAGE_SIZE as u32;
let a_location = a.location + offset;
let b_location = b.location + offset;
log::trace!(
"Exchange: Page {}, from a ({}) to b ({})",
page_index,
a_location,
b_location
);
storage
.read(a_location, &mut page_a_buf)
.map_err(ExchangeError::Storage)?;
storage
.read(b_location, &mut page_b_buf)
.map_err(ExchangeError::Storage)?;
storage
.write(a_location, &page_b_buf)
.map_err(ExchangeError::Storage)?;
storage
.write(b_location, &page_a_buf)
.map_err(ExchangeError::Storage)?;
// Store the exchange progress
last_state.update = Update::Exchanging(ExchangeProgress {
a,
b,
recovering,
page_index,
step,
});
state.write(&last_state).map_err(ExchangeError::State)?;
}
// TODO: Fit this into the while loop
if remaining_page_length > 0 {
let offset = full_pages * INTERNAL_PAGE_SIZE as u32;
let a_location = a.location + offset;
let b_location = b.location + offset;
storage
.read(a_location, &mut page_a_buf[0..remaining_page_length])
.map_err(ExchangeError::Storage)?;
storage
.read(b_location, &mut page_b_buf[0..remaining_page_length])
.map_err(ExchangeError::Storage)?;
storage
.write(a_location, &page_a_buf[0..remaining_page_length])
.map_err(ExchangeError::Storage)?;
storage
.write(b_location + offset, &page_b_buf[0..remaining_page_length])
.map_err(ExchangeError::Storage)?;
}
Ok(())
}
}