blob: 9c24a3eeb18c18483d63aef8502f956405cea728 [file] [log] [blame]
David Browne2acfae2020-01-21 16:45:01 -07001// Copyright (c) 2019 Linaro LTD
2// Copyright (c) 2019-2020 JUUL Labs
3// Copyright (c) 2019 Arm Limited
4//
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::{
18 distributions::{IndependentSample, Range},
19 Rng, SeedableRng, XorShiftRng,
20};
21use std::{
David Brown297029a2019-08-13 14:29:51 -060022 collections::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,
29 stream_cipher::{
30 generic_array::GenericArray,
31 NewFixStreamCipher,
32 StreamCipherCore,
33 },
34};
35
David Brown76101572019-02-28 11:29:03 -070036use simflash::{Flash, SimFlash, SimMultiFlash};
David Browne5133242019-02-28 11:05:19 -070037use mcuboot_sys::{c, AreaDesc, FlashId};
38use crate::{
39 ALL_DEVICES,
40 DeviceName,
41};
David Brown5c9e0f12019-01-09 16:34:33 -070042use crate::caps::Caps;
David Brownc3898d62019-08-05 14:20:02 -060043use crate::depends::{
44 BoringDep,
45 Depender,
46 DepTest,
David Brown873be312019-09-03 12:22:32 -060047 DepType,
David Brownc3898d62019-08-05 14:20:02 -060048 PairDep,
49 UpgradeInfo,
50};
Fabio Utzig90f449e2019-10-24 07:43:53 -030051use crate::tlv::{ManifestGen, TlvGen, TlvFlags};
David Brown5c9e0f12019-01-09 16:34:33 -070052
David Browne5133242019-02-28 11:05:19 -070053/// A builder for Images. This describes a single run of the simulator,
54/// capturing the configuration of a particular set of devices, including
55/// the flash simulator(s) and the information about the slots.
56#[derive(Clone)]
57pub struct ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070058 flash: SimMultiFlash,
David Browne5133242019-02-28 11:05:19 -070059 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070060 slots: Vec<[SlotInfo; 2]>,
David Browne5133242019-02-28 11:05:19 -070061}
62
David Brown998aa8d2019-02-28 10:54:50 -070063/// Images represents the state of a simulation for a given set of images.
David Brown76101572019-02-28 11:29:03 -070064/// The flash holds the state of the simulated flash, whereas primaries
David Brown998aa8d2019-02-28 10:54:50 -070065/// and upgrades hold the expected contents of these images.
66pub struct Images {
David Brown76101572019-02-28 11:29:03 -070067 flash: SimMultiFlash,
David Brownca234692019-02-28 11:22:19 -070068 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070069 images: Vec<OneImage>,
70 total_count: Option<i32>,
71}
72
73/// When doing multi-image, there is an instance of this information for
74/// each of the images. Single image there will be one of these.
75struct OneImage {
David Brownca234692019-02-28 11:22:19 -070076 slots: [SlotInfo; 2],
77 primaries: ImageData,
78 upgrades: ImageData,
David Brownca234692019-02-28 11:22:19 -070079}
80
81/// The Rust-side representation of an image. For unencrypted images, this
82/// is just the unencrypted payload. For encrypted images, we store both
83/// the encrypted and the plaintext.
84struct ImageData {
85 plain: Vec<u8>,
86 cipher: Option<Vec<u8>>,
David Brown998aa8d2019-02-28 10:54:50 -070087}
88
David Browne5133242019-02-28 11:05:19 -070089impl ImagesBuilder {
David Brown5bc62c62019-03-05 12:11:48 -070090 /// Construct a new image builder for the given device. Returns
91 /// Some(builder) if is possible to test this configuration, or None if
92 /// not possible (for example, if there aren't enough image slots).
Fabio Utzig114a6472019-11-28 10:24:09 -030093 pub fn new(device: DeviceName, align: usize, erased_val: u8) -> Result<Self, String> {
94 let (flash, areadesc, unsupported_caps) = Self::make_device(device, align, erased_val);
95
96 for cap in unsupported_caps {
97 if cap.present() {
98 return Err(format!("unsupported {:?}", cap));
99 }
100 }
David Browne5133242019-02-28 11:05:19 -0700101
David Brown06ef06e2019-03-05 12:28:10 -0700102 let num_images = Caps::get_num_images();
David Browne5133242019-02-28 11:05:19 -0700103
David Brown06ef06e2019-03-05 12:28:10 -0700104 let mut slots = Vec::with_capacity(num_images);
105 for image in 0..num_images {
106 // This mapping must match that defined in
107 // `boot/zephyr/include/sysflash/sysflash.h`.
108 let id0 = match image {
109 0 => FlashId::Image0,
110 1 => FlashId::Image2,
111 _ => panic!("More than 2 images not supported"),
112 };
113 let (primary_base, primary_len, primary_dev_id) = match areadesc.find(id0) {
114 Some(info) => info,
Fabio Utzig114a6472019-11-28 10:24:09 -0300115 None => return Err("insufficient partitions".to_string()),
David Brown06ef06e2019-03-05 12:28:10 -0700116 };
117 let id1 = match image {
118 0 => FlashId::Image1,
119 1 => FlashId::Image3,
120 _ => panic!("More than 2 images not supported"),
121 };
122 let (secondary_base, secondary_len, secondary_dev_id) = match areadesc.find(id1) {
123 Some(info) => info,
Fabio Utzig114a6472019-11-28 10:24:09 -0300124 None => return Err("insufficient partitions".to_string()),
David Brown06ef06e2019-03-05 12:28:10 -0700125 };
David Browne5133242019-02-28 11:05:19 -0700126
Christopher Collinsa1c12042019-05-23 14:00:28 -0700127 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 4;
David Browne5133242019-02-28 11:05:19 -0700128
David Brown06ef06e2019-03-05 12:28:10 -0700129 // Construct a primary image.
130 let primary = SlotInfo {
131 base_off: primary_base as usize,
132 trailer_off: primary_base + primary_len - offset_from_end,
133 len: primary_len as usize,
134 dev_id: primary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600135 index: 0,
David Brown06ef06e2019-03-05 12:28:10 -0700136 };
137
138 // And an upgrade image.
139 let secondary = SlotInfo {
140 base_off: secondary_base as usize,
141 trailer_off: secondary_base + secondary_len - offset_from_end,
142 len: secondary_len as usize,
143 dev_id: secondary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600144 index: 1,
David Brown06ef06e2019-03-05 12:28:10 -0700145 };
146
147 slots.push([primary, secondary]);
148 }
David Browne5133242019-02-28 11:05:19 -0700149
Fabio Utzig114a6472019-11-28 10:24:09 -0300150 Ok(ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -0700151 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700152 areadesc: areadesc,
David Brown06ef06e2019-03-05 12:28:10 -0700153 slots: slots,
David Brown5bc62c62019-03-05 12:11:48 -0700154 })
David Browne5133242019-02-28 11:05:19 -0700155 }
156
157 pub fn each_device<F>(f: F)
158 where F: Fn(Self)
159 {
160 for &dev in ALL_DEVICES {
David Brown95de4502019-11-15 12:01:34 -0700161 for &align in test_alignments() {
David Browne5133242019-02-28 11:05:19 -0700162 for &erased_val in &[0, 0xff] {
David Brown5bc62c62019-03-05 12:11:48 -0700163 match Self::new(dev, align, erased_val) {
Fabio Utzig114a6472019-11-28 10:24:09 -0300164 Ok(run) => f(run),
165 Err(msg) => warn!("Skipping {}: {}", dev, msg),
David Brown5bc62c62019-03-05 12:11:48 -0700166 }
David Browne5133242019-02-28 11:05:19 -0700167 }
168 }
169 }
170 }
171
172 /// Construct an `Images` that doesn't expect an upgrade to happen.
David Brownc3898d62019-08-05 14:20:02 -0600173 pub fn make_no_upgrade_image(self, deps: &DepTest) -> Images {
174 let num_images = self.num_images();
David Brown76101572019-02-28 11:29:03 -0700175 let mut flash = self.flash;
David Brownc3898d62019-08-05 14:20:02 -0600176 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
177 let dep: Box<dyn Depender> = if num_images > 1 {
178 Box::new(PairDep::new(num_images, image_num, deps))
179 } else {
180 Box::new(BoringDep(image_num))
181 };
182 let primaries = install_image(&mut flash, &slots[0], 42784, &*dep, false);
David Brown873be312019-09-03 12:22:32 -0600183 let upgrades = match deps.depends[image_num] {
184 DepType::NoUpgrade => install_no_image(),
185 _ => install_image(&mut flash, &slots[1], 46928, &*dep, false)
186 };
David Brown84b49f72019-03-01 10:58:22 -0700187 OneImage {
188 slots: slots,
189 primaries: primaries,
190 upgrades: upgrades,
191 }}).collect();
David Brown297029a2019-08-13 14:29:51 -0600192 install_ptable(&mut flash, &self.areadesc);
David Browne5133242019-02-28 11:05:19 -0700193 Images {
David Brown76101572019-02-28 11:29:03 -0700194 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700195 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700196 images: images,
David Browne5133242019-02-28 11:05:19 -0700197 total_count: None,
198 }
199 }
200
David Brownc3898d62019-08-05 14:20:02 -0600201 pub fn make_image(self, deps: &DepTest, permanent: bool) -> Images {
202 let mut images = self.make_no_upgrade_image(deps);
David Brown84b49f72019-03-01 10:58:22 -0700203 for image in &images.images {
204 mark_upgrade(&mut images.flash, &image.slots[1]);
205 }
David Browne5133242019-02-28 11:05:19 -0700206
207 // upgrades without fails, counts number of flash operations
Fabio Utziged4a5362019-07-30 12:43:23 -0300208 let total_count = match images.run_basic_upgrade(permanent) {
David Browne5133242019-02-28 11:05:19 -0700209 Ok(v) => v,
Fabio Utzig7c1d1552019-08-28 10:59:22 -0300210 Err(_) =>
David Brown0e6bc7f2019-09-03 12:29:56 -0600211 if deps.upgrades.iter().any(|u| *u == UpgradeInfo::Held) {
212 0
213 } else {
214 panic!("Unable to perform basic upgrade");
215 }
David Browne5133242019-02-28 11:05:19 -0700216 };
217
218 images.total_count = Some(total_count);
219 images
220 }
221
222 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700223 let mut bad_flash = self.flash;
David Brownc3898d62019-08-05 14:20:02 -0600224 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
225 let dep = BoringDep(image_num);
226 let primaries = install_image(&mut bad_flash, &slots[0], 32784, &dep, false);
227 let upgrades = install_image(&mut bad_flash, &slots[1], 41928, &dep, true);
David Brown84b49f72019-03-01 10:58:22 -0700228 OneImage {
229 slots: slots,
230 primaries: primaries,
231 upgrades: upgrades,
232 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700233 Images {
David Brown76101572019-02-28 11:29:03 -0700234 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700235 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700236 images: images,
David Browne5133242019-02-28 11:05:19 -0700237 total_count: None,
238 }
239 }
240
241 /// Build the Flash and area descriptor for a given device.
Fabio Utzig114a6472019-11-28 10:24:09 -0300242 pub fn make_device(device: DeviceName, align: usize, erased_val: u8) -> (SimMultiFlash, AreaDesc, &'static [Caps]) {
David Browne5133242019-02-28 11:05:19 -0700243 match device {
244 DeviceName::Stm32f4 => {
245 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700246 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
247 64 * 1024,
248 128 * 1024, 128 * 1024, 128 * 1024],
249 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700250 let dev_id = 0;
251 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700252 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700253 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
254 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
255 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
256
David Brown76101572019-02-28 11:29:03 -0700257 let mut flash = SimMultiFlash::new();
258 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300259 (flash, areadesc, &[Caps::SwapUsingMove])
David Browne5133242019-02-28 11:05:19 -0700260 }
261 DeviceName::K64f => {
262 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700263 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700264
265 let dev_id = 0;
266 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700267 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700268 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
269 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
270 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
271
David Brown76101572019-02-28 11:29:03 -0700272 let mut flash = SimMultiFlash::new();
273 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300274 (flash, areadesc, &[])
David Browne5133242019-02-28 11:05:19 -0700275 }
276 DeviceName::K64fBig => {
277 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
278 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700279 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700280
281 let dev_id = 0;
282 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700283 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700284 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
285 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
286 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
287
David Brown76101572019-02-28 11:29:03 -0700288 let mut flash = SimMultiFlash::new();
289 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300290 (flash, areadesc, &[Caps::SwapUsingMove])
David Browne5133242019-02-28 11:05:19 -0700291 }
292 DeviceName::Nrf52840 => {
293 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
294 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700295 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700296
297 let dev_id = 0;
298 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700299 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700300 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
301 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
302 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
303
David Brown76101572019-02-28 11:29:03 -0700304 let mut flash = SimMultiFlash::new();
305 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300306 (flash, areadesc, &[])
David Browne5133242019-02-28 11:05:19 -0700307 }
308 DeviceName::Nrf52840SpiFlash => {
309 // Simulate nrf52840 with external SPI flash. The external SPI flash
310 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700311 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
312 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700313
314 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700315 areadesc.add_flash_sectors(0, &dev0);
316 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700317
318 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
319 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
320 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
321
David Brown76101572019-02-28 11:29:03 -0700322 let mut flash = SimMultiFlash::new();
323 flash.insert(0, dev0);
324 flash.insert(1, dev1);
Fabio Utzig114a6472019-11-28 10:24:09 -0300325 (flash, areadesc, &[Caps::SwapUsingMove])
David Browne5133242019-02-28 11:05:19 -0700326 }
David Brown2bff6472019-03-05 13:58:35 -0700327 DeviceName::K64fMulti => {
328 // NXP style flash, but larger, to support multiple images.
329 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
330
331 let dev_id = 0;
332 let mut areadesc = AreaDesc::new();
333 areadesc.add_flash_sectors(dev_id, &dev);
334 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
335 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
336 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
337 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
338 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
339
340 let mut flash = SimMultiFlash::new();
341 flash.insert(dev_id, dev);
Fabio Utzig114a6472019-11-28 10:24:09 -0300342 (flash, areadesc, &[])
David Brown2bff6472019-03-05 13:58:35 -0700343 }
David Browne5133242019-02-28 11:05:19 -0700344 }
345 }
David Brownc3898d62019-08-05 14:20:02 -0600346
347 pub fn num_images(&self) -> usize {
348 self.slots.len()
349 }
David Browne5133242019-02-28 11:05:19 -0700350}
351
David Brown5c9e0f12019-01-09 16:34:33 -0700352impl Images {
353 /// A simple upgrade without forced failures.
354 ///
355 /// Returns the number of flash operations which can later be used to
356 /// inject failures at chosen steps.
Fabio Utziged4a5362019-07-30 12:43:23 -0300357 pub fn run_basic_upgrade(&self, permanent: bool) -> Result<i32, ()> {
358 let (flash, total_count) = self.try_upgrade(None, permanent);
David Brown5c9e0f12019-01-09 16:34:33 -0700359 info!("Total flash operation count={}", total_count);
360
David Brown84b49f72019-03-01 10:58:22 -0700361 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700362 warn!("Image mismatch after first boot");
363 Err(())
364 } else {
365 Ok(total_count)
366 }
367 }
368
David Brownc3898d62019-08-05 14:20:02 -0600369 /// Test a simple upgrade, with dependencies given, and verify that the
370 /// image does as is described in the test.
371 pub fn run_check_deps(&self, deps: &DepTest) -> bool {
372 let (flash, _) = self.try_upgrade(None, true);
373
374 self.verify_dep_images(&flash, deps)
375 }
376
Fabio Utzigf5480c72019-11-28 10:41:57 -0300377 fn is_swap_upgrade(&self) -> bool {
378 Caps::SwapUsingScratch.present() || Caps::SwapUsingMove.present()
379 }
380
David Brown5c9e0f12019-01-09 16:34:33 -0700381 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700382 if Caps::OverwriteUpgrade.present() {
383 return false;
384 }
David Brown5c9e0f12019-01-09 16:34:33 -0700385
David Brown5c9e0f12019-01-09 16:34:33 -0700386 let mut fails = 0;
387
388 // FIXME: this test would also pass if no swap is ever performed???
Fabio Utzigf5480c72019-11-28 10:41:57 -0300389 if self.is_swap_upgrade() {
David Brown5c9e0f12019-01-09 16:34:33 -0700390 for count in 2 .. 5 {
391 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700392 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700393 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700394 error!("Revert failure on count {}", count);
395 fails += 1;
396 }
397 }
398 }
399
400 fails > 0
401 }
402
403 pub fn run_perm_with_fails(&self) -> bool {
404 let mut fails = 0;
405 let total_flash_ops = self.total_count.unwrap();
406
407 // Let's try an image halfway through.
408 for i in 1 .. total_flash_ops {
409 info!("Try interruption at {}", i);
Fabio Utziged4a5362019-07-30 12:43:23 -0300410 let (flash, count) = self.try_upgrade(Some(i), true);
David Brown5c9e0f12019-01-09 16:34:33 -0700411 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700412 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700413 warn!("FAIL at step {} of {}", i, total_flash_ops);
414 fails += 1;
415 }
416
David Brown84b49f72019-03-01 10:58:22 -0700417 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
418 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100419 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700420 fails += 1;
421 }
422
David Brown84b49f72019-03-01 10:58:22 -0700423 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
424 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100425 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700426 fails += 1;
427 }
428
Fabio Utzigf5480c72019-11-28 10:41:57 -0300429 if self.is_swap_upgrade() {
David Brown84b49f72019-03-01 10:58:22 -0700430 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100431 warn!("Secondary slot FAIL at step {} of {}",
432 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700433 fails += 1;
434 }
435 }
436 }
437
438 if fails > 0 {
439 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
440 fails as f32 * 100.0 / total_flash_ops as f32);
441 }
442
443 fails > 0
444 }
445
David Brown5c9e0f12019-01-09 16:34:33 -0700446 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
447 let mut fails = 0;
448 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700449 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700450 info!("Random interruptions at reset points={:?}", total_counts);
451
David Brown84b49f72019-03-01 10:58:22 -0700452 let primary_slot_ok = self.verify_images(&flash, 0, 1);
Fabio Utzigf5480c72019-11-28 10:41:57 -0300453 let secondary_slot_ok = if self.is_swap_upgrade() {
David Brown84b49f72019-03-01 10:58:22 -0700454 // TODO: This result is ignored.
455 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700456 } else {
457 true
458 };
David Vincze2d736ad2019-02-18 11:50:22 +0100459 if !primary_slot_ok || !secondary_slot_ok {
460 error!("Image mismatch after random interrupts: primary slot={} \
461 secondary slot={}",
462 if primary_slot_ok { "ok" } else { "fail" },
463 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700464 fails += 1;
465 }
David Brown84b49f72019-03-01 10:58:22 -0700466 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
467 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100468 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700469 fails += 1;
470 }
David Brown84b49f72019-03-01 10:58:22 -0700471 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
472 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100473 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700474 fails += 1;
475 }
476
477 if fails > 0 {
478 error!("Error testing perm upgrade with {} fails", total_fails);
479 }
480
481 fails > 0
482 }
483
David Brown5c9e0f12019-01-09 16:34:33 -0700484 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700485 if Caps::OverwriteUpgrade.present() {
486 return false;
487 }
David Brown5c9e0f12019-01-09 16:34:33 -0700488
David Brown5c9e0f12019-01-09 16:34:33 -0700489 let mut fails = 0;
490
Fabio Utzigf5480c72019-11-28 10:41:57 -0300491 if self.is_swap_upgrade() {
Fabio Utziged4a5362019-07-30 12:43:23 -0300492 for i in 1 .. self.total_count.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -0700493 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700494 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700495 error!("Revert failed at interruption {}", i);
496 fails += 1;
497 }
498 }
499 }
500
501 fails > 0
502 }
503
David Brown5c9e0f12019-01-09 16:34:33 -0700504 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700505 if Caps::OverwriteUpgrade.present() {
506 return false;
507 }
David Brown5c9e0f12019-01-09 16:34:33 -0700508
David Brown76101572019-02-28 11:29:03 -0700509 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700510 let mut fails = 0;
511
512 info!("Try norevert");
513
514 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700515 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700516 if result != 0 {
517 warn!("Failed first boot");
518 fails += 1;
519 }
520
521 //FIXME: copy_done is written by boot_go, is it ok if no copy
522 // was ever done?
523
David Brown84b49f72019-03-01 10:58:22 -0700524 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100525 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700526 fails += 1;
527 }
David Brown84b49f72019-03-01 10:58:22 -0700528 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
529 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100530 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700531 fails += 1;
532 }
David Brown84b49f72019-03-01 10:58:22 -0700533 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
534 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100535 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700536 fails += 1;
537 }
538
David Vincze2d736ad2019-02-18 11:50:22 +0100539 // Marks image in the primary slot as permanent,
540 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700541 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700542
David Brown84b49f72019-03-01 10:58:22 -0700543 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
544 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100545 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700546 fails += 1;
547 }
548
David Brown76101572019-02-28 11:29:03 -0700549 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700550 if result != 0 {
551 warn!("Failed second boot");
552 fails += 1;
553 }
554
David Brown84b49f72019-03-01 10:58:22 -0700555 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
556 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100557 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700558 fails += 1;
559 }
David Brown84b49f72019-03-01 10:58:22 -0700560 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700561 warn!("Failed image verification");
562 fails += 1;
563 }
564
565 if fails > 0 {
566 error!("Error running upgrade without revert");
567 }
568
569 fails > 0
570 }
571
David Vincze2d736ad2019-02-18 11:50:22 +0100572 // Tests a new image written to the primary slot that already has magic and
573 // image_ok set while there is no image on the secondary slot, so no revert
574 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700575 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700576 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700577 let mut fails = 0;
578
579 info!("Try non-revert on imgtool generated image");
580
David Brown84b49f72019-03-01 10:58:22 -0700581 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700582
David Vincze2d736ad2019-02-18 11:50:22 +0100583 // This simulates writing an image created by imgtool to
584 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700585 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
586 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100587 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700588 fails += 1;
589 }
590
591 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700592 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700593 if result != 0 {
594 warn!("Failed first boot");
595 fails += 1;
596 }
597
598 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700599 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700600 warn!("Failed image verification");
601 fails += 1;
602 }
David Brown84b49f72019-03-01 10:58:22 -0700603 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
604 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100605 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700606 fails += 1;
607 }
David Brown84b49f72019-03-01 10:58:22 -0700608 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
609 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100610 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700611 fails += 1;
612 }
613
614 if fails > 0 {
615 error!("Expected a non revert with new image");
616 }
617
618 fails > 0
619 }
620
David Vincze2d736ad2019-02-18 11:50:22 +0100621 // Tests a new image written to the primary slot that already has magic and
622 // image_ok set while there is no image on the secondary slot, so no revert
623 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700624 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700625 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700626 let mut fails = 0;
627
628 info!("Try upgrade image with bad signature");
629
David Brown84b49f72019-03-01 10:58:22 -0700630 self.mark_upgrades(&mut flash, 0);
631 self.mark_permanent_upgrades(&mut flash, 0);
632 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700633
David Brown84b49f72019-03-01 10:58:22 -0700634 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
635 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100636 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700637 fails += 1;
638 }
639
640 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700641 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700642 if result != 0 {
643 warn!("Failed first boot");
644 fails += 1;
645 }
646
647 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700648 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700649 warn!("Failed image verification");
650 fails += 1;
651 }
David Brown84b49f72019-03-01 10:58:22 -0700652 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
653 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100654 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700655 fails += 1;
656 }
657
658 if fails > 0 {
659 error!("Expected an upgrade failure when image has bad signature");
660 }
661
662 fails > 0
663 }
664
David Brown5c9e0f12019-01-09 16:34:33 -0700665 fn trailer_sz(&self, align: usize) -> usize {
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300666 c::boot_trailer_sz(align as u32) as usize
David Brown5c9e0f12019-01-09 16:34:33 -0700667 }
668
David Brown5c9e0f12019-01-09 16:34:33 -0700669 fn status_sz(&self, align: usize) -> usize {
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300670 c::boot_status_sz(align as u32) as usize
David Brown5c9e0f12019-01-09 16:34:33 -0700671 }
672
673 /// This test runs a simple upgrade with no fails in the images, but
674 /// allowing for fails in the status area. This should run to the end
675 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700676 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100677 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700678 return false;
679 }
680
David Brown76101572019-02-28 11:29:03 -0700681 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700682 let mut fails = 0;
683
684 info!("Try swap with status fails");
685
David Brown84b49f72019-03-01 10:58:22 -0700686 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700687 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700688
David Brown76101572019-02-28 11:29:03 -0700689 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700690 if result != 0 {
691 warn!("Failed!");
692 fails += 1;
693 }
694
695 // Failed writes to the marked "bad" region don't assert anymore.
696 // Any detected assert() is happening in another part of the code.
697 if asserts != 0 {
698 warn!("At least one assert() was called");
699 fails += 1;
700 }
701
David Brown84b49f72019-03-01 10:58:22 -0700702 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
703 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100704 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700705 fails += 1;
706 }
707
David Brown84b49f72019-03-01 10:58:22 -0700708 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700709 warn!("Failed image verification");
710 fails += 1;
711 }
712
David Vincze2d736ad2019-02-18 11:50:22 +0100713 info!("validate primary slot enabled; \
714 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700715 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700716 if result != 0 {
717 warn!("Failed!");
718 fails += 1;
719 }
720
721 if fails > 0 {
722 error!("Error running upgrade with status write fails");
723 }
724
725 fails > 0
726 }
727
728 /// This test runs a simple upgrade with no fails in the images, but
729 /// allowing for fails in the status area. This should run to the end
730 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700731 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700732 if Caps::OverwriteUpgrade.present() {
733 false
David Vincze2d736ad2019-02-18 11:50:22 +0100734 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700735
David Brown76101572019-02-28 11:29:03 -0700736 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700737 let mut fails = 0;
738 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700739
David Brown85904a82019-01-11 13:45:12 -0700740 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700741
David Brown85904a82019-01-11 13:45:12 -0700742 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700743
David Brown84b49f72019-03-01 10:58:22 -0700744 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700745 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700746
747 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700748 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700749 if asserts != 0 {
750 warn!("At least one assert() was called");
751 fails += 1;
752 }
753
David Brown76101572019-02-28 11:29:03 -0700754 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700755
756 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700757 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700758
759 // This might throw no asserts, for large sector devices, where
760 // a single failure writing is indistinguishable from no failure,
761 // or throw a single assert for small sector devices that fail
762 // multiple times...
763 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100764 warn!("Expected single assert validating the primary slot, \
765 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700766 fails += 1;
767 }
768
769 if fails > 0 {
770 error!("Error running upgrade with status write fails");
771 }
772
773 fails > 0
774 } else {
David Brown76101572019-02-28 11:29:03 -0700775 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700776 let mut fails = 0;
777
778 info!("Try interrupted swap with status fails");
779
David Brown84b49f72019-03-01 10:58:22 -0700780 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700781 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700782
783 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700784 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700785 if asserts == 0 {
786 warn!("No assert() detected");
787 fails += 1;
788 }
789
790 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700791 }
David Brown5c9e0f12019-01-09 16:34:33 -0700792 }
793
794 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700795 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700796 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700797 if Caps::OverwriteUpgrade.present() {
798 return;
799 }
800
David Brown84b49f72019-03-01 10:58:22 -0700801 // Set this for each image.
802 for image in &self.images {
803 let dev_id = &image.slots[slot].dev_id;
804 let dev = flash.get_mut(&dev_id).unwrap();
805 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -0700806 let off = &image.slots[slot].base_off;
807 let len = &image.slots[slot].len;
David Brown84b49f72019-03-01 10:58:22 -0700808 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700809
David Brown84b49f72019-03-01 10:58:22 -0700810 // Mark the status area as a bad area
811 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
812 }
David Brown5c9e0f12019-01-09 16:34:33 -0700813 }
814
David Brown76101572019-02-28 11:29:03 -0700815 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100816 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700817 return;
818 }
819
David Brown84b49f72019-03-01 10:58:22 -0700820 for image in &self.images {
821 let dev_id = &image.slots[slot].dev_id;
822 let dev = flash.get_mut(&dev_id).unwrap();
823 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700824
David Brown84b49f72019-03-01 10:58:22 -0700825 // Disabling write verification the only assert triggered by
826 // boot_go should be checking for integrity of status bytes.
827 dev.set_verify_writes(false);
828 }
David Brown5c9e0f12019-01-09 16:34:33 -0700829 }
830
David Browndb505822019-03-01 10:04:20 -0700831 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
832 /// of the number of flash operations done total.
Fabio Utziged4a5362019-07-30 12:43:23 -0300833 fn try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32) {
David Browndb505822019-03-01 10:04:20 -0700834 // Clone the flash to have a new copy.
835 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700836
Fabio Utziged4a5362019-07-30 12:43:23 -0300837 if permanent {
838 self.mark_permanent_upgrades(&mut flash, 1);
839 }
David Brown5c9e0f12019-01-09 16:34:33 -0700840
David Browndb505822019-03-01 10:04:20 -0700841 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700842
David Browndb505822019-03-01 10:04:20 -0700843 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
844 (-0x13579, _) => (true, stop.unwrap()),
845 (0, _) => (false, -counter),
846 (x, _) => panic!("Unknown return: {}", x),
847 };
David Brown5c9e0f12019-01-09 16:34:33 -0700848
David Browndb505822019-03-01 10:04:20 -0700849 counter = 0;
850 if first_interrupted {
851 // fl.dump();
852 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
853 (-0x13579, _) => panic!("Shouldn't stop again"),
854 (0, _) => (),
855 (x, _) => panic!("Unknown return: {}", x),
856 }
857 }
David Brown5c9e0f12019-01-09 16:34:33 -0700858
David Browndb505822019-03-01 10:04:20 -0700859 (flash, count - counter)
860 }
861
862 fn try_revert(&self, count: usize) -> SimMultiFlash {
863 let mut flash = self.flash.clone();
864
865 // fl.write_file("image0.bin").unwrap();
866 for i in 0 .. count {
867 info!("Running boot pass {}", i + 1);
868 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
869 }
870 flash
871 }
872
873 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
874 let mut flash = self.flash.clone();
875 let mut fails = 0;
876
877 let mut counter = stop;
878 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
879 if x != -0x13579 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700880 warn!("Should have stopped test at interruption point");
David Browndb505822019-03-01 10:04:20 -0700881 fails += 1;
882 }
883
Fabio Utzig8af7f792019-07-30 12:40:01 -0300884 // In a multi-image setup, copy done might be set if any number of
885 // images was already successfully swapped.
886 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
887 warn!("copy_done should be unset");
888 fails += 1;
889 }
890
David Browndb505822019-03-01 10:04:20 -0700891 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
892 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700893 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -0700894 fails += 1;
895 }
896
David Brown84b49f72019-03-01 10:58:22 -0700897 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700898 warn!("Image in the primary slot before revert is invalid at stop={}",
899 stop);
900 fails += 1;
901 }
David Brown84b49f72019-03-01 10:58:22 -0700902 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700903 warn!("Image in the secondary slot before revert is invalid at stop={}",
904 stop);
905 fails += 1;
906 }
David Brown84b49f72019-03-01 10:58:22 -0700907 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
908 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700909 warn!("Mismatched trailer for the primary slot before revert");
910 fails += 1;
911 }
David Brown84b49f72019-03-01 10:58:22 -0700912 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
913 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700914 warn!("Mismatched trailer for the secondary slot before revert");
915 fails += 1;
916 }
917
918 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700919 let mut counter = stop;
920 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
921 if x != -0x13579 {
922 warn!("Should have stopped revert at interruption point");
923 fails += 1;
924 }
925
David Browndb505822019-03-01 10:04:20 -0700926 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
927 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700928 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -0700929 fails += 1;
930 }
931
David Brown84b49f72019-03-01 10:58:22 -0700932 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700933 warn!("Image in the primary slot after revert is invalid at stop={}",
934 stop);
935 fails += 1;
936 }
David Brown84b49f72019-03-01 10:58:22 -0700937 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700938 warn!("Image in the secondary slot after revert is invalid at stop={}",
939 stop);
940 fails += 1;
941 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700942
David Brown84b49f72019-03-01 10:58:22 -0700943 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
944 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700945 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -0700946 fails += 1;
947 }
David Brown84b49f72019-03-01 10:58:22 -0700948 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
949 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700950 warn!("Mismatched trailer for the secondary slot after revert");
951 fails += 1;
952 }
953
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700954 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
955 if x != 0 {
956 warn!("Should have finished 3rd boot");
957 fails += 1;
958 }
959
960 if !self.verify_images(&flash, 0, 0) {
961 warn!("Image in the primary slot is invalid on 1st boot after revert");
962 fails += 1;
963 }
964 if !self.verify_images(&flash, 1, 1) {
965 warn!("Image in the secondary slot is invalid on 1st boot after revert");
966 fails += 1;
967 }
968
David Browndb505822019-03-01 10:04:20 -0700969 fails > 0
970 }
971
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700972
David Browndb505822019-03-01 10:04:20 -0700973 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
974 let mut flash = self.flash.clone();
975
David Brown84b49f72019-03-01 10:58:22 -0700976 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700977
978 let mut rng = rand::thread_rng();
979 let mut resets = vec![0i32; count];
980 let mut remaining_ops = total_ops;
981 for i in 0 .. count {
982 let ops = Range::new(1, remaining_ops / 2);
983 let reset_counter = ops.ind_sample(&mut rng);
984 let mut counter = reset_counter;
985 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
986 (0, _) | (-0x13579, _) => (),
987 (x, _) => panic!("Unknown return: {}", x),
988 }
989 remaining_ops -= reset_counter;
990 resets[i] = reset_counter;
991 }
992
993 match c::boot_go(&mut flash, &self.areadesc, None, false) {
994 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700995 (0, _) => (),
996 (x, _) => panic!("Unknown return: {}", x),
997 }
David Brown5c9e0f12019-01-09 16:34:33 -0700998
David Browndb505822019-03-01 10:04:20 -0700999 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -07001000 }
David Brown84b49f72019-03-01 10:58:22 -07001001
1002 /// Verify the image in the given flash device, the specified slot
1003 /// against the expected image.
1004 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001005 self.images.iter().all(|image| {
1006 verify_image(flash, &image.slots[slot],
1007 match against {
1008 0 => &image.primaries,
1009 1 => &image.upgrades,
1010 _ => panic!("Invalid 'against'")
1011 })
1012 })
David Brown84b49f72019-03-01 10:58:22 -07001013 }
1014
David Brownc3898d62019-08-05 14:20:02 -06001015 /// Verify the images, according to the dependency test.
1016 fn verify_dep_images(&self, flash: &SimMultiFlash, deps: &DepTest) -> bool {
1017 for (image_num, (image, upgrade)) in self.images.iter().zip(deps.upgrades.iter()).enumerate() {
1018 info!("Upgrade: slot:{}, {:?}", image_num, upgrade);
1019 if !verify_image(flash, &image.slots[0],
1020 match upgrade {
1021 UpgradeInfo::Upgraded => &image.upgrades,
1022 UpgradeInfo::Held => &image.primaries,
1023 }) {
1024 error!("Failed to upgrade properly: image: {}, upgrade: {:?}", image_num, upgrade);
1025 return true;
1026 }
1027 }
1028
1029 false
1030 }
1031
Fabio Utzig8af7f792019-07-30 12:40:01 -03001032 /// Verify that at least one of the trailers of the images have the
1033 /// specified values.
1034 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
1035 magic: Option<u8>, image_ok: Option<u8>,
1036 copy_done: Option<u8>) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001037 self.images.iter().any(|image| {
1038 verify_trailer(flash, &image.slots[slot],
1039 magic, image_ok, copy_done)
1040 })
Fabio Utzig8af7f792019-07-30 12:40:01 -03001041 }
1042
David Brown84b49f72019-03-01 10:58:22 -07001043 /// Verify that the trailers of the images have the specified
1044 /// values.
1045 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
1046 magic: Option<u8>, image_ok: Option<u8>,
1047 copy_done: Option<u8>) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001048 self.images.iter().all(|image| {
1049 verify_trailer(flash, &image.slots[slot],
1050 magic, image_ok, copy_done)
1051 })
David Brown84b49f72019-03-01 10:58:22 -07001052 }
1053
1054 /// Mark each of the images for permanent upgrade.
1055 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1056 for image in &self.images {
1057 mark_permanent_upgrade(flash, &image.slots[slot]);
1058 }
1059 }
1060
1061 /// Mark each of the images for permanent upgrade.
1062 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1063 for image in &self.images {
1064 mark_upgrade(flash, &image.slots[slot]);
1065 }
1066 }
David Brown297029a2019-08-13 14:29:51 -06001067
1068 /// Dump out the flash image(s) to one or more files for debugging
1069 /// purposes. The names will be written as either "{prefix}.mcubin" or
1070 /// "{prefix}-001.mcubin" depending on how many images there are.
1071 pub fn debug_dump(&self, prefix: &str) {
1072 for (id, fdev) in &self.flash {
1073 let name = if self.flash.len() == 1 {
1074 format!("{}.mcubin", prefix)
1075 } else {
1076 format!("{}-{:>0}.mcubin", prefix, id)
1077 };
1078 fdev.write_file(&name).unwrap();
1079 }
1080 }
David Brown5c9e0f12019-01-09 16:34:33 -07001081}
1082
1083/// Show the flash layout.
1084#[allow(dead_code)]
1085fn show_flash(flash: &dyn Flash) {
1086 println!("---- Flash configuration ----");
1087 for sector in flash.sector_iter() {
1088 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1089 sector.num, sector.base, sector.size);
1090 }
1091 println!("");
1092}
1093
1094/// Install a "program" into the given image. This fakes the image header, or at least all of the
1095/// fields used by the given code. Returns a copy of the image that was written.
David Brown3b090212019-07-30 15:59:28 -06001096fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: usize,
David Brownc3898d62019-08-05 14:20:02 -06001097 deps: &dyn Depender, bad_sig: bool) -> ImageData {
David Brown3b090212019-07-30 15:59:28 -06001098 let offset = slot.base_off;
1099 let slot_len = slot.len;
1100 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001101
David Brown43643dd2019-01-11 15:43:28 -07001102 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001103
David Brownc3898d62019-08-05 14:20:02 -06001104 // Add the dependencies early to the tlv.
1105 for dep in deps.my_deps(offset, slot.index) {
1106 tlv.add_dependency(deps.other_id(), &dep);
1107 }
1108
David Brown5c9e0f12019-01-09 16:34:33 -07001109 const HDR_SIZE: usize = 32;
1110
1111 // Generate a boot header. Note that the size doesn't include the header.
1112 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001113 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001114 load_addr: 0,
1115 hdr_size: HDR_SIZE as u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001116 protect_tlv_size: tlv.protect_size(),
David Brown5c9e0f12019-01-09 16:34:33 -07001117 img_size: len as u32,
1118 flags: tlv.get_flags(),
David Brownc3898d62019-08-05 14:20:02 -06001119 ver: deps.my_version(offset, slot.index),
David Brown5c9e0f12019-01-09 16:34:33 -07001120 _pad2: 0,
1121 };
1122
1123 let mut b_header = [0; HDR_SIZE];
1124 b_header[..32].clone_from_slice(header.as_raw());
1125 assert_eq!(b_header.len(), HDR_SIZE);
1126
1127 tlv.add_bytes(&b_header);
1128
1129 // The core of the image itself is just pseudorandom data.
1130 let mut b_img = vec![0; len];
1131 splat(&mut b_img, offset);
1132
David Browncb47dd72019-08-05 14:21:49 -06001133 // Add some information at the start of the payload to make it easier
1134 // to see what it is. This will fail if the image itself is too small.
1135 {
1136 let mut wr = Cursor::new(&mut b_img);
1137 writeln!(&mut wr, "offset: {:#x}, dev_id: {:#x}, slot_info: {:?}",
1138 offset, dev_id, slot).unwrap();
1139 writeln!(&mut wr, "version: {:?}", deps.my_version(offset, slot.index)).unwrap();
1140 }
1141
David Brown5c9e0f12019-01-09 16:34:33 -07001142 // TLV signatures work over plain image
1143 tlv.add_bytes(&b_img);
1144
1145 // Generate encrypted images
1146 let flag = TlvFlags::ENCRYPTED as u32;
1147 let is_encrypted = (tlv.get_flags() & flag) == flag;
1148 let mut b_encimg = vec![];
1149 if is_encrypted {
Fabio Utzig90f449e2019-10-24 07:43:53 -03001150 tlv.generate_enc_key();
1151 let enc_key = tlv.get_enc_key();
1152 let key = GenericArray::from_slice(enc_key.as_slice());
David Brown5c9e0f12019-01-09 16:34:33 -07001153 let nonce = GenericArray::from_slice(&[0; 16]);
1154 let mut cipher = Aes128Ctr::new(&key, &nonce);
1155 b_encimg = b_img.clone();
1156 cipher.apply_keystream(&mut b_encimg);
1157 }
1158
1159 // Build the TLV itself.
David Browne90b13f2019-12-06 15:04:00 -07001160 if bad_sig {
1161 tlv.corrupt_sig();
1162 }
1163 let mut b_tlv = tlv.make_tlv();
David Brown5c9e0f12019-01-09 16:34:33 -07001164
Fabio Utzig2f6c1642019-09-11 19:36:30 -03001165 let dev = flash.get_mut(&dev_id).unwrap();
1166
David Brown5c9e0f12019-01-09 16:34:33 -07001167 let mut buf = vec![];
1168 buf.append(&mut b_header.to_vec());
1169 buf.append(&mut b_img);
1170 buf.append(&mut b_tlv.clone());
1171
David Brown95de4502019-11-15 12:01:34 -07001172 // Pad the buffer to a multiple of the flash alignment.
1173 let align = dev.align();
1174 while buf.len() % align != 0 {
1175 buf.push(dev.erased_val());
1176 }
1177
David Brown5c9e0f12019-01-09 16:34:33 -07001178 let mut encbuf = vec![];
1179 if is_encrypted {
1180 encbuf.append(&mut b_header.to_vec());
1181 encbuf.append(&mut b_encimg);
1182 encbuf.append(&mut b_tlv);
David Brown95de4502019-11-15 12:01:34 -07001183
1184 while encbuf.len() % align != 0 {
1185 encbuf.push(dev.erased_val());
1186 }
David Brown5c9e0f12019-01-09 16:34:33 -07001187 }
1188
David Vincze2d736ad2019-02-18 11:50:22 +01001189 // Since images are always non-encrypted in the primary slot, we first write
1190 // an encrypted image, re-read to use for verification, erase + flash
1191 // un-encrypted. In the secondary slot the image is written un-encrypted,
1192 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001193
David Brown3b090212019-07-30 15:59:28 -06001194 if slot.index == 0 {
David Brown5c9e0f12019-01-09 16:34:33 -07001195 let enc_copy: Option<Vec<u8>>;
1196
1197 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001198 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001199
1200 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001201 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001202
1203 enc_copy = Some(enc);
1204
David Brown76101572019-02-28 11:29:03 -07001205 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001206 } else {
1207 enc_copy = None;
1208 }
1209
David Brown76101572019-02-28 11:29:03 -07001210 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001211
1212 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001213 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001214
David Brownca234692019-02-28 11:22:19 -07001215 ImageData {
1216 plain: copy,
1217 cipher: enc_copy,
1218 }
David Brown5c9e0f12019-01-09 16:34:33 -07001219 } else {
1220
David Brown76101572019-02-28 11:29:03 -07001221 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001222
1223 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001224 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001225
1226 let enc_copy: Option<Vec<u8>>;
1227
1228 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001229 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001230
David Brown76101572019-02-28 11:29:03 -07001231 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001232
1233 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001234 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001235
1236 enc_copy = Some(enc);
1237 } else {
1238 enc_copy = None;
1239 }
1240
David Brownca234692019-02-28 11:22:19 -07001241 ImageData {
1242 plain: copy,
1243 cipher: enc_copy,
1244 }
David Brown5c9e0f12019-01-09 16:34:33 -07001245 }
David Brown5c9e0f12019-01-09 16:34:33 -07001246}
1247
David Brown873be312019-09-03 12:22:32 -06001248/// Install no image. This is used when no upgrade happens.
1249fn install_no_image() -> ImageData {
1250 ImageData {
1251 plain: vec![],
1252 cipher: None,
1253 }
1254}
1255
David Brown5c9e0f12019-01-09 16:34:33 -07001256fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001257 if Caps::EcdsaP224.present() {
1258 panic!("Ecdsa P224 not supported in Simulator");
1259 }
David Brown5c9e0f12019-01-09 16:34:33 -07001260
David Brownb8882112019-01-11 14:04:11 -07001261 if Caps::EncKw.present() {
1262 if Caps::RSA2048.present() {
1263 TlvGen::new_rsa_kw()
1264 } else if Caps::EcdsaP256.present() {
1265 TlvGen::new_ecdsa_kw()
1266 } else {
1267 TlvGen::new_enc_kw()
1268 }
1269 } else if Caps::EncRsa.present() {
1270 if Caps::RSA2048.present() {
1271 TlvGen::new_sig_enc_rsa()
1272 } else {
1273 TlvGen::new_enc_rsa()
1274 }
Fabio Utzig90f449e2019-10-24 07:43:53 -03001275 } else if Caps::EncEc256.present() {
Fabio Utzig66b4caa2020-01-04 20:19:28 -03001276 if Caps::EcdsaP256.present() {
1277 TlvGen::new_ecdsa_ecies_p256()
1278 } else {
1279 TlvGen::new_ecies_p256()
1280 }
David Brownb8882112019-01-11 14:04:11 -07001281 } else {
1282 // The non-encrypted configuration.
1283 if Caps::RSA2048.present() {
1284 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001285 } else if Caps::RSA3072.present() {
1286 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001287 } else if Caps::EcdsaP256.present() {
1288 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001289 } else if Caps::Ed25519.present() {
1290 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001291 } else {
1292 TlvGen::new_hash_only()
1293 }
1294 }
David Brown5c9e0f12019-01-09 16:34:33 -07001295}
1296
David Brownca234692019-02-28 11:22:19 -07001297impl ImageData {
1298 /// Find the image contents for the given slot. This assumes that slot 0
1299 /// is unencrypted, and slot 1 is encrypted.
1300 fn find(&self, slot: usize) -> &Vec<u8> {
Fabio Utzig90f449e2019-10-24 07:43:53 -03001301 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present() ||
1302 Caps::EncEc256.present();
David Brownca234692019-02-28 11:22:19 -07001303 match (encrypted, slot) {
1304 (false, _) => &self.plain,
1305 (true, 0) => &self.plain,
1306 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1307 _ => panic!("Invalid slot requested"),
1308 }
David Brown5c9e0f12019-01-09 16:34:33 -07001309 }
1310}
1311
David Brown5c9e0f12019-01-09 16:34:33 -07001312/// Verify that given image is present in the flash at the given offset.
David Brown3b090212019-07-30 15:59:28 -06001313fn verify_image(flash: &SimMultiFlash, slot: &SlotInfo, images: &ImageData) -> bool {
1314 let image = images.find(slot.index);
David Brown5c9e0f12019-01-09 16:34:33 -07001315 let buf = image.as_slice();
David Brown3b090212019-07-30 15:59:28 -06001316 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001317
1318 let mut copy = vec![0u8; buf.len()];
David Brown3b090212019-07-30 15:59:28 -06001319 let offset = slot.base_off;
David Brown76101572019-02-28 11:29:03 -07001320 let dev = flash.get(&dev_id).unwrap();
1321 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001322
1323 if buf != &copy[..] {
1324 for i in 0 .. buf.len() {
1325 if buf[i] != copy[i] {
David Brownc3898d62019-08-05 14:20:02 -06001326 info!("First failure for slot{} at {:#x} ({:#x} within) {:#x}!={:#x}",
1327 slot.index, offset + i, i, buf[i], copy[i]);
David Brown5c9e0f12019-01-09 16:34:33 -07001328 break;
1329 }
1330 }
1331 false
1332 } else {
1333 true
1334 }
1335}
1336
David Brown3b090212019-07-30 15:59:28 -06001337fn verify_trailer(flash: &SimMultiFlash, slot: &SlotInfo,
David Brown5c9e0f12019-01-09 16:34:33 -07001338 magic: Option<u8>, image_ok: Option<u8>,
1339 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001340 if Caps::OverwriteUpgrade.present() {
1341 return true;
1342 }
David Brown5c9e0f12019-01-09 16:34:33 -07001343
David Brown3b090212019-07-30 15:59:28 -06001344 let offset = slot.trailer_off + c::boot_max_align();
1345 let dev_id = slot.dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001346 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001347 let mut failed = false;
1348
David Brown76101572019-02-28 11:29:03 -07001349 let dev = flash.get(&dev_id).unwrap();
1350 let erased_val = dev.erased_val();
1351 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001352
1353 failed |= match magic {
1354 Some(v) => {
David Brown347dc572019-11-15 11:37:25 -07001355 if v == 1 && &copy[24..] != MAGIC {
David Brown5c9e0f12019-01-09 16:34:33 -07001356 warn!("\"magic\" mismatch at {:#x}", offset);
1357 true
1358 } else if v == 3 {
1359 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001360 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001361 warn!("\"magic\" mismatch at {:#x}", offset);
1362 true
1363 } else {
1364 false
1365 }
1366 } else {
1367 false
1368 }
1369 },
1370 None => false,
1371 };
1372
1373 failed |= match image_ok {
1374 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001375 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001376 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1377 true
1378 } else {
1379 false
1380 }
1381 },
1382 None => false,
1383 };
1384
1385 failed |= match copy_done {
1386 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001387 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001388 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1389 true
1390 } else {
1391 false
1392 }
1393 },
1394 None => false,
1395 };
1396
1397 !failed
1398}
1399
David Brown297029a2019-08-13 14:29:51 -06001400/// Install a partition table. This is a simplified partition table that
1401/// we write at the beginning of flash so make it easier for external tools
1402/// to analyze these images.
1403fn install_ptable(flash: &mut SimMultiFlash, areadesc: &AreaDesc) {
1404 let ids: HashSet<u8> = areadesc.iter_areas().map(|area| area.device_id).collect();
1405 for &id in &ids {
1406 // If there are any partitions in this device that start at 0, and
1407 // aren't marked as the BootLoader partition, avoid adding the
1408 // partition table. This makes it harder to view the image, but
1409 // avoids messing up images already written.
1410 if areadesc.iter_areas().any(|area| {
1411 area.device_id == id &&
1412 area.off == 0 &&
1413 area.flash_id != FlashId::BootLoader
1414 }) {
1415 if log_enabled!(Info) {
1416 let special: Vec<FlashId> = areadesc.iter_areas()
1417 .filter(|area| area.device_id == id && area.off == 0)
1418 .map(|area| area.flash_id)
1419 .collect();
1420 info!("Skipping partition table: {:?}", special);
1421 }
1422 break;
1423 }
1424
1425 let mut buf: Vec<u8> = vec![];
1426 write!(&mut buf, "mcuboot\0").unwrap();
1427
1428 // Iterate through all of the partitions in that device, and encode
1429 // into the table.
1430 let count = areadesc.iter_areas().filter(|area| area.device_id == id).count();
1431 buf.write_u32::<LittleEndian>(count as u32).unwrap();
1432
1433 for area in areadesc.iter_areas().filter(|area| area.device_id == id) {
1434 buf.write_u32::<LittleEndian>(area.flash_id as u32).unwrap();
1435 buf.write_u32::<LittleEndian>(area.off).unwrap();
1436 buf.write_u32::<LittleEndian>(area.size).unwrap();
1437 buf.write_u32::<LittleEndian>(0).unwrap();
1438 }
1439
1440 let dev = flash.get_mut(&id).unwrap();
1441
1442 // Pad to alignment.
1443 while buf.len() % dev.align() != 0 {
1444 buf.push(0);
1445 }
1446
1447 dev.write(0, &buf).unwrap();
1448 }
1449}
1450
David Brown5c9e0f12019-01-09 16:34:33 -07001451/// The image header
1452#[repr(C)]
1453pub struct ImageHeader {
1454 magic: u32,
1455 load_addr: u32,
1456 hdr_size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001457 protect_tlv_size: u16,
David Brown5c9e0f12019-01-09 16:34:33 -07001458 img_size: u32,
1459 flags: u32,
1460 ver: ImageVersion,
1461 _pad2: u32,
1462}
1463
1464impl AsRaw for ImageHeader {}
1465
1466#[repr(C)]
David Brownc3898d62019-08-05 14:20:02 -06001467#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001468pub struct ImageVersion {
David Brown7a81c4b2019-07-29 15:20:21 -06001469 pub major: u8,
1470 pub minor: u8,
1471 pub revision: u16,
1472 pub build_num: u32,
David Brown5c9e0f12019-01-09 16:34:33 -07001473}
1474
David Brownc3898d62019-08-05 14:20:02 -06001475#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001476pub struct SlotInfo {
1477 pub base_off: usize,
1478 pub trailer_off: usize,
1479 pub len: usize,
David Brown3b090212019-07-30 15:59:28 -06001480 // Which slot within this device.
1481 pub index: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001482 pub dev_id: u8,
1483}
1484
David Brown347dc572019-11-15 11:37:25 -07001485const MAGIC: &[u8] = &[0x77, 0xc2, 0x95, 0xf3,
1486 0x60, 0xd2, 0xef, 0x7f,
1487 0x35, 0x52, 0x50, 0x0f,
1488 0x2c, 0xb6, 0x79, 0x80];
David Brown5c9e0f12019-01-09 16:34:33 -07001489
1490// Replicates defines found in bootutil.h
1491const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1492const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1493
1494const BOOT_FLAG_SET: Option<u8> = Some(1);
1495const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1496
1497/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001498pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1499 let dev = flash.get_mut(&slot.dev_id).unwrap();
David Brown95de4502019-11-15 12:01:34 -07001500 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001501 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown95de4502019-11-15 12:01:34 -07001502 if offset % align != 0 || MAGIC.len() % align != 0 {
1503 // The write size is larger than the magic value. Fill a buffer
1504 // with the erased value, put the MAGIC in it, and write it in its
1505 // entirety.
1506 let mut buf = vec![dev.erased_val(); align];
1507 buf[(offset % align)..].copy_from_slice(MAGIC);
1508 dev.write(offset - (offset % align), &buf).unwrap();
1509 } else {
1510 dev.write(offset, MAGIC).unwrap();
1511 }
David Brown5c9e0f12019-01-09 16:34:33 -07001512}
1513
1514/// Writes the image_ok flag which, guess what, tells the bootloader
1515/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001516fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
David Browneecae522019-11-15 12:00:20 -07001517 // Overwrite mode always is permanent, and only the magic is used in
1518 // the trailer. To avoid problems with large write sizes, don't try to
1519 // set anything in this case.
1520 if Caps::OverwriteUpgrade.present() {
1521 return;
1522 }
1523
David Brown76101572019-02-28 11:29:03 -07001524 let dev = flash.get_mut(&slot.dev_id).unwrap();
1525 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001526 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001527 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001528 let align = dev.align();
1529 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001530}
1531
1532// Drop some pseudo-random gibberish onto the data.
1533fn splat(data: &mut [u8], seed: usize) {
1534 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1535 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1536 rng.fill_bytes(data);
1537}
1538
1539/// Return a read-only view into the raw bytes of this object
1540trait AsRaw : Sized {
1541 fn as_raw<'a>(&'a self) -> &'a [u8] {
1542 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1543 mem::size_of::<Self>()) }
1544 }
1545}
1546
1547pub fn show_sizes() {
1548 // This isn't panic safe.
1549 for min in &[1, 2, 4, 8] {
1550 let msize = c::boot_trailer_sz(*min);
1551 println!("{:2}: {} (0x{:x})", min, msize, msize);
1552 }
1553}
David Brown95de4502019-11-15 12:01:34 -07001554
1555#[cfg(not(feature = "large-write"))]
1556fn test_alignments() -> &'static [usize] {
David Brown95de4502019-11-15 12:01:34 -07001557 &[1, 2, 4, 8]
1558}
1559
1560#[cfg(feature = "large-write")]
1561fn test_alignments() -> &'static [usize] {
David Brown95de4502019-11-15 12:01:34 -07001562 &[1, 2, 4, 8, 128, 512]
1563}