mirror of
https://github.com/jhbruhn/moonboot.git
synced 2025-03-15 01:55: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::{
|
use crate::{
|
||||||
|
exchange::Exchange,
|
||||||
hardware::processor::Processor,
|
hardware::processor::Processor,
|
||||||
hardware::{Bank, Config},
|
hardware::{Bank, Config},
|
||||||
state::{Exchange, ExchangeProgress, ExchangeStep, State, Update, UpdateError},
|
state::{ExchangeProgress, ExchangeStep, State, Update, UpdateError},
|
||||||
Context,
|
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 embedded_storage::Storage;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
exchange::Exchange,
|
||||||
log,
|
log,
|
||||||
state::{Exchange, ExchangeProgress, ExchangeStep, State, Update},
|
state::{ExchangeProgress, ExchangeStep, State, Update},
|
||||||
Address,
|
Address,
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,8 @@ mod manager;
|
||||||
/// Implementations for use in the firmware
|
/// Implementations for use in the firmware
|
||||||
pub use manager::MoonbootManager;
|
pub use manager::MoonbootManager;
|
||||||
|
|
||||||
|
/// Various processes for exchanging pages
|
||||||
|
pub mod exchange;
|
||||||
/// Common hardware abstractions and associated implementations
|
/// Common hardware abstractions and associated implementations
|
||||||
pub mod hardware;
|
pub mod hardware;
|
||||||
/// Shared state management between firmware and bootloader
|
/// Shared state management between firmware and bootloader
|
||||||
|
@ -49,7 +51,7 @@ pub trait Context {
|
||||||
type Storage: embedded_storage::Storage;
|
type Storage: embedded_storage::Storage;
|
||||||
type State: state::State;
|
type State: state::State;
|
||||||
type Processor: hardware::processor::Processor;
|
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")))]
|
#[cfg(not(any(feature = "use-log", feature = "use-defmt")))]
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
#[cfg(feature = "ram-state")]
|
#[cfg(feature = "ram-state")]
|
||||||
pub mod ram;
|
pub mod ram;
|
||||||
|
|
||||||
#[cfg(feature = "scratch-state")]
|
|
||||||
pub mod scratch;
|
|
||||||
|
|
||||||
use crate::hardware::Bank;
|
use crate::hardware::Bank;
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use embedded_storage::Storage;
|
|
||||||
|
|
||||||
use crc::{Crc, CRC_32_CKSUM};
|
use crc::{Crc, CRC_32_CKSUM};
|
||||||
#[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
|
@ -17,18 +13,6 @@ use desse::{Desse, DesseSized};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
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
|
/// Decision making states for the bootloader
|
||||||
// TODO: Hash + Signature? Should be done on download I think! This way, the algorithms can be
|
// TODO: Hash + Signature? Should be done on download I think! This way, the algorithms can be
|
||||||
// exchanged via software updates easily
|
// 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;
|
||||||
|
|
||||||
use crate::{log, Address};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -57,120 +55,3 @@ impl State for RamState {
|
||||||
Ok(())
|
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