wip: Add sim support for loaded images
For developing new functionality, allow the simulator to test using a
loaded image. For this particular case, for example, we could test
ecdsa booting with the following:
$ dd if=/dev/zero bs=128 of=header.bin
$ dd if=/dev/random bs=1024 count=2 of=payload.bin
$ cat header.bin payload.bin loaded.bin
$ ../scripts/imgtool.py sign \
-k ../root-ec-p256.pem \
--align 8 \
--version 1.2.3 \
--header-size 128 \
-S 16384 \
loaded.bin loaded.suit
$ cargo test \
--features "overwrite-only validate-primary-slot sig-ecdsa" \
-- --nocapture --test-threads 1 \
external_load
Signed-off-by: David Brown <david.brown@linaro.org>
diff --git a/sim/src/image.rs b/sim/src/image.rs
index ae0c26f..2704a19 100644
--- a/sim/src/image.rs
+++ b/sim/src/image.rs
@@ -20,8 +20,10 @@
};
use std::{
collections::{BTreeMap, HashSet},
- io::{Cursor, Write},
+ fs::File,
+ io::{Cursor, Read, Write},
mem,
+ path::Path,
slice,
};
use aes_ctr::{
@@ -282,6 +284,35 @@
}
}
+ pub fn make_loaded_image<P>(self, path: P) -> Images
+ where P: AsRef<Path>,
+ {
+ // let num_images = self.num_images();
+ let mut flash = self.flash;
+ // let ram = self.ram.clone(); // TODO: Avoid this clone.
+ let images = self.slots.into_iter().enumerate().map(|(_image_num, slots)| {
+ let primaries = load_image(&mut flash, &slots[0], path.as_ref());
+ /*
+ let upgrades = match deps.depends[image_num] {
+ DepType::NoUpgrade => install_no_image(),
+ _ => todo!(), // install_image(&mut flash, &slots[1], size, &ram, &*dep, false)
+ };
+ */
+ let upgrades = install_no_image();
+ OneImage {
+ slots,
+ primaries,
+ upgrades,
+ }}).collect();
+ Images {
+ flash,
+ areadesc: self.areadesc,
+ images,
+ total_count: None,
+ ram: self.ram,
+ }
+ }
+
pub fn make_erased_secondary_image(self) -> Images {
let mut flash = self.flash;
let ram = self.ram.clone(); // TODO: Avoid this clone.
@@ -1081,6 +1112,18 @@
return false;
}
+ /// Verify a normal boot works on the first image.
+ pub fn test_normal_boot(&self) -> bool {
+ let mut flash = self.flash.clone();
+
+ if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
+ warn!("Failed to boot image");
+ return true;
+ }
+
+ false
+ }
+
/// Adds a new flash area that fails statistically
fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
rate: f32) {
@@ -1579,6 +1622,37 @@
}
}
+/// Install an image coming from an external file. Returns a copy of the image that was written.
+fn load_image(flash: &mut SimMultiFlash, slot: &SlotInfo, path: &Path) -> ImageData {
+ let mut buf = vec![];
+ // This is not in a Result context, so just expect these.
+ File::open(path).expect("open image file").read_to_end(&mut buf).expect("read data from image file");
+
+ // Corrupt the image so that it doesn't validate.
+ // buf[1025] ^= 1;
+
+ // Corrupt the image.
+ buf[1025] ^= 1;
+
+ // Pad the image to the largest alignment.
+ while buf.len() & 15 != 0 {
+ buf.push(0xFF);
+ }
+
+ let offset = slot.base_off;
+ let dev_id = slot.dev_id;
+ let dev = flash.get_mut(&dev_id).unwrap();
+
+ dev.write(offset, &buf).unwrap();
+ let mut copy = vec![0u8; buf.len()];
+ dev.read(offset, &mut copy).unwrap();
+
+ ImageData {
+ plain: copy,
+ cipher: None,
+ }
+}
+
/// Install no image. This is used when no upgrade happens.
fn install_no_image() -> ImageData {
ImageData {
diff --git a/sim/tests/core.rs b/sim/tests/core.rs
index ca91bbb..b394ff5 100644
--- a/sim/tests/core.rs
+++ b/sim/tests/core.rs
@@ -62,6 +62,8 @@
sim_test!(direct_xip_first, make_no_upgrade_image(&NO_DEPS), run_direct_xip());
sim_test!(ram_load_first, make_no_upgrade_image(&NO_DEPS), run_ram_load());
+sim_test!(external_load, make_loaded_image("loaded.suit"), test_normal_boot());
+
// Test various combinations of incorrect dependencies.
test_shell!(dependency_combos, r, {
// Only test setups with two images.