From 1e1c174f32b3487062c3c35cd6a1c1d6e1002cf3 Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Tue, 12 Jul 2022 08:57:14 +0200 Subject: [PATCH] Moved exchange back into separate module --- src/boot/mod.rs | 3 +- src/exchange/mod.rs | 18 ++++ src/exchange/ram.rs | 127 +++++++++++++++++++++++++++++ src/{state => exchange}/scratch.rs | 3 +- src/lib.rs | 4 +- src/state/mod.rs | 16 ---- src/state/ram.rs | 121 +-------------------------- 7 files changed, 153 insertions(+), 139 deletions(-) create mode 100644 src/exchange/mod.rs create mode 100644 src/exchange/ram.rs rename src/{state => exchange}/scratch.rs (98%) diff --git a/src/boot/mod.rs b/src/boot/mod.rs index aad1abb..7d09796 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -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, }; diff --git a/src/exchange/mod.rs b/src/exchange/mod.rs new file mode 100644 index 0000000..6f7592e --- /dev/null +++ b/src/exchange/mod.rs @@ -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 { + type Error: core::fmt::Debug; + + fn exchange( + &mut self, + storage: &mut STORAGE, + state: &mut STATE, + progress: ExchangeProgress, + ) -> Result<(), Self::Error>; +} diff --git a/src/exchange/ram.rs b/src/exchange/ram.rs new file mode 100644 index 0000000..9be9f9a --- /dev/null +++ b/src/exchange/ram.rs @@ -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(STORAGE), + State(STATE), +} + +impl core::fmt::Debug for ExchangeError +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 Exchange for Ram +where + STORAGE::Error: core::fmt::Debug, + STATE::Error: core::fmt::Debug, +{ + type Error = ExchangeError; + + fn exchange( + &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(()) + } +} diff --git a/src/state/scratch.rs b/src/exchange/scratch.rs similarity index 98% rename from src/state/scratch.rs rename to src/exchange/scratch.rs index e8eddec..67e4e4b 100644 --- a/src/state/scratch.rs +++ b/src/exchange/scratch.rs @@ -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, }; diff --git a/src/lib.rs b/src/lib.rs index 37942b6..d11600c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; + type Exchange: exchange::Exchange; } #[cfg(not(any(feature = "use-log", feature = "use-defmt")))] diff --git a/src/state/mod.rs b/src/state/mod.rs index bed0480..18501c6 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -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 { - type Error: Debug; - - fn exchange( - &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 diff --git a/src/state/ram.rs b/src/state/ram.rs index dd61c3a..4601edf 100644 --- a/src/state/ram.rs +++ b/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(STORAGE), - State(STATE), -} - -impl Debug for ExchangeError -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 Exchange for RamState -where - STORAGE::Error: Debug, - STATE::Error: Debug, -{ - type Error = ExchangeError; - - fn exchange( - &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(()) - } -}