Align tests

This commit is contained in:
Rasmus Melchior Jacobsen 2023-05-30 13:55:49 +02:00
parent 551f76c700
commit c6a984f506
4 changed files with 162 additions and 117 deletions

View File

@ -40,7 +40,7 @@ where
/// If only a single flash is actually used, then that flash should be partitioned into three partitions before use. /// If only a single flash is actually used, then that flash should be partitioned into three partitions before use.
/// The easiest way to do this is to use [`BootLoaderConfig::from_linkerfile_blocking`] which will partition /// The easiest way to do this is to use [`BootLoaderConfig::from_linkerfile_blocking`] which will partition
/// the provided flash according to symbols defined in the linkerfile. /// the provided flash according to symbols defined in the linkerfile.
pub struct BootLoaderConfig<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> { pub struct BootLoaderConfig<ACTIVE, DFU, STATE> {
/// Flash type used for the active partition - the partition which will be booted from. /// Flash type used for the active partition - the partition which will be booted from.
pub active: ACTIVE, pub active: ACTIVE,
/// Flash type used for the dfu partition - the partition which will be swapped in when requested. /// Flash type used for the dfu partition - the partition which will be swapped in when requested.

View File

@ -51,10 +51,18 @@ impl<const N: usize> AsMut<[u8]> for AlignedBuffer<N> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
#[cfg(feature = "nightly")]
use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash;
use futures::executor::block_on; use futures::executor::block_on;
use super::*; use super::*;
use crate::boot_loader::BootLoaderConfig;
use crate::firmware_updater::FirmwareUpdaterConfig;
use crate::mem_flash::MemFlash; use crate::mem_flash::MemFlash;
#[cfg(feature = "nightly")]
use crate::test_flash::AsyncTestFlash;
use crate::test_flash::BlockingTestFlash;
/* /*
#[test] #[test]
@ -73,147 +81,173 @@ mod tests {
#[test] #[test]
fn test_boot_state() { fn test_boot_state() {
const STATE: Partition = Partition::new(0, 4096); let flash = BlockingTestFlash::new(BootLoaderConfig {
const ACTIVE: Partition = Partition::new(4096, 61440); active: MemFlash::<57344, 4096, 4>::default(),
const DFU: Partition = Partition::new(61440, 122880); dfu: MemFlash::<61440, 4096, 4>::default(),
state: MemFlash::<4096, 4096, 4>::default(),
});
let mut flash = MemFlash::<131072, 4096, 4>::default(); flash.state().write(0, &[BOOT_MAGIC; 4]).unwrap();
flash.mem[0..4].copy_from_slice(&[BOOT_MAGIC; 4]);
let mut flash = SingleFlashConfig::new(&mut flash);
let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); let mut bootloader = BootLoader::new(BootLoaderConfig {
active: flash.active(),
dfu: flash.dfu(),
state: flash.state(),
});
let mut page = [0; 4096]; let mut page = [0; 4096];
assert_eq!(State::Boot, bootloader.prepare_boot(&mut flash, &mut page).unwrap()); assert_eq!(State::Boot, bootloader.prepare_boot(&mut page).unwrap());
} }
#[test] #[test]
#[cfg(all(feature = "nightly", not(feature = "_verify")))] #[cfg(all(feature = "nightly", not(feature = "_verify")))]
fn test_swap_state() { fn test_swap_state() {
const STATE: Partition = Partition::new(0, 4096); const FIRMWARE_SIZE: usize = 57344;
const ACTIVE: Partition = Partition::new(4096, 61440); let flash = AsyncTestFlash::new(BootLoaderConfig {
const DFU: Partition = Partition::new(61440, 122880); active: MemFlash::<FIRMWARE_SIZE, 4096, 4>::default(),
let mut flash = MemFlash::<131072, 4096, 4>::random(); dfu: MemFlash::<61440, 4096, 4>::default(),
state: MemFlash::<4096, 4096, 4>::default(),
});
let original = [rand::random::<u8>(); ACTIVE.size() as usize]; const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE];
let update = [rand::random::<u8>(); ACTIVE.size() as usize]; const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE];
let mut aligned = [0; 4]; let mut aligned = [0; 4];
flash.program(ACTIVE.from, &original).unwrap(); block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap();
block_on(flash.active().write(0, &ORIGINAL)).unwrap();
let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig {
let mut updater = FirmwareUpdater::new(DFU, STATE); dfu: flash.dfu(),
block_on(updater.write_firmware(0, &update, &mut flash)).unwrap(); state: flash.state(),
block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap(); });
block_on(updater.write_firmware(0, &UPDATE)).unwrap();
block_on(updater.mark_updated(&mut aligned)).unwrap();
let flash = flash.into_blocking();
let mut bootloader = BootLoader::new(BootLoaderConfig {
active: flash.active(),
dfu: flash.dfu(),
state: flash.state(),
});
let mut page = [0; 1024]; let mut page = [0; 1024];
assert_eq!( assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
State::Swap,
bootloader
.prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page)
.unwrap()
);
flash.assert_eq(ACTIVE.from, &update); let mut read_buf = [0; FIRMWARE_SIZE];
flash.active().read(0, &mut read_buf).unwrap();
assert_eq!(UPDATE, read_buf);
// First DFU page is untouched // First DFU page is untouched
flash.assert_eq(DFU.from + 4096, &original); flash.dfu().read(4096, &mut read_buf).unwrap();
assert_eq!(ORIGINAL, read_buf);
// Running again should cause a revert // Running again should cause a revert
assert_eq!( assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
State::Swap,
bootloader
.prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page)
.unwrap()
);
flash.assert_eq(ACTIVE.from, &original); let mut read_buf = [0; FIRMWARE_SIZE];
// Last page is untouched flash.active().read(0, &mut read_buf).unwrap();
flash.assert_eq(DFU.from, &update); assert_eq!(ORIGINAL, read_buf);
// Last DFU page is untouched
flash.dfu().read(0, &mut read_buf).unwrap();
assert_eq!(UPDATE, read_buf);
// Mark as booted // Mark as booted
block_on(updater.mark_booted(&mut flash, &mut aligned)).unwrap(); let flash = flash.into_async();
assert_eq!( let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig {
State::Boot, dfu: flash.dfu(),
bootloader state: flash.state(),
.prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page) });
.unwrap() block_on(updater.mark_booted(&mut aligned)).unwrap();
);
let flash = flash.into_blocking();
let mut bootloader = BootLoader::new(BootLoaderConfig {
active: flash.active(),
dfu: flash.dfu(),
state: flash.state(),
});
assert_eq!(State::Boot, bootloader.prepare_boot(&mut page).unwrap());
} }
#[test] #[test]
#[cfg(all(feature = "nightly", not(feature = "_verify")))] #[cfg(all(feature = "nightly", not(feature = "_verify")))]
fn test_separate_flash_active_page_biggest() { fn test_swap_state_active_page_biggest() {
const STATE: Partition = Partition::new(2048, 4096); const FIRMWARE_SIZE: usize = 12288;
const ACTIVE: Partition = Partition::new(4096, 16384); let flash = AsyncTestFlash::new(BootLoaderConfig {
const DFU: Partition = Partition::new(0, 16384); active: MemFlash::<12288, 4096, 8>::random(),
dfu: MemFlash::<16384, 2048, 8>::random(),
state: MemFlash::<2048, 128, 4>::random(),
});
let mut active = MemFlash::<16384, 4096, 8>::random(); const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE];
let mut dfu = MemFlash::<16384, 2048, 8>::random(); const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE];
let mut state = MemFlash::<4096, 128, 4>::random();
let mut aligned = [0; 4]; let mut aligned = [0; 4];
let original = [rand::random::<u8>(); ACTIVE.size() as usize]; block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap();
let update = [rand::random::<u8>(); ACTIVE.size() as usize]; block_on(flash.active().write(0, &ORIGINAL)).unwrap();
active.program(ACTIVE.from, &original).unwrap(); let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig {
dfu: flash.dfu(),
state: flash.state(),
});
block_on(updater.write_firmware(0, &UPDATE)).unwrap();
block_on(updater.mark_updated(&mut aligned)).unwrap();
let mut updater = FirmwareUpdater::new(DFU, STATE); let flash = flash.into_blocking();
let mut bootloader = BootLoader::new(BootLoaderConfig {
active: flash.active(),
dfu: flash.dfu(),
state: flash.state(),
});
block_on(updater.write_firmware(0, &update, &mut dfu)).unwrap();
block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap();
let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
let mut page = [0; 4096]; let mut page = [0; 4096];
assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
assert_eq!( let mut read_buf = [0; FIRMWARE_SIZE];
State::Swap, flash.active().read(0, &mut read_buf).unwrap();
bootloader assert_eq!(UPDATE, read_buf);
.prepare_boot(&mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu), &mut page)
.unwrap()
);
active.assert_eq(ACTIVE.from, &update);
// First DFU page is untouched // First DFU page is untouched
dfu.assert_eq(DFU.from + 4096, &original); flash.dfu().read(4096, &mut read_buf).unwrap();
assert_eq!(ORIGINAL, read_buf);
} }
#[test] #[test]
#[cfg(all(feature = "nightly", not(feature = "_verify")))] #[cfg(all(feature = "nightly", not(feature = "_verify")))]
fn test_separate_flash_dfu_page_biggest() { fn test_swap_state_dfu_page_biggest() {
const STATE: Partition = Partition::new(2048, 4096); const FIRMWARE_SIZE: usize = 12288;
const ACTIVE: Partition = Partition::new(4096, 16384); let flash = AsyncTestFlash::new(BootLoaderConfig {
const DFU: Partition = Partition::new(0, 16384); active: MemFlash::<FIRMWARE_SIZE, 2048, 4>::random(),
dfu: MemFlash::<16384, 4096, 8>::random(),
state: MemFlash::<2048, 128, 4>::random(),
});
const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE];
const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE];
let mut aligned = [0; 4]; let mut aligned = [0; 4];
let mut active = MemFlash::<16384, 2048, 4>::random();
let mut dfu = MemFlash::<16384, 4096, 8>::random();
let mut state = MemFlash::<4096, 128, 4>::random();
let original = [rand::random::<u8>(); ACTIVE.size() as usize]; block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap();
let update = [rand::random::<u8>(); ACTIVE.size() as usize]; block_on(flash.active().write(0, &ORIGINAL)).unwrap();
active.program(ACTIVE.from, &original).unwrap(); let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig {
dfu: flash.dfu(),
state: flash.state(),
});
block_on(updater.write_firmware(0, &UPDATE)).unwrap();
block_on(updater.mark_updated(&mut aligned)).unwrap();
let mut updater = FirmwareUpdater::new(DFU, STATE); let flash = flash.into_blocking();
let mut bootloader = BootLoader::new(BootLoaderConfig {
block_on(updater.write_firmware(0, &update, &mut dfu)).unwrap(); active: flash.active(),
block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); dfu: flash.dfu(),
state: flash.state(),
let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); });
let mut page = [0; 4096]; let mut page = [0; 4096];
assert_eq!( assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
State::Swap,
bootloader
.prepare_boot(
&mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu,),
&mut page
)
.unwrap()
);
active.assert_eq(ACTIVE.from, &update); let mut read_buf = [0; FIRMWARE_SIZE];
flash.active().read(0, &mut read_buf).unwrap();
assert_eq!(UPDATE, read_buf);
// First DFU page is untouched // First DFU page is untouched
dfu.assert_eq(DFU.from + 4096, &original); flash.dfu().read(4096, &mut read_buf).unwrap();
assert_eq!(ORIGINAL, read_buf);
} }
#[test] #[test]
@ -239,25 +273,25 @@ mod tests {
let public_key: PublicKey = keypair.public; let public_key: PublicKey = keypair.public;
// Setup flash // Setup flash
let flash = BlockingTestFlash::new(BootLoaderConfig {
const STATE: Partition = Partition::new(0, 4096); active: MemFlash::<0, 0, 0>::default(),
const DFU: Partition = Partition::new(4096, 8192); dfu: MemFlash::<4096, 4096, 4>::default(),
let mut flash = MemFlash::<8192, 4096, 4>::default(); state: MemFlash::<4096, 4096, 4>::default(),
});
let firmware_len = firmware.len(); let firmware_len = firmware.len();
let mut write_buf = [0; 4096]; let mut write_buf = [0; 4096];
write_buf[0..firmware_len].copy_from_slice(firmware); write_buf[0..firmware_len].copy_from_slice(firmware);
DFU.write_blocking(&mut flash, 0, &write_buf).unwrap(); flash.dfu().write(0, &write_buf).unwrap();
// On with the test // On with the test
let flash = flash.into_async();
let mut updater = FirmwareUpdater::new(DFU, STATE); let mut updater = FirmwareUpdater::new(flash.dfu(), flash.state());
let mut aligned = [0; 4]; let mut aligned = [0; 4];
assert!(block_on(updater.verify_and_mark_updated( assert!(block_on(updater.verify_and_mark_updated(
&mut flash,
&public_key.to_bytes(), &public_key.to_bytes(),
&signature.to_bytes(), &signature.to_bytes(),
firmware_len as u32, firmware_len as u32,

View File

@ -3,6 +3,8 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
use embedded_storage_async::nor_flash::NorFlash; use embedded_storage_async::nor_flash::NorFlash;
use crate::BootLoaderConfig;
pub struct AsyncTestFlash<ACTIVE, DFU, STATE> pub struct AsyncTestFlash<ACTIVE, DFU, STATE>
where where
ACTIVE: NorFlash, ACTIVE: NorFlash,
@ -20,11 +22,11 @@ where
DFU: NorFlash, DFU: NorFlash,
STATE: NorFlash, STATE: NorFlash,
{ {
pub fn new(active: ACTIVE, dfu: DFU, state: STATE) -> Self { pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self {
Self { Self {
active: Mutex::new(active), active: Mutex::new(config.active),
dfu: Mutex::new(dfu), dfu: Mutex::new(config.dfu),
state: Mutex::new(state), state: Mutex::new(config.state),
} }
} }
@ -52,6 +54,11 @@ where
STATE: NorFlash + embedded_storage::nor_flash::NorFlash, STATE: NorFlash + embedded_storage::nor_flash::NorFlash,
{ {
pub fn into_blocking(self) -> super::BlockingTestFlash<ACTIVE, DFU, STATE> { pub fn into_blocking(self) -> super::BlockingTestFlash<ACTIVE, DFU, STATE> {
super::BlockingTestFlash::new(self.active.into_inner(), self.dfu.into_inner(), self.state.into_inner()) let config = BootLoaderConfig {
active: self.active.into_inner(),
dfu: self.dfu.into_inner(),
state: self.state.into_inner(),
};
super::BlockingTestFlash::new(config)
} }
} }

View File

@ -5,6 +5,8 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::blocking_mutex::Mutex; use embassy_sync::blocking_mutex::Mutex;
use embedded_storage::nor_flash::NorFlash; use embedded_storage::nor_flash::NorFlash;
use crate::BootLoaderConfig;
pub struct BlockingTestFlash<ACTIVE, DFU, STATE> pub struct BlockingTestFlash<ACTIVE, DFU, STATE>
where where
ACTIVE: NorFlash, ACTIVE: NorFlash,
@ -22,11 +24,11 @@ where
DFU: NorFlash, DFU: NorFlash,
STATE: NorFlash, STATE: NorFlash,
{ {
pub fn new(active: ACTIVE, dfu: DFU, state: STATE) -> Self { pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self {
Self { Self {
active: Mutex::new(RefCell::new(active)), active: Mutex::new(RefCell::new(config.active)),
dfu: Mutex::new(RefCell::new(dfu)), dfu: Mutex::new(RefCell::new(config.dfu)),
state: Mutex::new(RefCell::new(state)), state: Mutex::new(RefCell::new(config.state)),
} }
} }
@ -49,6 +51,7 @@ where
} }
} }
#[cfg(feature = "nightly")]
impl<ACTIVE, DFU, STATE> BlockingTestFlash<ACTIVE, DFU, STATE> impl<ACTIVE, DFU, STATE> BlockingTestFlash<ACTIVE, DFU, STATE>
where where
ACTIVE: NorFlash + embedded_storage_async::nor_flash::NorFlash, ACTIVE: NorFlash + embedded_storage_async::nor_flash::NorFlash,
@ -56,10 +59,11 @@ where
STATE: NorFlash + embedded_storage_async::nor_flash::NorFlash, STATE: NorFlash + embedded_storage_async::nor_flash::NorFlash,
{ {
pub fn into_async(self) -> super::AsyncTestFlash<ACTIVE, DFU, STATE> { pub fn into_async(self) -> super::AsyncTestFlash<ACTIVE, DFU, STATE> {
super::AsyncTestFlash::new( let config = BootLoaderConfig {
self.active.into_inner().into_inner(), active: self.active.into_inner().into_inner(),
self.dfu.into_inner().into_inner(), dfu: self.dfu.into_inner().into_inner(),
self.state.into_inner().into_inner(), state: self.state.into_inner().into_inner(),
) };
super::AsyncTestFlash::new(config)
} }
} }