blob: ae0c26fa2d7b30d146b61582957379d136d0453c [file] [log] [blame]
David Browne2acfae2020-01-21 16:45:01 -07001// Copyright (c) 2019 Linaro LTD
2// Copyright (c) 2019-2020 JUUL Labs
Salome Thirot6fdbf552021-05-14 16:46:14 +01003// Copyright (c) 2019-2021 Arm Limited
David Browne2acfae2020-01-21 16:45:01 -07004//
5// SPDX-License-Identifier: Apache-2.0
6
David Brown297029a2019-08-13 14:29:51 -06007use byteorder::{
8 LittleEndian, WriteBytesExt,
9};
10use log::{
11 Level::Info,
12 error,
13 info,
14 log_enabled,
15 warn,
16};
David Brown5c9e0f12019-01-09 16:34:33 -070017use rand::{
David Browncd842842020-07-09 15:46:53 -060018 Rng, RngCore, SeedableRng,
19 rngs::SmallRng,
David Brown5c9e0f12019-01-09 16:34:33 -070020};
21use std::{
David Brownbf32c272021-06-16 17:11:37 -060022 collections::{BTreeMap, HashSet},
David Browncb47dd72019-08-05 14:21:49 -060023 io::{Cursor, Write},
David Brown5c9e0f12019-01-09 16:34:33 -070024 mem,
25 slice,
26};
27use aes_ctr::{
28 Aes128Ctr,
Salome Thirot6fdbf552021-05-14 16:46:14 +010029 Aes256Ctr,
David Brown5c9e0f12019-01-09 16:34:33 -070030 stream_cipher::{
31 generic_array::GenericArray,
David Brown8a99adf2020-07-09 16:52:38 -060032 NewStreamCipher,
33 SyncStreamCipher,
David Brown5c9e0f12019-01-09 16:34:33 -070034 },
35};
36
David Brown76101572019-02-28 11:29:03 -070037use simflash::{Flash, SimFlash, SimMultiFlash};
David Brown8a4e23b2021-06-11 10:29:01 -060038use mcuboot_sys::{c, AreaDesc, FlashId, RamBlock};
David Browne5133242019-02-28 11:05:19 -070039use crate::{
40 ALL_DEVICES,
41 DeviceName,
42};
David Brown5c9e0f12019-01-09 16:34:33 -070043use crate::caps::Caps;
David Brownc3898d62019-08-05 14:20:02 -060044use crate::depends::{
45 BoringDep,
46 Depender,
47 DepTest,
David Brown873be312019-09-03 12:22:32 -060048 DepType,
David Brown2ee5f7f2020-01-13 14:04:01 -070049 NO_DEPS,
David Brownc3898d62019-08-05 14:20:02 -060050 PairDep,
51 UpgradeInfo,
52};
Fabio Utzig90f449e2019-10-24 07:43:53 -030053use crate::tlv::{ManifestGen, TlvGen, TlvFlags};
Salome Thirot6fdbf552021-05-14 16:46:14 +010054use typenum::{U32, U16};
David Brown5c9e0f12019-01-09 16:34:33 -070055
David Brown8a4e23b2021-06-11 10:29:01 -060056/// For testing, use a non-zero offset for the ram-load, to make sure the offset is getting used
57/// properly, but the value is not really that important.
58const RAM_LOAD_ADDR: u32 = 1024;
59
David Browne5133242019-02-28 11:05:19 -070060/// A builder for Images. This describes a single run of the simulator,
61/// capturing the configuration of a particular set of devices, including
62/// the flash simulator(s) and the information about the slots.
63#[derive(Clone)]
64pub struct ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070065 flash: SimMultiFlash,
David Browne5133242019-02-28 11:05:19 -070066 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070067 slots: Vec<[SlotInfo; 2]>,
David Brownbf32c272021-06-16 17:11:37 -060068 ram: RamData,
David Browne5133242019-02-28 11:05:19 -070069}
70
David Brown998aa8d2019-02-28 10:54:50 -070071/// Images represents the state of a simulation for a given set of images.
David Brown76101572019-02-28 11:29:03 -070072/// The flash holds the state of the simulated flash, whereas primaries
David Brown998aa8d2019-02-28 10:54:50 -070073/// and upgrades hold the expected contents of these images.
74pub struct Images {
David Brown76101572019-02-28 11:29:03 -070075 flash: SimMultiFlash,
David Brownca234692019-02-28 11:22:19 -070076 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070077 images: Vec<OneImage>,
78 total_count: Option<i32>,
David Brownbf32c272021-06-16 17:11:37 -060079 ram: RamData,
David Brown84b49f72019-03-01 10:58:22 -070080}
81
82/// When doing multi-image, there is an instance of this information for
83/// each of the images. Single image there will be one of these.
84struct OneImage {
David Brownca234692019-02-28 11:22:19 -070085 slots: [SlotInfo; 2],
86 primaries: ImageData,
87 upgrades: ImageData,
David Brownca234692019-02-28 11:22:19 -070088}
89
90/// The Rust-side representation of an image. For unencrypted images, this
91/// is just the unencrypted payload. For encrypted images, we store both
92/// the encrypted and the plaintext.
93struct ImageData {
94 plain: Vec<u8>,
95 cipher: Option<Vec<u8>>,
David Brown998aa8d2019-02-28 10:54:50 -070096}
97
David Brownbf32c272021-06-16 17:11:37 -060098/// For the RamLoad test cases, we need a contiguous area of RAM to load these images into. For
99/// multi-image builds, these may not correspond with the offsets. This has to be computed early,
100/// before images are built, because each image contains the offset where the image is to be loaded
101/// in the header, which is contained within the signature.
102#[derive(Clone, Debug)]
103struct RamData {
104 places: BTreeMap<SlotKey, SlotPlace>,
105 total: u32,
106}
107
108/// Every slot is indexed by this key.
109#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
110struct SlotKey {
111 dev_id: u8,
David Brownf17d3912021-06-23 16:10:51 -0600112 base_off: usize,
David Brownbf32c272021-06-16 17:11:37 -0600113}
114
115#[derive(Clone, Debug)]
116struct SlotPlace {
117 offset: u32,
118 size: u32,
119}
120
David Browne5133242019-02-28 11:05:19 -0700121impl ImagesBuilder {
David Brown5bc62c62019-03-05 12:11:48 -0700122 /// Construct a new image builder for the given device. Returns
123 /// Some(builder) if is possible to test this configuration, or None if
124 /// not possible (for example, if there aren't enough image slots).
Fabio Utzig114a6472019-11-28 10:24:09 -0300125 pub fn new(device: DeviceName, align: usize, erased_val: u8) -> Result<Self, String> {
126 let (flash, areadesc, unsupported_caps) = Self::make_device(device, align, erased_val);
127
128 for cap in unsupported_caps {
129 if cap.present() {
130 return Err(format!("unsupported {:?}", cap));
131 }
132 }
David Browne5133242019-02-28 11:05:19 -0700133
David Brown06ef06e2019-03-05 12:28:10 -0700134 let num_images = Caps::get_num_images();
David Browne5133242019-02-28 11:05:19 -0700135
David Brown06ef06e2019-03-05 12:28:10 -0700136 let mut slots = Vec::with_capacity(num_images);
137 for image in 0..num_images {
138 // This mapping must match that defined in
139 // `boot/zephyr/include/sysflash/sysflash.h`.
140 let id0 = match image {
141 0 => FlashId::Image0,
142 1 => FlashId::Image2,
143 _ => panic!("More than 2 images not supported"),
144 };
145 let (primary_base, primary_len, primary_dev_id) = match areadesc.find(id0) {
146 Some(info) => info,
Fabio Utzig114a6472019-11-28 10:24:09 -0300147 None => return Err("insufficient partitions".to_string()),
David Brown06ef06e2019-03-05 12:28:10 -0700148 };
149 let id1 = match image {
150 0 => FlashId::Image1,
151 1 => FlashId::Image3,
152 _ => panic!("More than 2 images not supported"),
153 };
154 let (secondary_base, secondary_len, secondary_dev_id) = match areadesc.find(id1) {
155 Some(info) => info,
Fabio Utzig114a6472019-11-28 10:24:09 -0300156 None => return Err("insufficient partitions".to_string()),
David Brown06ef06e2019-03-05 12:28:10 -0700157 };
David Browne5133242019-02-28 11:05:19 -0700158
Christopher Collinsa1c12042019-05-23 14:00:28 -0700159 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 4;
David Browne5133242019-02-28 11:05:19 -0700160
David Brown06ef06e2019-03-05 12:28:10 -0700161 // Construct a primary image.
162 let primary = SlotInfo {
163 base_off: primary_base as usize,
164 trailer_off: primary_base + primary_len - offset_from_end,
165 len: primary_len as usize,
166 dev_id: primary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600167 index: 0,
David Brown06ef06e2019-03-05 12:28:10 -0700168 };
169
170 // And an upgrade image.
171 let secondary = SlotInfo {
172 base_off: secondary_base as usize,
173 trailer_off: secondary_base + secondary_len - offset_from_end,
174 len: secondary_len as usize,
175 dev_id: secondary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600176 index: 1,
David Brown06ef06e2019-03-05 12:28:10 -0700177 };
178
179 slots.push([primary, secondary]);
180 }
David Browne5133242019-02-28 11:05:19 -0700181
David Brownbf32c272021-06-16 17:11:37 -0600182 let ram = RamData::new(&slots);
183
Fabio Utzig114a6472019-11-28 10:24:09 -0300184 Ok(ImagesBuilder {
David Brown4dfb33c2021-03-10 05:15:45 -0700185 flash,
186 areadesc,
187 slots,
David Brownbf32c272021-06-16 17:11:37 -0600188 ram,
David Brown5bc62c62019-03-05 12:11:48 -0700189 })
David Browne5133242019-02-28 11:05:19 -0700190 }
191
192 pub fn each_device<F>(f: F)
193 where F: Fn(Self)
194 {
195 for &dev in ALL_DEVICES {
David Brown95de4502019-11-15 12:01:34 -0700196 for &align in test_alignments() {
David Browne5133242019-02-28 11:05:19 -0700197 for &erased_val in &[0, 0xff] {
David Brown5bc62c62019-03-05 12:11:48 -0700198 match Self::new(dev, align, erased_val) {
Fabio Utzig114a6472019-11-28 10:24:09 -0300199 Ok(run) => f(run),
200 Err(msg) => warn!("Skipping {}: {}", dev, msg),
David Brown5bc62c62019-03-05 12:11:48 -0700201 }
David Browne5133242019-02-28 11:05:19 -0700202 }
203 }
204 }
205 }
206
207 /// Construct an `Images` that doesn't expect an upgrade to happen.
David Brownc3898d62019-08-05 14:20:02 -0600208 pub fn make_no_upgrade_image(self, deps: &DepTest) -> Images {
209 let num_images = self.num_images();
David Brown76101572019-02-28 11:29:03 -0700210 let mut flash = self.flash;
David Brownbf32c272021-06-16 17:11:37 -0600211 let ram = self.ram.clone(); // TODO: This is wasteful.
David Brownc3898d62019-08-05 14:20:02 -0600212 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
213 let dep: Box<dyn Depender> = if num_images > 1 {
214 Box::new(PairDep::new(num_images, image_num, deps))
215 } else {
David Brown2ee5f7f2020-01-13 14:04:01 -0700216 Box::new(BoringDep::new(image_num, deps))
David Brownc3898d62019-08-05 14:20:02 -0600217 };
David Brownbf32c272021-06-16 17:11:37 -0600218 let primaries = install_image(&mut flash, &slots[0], 42784, &ram, &*dep, false);
David Brown873be312019-09-03 12:22:32 -0600219 let upgrades = match deps.depends[image_num] {
220 DepType::NoUpgrade => install_no_image(),
David Brownbf32c272021-06-16 17:11:37 -0600221 _ => install_image(&mut flash, &slots[1], 46928, &ram, &*dep, false)
David Brown873be312019-09-03 12:22:32 -0600222 };
David Brown84b49f72019-03-01 10:58:22 -0700223 OneImage {
David Brown4dfb33c2021-03-10 05:15:45 -0700224 slots,
225 primaries,
226 upgrades,
David Brown84b49f72019-03-01 10:58:22 -0700227 }}).collect();
David Brown297029a2019-08-13 14:29:51 -0600228 install_ptable(&mut flash, &self.areadesc);
David Browne5133242019-02-28 11:05:19 -0700229 Images {
David Brown4dfb33c2021-03-10 05:15:45 -0700230 flash,
David Browne5133242019-02-28 11:05:19 -0700231 areadesc: self.areadesc,
David Brown4dfb33c2021-03-10 05:15:45 -0700232 images,
David Browne5133242019-02-28 11:05:19 -0700233 total_count: None,
David Brownbf32c272021-06-16 17:11:37 -0600234 ram: self.ram,
David Browne5133242019-02-28 11:05:19 -0700235 }
236 }
237
David Brownc3898d62019-08-05 14:20:02 -0600238 pub fn make_image(self, deps: &DepTest, permanent: bool) -> Images {
239 let mut images = self.make_no_upgrade_image(deps);
David Brown84b49f72019-03-01 10:58:22 -0700240 for image in &images.images {
241 mark_upgrade(&mut images.flash, &image.slots[1]);
242 }
David Browne5133242019-02-28 11:05:19 -0700243
David Brown6db44d72021-05-26 16:22:58 -0600244 // The count is meaningless if no flash operations are performed.
245 if !Caps::modifies_flash() {
246 return images;
247 }
248
David Browne5133242019-02-28 11:05:19 -0700249 // upgrades without fails, counts number of flash operations
Fabio Utziged4a5362019-07-30 12:43:23 -0300250 let total_count = match images.run_basic_upgrade(permanent) {
David Brown8973f552021-03-10 05:21:11 -0700251 Some(v) => v,
252 None =>
David Brown0e6bc7f2019-09-03 12:29:56 -0600253 if deps.upgrades.iter().any(|u| *u == UpgradeInfo::Held) {
254 0
255 } else {
256 panic!("Unable to perform basic upgrade");
257 }
David Browne5133242019-02-28 11:05:19 -0700258 };
259
260 images.total_count = Some(total_count);
261 images
262 }
263
264 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700265 let mut bad_flash = self.flash;
David Brownbf32c272021-06-16 17:11:37 -0600266 let ram = self.ram.clone(); // TODO: Avoid this clone.
David Brownc3898d62019-08-05 14:20:02 -0600267 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
David Brown2ee5f7f2020-01-13 14:04:01 -0700268 let dep = BoringDep::new(image_num, &NO_DEPS);
David Brownbf32c272021-06-16 17:11:37 -0600269 let primaries = install_image(&mut bad_flash, &slots[0], 32784, &ram, &dep, false);
270 let upgrades = install_image(&mut bad_flash, &slots[1], 41928, &ram, &dep, true);
David Brown84b49f72019-03-01 10:58:22 -0700271 OneImage {
David Brown4dfb33c2021-03-10 05:15:45 -0700272 slots,
273 primaries,
274 upgrades,
David Brown84b49f72019-03-01 10:58:22 -0700275 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700276 Images {
David Brown76101572019-02-28 11:29:03 -0700277 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700278 areadesc: self.areadesc,
David Brown4dfb33c2021-03-10 05:15:45 -0700279 images,
David Browne5133242019-02-28 11:05:19 -0700280 total_count: None,
David Brownbf32c272021-06-16 17:11:37 -0600281 ram: self.ram,
David Browne5133242019-02-28 11:05:19 -0700282 }
283 }
284
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300285 pub fn make_erased_secondary_image(self) -> Images {
286 let mut flash = self.flash;
David Brownbf32c272021-06-16 17:11:37 -0600287 let ram = self.ram.clone(); // TODO: Avoid this clone.
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300288 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
289 let dep = BoringDep::new(image_num, &NO_DEPS);
David Brownbf32c272021-06-16 17:11:37 -0600290 let primaries = install_image(&mut flash, &slots[0], 32784, &ram, &dep, false);
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300291 let upgrades = install_no_image();
292 OneImage {
David Brown4dfb33c2021-03-10 05:15:45 -0700293 slots,
294 primaries,
295 upgrades,
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300296 }}).collect();
297 Images {
David Brown4dfb33c2021-03-10 05:15:45 -0700298 flash,
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300299 areadesc: self.areadesc,
David Brown4dfb33c2021-03-10 05:15:45 -0700300 images,
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300301 total_count: None,
David Brownbf32c272021-06-16 17:11:37 -0600302 ram: self.ram,
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300303 }
304 }
305
Fabio Utzigd0157342020-10-02 15:22:11 -0300306 pub fn make_bootstrap_image(self) -> Images {
307 let mut flash = self.flash;
David Brownbf32c272021-06-16 17:11:37 -0600308 let ram = self.ram.clone(); // TODO: Avoid this clone.
Fabio Utzigd0157342020-10-02 15:22:11 -0300309 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
310 let dep = BoringDep::new(image_num, &NO_DEPS);
311 let primaries = install_no_image();
David Brownbf32c272021-06-16 17:11:37 -0600312 let upgrades = install_image(&mut flash, &slots[1], 32784, &ram, &dep, false);
Fabio Utzigd0157342020-10-02 15:22:11 -0300313 OneImage {
David Brown4dfb33c2021-03-10 05:15:45 -0700314 slots,
315 primaries,
316 upgrades,
Fabio Utzigd0157342020-10-02 15:22:11 -0300317 }}).collect();
318 Images {
David Brown4dfb33c2021-03-10 05:15:45 -0700319 flash,
Fabio Utzigd0157342020-10-02 15:22:11 -0300320 areadesc: self.areadesc,
David Brown4dfb33c2021-03-10 05:15:45 -0700321 images,
Fabio Utzigd0157342020-10-02 15:22:11 -0300322 total_count: None,
David Brownbf32c272021-06-16 17:11:37 -0600323 ram: self.ram,
Fabio Utzigd0157342020-10-02 15:22:11 -0300324 }
325 }
326
David Browne5133242019-02-28 11:05:19 -0700327 /// Build the Flash and area descriptor for a given device.
Fabio Utzig114a6472019-11-28 10:24:09 -0300328 pub fn make_device(device: DeviceName, align: usize, erased_val: u8) -> (SimMultiFlash, AreaDesc, &'static [Caps]) {
David Browne5133242019-02-28 11:05:19 -0700329 match device {
330 DeviceName::Stm32f4 => {
331 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700332 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
333 64 * 1024,
334 128 * 1024, 128 * 1024, 128 * 1024],
335 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700336 let dev_id = 0;
337 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700338 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700339 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
340 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
341 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
342
David Brown76101572019-02-28 11:29:03 -0700343 let mut flash = SimMultiFlash::new();
344 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300345 (flash, areadesc, &[Caps::SwapUsingMove])
David Browne5133242019-02-28 11:05:19 -0700346 }
347 DeviceName::K64f => {
348 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700349 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700350
351 let dev_id = 0;
352 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700353 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700354 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
355 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
356 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
357
David Brown76101572019-02-28 11:29:03 -0700358 let mut flash = SimMultiFlash::new();
359 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300360 (flash, areadesc, &[])
David Browne5133242019-02-28 11:05:19 -0700361 }
362 DeviceName::K64fBig => {
363 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
364 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700365 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700366
367 let dev_id = 0;
368 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700369 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700370 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
371 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
372 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
373
David Brown76101572019-02-28 11:29:03 -0700374 let mut flash = SimMultiFlash::new();
375 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300376 (flash, areadesc, &[Caps::SwapUsingMove])
David Browne5133242019-02-28 11:05:19 -0700377 }
378 DeviceName::Nrf52840 => {
379 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
380 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700381 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700382
383 let dev_id = 0;
384 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700385 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700386 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
387 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
388 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
389
David Brown76101572019-02-28 11:29:03 -0700390 let mut flash = SimMultiFlash::new();
391 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300392 (flash, areadesc, &[])
David Browne5133242019-02-28 11:05:19 -0700393 }
Fabio Utzigc659ec52020-07-13 21:18:48 -0300394 DeviceName::Nrf52840UnequalSlots => {
395 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
396
397 let dev_id = 0;
398 let mut areadesc = AreaDesc::new();
399 areadesc.add_flash_sectors(dev_id, &dev);
400 areadesc.add_image(0x008000, 0x03c000, FlashId::Image0, dev_id);
401 areadesc.add_image(0x044000, 0x03b000, FlashId::Image1, dev_id);
402
403 let mut flash = SimMultiFlash::new();
404 flash.insert(dev_id, dev);
405 (flash, areadesc, &[Caps::SwapUsingScratch, Caps::OverwriteUpgrade])
406 }
David Browne5133242019-02-28 11:05:19 -0700407 DeviceName::Nrf52840SpiFlash => {
408 // Simulate nrf52840 with external SPI flash. The external SPI flash
409 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700410 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
411 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700412
413 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700414 areadesc.add_flash_sectors(0, &dev0);
415 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700416
417 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
418 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
419 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
420
David Brown76101572019-02-28 11:29:03 -0700421 let mut flash = SimMultiFlash::new();
422 flash.insert(0, dev0);
423 flash.insert(1, dev1);
Fabio Utzig114a6472019-11-28 10:24:09 -0300424 (flash, areadesc, &[Caps::SwapUsingMove])
David Browne5133242019-02-28 11:05:19 -0700425 }
David Brown2bff6472019-03-05 13:58:35 -0700426 DeviceName::K64fMulti => {
427 // NXP style flash, but larger, to support multiple images.
428 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
429
430 let dev_id = 0;
431 let mut areadesc = AreaDesc::new();
432 areadesc.add_flash_sectors(dev_id, &dev);
433 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
434 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
435 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
436 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
437 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
438
439 let mut flash = SimMultiFlash::new();
440 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300441 (flash, areadesc, &[])
David Brown2bff6472019-03-05 13:58:35 -0700442 }
David Browne5133242019-02-28 11:05:19 -0700443 }
444 }
David Brownc3898d62019-08-05 14:20:02 -0600445
446 pub fn num_images(&self) -> usize {
447 self.slots.len()
448 }
David Browne5133242019-02-28 11:05:19 -0700449}
450
David Brown5c9e0f12019-01-09 16:34:33 -0700451impl Images {
452 /// A simple upgrade without forced failures.
453 ///
454 /// Returns the number of flash operations which can later be used to
David Brown8973f552021-03-10 05:21:11 -0700455 /// inject failures at chosen steps. Returns None if it was unable to
456 /// count the operations in a basic upgrade.
457 pub fn run_basic_upgrade(&self, permanent: bool) -> Option<i32> {
Fabio Utziged4a5362019-07-30 12:43:23 -0300458 let (flash, total_count) = self.try_upgrade(None, permanent);
David Brown5c9e0f12019-01-09 16:34:33 -0700459 info!("Total flash operation count={}", total_count);
460
David Brown84b49f72019-03-01 10:58:22 -0700461 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700462 warn!("Image mismatch after first boot");
David Brown8973f552021-03-10 05:21:11 -0700463 None
David Brown5c9e0f12019-01-09 16:34:33 -0700464 } else {
David Brown8973f552021-03-10 05:21:11 -0700465 Some(total_count)
David Brown5c9e0f12019-01-09 16:34:33 -0700466 }
467 }
468
Fabio Utzigd0157342020-10-02 15:22:11 -0300469 pub fn run_bootstrap(&self) -> bool {
470 let mut flash = self.flash.clone();
471 let mut fails = 0;
472
473 if Caps::Bootstrap.present() {
474 info!("Try bootstraping image in the primary");
475
David Brownc423ac42021-06-04 13:47:34 -0600476 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
Fabio Utzigd0157342020-10-02 15:22:11 -0300477 warn!("Failed first boot");
478 fails += 1;
479 }
480
481 if !self.verify_images(&flash, 0, 1) {
482 warn!("Image in the first slot was not bootstrapped");
483 fails += 1;
484 }
485
486 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
487 BOOT_FLAG_SET, BOOT_FLAG_SET) {
488 warn!("Mismatched trailer for the primary slot");
489 fails += 1;
490 }
491 }
492
493 if fails > 0 {
494 error!("Expected trailer on secondary slot to be erased");
495 }
496
497 fails > 0
498 }
499
500
David Brownc3898d62019-08-05 14:20:02 -0600501 /// Test a simple upgrade, with dependencies given, and verify that the
502 /// image does as is described in the test.
503 pub fn run_check_deps(&self, deps: &DepTest) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600504 if !Caps::modifies_flash() {
505 return false;
506 }
507
David Brownc3898d62019-08-05 14:20:02 -0600508 let (flash, _) = self.try_upgrade(None, true);
509
510 self.verify_dep_images(&flash, deps)
511 }
512
Fabio Utzigf5480c72019-11-28 10:41:57 -0300513 fn is_swap_upgrade(&self) -> bool {
514 Caps::SwapUsingScratch.present() || Caps::SwapUsingMove.present()
515 }
516
David Brown5c9e0f12019-01-09 16:34:33 -0700517 pub fn run_basic_revert(&self) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600518 if Caps::OverwriteUpgrade.present() || !Caps::modifies_flash() {
David Brown3910ab12019-01-11 12:02:26 -0700519 return false;
520 }
David Brown5c9e0f12019-01-09 16:34:33 -0700521
David Brown5c9e0f12019-01-09 16:34:33 -0700522 let mut fails = 0;
523
524 // FIXME: this test would also pass if no swap is ever performed???
Fabio Utzigf5480c72019-11-28 10:41:57 -0300525 if self.is_swap_upgrade() {
David Brown5c9e0f12019-01-09 16:34:33 -0700526 for count in 2 .. 5 {
527 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700528 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700529 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700530 error!("Revert failure on count {}", count);
531 fails += 1;
532 }
533 }
534 }
535
536 fails > 0
537 }
538
539 pub fn run_perm_with_fails(&self) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600540 if !Caps::modifies_flash() {
541 return false;
542 }
543
David Brown5c9e0f12019-01-09 16:34:33 -0700544 let mut fails = 0;
545 let total_flash_ops = self.total_count.unwrap();
546
547 // Let's try an image halfway through.
548 for i in 1 .. total_flash_ops {
549 info!("Try interruption at {}", i);
Fabio Utziged4a5362019-07-30 12:43:23 -0300550 let (flash, count) = self.try_upgrade(Some(i), true);
David Brown5c9e0f12019-01-09 16:34:33 -0700551 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700552 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700553 warn!("FAIL at step {} of {}", i, total_flash_ops);
554 fails += 1;
555 }
556
David Brown84b49f72019-03-01 10:58:22 -0700557 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
558 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100559 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700560 fails += 1;
561 }
562
David Brown84b49f72019-03-01 10:58:22 -0700563 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
564 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100565 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700566 fails += 1;
567 }
568
David Brownaec56b22021-03-10 05:22:07 -0700569 if self.is_swap_upgrade() && !self.verify_images(&flash, 1, 0) {
570 warn!("Secondary slot FAIL at step {} of {}",
571 i, total_flash_ops);
572 fails += 1;
David Brown5c9e0f12019-01-09 16:34:33 -0700573 }
574 }
575
576 if fails > 0 {
577 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
578 fails as f32 * 100.0 / total_flash_ops as f32);
579 }
580
581 fails > 0
582 }
583
David Brown5c9e0f12019-01-09 16:34:33 -0700584 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600585 if !Caps::modifies_flash() {
586 return false;
587 }
588
David Brown5c9e0f12019-01-09 16:34:33 -0700589 let mut fails = 0;
590 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700591 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700592 info!("Random interruptions at reset points={:?}", total_counts);
593
David Brown84b49f72019-03-01 10:58:22 -0700594 let primary_slot_ok = self.verify_images(&flash, 0, 1);
Fabio Utzigf5480c72019-11-28 10:41:57 -0300595 let secondary_slot_ok = if self.is_swap_upgrade() {
David Brown84b49f72019-03-01 10:58:22 -0700596 // TODO: This result is ignored.
597 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700598 } else {
599 true
600 };
David Vincze2d736ad2019-02-18 11:50:22 +0100601 if !primary_slot_ok || !secondary_slot_ok {
602 error!("Image mismatch after random interrupts: primary slot={} \
603 secondary slot={}",
604 if primary_slot_ok { "ok" } else { "fail" },
605 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700606 fails += 1;
607 }
David Brown84b49f72019-03-01 10:58:22 -0700608 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
609 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100610 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700611 fails += 1;
612 }
David Brown84b49f72019-03-01 10:58:22 -0700613 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
614 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100615 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700616 fails += 1;
617 }
618
619 if fails > 0 {
620 error!("Error testing perm upgrade with {} fails", total_fails);
621 }
622
623 fails > 0
624 }
625
David Brown5c9e0f12019-01-09 16:34:33 -0700626 pub fn run_revert_with_fails(&self) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600627 if Caps::OverwriteUpgrade.present() || !Caps::modifies_flash() {
David Brown3910ab12019-01-11 12:02:26 -0700628 return false;
629 }
David Brown5c9e0f12019-01-09 16:34:33 -0700630
David Brown5c9e0f12019-01-09 16:34:33 -0700631 let mut fails = 0;
632
Fabio Utzigf5480c72019-11-28 10:41:57 -0300633 if self.is_swap_upgrade() {
Fabio Utziged4a5362019-07-30 12:43:23 -0300634 for i in 1 .. self.total_count.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -0700635 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700636 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700637 error!("Revert failed at interruption {}", i);
638 fails += 1;
639 }
640 }
641 }
642
643 fails > 0
644 }
645
David Brown5c9e0f12019-01-09 16:34:33 -0700646 pub fn run_norevert(&self) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600647 if Caps::OverwriteUpgrade.present() || !Caps::modifies_flash() {
David Brown3910ab12019-01-11 12:02:26 -0700648 return false;
649 }
David Brown5c9e0f12019-01-09 16:34:33 -0700650
David Brown76101572019-02-28 11:29:03 -0700651 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700652 let mut fails = 0;
653
654 info!("Try norevert");
655
656 // First do a normal upgrade...
David Brownc423ac42021-06-04 13:47:34 -0600657 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
David Brown5c9e0f12019-01-09 16:34:33 -0700658 warn!("Failed first boot");
659 fails += 1;
660 }
661
662 //FIXME: copy_done is written by boot_go, is it ok if no copy
663 // was ever done?
664
David Brown84b49f72019-03-01 10:58:22 -0700665 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100666 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700667 fails += 1;
668 }
David Brown84b49f72019-03-01 10:58:22 -0700669 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
670 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100671 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700672 fails += 1;
673 }
David Brown84b49f72019-03-01 10:58:22 -0700674 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
675 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100676 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700677 fails += 1;
678 }
679
David Vincze2d736ad2019-02-18 11:50:22 +0100680 // Marks image in the primary slot as permanent,
681 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700682 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700683
David Brown84b49f72019-03-01 10:58:22 -0700684 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
685 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100686 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700687 fails += 1;
688 }
689
David Brownc423ac42021-06-04 13:47:34 -0600690 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
David Brown5c9e0f12019-01-09 16:34:33 -0700691 warn!("Failed second boot");
692 fails += 1;
693 }
694
David Brown84b49f72019-03-01 10:58:22 -0700695 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
696 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100697 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700698 fails += 1;
699 }
David Brown84b49f72019-03-01 10:58:22 -0700700 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700701 warn!("Failed image verification");
702 fails += 1;
703 }
704
705 if fails > 0 {
706 error!("Error running upgrade without revert");
707 }
708
709 fails > 0
710 }
711
David Brown2ee5f7f2020-01-13 14:04:01 -0700712 // Test that an upgrade is rejected. Assumes that the image was build
713 // such that the upgrade is instead a downgrade.
714 pub fn run_nodowngrade(&self) -> bool {
715 if !Caps::DowngradePrevention.present() {
716 return false;
717 }
718
719 let mut flash = self.flash.clone();
720 let mut fails = 0;
721
722 info!("Try no downgrade");
723
724 // First, do a normal upgrade.
David Brownc423ac42021-06-04 13:47:34 -0600725 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
David Brown2ee5f7f2020-01-13 14:04:01 -0700726 warn!("Failed first boot");
727 fails += 1;
728 }
729
730 if !self.verify_images(&flash, 0, 0) {
731 warn!("Failed verification after downgrade rejection");
732 fails += 1;
733 }
734
735 if fails > 0 {
736 error!("Error testing downgrade rejection");
737 }
738
739 fails > 0
740 }
741
David Vincze2d736ad2019-02-18 11:50:22 +0100742 // Tests a new image written to the primary slot that already has magic and
743 // image_ok set while there is no image on the secondary slot, so no revert
744 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700745 pub fn run_norevert_newimage(&self) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600746 if !Caps::modifies_flash() {
747 info!("Skipping run_norevert_newimage, as configuration doesn't modify flash");
748 return false;
749 }
750
David Brown76101572019-02-28 11:29:03 -0700751 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700752 let mut fails = 0;
753
754 info!("Try non-revert on imgtool generated image");
755
David Brown84b49f72019-03-01 10:58:22 -0700756 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700757
David Vincze2d736ad2019-02-18 11:50:22 +0100758 // This simulates writing an image created by imgtool to
759 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700760 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
761 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100762 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700763 fails += 1;
764 }
765
766 // Run the bootloader...
David Brownc423ac42021-06-04 13:47:34 -0600767 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
David Brown5c9e0f12019-01-09 16:34:33 -0700768 warn!("Failed first boot");
769 fails += 1;
770 }
771
772 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700773 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700774 warn!("Failed image verification");
775 fails += 1;
776 }
David Brown84b49f72019-03-01 10:58:22 -0700777 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
778 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100779 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700780 fails += 1;
781 }
David Brown84b49f72019-03-01 10:58:22 -0700782 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
783 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100784 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700785 fails += 1;
786 }
787
788 if fails > 0 {
789 error!("Expected a non revert with new image");
790 }
791
792 fails > 0
793 }
794
David Vincze2d736ad2019-02-18 11:50:22 +0100795 // Tests a new image written to the primary slot that already has magic and
796 // image_ok set while there is no image on the secondary slot, so no revert
797 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700798 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700799 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700800 let mut fails = 0;
801
802 info!("Try upgrade image with bad signature");
803
David Brown6db44d72021-05-26 16:22:58 -0600804 // Only perform this test if an upgrade is expected to happen.
805 if !Caps::modifies_flash() {
806 info!("Skipping upgrade image with bad signature");
807 return false;
808 }
809
David Brown84b49f72019-03-01 10:58:22 -0700810 self.mark_upgrades(&mut flash, 0);
811 self.mark_permanent_upgrades(&mut flash, 0);
812 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700813
David Brown84b49f72019-03-01 10:58:22 -0700814 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
815 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100816 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700817 fails += 1;
818 }
819
820 // Run the bootloader...
David Brownc423ac42021-06-04 13:47:34 -0600821 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
David Brown5c9e0f12019-01-09 16:34:33 -0700822 warn!("Failed first boot");
823 fails += 1;
824 }
825
826 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700827 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700828 warn!("Failed image verification");
829 fails += 1;
830 }
David Brown84b49f72019-03-01 10:58:22 -0700831 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
832 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100833 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700834 fails += 1;
835 }
836
837 if fails > 0 {
838 error!("Expected an upgrade failure when image has bad signature");
839 }
840
841 fails > 0
842 }
843
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300844 // Should detect there is a leftover trailer in an otherwise erased
845 // secondary slot and erase its trailer.
846 pub fn run_secondary_leftover_trailer(&self) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600847 if !Caps::modifies_flash() {
848 return false;
849 }
850
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300851 let mut flash = self.flash.clone();
852 let mut fails = 0;
853
854 info!("Try with a leftover trailer in the secondary; must be erased");
855
856 // Add a trailer on the secondary slot
857 self.mark_permanent_upgrades(&mut flash, 1);
858 self.mark_upgrades(&mut flash, 1);
859
860 // Run the bootloader...
David Brownc423ac42021-06-04 13:47:34 -0600861 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
Fabio Utzig2c3be5c2020-07-09 19:54:45 -0300862 warn!("Failed first boot");
863 fails += 1;
864 }
865
866 // State should not have changed
867 if !self.verify_images(&flash, 0, 0) {
868 warn!("Failed image verification");
869 fails += 1;
870 }
871 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
872 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
873 warn!("Mismatched trailer for the secondary slot");
874 fails += 1;
875 }
876
877 if fails > 0 {
878 error!("Expected trailer on secondary slot to be erased");
879 }
880
881 fails > 0
882 }
883
David Brown5c9e0f12019-01-09 16:34:33 -0700884 fn trailer_sz(&self, align: usize) -> usize {
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300885 c::boot_trailer_sz(align as u32) as usize
David Brown5c9e0f12019-01-09 16:34:33 -0700886 }
887
David Brown5c9e0f12019-01-09 16:34:33 -0700888 fn status_sz(&self, align: usize) -> usize {
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300889 c::boot_status_sz(align as u32) as usize
David Brown5c9e0f12019-01-09 16:34:33 -0700890 }
891
892 /// This test runs a simple upgrade with no fails in the images, but
893 /// allowing for fails in the status area. This should run to the end
894 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700895 pub fn run_with_status_fails_complete(&self) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600896 if !Caps::ValidatePrimarySlot.present() || !Caps::modifies_flash() {
David Brown85904a82019-01-11 13:45:12 -0700897 return false;
898 }
899
David Brown76101572019-02-28 11:29:03 -0700900 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700901 let mut fails = 0;
902
903 info!("Try swap with status fails");
904
David Brown84b49f72019-03-01 10:58:22 -0700905 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700906 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700907
David Brownc423ac42021-06-04 13:47:34 -0600908 let result = c::boot_go(&mut flash, &self.areadesc, None, true);
909 if !result.success() {
David Brown5c9e0f12019-01-09 16:34:33 -0700910 warn!("Failed!");
911 fails += 1;
912 }
913
914 // Failed writes to the marked "bad" region don't assert anymore.
915 // Any detected assert() is happening in another part of the code.
David Brownc423ac42021-06-04 13:47:34 -0600916 if result.asserts() != 0 {
David Brown5c9e0f12019-01-09 16:34:33 -0700917 warn!("At least one assert() was called");
918 fails += 1;
919 }
920
David Brown84b49f72019-03-01 10:58:22 -0700921 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
922 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100923 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700924 fails += 1;
925 }
926
David Brown84b49f72019-03-01 10:58:22 -0700927 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700928 warn!("Failed image verification");
929 fails += 1;
930 }
931
David Vincze2d736ad2019-02-18 11:50:22 +0100932 info!("validate primary slot enabled; \
933 re-run of boot_go should just work");
David Brownc423ac42021-06-04 13:47:34 -0600934 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
David Brown5c9e0f12019-01-09 16:34:33 -0700935 warn!("Failed!");
936 fails += 1;
937 }
938
939 if fails > 0 {
940 error!("Error running upgrade with status write fails");
941 }
942
943 fails > 0
944 }
945
946 /// This test runs a simple upgrade with no fails in the images, but
947 /// allowing for fails in the status area. This should run to the end
948 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700949 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown6db44d72021-05-26 16:22:58 -0600950 if Caps::OverwriteUpgrade.present() || !Caps::modifies_flash() {
David Brown85904a82019-01-11 13:45:12 -0700951 false
David Vincze2d736ad2019-02-18 11:50:22 +0100952 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700953
David Brown76101572019-02-28 11:29:03 -0700954 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700955 let mut fails = 0;
956 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700957
David Brown85904a82019-01-11 13:45:12 -0700958 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700959
David Brown85904a82019-01-11 13:45:12 -0700960 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700961
David Brown84b49f72019-03-01 10:58:22 -0700962 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700963 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700964
965 // Should not fail, writing to bad regions does not assert
David Brownc423ac42021-06-04 13:47:34 -0600966 let asserts = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true).asserts();
David Brown85904a82019-01-11 13:45:12 -0700967 if asserts != 0 {
968 warn!("At least one assert() was called");
969 fails += 1;
970 }
971
David Brown76101572019-02-28 11:29:03 -0700972 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700973
974 info!("Resuming an interrupted swap operation");
David Brownc423ac42021-06-04 13:47:34 -0600975 let asserts = c::boot_go(&mut flash, &self.areadesc, None, true).asserts();
David Brown85904a82019-01-11 13:45:12 -0700976
977 // This might throw no asserts, for large sector devices, where
978 // a single failure writing is indistinguishable from no failure,
979 // or throw a single assert for small sector devices that fail
980 // multiple times...
981 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100982 warn!("Expected single assert validating the primary slot, \
983 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700984 fails += 1;
985 }
986
987 if fails > 0 {
988 error!("Error running upgrade with status write fails");
989 }
990
991 fails > 0
992 } else {
David Brown76101572019-02-28 11:29:03 -0700993 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700994 let mut fails = 0;
995
996 info!("Try interrupted swap with status fails");
997
David Brown84b49f72019-03-01 10:58:22 -0700998 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700999 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -07001000
1001 // This is expected to fail while writing to bad regions...
David Brownc423ac42021-06-04 13:47:34 -06001002 let asserts = c::boot_go(&mut flash, &self.areadesc, None, true).asserts();
David Brown85904a82019-01-11 13:45:12 -07001003 if asserts == 0 {
1004 warn!("No assert() detected");
1005 fails += 1;
1006 }
1007
1008 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -07001009 }
David Brown5c9e0f12019-01-09 16:34:33 -07001010 }
1011
David Brown0dfb8102021-06-03 15:29:11 -06001012 /// Test the direct XIP configuration. With this mode, flash images are never moved, and the
1013 /// bootloader merely selects which partition is the proper one to boot.
1014 pub fn run_direct_xip(&self) -> bool {
1015 if !Caps::DirectXip.present() {
1016 return false;
1017 }
1018
1019 // Clone the flash so we can tell if unchanged.
1020 let mut flash = self.flash.clone();
1021
1022 let result = c::boot_go(&mut flash, &self.areadesc, None, true);
1023
1024 // Ensure the boot was successful.
1025 let resp = if let Some(resp) = result.resp() {
1026 resp
1027 } else {
1028 panic!("Boot didn't return a valid result");
1029 };
1030
1031 // This configuration should always try booting from the first upgrade slot.
1032 if let Some((offset, _, dev_id)) = self.areadesc.find(FlashId::Image1) {
1033 assert_eq!(offset, resp.image_off as usize);
1034 assert_eq!(dev_id, resp.flash_dev_id);
1035 } else {
1036 panic!("Unable to find upgrade image");
1037 }
1038 false
1039 }
1040
David Brown8a4e23b2021-06-11 10:29:01 -06001041 /// Test the ram-loading.
1042 pub fn run_ram_load(&self) -> bool {
1043 if !Caps::RamLoad.present() {
1044 return false;
1045 }
1046
1047 // Clone the flash so we can tell if unchanged.
1048 let mut flash = self.flash.clone();
1049
David Brownf17d3912021-06-23 16:10:51 -06001050 // Setup ram based on the ram configuration we determined earlier for the images.
1051 let ram = RamBlock::new(self.ram.total - RAM_LOAD_ADDR, RAM_LOAD_ADDR);
David Brown8a4e23b2021-06-11 10:29:01 -06001052
David Brownf17d3912021-06-23 16:10:51 -06001053 // println!("Ram: {:#?}", self.ram);
David Brown8a4e23b2021-06-11 10:29:01 -06001054
David Brownf17d3912021-06-23 16:10:51 -06001055 // Verify that the images area loaded into this.
David Brown8a4e23b2021-06-11 10:29:01 -06001056 let result = ram.invoke(|| c::boot_go(&mut flash, &self.areadesc, None, true));
1057 if !result.success() {
David Brownf17d3912021-06-23 16:10:51 -06001058 error!("Failed to execute ram-load");
David Brown8a4e23b2021-06-11 10:29:01 -06001059 return true;
1060 }
1061
David Brownf17d3912021-06-23 16:10:51 -06001062 // Verify each image.
1063 for image in &self.images {
1064 let place = self.ram.lookup(&image.slots[0]);
1065 let ram_image = ram.borrow_part(place.offset as usize - RAM_LOAD_ADDR as usize,
1066 place.size as usize);
1067 let src_image = &image.upgrades.plain;
1068 if src_image.len() > ram_image.len() {
1069 error!("Image ended up too large, nonsensical");
1070 return true;
1071 }
1072
1073 let ram_image = &ram_image[0..src_image.len()];
1074 if ram_image != src_image {
1075 error!("Image not loaded correctly");
1076 return true;
1077 }
1078
1079 }
1080
1081 return false;
David Brown8a4e23b2021-06-11 10:29:01 -06001082 }
1083
David Brown5c9e0f12019-01-09 16:34:33 -07001084 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -07001085 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001086 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -07001087 if Caps::OverwriteUpgrade.present() {
1088 return;
1089 }
1090
David Brown84b49f72019-03-01 10:58:22 -07001091 // Set this for each image.
1092 for image in &self.images {
1093 let dev_id = &image.slots[slot].dev_id;
1094 let dev = flash.get_mut(&dev_id).unwrap();
1095 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001096 let off = &image.slots[slot].base_off;
1097 let len = &image.slots[slot].len;
David Brown84b49f72019-03-01 10:58:22 -07001098 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -07001099
David Brown84b49f72019-03-01 10:58:22 -07001100 // Mark the status area as a bad area
1101 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
1102 }
David Brown5c9e0f12019-01-09 16:34:33 -07001103 }
1104
David Brown76101572019-02-28 11:29:03 -07001105 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +01001106 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -07001107 return;
1108 }
1109
David Brown84b49f72019-03-01 10:58:22 -07001110 for image in &self.images {
1111 let dev_id = &image.slots[slot].dev_id;
1112 let dev = flash.get_mut(&dev_id).unwrap();
1113 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -07001114
David Brown84b49f72019-03-01 10:58:22 -07001115 // Disabling write verification the only assert triggered by
1116 // boot_go should be checking for integrity of status bytes.
1117 dev.set_verify_writes(false);
1118 }
David Brown5c9e0f12019-01-09 16:34:33 -07001119 }
1120
David Browndb505822019-03-01 10:04:20 -07001121 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
1122 /// of the number of flash operations done total.
Fabio Utziged4a5362019-07-30 12:43:23 -03001123 fn try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32) {
David Browndb505822019-03-01 10:04:20 -07001124 // Clone the flash to have a new copy.
1125 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -07001126
Fabio Utziged4a5362019-07-30 12:43:23 -03001127 if permanent {
1128 self.mark_permanent_upgrades(&mut flash, 1);
1129 }
David Brown5c9e0f12019-01-09 16:34:33 -07001130
David Browndb505822019-03-01 10:04:20 -07001131 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -07001132
David Browndb505822019-03-01 10:04:20 -07001133 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
David Brownc423ac42021-06-04 13:47:34 -06001134 x if x.interrupted() => (true, stop.unwrap()),
1135 x if x.success() => (false, -counter),
1136 x => panic!("Unknown return: {:?}", x),
David Browndb505822019-03-01 10:04:20 -07001137 };
David Brown5c9e0f12019-01-09 16:34:33 -07001138
David Browndb505822019-03-01 10:04:20 -07001139 counter = 0;
1140 if first_interrupted {
1141 // fl.dump();
1142 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
David Brownc423ac42021-06-04 13:47:34 -06001143 x if x.interrupted() => panic!("Shouldn't stop again"),
1144 x if x.success() => (),
1145 x => panic!("Unknown return: {:?}", x),
David Browndb505822019-03-01 10:04:20 -07001146 }
1147 }
David Brown5c9e0f12019-01-09 16:34:33 -07001148
David Browndb505822019-03-01 10:04:20 -07001149 (flash, count - counter)
1150 }
1151
1152 fn try_revert(&self, count: usize) -> SimMultiFlash {
1153 let mut flash = self.flash.clone();
1154
1155 // fl.write_file("image0.bin").unwrap();
1156 for i in 0 .. count {
1157 info!("Running boot pass {}", i + 1);
David Brownc423ac42021-06-04 13:47:34 -06001158 assert!(c::boot_go(&mut flash, &self.areadesc, None, false).success_no_asserts());
David Browndb505822019-03-01 10:04:20 -07001159 }
1160 flash
1161 }
1162
1163 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
1164 let mut flash = self.flash.clone();
1165 let mut fails = 0;
1166
1167 let mut counter = stop;
David Brownc423ac42021-06-04 13:47:34 -06001168 if !c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false).interrupted() {
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001169 warn!("Should have stopped test at interruption point");
David Browndb505822019-03-01 10:04:20 -07001170 fails += 1;
1171 }
1172
Fabio Utzig8af7f792019-07-30 12:40:01 -03001173 // In a multi-image setup, copy done might be set if any number of
1174 // images was already successfully swapped.
1175 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
1176 warn!("copy_done should be unset");
1177 fails += 1;
1178 }
1179
David Brownc423ac42021-06-04 13:47:34 -06001180 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001181 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -07001182 fails += 1;
1183 }
1184
David Brown84b49f72019-03-01 10:58:22 -07001185 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -07001186 warn!("Image in the primary slot before revert is invalid at stop={}",
1187 stop);
1188 fails += 1;
1189 }
David Brown84b49f72019-03-01 10:58:22 -07001190 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -07001191 warn!("Image in the secondary slot before revert is invalid at stop={}",
1192 stop);
1193 fails += 1;
1194 }
David Brown84b49f72019-03-01 10:58:22 -07001195 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
1196 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -07001197 warn!("Mismatched trailer for the primary slot before revert");
1198 fails += 1;
1199 }
David Brown84b49f72019-03-01 10:58:22 -07001200 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
1201 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -07001202 warn!("Mismatched trailer for the secondary slot before revert");
1203 fails += 1;
1204 }
1205
1206 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001207 let mut counter = stop;
David Brownc423ac42021-06-04 13:47:34 -06001208 if !c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false).interrupted() {
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001209 warn!("Should have stopped revert at interruption point");
1210 fails += 1;
1211 }
1212
David Brownc423ac42021-06-04 13:47:34 -06001213 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001214 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -07001215 fails += 1;
1216 }
1217
David Brown84b49f72019-03-01 10:58:22 -07001218 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -07001219 warn!("Image in the primary slot after revert is invalid at stop={}",
1220 stop);
1221 fails += 1;
1222 }
David Brown84b49f72019-03-01 10:58:22 -07001223 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -07001224 warn!("Image in the secondary slot after revert is invalid at stop={}",
1225 stop);
1226 fails += 1;
1227 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001228
David Brown84b49f72019-03-01 10:58:22 -07001229 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
1230 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001231 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -07001232 fails += 1;
1233 }
David Brown84b49f72019-03-01 10:58:22 -07001234 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
1235 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -07001236 warn!("Mismatched trailer for the secondary slot after revert");
1237 fails += 1;
1238 }
1239
David Brownc423ac42021-06-04 13:47:34 -06001240 if !c::boot_go(&mut flash, &self.areadesc, None, false).success() {
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001241 warn!("Should have finished 3rd boot");
1242 fails += 1;
1243 }
1244
1245 if !self.verify_images(&flash, 0, 0) {
1246 warn!("Image in the primary slot is invalid on 1st boot after revert");
1247 fails += 1;
1248 }
1249 if !self.verify_images(&flash, 1, 1) {
1250 warn!("Image in the secondary slot is invalid on 1st boot after revert");
1251 fails += 1;
1252 }
1253
David Browndb505822019-03-01 10:04:20 -07001254 fails > 0
1255 }
1256
Fabio Utzigfc07eab2019-05-17 10:23:38 -07001257
David Browndb505822019-03-01 10:04:20 -07001258 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
1259 let mut flash = self.flash.clone();
1260
David Brown84b49f72019-03-01 10:58:22 -07001261 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -07001262
1263 let mut rng = rand::thread_rng();
1264 let mut resets = vec![0i32; count];
1265 let mut remaining_ops = total_ops;
David Brownfbc8f7c2021-03-10 05:22:39 -07001266 for reset in &mut resets {
David Browncd842842020-07-09 15:46:53 -06001267 let reset_counter = rng.gen_range(1, remaining_ops / 2);
David Browndb505822019-03-01 10:04:20 -07001268 let mut counter = reset_counter;
1269 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
David Brownc423ac42021-06-04 13:47:34 -06001270 x if x.interrupted() => (),
1271 x => panic!("Unknown return: {:?}", x),
David Browndb505822019-03-01 10:04:20 -07001272 }
1273 remaining_ops -= reset_counter;
David Brownfbc8f7c2021-03-10 05:22:39 -07001274 *reset = reset_counter;
David Browndb505822019-03-01 10:04:20 -07001275 }
1276
1277 match c::boot_go(&mut flash, &self.areadesc, None, false) {
David Brownc423ac42021-06-04 13:47:34 -06001278 x if x.interrupted() => panic!("Should not be have been interrupted!"),
1279 x if x.success() => (),
1280 x => panic!("Unknown return: {:?}", x),
David Brown5c9e0f12019-01-09 16:34:33 -07001281 }
David Brown5c9e0f12019-01-09 16:34:33 -07001282
David Browndb505822019-03-01 10:04:20 -07001283 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -07001284 }
David Brown84b49f72019-03-01 10:58:22 -07001285
1286 /// Verify the image in the given flash device, the specified slot
1287 /// against the expected image.
1288 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001289 self.images.iter().all(|image| {
1290 verify_image(flash, &image.slots[slot],
1291 match against {
1292 0 => &image.primaries,
1293 1 => &image.upgrades,
1294 _ => panic!("Invalid 'against'")
1295 })
1296 })
David Brown84b49f72019-03-01 10:58:22 -07001297 }
1298
David Brownc3898d62019-08-05 14:20:02 -06001299 /// Verify the images, according to the dependency test.
1300 fn verify_dep_images(&self, flash: &SimMultiFlash, deps: &DepTest) -> bool {
1301 for (image_num, (image, upgrade)) in self.images.iter().zip(deps.upgrades.iter()).enumerate() {
1302 info!("Upgrade: slot:{}, {:?}", image_num, upgrade);
1303 if !verify_image(flash, &image.slots[0],
1304 match upgrade {
1305 UpgradeInfo::Upgraded => &image.upgrades,
1306 UpgradeInfo::Held => &image.primaries,
1307 }) {
1308 error!("Failed to upgrade properly: image: {}, upgrade: {:?}", image_num, upgrade);
1309 return true;
1310 }
1311 }
1312
1313 false
1314 }
1315
Fabio Utzig8af7f792019-07-30 12:40:01 -03001316 /// Verify that at least one of the trailers of the images have the
1317 /// specified values.
1318 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
1319 magic: Option<u8>, image_ok: Option<u8>,
1320 copy_done: Option<u8>) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001321 self.images.iter().any(|image| {
1322 verify_trailer(flash, &image.slots[slot],
1323 magic, image_ok, copy_done)
1324 })
Fabio Utzig8af7f792019-07-30 12:40:01 -03001325 }
1326
David Brown84b49f72019-03-01 10:58:22 -07001327 /// Verify that the trailers of the images have the specified
1328 /// values.
1329 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
1330 magic: Option<u8>, image_ok: Option<u8>,
1331 copy_done: Option<u8>) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001332 self.images.iter().all(|image| {
1333 verify_trailer(flash, &image.slots[slot],
1334 magic, image_ok, copy_done)
1335 })
David Brown84b49f72019-03-01 10:58:22 -07001336 }
1337
1338 /// Mark each of the images for permanent upgrade.
1339 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1340 for image in &self.images {
1341 mark_permanent_upgrade(flash, &image.slots[slot]);
1342 }
1343 }
1344
1345 /// Mark each of the images for permanent upgrade.
1346 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1347 for image in &self.images {
1348 mark_upgrade(flash, &image.slots[slot]);
1349 }
1350 }
David Brown297029a2019-08-13 14:29:51 -06001351
1352 /// Dump out the flash image(s) to one or more files for debugging
1353 /// purposes. The names will be written as either "{prefix}.mcubin" or
1354 /// "{prefix}-001.mcubin" depending on how many images there are.
1355 pub fn debug_dump(&self, prefix: &str) {
1356 for (id, fdev) in &self.flash {
1357 let name = if self.flash.len() == 1 {
1358 format!("{}.mcubin", prefix)
1359 } else {
1360 format!("{}-{:>0}.mcubin", prefix, id)
1361 };
1362 fdev.write_file(&name).unwrap();
1363 }
1364 }
David Brown5c9e0f12019-01-09 16:34:33 -07001365}
1366
David Brownbf32c272021-06-16 17:11:37 -06001367impl RamData {
David Brownf17d3912021-06-23 16:10:51 -06001368 // TODO: This is not correct. The second slot of each image should be at the same address as
1369 // the primary.
David Brownbf32c272021-06-16 17:11:37 -06001370 fn new(slots: &[[SlotInfo; 2]]) -> RamData {
1371 let mut addr = RAM_LOAD_ADDR;
1372 let mut places = BTreeMap::new();
David Brownf17d3912021-06-23 16:10:51 -06001373 // println!("Setup:-------------");
David Brownbf32c272021-06-16 17:11:37 -06001374 for imgs in slots {
1375 for si in imgs {
David Brownf17d3912021-06-23 16:10:51 -06001376 // println!("Setup: si: {:?}", si);
David Brownbf32c272021-06-16 17:11:37 -06001377 let offset = addr;
1378 let size = si.len as u32;
David Brownbf32c272021-06-16 17:11:37 -06001379 places.insert(SlotKey {
1380 dev_id: si.dev_id,
David Brownf17d3912021-06-23 16:10:51 -06001381 base_off: si.base_off,
David Brownbf32c272021-06-16 17:11:37 -06001382 }, SlotPlace { offset, size });
David Brownf17d3912021-06-23 16:10:51 -06001383 // println!(" load: offset: {}, size: {}", offset, size);
David Brownbf32c272021-06-16 17:11:37 -06001384 }
David Brownf17d3912021-06-23 16:10:51 -06001385 addr += imgs[0].len as u32;
David Brownbf32c272021-06-16 17:11:37 -06001386 }
1387 RamData {
1388 places,
1389 total: addr,
1390 }
1391 }
David Brownf17d3912021-06-23 16:10:51 -06001392
1393 /// Lookup the ram data associated with a given flash partition. We just panic if not present,
1394 /// because all slots used should be in the map.
1395 fn lookup(&self, slot: &SlotInfo) -> &SlotPlace {
1396 self.places.get(&SlotKey{dev_id: slot.dev_id, base_off: slot.base_off})
1397 .expect("RamData should contain all slots")
1398 }
David Brownbf32c272021-06-16 17:11:37 -06001399}
1400
David Brown5c9e0f12019-01-09 16:34:33 -07001401/// Show the flash layout.
1402#[allow(dead_code)]
1403fn show_flash(flash: &dyn Flash) {
1404 println!("---- Flash configuration ----");
1405 for sector in flash.sector_iter() {
1406 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1407 sector.num, sector.base, sector.size);
1408 }
David Brown599b2db2021-03-10 05:23:26 -07001409 println!();
David Brown5c9e0f12019-01-09 16:34:33 -07001410}
1411
1412/// Install a "program" into the given image. This fakes the image header, or at least all of the
1413/// fields used by the given code. Returns a copy of the image that was written.
David Brown3b090212019-07-30 15:59:28 -06001414fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: usize,
David Brownf17d3912021-06-23 16:10:51 -06001415 ram: &RamData,
David Brownc3898d62019-08-05 14:20:02 -06001416 deps: &dyn Depender, bad_sig: bool) -> ImageData {
David Brown3b090212019-07-30 15:59:28 -06001417 let offset = slot.base_off;
1418 let slot_len = slot.len;
1419 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001420
David Brown43643dd2019-01-11 15:43:28 -07001421 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001422
David Brownc3898d62019-08-05 14:20:02 -06001423 // Add the dependencies early to the tlv.
1424 for dep in deps.my_deps(offset, slot.index) {
1425 tlv.add_dependency(deps.other_id(), &dep);
1426 }
1427
David Brown5c9e0f12019-01-09 16:34:33 -07001428 const HDR_SIZE: usize = 32;
1429
David Brownf17d3912021-06-23 16:10:51 -06001430 let place = ram.lookup(&slot);
1431 let load_addr = if Caps::RamLoad.present() {
1432 place.offset
1433 } else {
1434 0
1435 };
1436
David Brown5c9e0f12019-01-09 16:34:33 -07001437 // Generate a boot header. Note that the size doesn't include the header.
1438 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001439 magic: tlv.get_magic(),
David Brownf17d3912021-06-23 16:10:51 -06001440 load_addr,
David Brown5c9e0f12019-01-09 16:34:33 -07001441 hdr_size: HDR_SIZE as u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001442 protect_tlv_size: tlv.protect_size(),
David Brown5c9e0f12019-01-09 16:34:33 -07001443 img_size: len as u32,
1444 flags: tlv.get_flags(),
David Brownc3898d62019-08-05 14:20:02 -06001445 ver: deps.my_version(offset, slot.index),
David Brown5c9e0f12019-01-09 16:34:33 -07001446 _pad2: 0,
1447 };
1448
1449 let mut b_header = [0; HDR_SIZE];
1450 b_header[..32].clone_from_slice(header.as_raw());
1451 assert_eq!(b_header.len(), HDR_SIZE);
1452
1453 tlv.add_bytes(&b_header);
1454
1455 // The core of the image itself is just pseudorandom data.
1456 let mut b_img = vec![0; len];
1457 splat(&mut b_img, offset);
1458
David Browncb47dd72019-08-05 14:21:49 -06001459 // Add some information at the start of the payload to make it easier
1460 // to see what it is. This will fail if the image itself is too small.
1461 {
1462 let mut wr = Cursor::new(&mut b_img);
1463 writeln!(&mut wr, "offset: {:#x}, dev_id: {:#x}, slot_info: {:?}",
1464 offset, dev_id, slot).unwrap();
1465 writeln!(&mut wr, "version: {:?}", deps.my_version(offset, slot.index)).unwrap();
1466 }
1467
David Brown5c9e0f12019-01-09 16:34:33 -07001468 // TLV signatures work over plain image
1469 tlv.add_bytes(&b_img);
1470
1471 // Generate encrypted images
Salome Thirot6fdbf552021-05-14 16:46:14 +01001472 let flag = TlvFlags::ENCRYPTED_AES128 as u32 | TlvFlags::ENCRYPTED_AES256 as u32;
1473 let is_encrypted = (tlv.get_flags() & flag) != 0;
David Brown5c9e0f12019-01-09 16:34:33 -07001474 let mut b_encimg = vec![];
1475 if is_encrypted {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001476 let flag = TlvFlags::ENCRYPTED_AES256 as u32;
1477 let aes256 = (tlv.get_flags() & flag) == flag;
Fabio Utzig90f449e2019-10-24 07:43:53 -03001478 tlv.generate_enc_key();
1479 let enc_key = tlv.get_enc_key();
David Brown5c9e0f12019-01-09 16:34:33 -07001480 let nonce = GenericArray::from_slice(&[0; 16]);
David Brown5c9e0f12019-01-09 16:34:33 -07001481 b_encimg = b_img.clone();
Salome Thirot6fdbf552021-05-14 16:46:14 +01001482 if aes256 {
1483 let key: &GenericArray<u8, U32> = GenericArray::from_slice(enc_key.as_slice());
1484 let mut cipher = Aes256Ctr::new(&key, &nonce);
1485 cipher.apply_keystream(&mut b_encimg);
1486 } else {
1487 let key: &GenericArray<u8, U16> = GenericArray::from_slice(enc_key.as_slice());
1488 let mut cipher = Aes128Ctr::new(&key, &nonce);
1489 cipher.apply_keystream(&mut b_encimg);
1490 }
David Brown5c9e0f12019-01-09 16:34:33 -07001491 }
1492
1493 // Build the TLV itself.
David Browne90b13f2019-12-06 15:04:00 -07001494 if bad_sig {
1495 tlv.corrupt_sig();
1496 }
1497 let mut b_tlv = tlv.make_tlv();
David Brown5c9e0f12019-01-09 16:34:33 -07001498
Fabio Utzig2f6c1642019-09-11 19:36:30 -03001499 let dev = flash.get_mut(&dev_id).unwrap();
1500
David Brown5c9e0f12019-01-09 16:34:33 -07001501 let mut buf = vec![];
1502 buf.append(&mut b_header.to_vec());
1503 buf.append(&mut b_img);
1504 buf.append(&mut b_tlv.clone());
1505
David Brown95de4502019-11-15 12:01:34 -07001506 // Pad the buffer to a multiple of the flash alignment.
1507 let align = dev.align();
1508 while buf.len() % align != 0 {
1509 buf.push(dev.erased_val());
1510 }
1511
David Brown5c9e0f12019-01-09 16:34:33 -07001512 let mut encbuf = vec![];
1513 if is_encrypted {
1514 encbuf.append(&mut b_header.to_vec());
1515 encbuf.append(&mut b_encimg);
1516 encbuf.append(&mut b_tlv);
David Brown95de4502019-11-15 12:01:34 -07001517
1518 while encbuf.len() % align != 0 {
1519 encbuf.push(dev.erased_val());
1520 }
David Brown5c9e0f12019-01-09 16:34:33 -07001521 }
1522
David Vincze2d736ad2019-02-18 11:50:22 +01001523 // Since images are always non-encrypted in the primary slot, we first write
1524 // an encrypted image, re-read to use for verification, erase + flash
1525 // un-encrypted. In the secondary slot the image is written un-encrypted,
1526 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001527
David Brown3b090212019-07-30 15:59:28 -06001528 if slot.index == 0 {
David Brown5c9e0f12019-01-09 16:34:33 -07001529 let enc_copy: Option<Vec<u8>>;
1530
1531 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001532 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001533
1534 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001535 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001536
1537 enc_copy = Some(enc);
1538
David Brown76101572019-02-28 11:29:03 -07001539 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001540 } else {
1541 enc_copy = None;
1542 }
1543
David Brown76101572019-02-28 11:29:03 -07001544 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001545
1546 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001547 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001548
David Brownca234692019-02-28 11:22:19 -07001549 ImageData {
1550 plain: copy,
1551 cipher: enc_copy,
1552 }
David Brown5c9e0f12019-01-09 16:34:33 -07001553 } else {
1554
David Brown76101572019-02-28 11:29:03 -07001555 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001556
1557 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001558 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001559
1560 let enc_copy: Option<Vec<u8>>;
1561
1562 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001563 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001564
David Brown76101572019-02-28 11:29:03 -07001565 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001566
1567 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001568 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001569
1570 enc_copy = Some(enc);
1571 } else {
1572 enc_copy = None;
1573 }
1574
David Brownca234692019-02-28 11:22:19 -07001575 ImageData {
1576 plain: copy,
1577 cipher: enc_copy,
1578 }
David Brown5c9e0f12019-01-09 16:34:33 -07001579 }
David Brown5c9e0f12019-01-09 16:34:33 -07001580}
1581
David Brown873be312019-09-03 12:22:32 -06001582/// Install no image. This is used when no upgrade happens.
1583fn install_no_image() -> ImageData {
1584 ImageData {
1585 plain: vec![],
1586 cipher: None,
1587 }
1588}
1589
David Brown5c9e0f12019-01-09 16:34:33 -07001590fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001591 if Caps::EcdsaP224.present() {
1592 panic!("Ecdsa P224 not supported in Simulator");
1593 }
Salome Thirot6fdbf552021-05-14 16:46:14 +01001594 let mut aes_key_size = 128;
1595 if Caps::Aes256.present() {
1596 aes_key_size = 256;
1597 }
David Brown5c9e0f12019-01-09 16:34:33 -07001598
David Brownb8882112019-01-11 14:04:11 -07001599 if Caps::EncKw.present() {
1600 if Caps::RSA2048.present() {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001601 TlvGen::new_rsa_kw(aes_key_size)
David Brownb8882112019-01-11 14:04:11 -07001602 } else if Caps::EcdsaP256.present() {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001603 TlvGen::new_ecdsa_kw(aes_key_size)
David Brownb8882112019-01-11 14:04:11 -07001604 } else {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001605 TlvGen::new_enc_kw(aes_key_size)
David Brownb8882112019-01-11 14:04:11 -07001606 }
1607 } else if Caps::EncRsa.present() {
1608 if Caps::RSA2048.present() {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001609 TlvGen::new_sig_enc_rsa(aes_key_size)
David Brownb8882112019-01-11 14:04:11 -07001610 } else {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001611 TlvGen::new_enc_rsa(aes_key_size)
David Brownb8882112019-01-11 14:04:11 -07001612 }
Fabio Utzig90f449e2019-10-24 07:43:53 -03001613 } else if Caps::EncEc256.present() {
Fabio Utzig66b4caa2020-01-04 20:19:28 -03001614 if Caps::EcdsaP256.present() {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001615 TlvGen::new_ecdsa_ecies_p256(aes_key_size)
Fabio Utzig66b4caa2020-01-04 20:19:28 -03001616 } else {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001617 TlvGen::new_ecies_p256(aes_key_size)
Fabio Utzig66b4caa2020-01-04 20:19:28 -03001618 }
Fabio Utzig3fa72ca2020-04-02 11:20:37 -03001619 } else if Caps::EncX25519.present() {
1620 if Caps::Ed25519.present() {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001621 TlvGen::new_ed25519_ecies_x25519(aes_key_size)
Fabio Utzig3fa72ca2020-04-02 11:20:37 -03001622 } else {
Salome Thirot6fdbf552021-05-14 16:46:14 +01001623 TlvGen::new_ecies_x25519(aes_key_size)
Fabio Utzig3fa72ca2020-04-02 11:20:37 -03001624 }
David Brownb8882112019-01-11 14:04:11 -07001625 } else {
1626 // The non-encrypted configuration.
1627 if Caps::RSA2048.present() {
1628 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001629 } else if Caps::RSA3072.present() {
1630 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001631 } else if Caps::EcdsaP256.present() {
1632 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001633 } else if Caps::Ed25519.present() {
1634 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001635 } else {
1636 TlvGen::new_hash_only()
1637 }
1638 }
David Brown5c9e0f12019-01-09 16:34:33 -07001639}
1640
David Brownca234692019-02-28 11:22:19 -07001641impl ImageData {
1642 /// Find the image contents for the given slot. This assumes that slot 0
1643 /// is unencrypted, and slot 1 is encrypted.
1644 fn find(&self, slot: usize) -> &Vec<u8> {
Fabio Utzig90f449e2019-10-24 07:43:53 -03001645 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present() ||
Fabio Utzig3fa72ca2020-04-02 11:20:37 -03001646 Caps::EncEc256.present() || Caps::EncX25519.present();
David Brownca234692019-02-28 11:22:19 -07001647 match (encrypted, slot) {
1648 (false, _) => &self.plain,
1649 (true, 0) => &self.plain,
1650 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1651 _ => panic!("Invalid slot requested"),
1652 }
David Brown5c9e0f12019-01-09 16:34:33 -07001653 }
1654}
1655
David Brown5c9e0f12019-01-09 16:34:33 -07001656/// Verify that given image is present in the flash at the given offset.
David Brown3b090212019-07-30 15:59:28 -06001657fn verify_image(flash: &SimMultiFlash, slot: &SlotInfo, images: &ImageData) -> bool {
1658 let image = images.find(slot.index);
David Brown5c9e0f12019-01-09 16:34:33 -07001659 let buf = image.as_slice();
David Brown3b090212019-07-30 15:59:28 -06001660 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001661
1662 let mut copy = vec![0u8; buf.len()];
David Brown3b090212019-07-30 15:59:28 -06001663 let offset = slot.base_off;
David Brown76101572019-02-28 11:29:03 -07001664 let dev = flash.get(&dev_id).unwrap();
1665 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001666
1667 if buf != &copy[..] {
1668 for i in 0 .. buf.len() {
1669 if buf[i] != copy[i] {
David Brownc3898d62019-08-05 14:20:02 -06001670 info!("First failure for slot{} at {:#x} ({:#x} within) {:#x}!={:#x}",
1671 slot.index, offset + i, i, buf[i], copy[i]);
David Brown5c9e0f12019-01-09 16:34:33 -07001672 break;
1673 }
1674 }
1675 false
1676 } else {
1677 true
1678 }
1679}
1680
David Brown3b090212019-07-30 15:59:28 -06001681fn verify_trailer(flash: &SimMultiFlash, slot: &SlotInfo,
David Brown5c9e0f12019-01-09 16:34:33 -07001682 magic: Option<u8>, image_ok: Option<u8>,
1683 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001684 if Caps::OverwriteUpgrade.present() {
1685 return true;
1686 }
David Brown5c9e0f12019-01-09 16:34:33 -07001687
David Brown3b090212019-07-30 15:59:28 -06001688 let offset = slot.trailer_off + c::boot_max_align();
1689 let dev_id = slot.dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001690 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001691 let mut failed = false;
1692
David Brown76101572019-02-28 11:29:03 -07001693 let dev = flash.get(&dev_id).unwrap();
1694 let erased_val = dev.erased_val();
1695 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001696
1697 failed |= match magic {
1698 Some(v) => {
David Brown347dc572019-11-15 11:37:25 -07001699 if v == 1 && &copy[24..] != MAGIC {
David Brown5c9e0f12019-01-09 16:34:33 -07001700 warn!("\"magic\" mismatch at {:#x}", offset);
1701 true
1702 } else if v == 3 {
1703 let expected = [erased_val; 16];
David Brownd36f6b12021-03-10 05:23:56 -07001704 if copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001705 warn!("\"magic\" mismatch at {:#x}", offset);
1706 true
1707 } else {
1708 false
1709 }
1710 } else {
1711 false
1712 }
1713 },
1714 None => false,
1715 };
1716
1717 failed |= match image_ok {
1718 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001719 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001720 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1721 true
1722 } else {
1723 false
1724 }
1725 },
1726 None => false,
1727 };
1728
1729 failed |= match copy_done {
1730 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001731 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001732 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1733 true
1734 } else {
1735 false
1736 }
1737 },
1738 None => false,
1739 };
1740
1741 !failed
1742}
1743
David Brown297029a2019-08-13 14:29:51 -06001744/// Install a partition table. This is a simplified partition table that
1745/// we write at the beginning of flash so make it easier for external tools
1746/// to analyze these images.
1747fn install_ptable(flash: &mut SimMultiFlash, areadesc: &AreaDesc) {
1748 let ids: HashSet<u8> = areadesc.iter_areas().map(|area| area.device_id).collect();
1749 for &id in &ids {
1750 // If there are any partitions in this device that start at 0, and
1751 // aren't marked as the BootLoader partition, avoid adding the
1752 // partition table. This makes it harder to view the image, but
1753 // avoids messing up images already written.
David Brown80f836d2021-03-10 05:24:33 -07001754 let skip_ptable = areadesc
1755 .iter_areas()
1756 .any(|area| {
1757 area.device_id == id &&
1758 area.off == 0 &&
1759 area.flash_id != FlashId::BootLoader
1760 });
1761 if skip_ptable {
David Brown297029a2019-08-13 14:29:51 -06001762 if log_enabled!(Info) {
1763 let special: Vec<FlashId> = areadesc.iter_areas()
1764 .filter(|area| area.device_id == id && area.off == 0)
1765 .map(|area| area.flash_id)
1766 .collect();
1767 info!("Skipping partition table: {:?}", special);
1768 }
1769 break;
1770 }
1771
1772 let mut buf: Vec<u8> = vec![];
1773 write!(&mut buf, "mcuboot\0").unwrap();
1774
1775 // Iterate through all of the partitions in that device, and encode
1776 // into the table.
1777 let count = areadesc.iter_areas().filter(|area| area.device_id == id).count();
1778 buf.write_u32::<LittleEndian>(count as u32).unwrap();
1779
1780 for area in areadesc.iter_areas().filter(|area| area.device_id == id) {
1781 buf.write_u32::<LittleEndian>(area.flash_id as u32).unwrap();
1782 buf.write_u32::<LittleEndian>(area.off).unwrap();
1783 buf.write_u32::<LittleEndian>(area.size).unwrap();
1784 buf.write_u32::<LittleEndian>(0).unwrap();
1785 }
1786
1787 let dev = flash.get_mut(&id).unwrap();
1788
1789 // Pad to alignment.
1790 while buf.len() % dev.align() != 0 {
1791 buf.push(0);
1792 }
1793
1794 dev.write(0, &buf).unwrap();
1795 }
1796}
1797
David Brown5c9e0f12019-01-09 16:34:33 -07001798/// The image header
1799#[repr(C)]
David Brown2ee5f7f2020-01-13 14:04:01 -07001800#[derive(Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001801pub struct ImageHeader {
1802 magic: u32,
1803 load_addr: u32,
1804 hdr_size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001805 protect_tlv_size: u16,
David Brown5c9e0f12019-01-09 16:34:33 -07001806 img_size: u32,
1807 flags: u32,
1808 ver: ImageVersion,
1809 _pad2: u32,
1810}
1811
1812impl AsRaw for ImageHeader {}
1813
1814#[repr(C)]
David Brownc3898d62019-08-05 14:20:02 -06001815#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001816pub struct ImageVersion {
David Brown7a81c4b2019-07-29 15:20:21 -06001817 pub major: u8,
1818 pub minor: u8,
1819 pub revision: u16,
1820 pub build_num: u32,
David Brown5c9e0f12019-01-09 16:34:33 -07001821}
1822
David Brownc3898d62019-08-05 14:20:02 -06001823#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001824pub struct SlotInfo {
1825 pub base_off: usize,
1826 pub trailer_off: usize,
1827 pub len: usize,
David Brown3b090212019-07-30 15:59:28 -06001828 // Which slot within this device.
1829 pub index: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001830 pub dev_id: u8,
1831}
1832
David Brown347dc572019-11-15 11:37:25 -07001833const MAGIC: &[u8] = &[0x77, 0xc2, 0x95, 0xf3,
1834 0x60, 0xd2, 0xef, 0x7f,
1835 0x35, 0x52, 0x50, 0x0f,
1836 0x2c, 0xb6, 0x79, 0x80];
David Brown5c9e0f12019-01-09 16:34:33 -07001837
1838// Replicates defines found in bootutil.h
1839const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1840const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1841
1842const BOOT_FLAG_SET: Option<u8> = Some(1);
1843const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1844
1845/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001846pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1847 let dev = flash.get_mut(&slot.dev_id).unwrap();
David Brown95de4502019-11-15 12:01:34 -07001848 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001849 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown95de4502019-11-15 12:01:34 -07001850 if offset % align != 0 || MAGIC.len() % align != 0 {
1851 // The write size is larger than the magic value. Fill a buffer
1852 // with the erased value, put the MAGIC in it, and write it in its
1853 // entirety.
1854 let mut buf = vec![dev.erased_val(); align];
1855 buf[(offset % align)..].copy_from_slice(MAGIC);
1856 dev.write(offset - (offset % align), &buf).unwrap();
1857 } else {
1858 dev.write(offset, MAGIC).unwrap();
1859 }
David Brown5c9e0f12019-01-09 16:34:33 -07001860}
1861
1862/// Writes the image_ok flag which, guess what, tells the bootloader
1863/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001864fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
David Browneecae522019-11-15 12:00:20 -07001865 // Overwrite mode always is permanent, and only the magic is used in
1866 // the trailer. To avoid problems with large write sizes, don't try to
1867 // set anything in this case.
1868 if Caps::OverwriteUpgrade.present() {
1869 return;
1870 }
1871
David Brown76101572019-02-28 11:29:03 -07001872 let dev = flash.get_mut(&slot.dev_id).unwrap();
1873 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001874 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001875 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001876 let align = dev.align();
1877 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001878}
1879
1880// Drop some pseudo-random gibberish onto the data.
1881fn splat(data: &mut [u8], seed: usize) {
David Browncd842842020-07-09 15:46:53 -06001882 let mut seed_block = [0u8; 16];
1883 let mut buf = Cursor::new(&mut seed_block[..]);
1884 buf.write_u32::<LittleEndian>(0x135782ea).unwrap();
1885 buf.write_u32::<LittleEndian>(0x92184728).unwrap();
1886 buf.write_u32::<LittleEndian>(data.len() as u32).unwrap();
1887 buf.write_u32::<LittleEndian>(seed as u32).unwrap();
1888 let mut rng: SmallRng = SeedableRng::from_seed(seed_block);
David Brown5c9e0f12019-01-09 16:34:33 -07001889 rng.fill_bytes(data);
1890}
1891
1892/// Return a read-only view into the raw bytes of this object
1893trait AsRaw : Sized {
David Brown173e6ca2021-03-10 05:25:36 -07001894 fn as_raw(&self) -> &[u8] {
David Brown5c9e0f12019-01-09 16:34:33 -07001895 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1896 mem::size_of::<Self>()) }
1897 }
1898}
1899
1900pub fn show_sizes() {
1901 // This isn't panic safe.
1902 for min in &[1, 2, 4, 8] {
1903 let msize = c::boot_trailer_sz(*min);
1904 println!("{:2}: {} (0x{:x})", min, msize, msize);
1905 }
1906}
David Brown95de4502019-11-15 12:01:34 -07001907
1908#[cfg(not(feature = "large-write"))]
1909fn test_alignments() -> &'static [usize] {
David Brown95de4502019-11-15 12:01:34 -07001910 &[1, 2, 4, 8]
1911}
1912
1913#[cfg(feature = "large-write")]
1914fn test_alignments() -> &'static [usize] {
David Brown95de4502019-11-15 12:01:34 -07001915 &[1, 2, 4, 8, 128, 512]
1916}