mirror of
https://github.com/jhbruhn/moonboot.git
synced 2025-03-14 17:45:50 +00:00
Moved exchange back into separate module
This commit is contained in:
parent
34e6326482
commit
1e1c174f32
7 changed files with 153 additions and 139 deletions
|
@ -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
18
src/exchange/mod.rs
Normal 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
127
src/exchange/ram.rs
Normal 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(())
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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")))]
|
||||
|
|
|
@ -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
|
||||
|
|
121
src/state/ram.rs
121
src/state/ram.rs
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue