mirror of
https://github.com/jhbruhn/moonboot.git
synced 2025-03-15 01:55:50 +00:00
Reworked errors
This commit is contained in:
parent
e2d1ce797b
commit
1cd3c4f5be
4 changed files with 183 additions and 194 deletions
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
hardware::processor::Processor,
|
hardware::processor::Processor,
|
||||||
hardware::{Bank, Config},
|
hardware::{Bank, Config},
|
||||||
state::{Exchange, ExchangeProgress, ExchangeStep, MemoryError, State, Update, UpdateError},
|
state::{Exchange, ExchangeError, ExchangeProgress, ExchangeStep, State, Update, UpdateError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use embedded_storage::Storage;
|
use embedded_storage::Storage;
|
||||||
|
@ -58,13 +58,13 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the update and boot logic of the bootloader
|
/// Execute the update and boot logic of the bootloader
|
||||||
pub fn boot(&mut self) -> Result<void::Void, ()> {
|
pub fn boot(&mut self) -> Result<void::Void, STATE::Error> {
|
||||||
// TODO: consider error handling
|
// TODO: consider error handling
|
||||||
log::info!("Booting with moonboot!");
|
log::info!("Booting with moonboot!");
|
||||||
|
|
||||||
self.processor.setup(&self.config);
|
self.processor.setup(&self.config);
|
||||||
|
|
||||||
let mut state = self.state.read();
|
let mut state = self.state.read()?;
|
||||||
|
|
||||||
log::info!("Old State: {:?}", state);
|
log::info!("Old State: {:?}", state);
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ impl<
|
||||||
Update::None => self.handle_none(),
|
Update::None => self.handle_none(),
|
||||||
Update::Request(bank) => self.handle_request(bank),
|
Update::Request(bank) => self.handle_request(bank),
|
||||||
Update::Revert(bank) => self.handle_revert(bank),
|
Update::Revert(bank) => self.handle_revert(bank),
|
||||||
Update::Exchanging(progress) => self.handle_exchanging(progress),
|
Update::Exchanging(progress) => self.handle_exchanging(progress)?,
|
||||||
Update::Error(err) => Update::Error(err),
|
Update::Error(err) => Update::Error(err),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ impl<
|
||||||
|
|
||||||
// Handle a case of power interruption or similar, which lead to a exchange_banks being
|
// Handle a case of power interruption or similar, which lead to a exchange_banks being
|
||||||
// interrupted.
|
// interrupted.
|
||||||
fn handle_exchanging(&mut self, progress: ExchangeProgress) -> Update {
|
fn handle_exchanging(&mut self, progress: ExchangeProgress) -> Result<Update, STATE::Error> {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Firmware Update was interrupted! Trying to recover with exchange operation: {:?}",
|
"Firmware Update was interrupted! Trying to recover with exchange operation: {:?}",
|
||||||
progress
|
progress
|
||||||
|
@ -130,8 +130,8 @@ impl<
|
||||||
progress,
|
progress,
|
||||||
);
|
);
|
||||||
|
|
||||||
if exchange_result.is_ok() {
|
Ok(if exchange_result.is_ok() {
|
||||||
let state = self.state.read().update;
|
let state = self.state.read()?.update;
|
||||||
match state {
|
match state {
|
||||||
Update::Exchanging(progress) => {
|
Update::Exchanging(progress) => {
|
||||||
if progress.recovering {
|
if progress.recovering {
|
||||||
|
@ -148,7 +148,7 @@ impl<
|
||||||
exchange_result
|
exchange_result
|
||||||
);
|
);
|
||||||
Update::Error(UpdateError::ImageExchangeFailed)
|
Update::Error(UpdateError::ImageExchangeFailed)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revert the bootable image with the image in index new_firmware. Returns Revert on success if
|
// Revert the bootable image with the image in index new_firmware. Returns Revert on success if
|
||||||
|
@ -193,7 +193,11 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exchange_banks(&mut self, a: Bank, b: Bank) -> Result<(), MemoryError> {
|
fn exchange_banks(
|
||||||
|
&mut self,
|
||||||
|
a: Bank,
|
||||||
|
b: Bank,
|
||||||
|
) -> Result<(), ExchangeError<STORAGE::Error, STATE::Error, EXCHANGE::OtherError>> {
|
||||||
self.exchange
|
self.exchange
|
||||||
.exchange::<STORAGE, STATE, INTERNAL_PAGE_SIZE>(
|
.exchange::<STORAGE, STATE, INTERNAL_PAGE_SIZE>(
|
||||||
&mut self.storage,
|
&mut self.storage,
|
||||||
|
|
|
@ -3,55 +3,67 @@ use crate::{
|
||||||
state::{State, Update},
|
state::{State, Update},
|
||||||
};
|
};
|
||||||
|
|
||||||
use embedded_storage::{ReadStorage, Storage};
|
use embedded_storage::Storage;
|
||||||
|
|
||||||
use crate::log;
|
use crate::log;
|
||||||
|
|
||||||
/// Instantiate this in your application to enable mutation of the State specified in this and jump
|
/// Instantiate this in your application to enable mutation of the State specified in this and jump
|
||||||
/// to the bootloader to apply any updates.
|
/// to the bootloader to apply any updates.
|
||||||
pub struct MoonbootManager<
|
pub struct MoonbootManager<
|
||||||
InternalMemory: Storage,
|
STORAGE: Storage,
|
||||||
HardwareState: State,
|
STATE: State,
|
||||||
CPU: Processor,
|
PROCESSOR: Processor,
|
||||||
const INTERNAL_PAGE_SIZE: usize,
|
const INTERNAL_PAGE_SIZE: usize,
|
||||||
> {
|
> {
|
||||||
config: Config,
|
config: Config,
|
||||||
internal_memory: InternalMemory,
|
storage: STORAGE,
|
||||||
state: HardwareState,
|
state: STATE,
|
||||||
processor: CPU,
|
processor: PROCESSOR,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
pub struct InitError;
|
||||||
InternalMemory: Storage,
|
|
||||||
HardwareState: State,
|
pub enum MarkError<E> {
|
||||||
CPU: Processor,
|
UpdateQueuedButNotInstalled,
|
||||||
const INTERNAL_PAGE_SIZE: usize,
|
State(E),
|
||||||
> MoonbootManager<InternalMemory, HardwareState, CPU, INTERNAL_PAGE_SIZE>
|
}
|
||||||
|
|
||||||
|
impl<STORAGE: Storage, STATE: State, PROCESSOR: Processor, const INTERNAL_PAGE_SIZE: usize>
|
||||||
|
MoonbootManager<STORAGE, STATE, PROCESSOR, INTERNAL_PAGE_SIZE>
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config: Config,
|
config: Config,
|
||||||
internal_memory: InternalMemory,
|
storage: STORAGE,
|
||||||
state: HardwareState,
|
state: STATE,
|
||||||
processor: CPU,
|
processor: PROCESSOR,
|
||||||
) -> MoonbootManager<InternalMemory, HardwareState, CPU, INTERNAL_PAGE_SIZE> {
|
) -> Result<MoonbootManager<STORAGE, STATE, PROCESSOR, INTERNAL_PAGE_SIZE>, InitError> {
|
||||||
Self {
|
if config.update_bank.size > config.boot_bank.size {
|
||||||
|
log::error!(
|
||||||
|
"Requested update bank {:?} is larger than boot bank {:?}",
|
||||||
|
bank,
|
||||||
|
self.config.boot_bank
|
||||||
|
);
|
||||||
|
return Err(InitError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
config,
|
config,
|
||||||
internal_memory,
|
storage,
|
||||||
state,
|
state,
|
||||||
processor,
|
processor,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroy this instance of the boot manager and return access to the hardware peripheral
|
/// Destroy this instance of the boot manager and return access to the hardware peripheral
|
||||||
pub fn destroy(self) -> (InternalMemory, HardwareState, CPU) {
|
pub fn destroy(self) -> (STORAGE, STATE, PROCESSOR) {
|
||||||
(self.internal_memory, self.state, self.processor)
|
(self.storage, self.state, self.processor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run this immediately after booting your new image successfully to mark the boot as
|
/// Run this immediately after booting your new image successfully to mark the boot as
|
||||||
/// succesful. If you do not do this, any reset will cause the bootloader to restore to the
|
/// succesful. If you do not do this, any reset will cause the bootloader to restore to the
|
||||||
/// previous firmware image.
|
/// previous firmware image.
|
||||||
pub fn mark_boot_successful(&mut self) -> Result<(), ()> {
|
pub fn mark_boot_successful(&mut self) -> Result<(), MarkError<STATE::Error>> {
|
||||||
let mut current_state = self.state.read();
|
let mut current_state = self.state.read().map_err(MarkError::State)?;
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"Application running, marking boot as successful. Current state: {:?}",
|
"Application running, marking boot as successful. Current state: {:?}",
|
||||||
|
@ -69,34 +81,24 @@ impl<
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("There is an update queued, but it has not been installed yet. Did you skip the bootloader?");
|
log::error!("There is an update queued, but it has not been installed yet. Did you skip the bootloader?");
|
||||||
return Err(());
|
return Err(MarkError::UpdateQueuedButNotInstalled);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
log::trace!("New state: {:?}", current_state);
|
log::trace!("New state: {:?}", current_state);
|
||||||
|
|
||||||
self.state.write(¤t_state)
|
self.state.write(¤t_state).map_err(MarkError::State)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upgrade firmware verifiying the given signature over the size of size.
|
// Upgrade firmware verifiying the given signature over the size of size.
|
||||||
// Can only return an error or diverge (!, represented by Void while ! is not a type yet)
|
// Can only return an error or diverge (!, represented by Void while ! is not a type yet)
|
||||||
pub fn update(&mut self) -> Result<void::Void, ()> {
|
pub fn update(&mut self) -> Result<void::Void, STATE::Error> {
|
||||||
// Apply the update stored in the update bank
|
// Apply the update stored in the update bank
|
||||||
let bank = self.config.update_bank;
|
let bank = self.config.update_bank;
|
||||||
// TODO: Check size value!
|
|
||||||
|
|
||||||
log::info!("Update requested on slot {:?}", bank);
|
log::info!("Update requested on slot {:?}", bank);
|
||||||
|
|
||||||
if bank.size > self.config.boot_bank.size {
|
let mut current_state = self.state.read()?;
|
||||||
log::error!(
|
|
||||||
"Requested update bank {:?} is larger than boot bank {:?}",
|
|
||||||
bank,
|
|
||||||
self.config.boot_bank
|
|
||||||
);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut current_state = self.state.read();
|
|
||||||
|
|
||||||
if current_state.update != Update::None {
|
if current_state.update != Update::None {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
|
@ -125,78 +127,78 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Easily get read access to the update bank
|
// /// Easily get read access to the update bank
|
||||||
impl<
|
// impl<
|
||||||
InternalMemory: Storage,
|
// InternalMemory: Storage,
|
||||||
HardwareState: State,
|
// HardwareState: State,
|
||||||
CPU: Processor,
|
// PROCESSOR: Processor,
|
||||||
const INTERNAL_PAGE_SIZE: usize,
|
// const INTERNAL_PAGE_SIZE: usize,
|
||||||
> core::convert::AsRef<[u8]>
|
// > core::convert::AsRef<[u8]>
|
||||||
for MoonbootManager<InternalMemory, HardwareState, CPU, INTERNAL_PAGE_SIZE>
|
// for MoonbootManager<InternalMemory, HardwareState, CPU, INTERNAL_PAGE_SIZE>
|
||||||
{
|
// {
|
||||||
#[inline]
|
// #[inline]
|
||||||
fn as_ref(&self) -> &[u8] {
|
// fn as_ref(&self) -> &[u8] {
|
||||||
unsafe {
|
// unsafe {
|
||||||
core::slice::from_raw_parts(
|
// core::slice::from_raw_parts(
|
||||||
self.config.update_bank.location as *const u8,
|
// self.config.update_bank.location as *const u8,
|
||||||
self.config.update_bank.size as usize,
|
// self.config.update_bank.size as usize,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Read Access to the current update target slot
|
// /// Read Access to the current update target slot
|
||||||
impl<
|
// impl<
|
||||||
InternalMemory: Storage,
|
// InternalMemory: Storage,
|
||||||
HardwareState: State,
|
// HardwareState: State,
|
||||||
CPU: Processor,
|
// CPU: Processor,
|
||||||
const INTERNAL_PAGE_SIZE: usize,
|
// const INTERNAL_PAGE_SIZE: usize,
|
||||||
> ReadStorage for MoonbootManager<InternalMemory, HardwareState, CPU, INTERNAL_PAGE_SIZE>
|
// > ReadStorage for MoonbootManager<InternalMemory, HardwareState, CPU, INTERNAL_PAGE_SIZE>
|
||||||
{
|
// {
|
||||||
type Error = (); // TODO
|
// type Error = (); // TODO
|
||||||
|
|
||||||
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
// fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
let bank = self.config.update_bank; // For now we always write updates to this bank.
|
// let bank = self.config.update_bank; // For now we always write updates to this bank.
|
||||||
if offset > bank.size || offset + bytes.len() as u32 > bank.size {
|
// if offset > bank.size || offset + bytes.len() as u32 > bank.size {
|
||||||
Err(()) // TODO: We want better error types!
|
// Err(()) // TODO: We want better error types!
|
||||||
} else {
|
// } else {
|
||||||
// TODO! fix
|
// // TODO! fix
|
||||||
let bank_start = bank.location;
|
// let bank_start = bank.location;
|
||||||
log::info!("Writing at {:x}[{:x}]", bank_start, offset);
|
// log::info!("Writing at {:x}[{:x}]", bank_start, offset);
|
||||||
match bank.memory_unit {
|
// match bank.memory_unit {
|
||||||
crate::hardware::MemoryUnit::Internal => {
|
// crate::hardware::MemoryUnit::Internal => {
|
||||||
{ self.internal_memory.read(bank_start + offset, bytes) }.map_err(|_| ())
|
// { self.storage.read(bank_start + offset, bytes) }.map_err(|_| ())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn capacity(&self) -> usize {
|
// fn capacity(&self) -> usize {
|
||||||
self.config.update_bank.size as usize
|
// self.config.update_bank.size as usize
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Write Access to the current update target slot
|
// /// Write Access to the current update target slot
|
||||||
impl<
|
// impl<
|
||||||
InternalMemory: Storage,
|
// InternalMemory: Storage,
|
||||||
HardwareState: State,
|
// HardwareState: State,
|
||||||
CPU: Processor,
|
// CPU: Processor,
|
||||||
const INTERNAL_PAGE_SIZE: usize,
|
// const INTERNAL_PAGE_SIZE: usize,
|
||||||
> Storage for MoonbootManager<InternalMemory, HardwareState, CPU, INTERNAL_PAGE_SIZE>
|
// > Storage for MoonbootManager<InternalMemory, HardwareState, CPU, INTERNAL_PAGE_SIZE>
|
||||||
{
|
// {
|
||||||
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
// fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||||
let bank = self.config.update_bank; // For now we always write updates to this bank.
|
// let bank = self.config.update_bank; // For now we always write updates to this bank.
|
||||||
if offset > bank.size || offset + bytes.len() as u32 > bank.size {
|
// if offset > bank.size || offset + bytes.len() as u32 > bank.size {
|
||||||
Err(()) // TODO: We want better error types!
|
// Err(()) // TODO: We want better error types!
|
||||||
} else {
|
// } else {
|
||||||
// TODO! fix
|
// // TODO! fix
|
||||||
let bank_start = bank.location;
|
// let bank_start = bank.location;
|
||||||
log::info!("Writing at {:x}[{:x}]", bank_start, offset);
|
// log::info!("Writing at {:x}[{:x}]", bank_start, offset);
|
||||||
match bank.memory_unit {
|
// match bank.memory_unit {
|
||||||
crate::hardware::MemoryUnit::Internal => {
|
// crate::hardware::MemoryUnit::Internal => {
|
||||||
{ self.internal_memory.write(bank_start + offset, bytes) }.map_err(|_| ())
|
// { self.internal_memory.write(bank_start + offset, bytes) }.map_err(|_| ())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -6,24 +6,22 @@ pub mod scratch;
|
||||||
|
|
||||||
use embedded_storage::Storage;
|
use embedded_storage::Storage;
|
||||||
|
|
||||||
/// Error occured during memory access
|
pub enum ExchangeError<STORAGE, STATE, OTHER> {
|
||||||
#[cfg_attr(feature = "use-defmt", derive(Format))]
|
Storage(STORAGE),
|
||||||
#[derive(Debug)]
|
State(STATE),
|
||||||
pub enum MemoryError {
|
Other(OTHER),
|
||||||
BankSizeNotEqual,
|
|
||||||
BankSizeZero,
|
|
||||||
ReadFailure,
|
|
||||||
WriteFailure,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Abstraction for the exchange operation of the current state.
|
/// Abstraction for the exchange operation of the current state.
|
||||||
pub trait Exchange {
|
pub trait Exchange {
|
||||||
|
type OtherError;
|
||||||
|
|
||||||
fn exchange<STORAGE: Storage, STATE: State, const INTERNAL_PAGE_SIZE: usize>(
|
fn exchange<STORAGE: Storage, STATE: State, const INTERNAL_PAGE_SIZE: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
internal_memory: &mut STORAGE,
|
internal_memory: &mut STORAGE,
|
||||||
state: &mut STATE,
|
state: &mut STATE,
|
||||||
progress: ExchangeProgress,
|
progress: ExchangeProgress,
|
||||||
) -> Result<(), MemoryError>;
|
) -> Result<(), ExchangeError<STORAGE::Error, STATE::Error, Self::OtherError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::hardware::Bank;
|
use crate::hardware::Bank;
|
||||||
|
@ -139,10 +137,12 @@ pub struct MoonbootState {
|
||||||
/// RAM. As long as you don't want to perform update download, power cycle the device, and then
|
/// RAM. As long as you don't want to perform update download, power cycle the device, and then
|
||||||
/// apply the update, storing it in volatile memory is fine.
|
/// apply the update, storing it in volatile memory is fine.
|
||||||
pub trait State {
|
pub trait State {
|
||||||
|
type Error;
|
||||||
|
|
||||||
/// Read the shared state
|
/// Read the shared state
|
||||||
fn read(&mut self) -> MoonbootState;
|
fn read(&mut self) -> Result<MoonbootState, Self::Error>;
|
||||||
/// Write the new state to the shared state
|
/// Write the new state to the shared state
|
||||||
fn write(&mut self, data: &MoonbootState) -> Result<(), ()>;
|
fn write(&mut self, data: &MoonbootState) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Size of the serialized state
|
/// Size of the serialized state
|
||||||
|
|
111
src/state/ram.rs
111
src/state/ram.rs
|
@ -15,7 +15,9 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State for RamState {
|
impl State for RamState {
|
||||||
fn read(&mut self) -> MoonbootState {
|
type Error = void::Void;
|
||||||
|
|
||||||
|
fn read(&mut self) -> Result<MoonbootState, void::Void> {
|
||||||
let crc = unsafe { _moonboot_state_crc_start };
|
let crc = unsafe { _moonboot_state_crc_start };
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
|
@ -28,17 +30,16 @@ impl State for RamState {
|
||||||
if crc == checksum {
|
if crc == checksum {
|
||||||
let data = MoonbootState::deserialize_from(unsafe { &_moonboot_state_data_start });
|
let data = MoonbootState::deserialize_from(unsafe { &_moonboot_state_data_start });
|
||||||
log::trace!("CRC Match! {}: {:?}", crc, data);
|
log::trace!("CRC Match! {}: {:?}", crc, data);
|
||||||
return data;
|
Ok(data)
|
||||||
} else {
|
} else {
|
||||||
log::trace!("CRC Mismatch! {} vs {}", crc, checksum);
|
log::trace!("CRC Mismatch! {} vs {}", crc, checksum);
|
||||||
}
|
Ok(MoonbootState {
|
||||||
|
|
||||||
MoonbootState {
|
|
||||||
update: Update::None,
|
update: Update::None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, data: &MoonbootState) -> Result<(), ()> {
|
fn write(&mut self, data: &MoonbootState) -> Result<(), Self::Error> {
|
||||||
log::trace!("Writing data {:?}", data);
|
log::trace!("Writing data {:?}", data);
|
||||||
|
|
||||||
unsafe { _moonboot_state_data_start = data.serialize() };
|
unsafe { _moonboot_state_data_start = data.serialize() };
|
||||||
|
@ -58,28 +59,21 @@ impl State for RamState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Exchange for RamState {
|
impl Exchange for RamState {
|
||||||
fn exchange<InternalMemory: Storage, HardwareState: State, const INTERNAL_PAGE_SIZE: usize>(
|
type OtherError = void::Void;
|
||||||
|
|
||||||
|
fn exchange<STORAGE: Storage, STATE: State, const INTERNAL_PAGE_SIZE: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
internal_memory: &mut InternalMemory,
|
storage: &mut STORAGE,
|
||||||
state: &mut HardwareState,
|
state: &mut STATE,
|
||||||
exchange: ExchangeProgress,
|
progress: ExchangeProgress,
|
||||||
) -> Result<(), MemoryError> {
|
) -> Result<(), ExchangeError<STORAGE::Error, STATE::Error, Self::OtherError>> {
|
||||||
let ExchangeProgress {
|
let ExchangeProgress {
|
||||||
a,
|
a,
|
||||||
b,
|
b,
|
||||||
page_index,
|
page_index,
|
||||||
step,
|
step,
|
||||||
..
|
..
|
||||||
} = exchange;
|
} = progress;
|
||||||
|
|
||||||
// TODO: Sanity Check start_index
|
|
||||||
if a.size != b.size {
|
|
||||||
return Err(MemoryError::BankSizeNotEqual);
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.size == 0 || b.size == 0 {
|
|
||||||
return Err(MemoryError::BankSizeZero);
|
|
||||||
}
|
|
||||||
|
|
||||||
let size = a.size; // Both are equal
|
let size = a.size; // Both are equal
|
||||||
|
|
||||||
|
@ -88,41 +82,36 @@ impl Exchange for RamState {
|
||||||
|
|
||||||
let mut page_a_buf = [0_u8; 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 page_b_buf = [0_u8; INTERNAL_PAGE_SIZE];
|
||||||
// can we reduce this to 1 buf and fancy operations?
|
|
||||||
// probably not with the read/write API.
|
|
||||||
// classic memory exchange problem :)
|
|
||||||
|
|
||||||
let mut last_state = state.read();
|
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
|
// Set this in the exchanging part to know whether we are in a recovery process from a
|
||||||
// failed update or on the initial update
|
// failed update or on the initial update
|
||||||
let recovering = matches!(last_state.update, Update::Revert(_));
|
let recovering = matches!(last_state.update, Update::Revert(_));
|
||||||
|
|
||||||
// TODO: Fix
|
|
||||||
let a_location = a.location;
|
|
||||||
let b_location = b.location;
|
|
||||||
|
|
||||||
for page_index in page_index..full_pages {
|
for page_index in page_index..full_pages {
|
||||||
let offset = page_index * INTERNAL_PAGE_SIZE as u32;
|
let offset = page_index * INTERNAL_PAGE_SIZE as u32;
|
||||||
|
let a_location = a.location + offset;
|
||||||
|
let b_location = b.location + offset;
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"Exchange: Page {}, from a ({}) to b ({})",
|
"Exchange: Page {}, from a ({}) to b ({})",
|
||||||
page_index,
|
page_index,
|
||||||
a_location + offset,
|
a_location,
|
||||||
b_location + offset
|
b_location
|
||||||
);
|
);
|
||||||
|
|
||||||
internal_memory
|
storage
|
||||||
.read(a_location + offset, &mut page_a_buf)
|
.read(a_location, &mut page_a_buf)
|
||||||
.map_err(|_| MemoryError::ReadFailure)?;
|
.map_err(ExchangeError::Storage)?;
|
||||||
internal_memory
|
storage
|
||||||
.read(b_location + offset, &mut page_b_buf)
|
.read(b_location, &mut page_b_buf)
|
||||||
.map_err(|_| MemoryError::ReadFailure)?;
|
.map_err(ExchangeError::Storage)?;
|
||||||
internal_memory
|
storage
|
||||||
.write(a_location + offset, &page_b_buf)
|
.write(a_location, &page_b_buf)
|
||||||
.map_err(|_| MemoryError::WriteFailure)?;
|
.map_err(ExchangeError::Storage)?;
|
||||||
internal_memory
|
storage
|
||||||
.write(b_location + offset, &page_a_buf)
|
.write(b_location, &page_a_buf)
|
||||||
.map_err(|_| MemoryError::WriteFailure)?;
|
.map_err(ExchangeError::Storage)?;
|
||||||
|
|
||||||
// Store the exchange progress
|
// Store the exchange progress
|
||||||
|
|
||||||
|
@ -134,32 +123,26 @@ impl Exchange for RamState {
|
||||||
step,
|
step,
|
||||||
});
|
});
|
||||||
|
|
||||||
state
|
state.write(&last_state).map_err(ExchangeError::State)?;
|
||||||
.write(&last_state)
|
|
||||||
.map_err(|_| MemoryError::WriteFailure)?;
|
|
||||||
}
|
}
|
||||||
// TODO: Fit this into the while loop
|
// TODO: Fit this into the while loop
|
||||||
if remaining_page_length > 0 {
|
if remaining_page_length > 0 {
|
||||||
let offset = full_pages * INTERNAL_PAGE_SIZE as u32;
|
let offset = full_pages * INTERNAL_PAGE_SIZE as u32;
|
||||||
|
let a_location = a.location + offset;
|
||||||
|
let b_location = b.location + offset;
|
||||||
|
|
||||||
internal_memory
|
storage
|
||||||
.read(
|
.read(a_location, &mut page_a_buf[0..remaining_page_length])
|
||||||
a.location + offset,
|
.map_err(ExchangeError::Storage)?;
|
||||||
&mut page_a_buf[0..remaining_page_length],
|
storage
|
||||||
)
|
.read(b_location, &mut page_b_buf[0..remaining_page_length])
|
||||||
.map_err(|_| MemoryError::ReadFailure)?;
|
.map_err(ExchangeError::Storage)?;
|
||||||
internal_memory
|
storage
|
||||||
.read(
|
.write(a_location, &page_a_buf[0..remaining_page_length])
|
||||||
b.location + offset,
|
.map_err(ExchangeError::Storage)?;
|
||||||
&mut page_b_buf[0..remaining_page_length],
|
storage
|
||||||
)
|
.write(b_location + offset, &page_b_buf[0..remaining_page_length])
|
||||||
.map_err(|_| MemoryError::ReadFailure)?;
|
.map_err(ExchangeError::Storage)?;
|
||||||
internal_memory
|
|
||||||
.write(a.location + offset, &page_a_buf[0..remaining_page_length])
|
|
||||||
.map_err(|_| MemoryError::WriteFailure)?;
|
|
||||||
internal_memory
|
|
||||||
.write(b.location + offset, &page_b_buf[0..remaining_page_length])
|
|
||||||
.map_err(|_| MemoryError::WriteFailure)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue