blob: c02a29f5ffccffdaf015259501db829e3dc268cc [file] [log] [blame]
David Brown5c9e0f12019-01-09 16:34:33 -07001use log::{info, warn, error};
2use rand::{
3 distributions::{IndependentSample, Range},
4 Rng, SeedableRng, XorShiftRng,
5};
6use std::{
7 mem,
8 slice,
9};
10use aes_ctr::{
11 Aes128Ctr,
12 stream_cipher::{
13 generic_array::GenericArray,
14 NewFixStreamCipher,
15 StreamCipherCore,
16 },
17};
18
David Brown76101572019-02-28 11:29:03 -070019use simflash::{Flash, SimFlash, SimMultiFlash};
David Browne5133242019-02-28 11:05:19 -070020use mcuboot_sys::{c, AreaDesc, FlashId};
21use crate::{
22 ALL_DEVICES,
23 DeviceName,
24};
David Brown5c9e0f12019-01-09 16:34:33 -070025use crate::caps::Caps;
David Brown43643dd2019-01-11 15:43:28 -070026use crate::tlv::{ManifestGen, TlvGen, TlvFlags, AES_SEC_KEY};
David Brown5c9e0f12019-01-09 16:34:33 -070027
David Browne5133242019-02-28 11:05:19 -070028/// A builder for Images. This describes a single run of the simulator,
29/// capturing the configuration of a particular set of devices, including
30/// the flash simulator(s) and the information about the slots.
31#[derive(Clone)]
32pub struct ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070033 flash: SimMultiFlash,
David Browne5133242019-02-28 11:05:19 -070034 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070035 slots: Vec<[SlotInfo; 2]>,
David Browne5133242019-02-28 11:05:19 -070036}
37
David Brown998aa8d2019-02-28 10:54:50 -070038/// Images represents the state of a simulation for a given set of images.
David Brown76101572019-02-28 11:29:03 -070039/// The flash holds the state of the simulated flash, whereas primaries
David Brown998aa8d2019-02-28 10:54:50 -070040/// and upgrades hold the expected contents of these images.
41pub struct Images {
David Brown76101572019-02-28 11:29:03 -070042 flash: SimMultiFlash,
David Brownca234692019-02-28 11:22:19 -070043 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070044 images: Vec<OneImage>,
45 total_count: Option<i32>,
46}
47
48/// When doing multi-image, there is an instance of this information for
49/// each of the images. Single image there will be one of these.
50struct OneImage {
David Brownca234692019-02-28 11:22:19 -070051 slots: [SlotInfo; 2],
52 primaries: ImageData,
53 upgrades: ImageData,
David Brownca234692019-02-28 11:22:19 -070054}
55
56/// The Rust-side representation of an image. For unencrypted images, this
57/// is just the unencrypted payload. For encrypted images, we store both
58/// the encrypted and the plaintext.
59struct ImageData {
60 plain: Vec<u8>,
61 cipher: Option<Vec<u8>>,
David Brown998aa8d2019-02-28 10:54:50 -070062}
63
David Browne5133242019-02-28 11:05:19 -070064impl ImagesBuilder {
David Brown5bc62c62019-03-05 12:11:48 -070065 /// Construct a new image builder for the given device. Returns
66 /// Some(builder) if is possible to test this configuration, or None if
67 /// not possible (for example, if there aren't enough image slots).
68 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Option<Self> {
David Brown76101572019-02-28 11:29:03 -070069 let (flash, areadesc) = Self::make_device(device, align, erased_val);
David Browne5133242019-02-28 11:05:19 -070070
David Brown06ef06e2019-03-05 12:28:10 -070071 let num_images = Caps::get_num_images();
David Browne5133242019-02-28 11:05:19 -070072
David Brown06ef06e2019-03-05 12:28:10 -070073 let mut slots = Vec::with_capacity(num_images);
74 for image in 0..num_images {
75 // This mapping must match that defined in
76 // `boot/zephyr/include/sysflash/sysflash.h`.
77 let id0 = match image {
78 0 => FlashId::Image0,
79 1 => FlashId::Image2,
80 _ => panic!("More than 2 images not supported"),
81 };
82 let (primary_base, primary_len, primary_dev_id) = match areadesc.find(id0) {
83 Some(info) => info,
84 None => return None,
85 };
86 let id1 = match image {
87 0 => FlashId::Image1,
88 1 => FlashId::Image3,
89 _ => panic!("More than 2 images not supported"),
90 };
91 let (secondary_base, secondary_len, secondary_dev_id) = match areadesc.find(id1) {
92 Some(info) => info,
93 None => return None,
94 };
David Browne5133242019-02-28 11:05:19 -070095
David Brown06ef06e2019-03-05 12:28:10 -070096 // NOTE: not accounting "swap_size" because it is not used by sim...
97 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
David Browne5133242019-02-28 11:05:19 -070098
David Brown06ef06e2019-03-05 12:28:10 -070099 // Construct a primary image.
100 let primary = SlotInfo {
101 base_off: primary_base as usize,
102 trailer_off: primary_base + primary_len - offset_from_end,
103 len: primary_len as usize,
104 dev_id: primary_dev_id,
105 };
106
107 // And an upgrade image.
108 let secondary = SlotInfo {
109 base_off: secondary_base as usize,
110 trailer_off: secondary_base + secondary_len - offset_from_end,
111 len: secondary_len as usize,
112 dev_id: secondary_dev_id,
113 };
114
115 slots.push([primary, secondary]);
116 }
David Browne5133242019-02-28 11:05:19 -0700117
David Brown5bc62c62019-03-05 12:11:48 -0700118 Some(ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -0700119 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700120 areadesc: areadesc,
David Brown06ef06e2019-03-05 12:28:10 -0700121 slots: slots,
David Brown5bc62c62019-03-05 12:11:48 -0700122 })
David Browne5133242019-02-28 11:05:19 -0700123 }
124
125 pub fn each_device<F>(f: F)
126 where F: Fn(Self)
127 {
128 for &dev in ALL_DEVICES {
129 for &align in &[1, 2, 4, 8] {
130 for &erased_val in &[0, 0xff] {
David Brown5bc62c62019-03-05 12:11:48 -0700131 match Self::new(dev, align, erased_val) {
132 Some(run) => f(run),
133 None => warn!("Skipping {:?}, insufficient partitions", dev),
134 }
David Browne5133242019-02-28 11:05:19 -0700135 }
136 }
137 }
138 }
139
140 /// Construct an `Images` that doesn't expect an upgrade to happen.
141 pub fn make_no_upgrade_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700142 let mut flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700143 let images = self.slots.into_iter().map(|slots| {
144 let primaries = install_image(&mut flash, &slots, 0, 32784, false);
145 let upgrades = install_image(&mut flash, &slots, 1, 41928, false);
146 OneImage {
147 slots: slots,
148 primaries: primaries,
149 upgrades: upgrades,
150 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700151 Images {
David Brown76101572019-02-28 11:29:03 -0700152 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700153 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700154 images: images,
David Browne5133242019-02-28 11:05:19 -0700155 total_count: None,
156 }
157 }
158
159 /// Construct an `Images` for normal testing.
160 pub fn make_image(self) -> Images {
161 let mut images = self.make_no_upgrade_image();
David Brown84b49f72019-03-01 10:58:22 -0700162 for image in &images.images {
163 mark_upgrade(&mut images.flash, &image.slots[1]);
164 }
David Browne5133242019-02-28 11:05:19 -0700165
166 // upgrades without fails, counts number of flash operations
167 let total_count = match images.run_basic_upgrade() {
168 Ok(v) => v,
169 Err(_) => {
170 panic!("Unable to perform basic upgrade");
171 },
172 };
173
174 images.total_count = Some(total_count);
175 images
176 }
177
178 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700179 let mut bad_flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700180 let images = self.slots.into_iter().map(|slots| {
181 let primaries = install_image(&mut bad_flash, &slots, 0, 32784, false);
182 let upgrades = install_image(&mut bad_flash, &slots, 1, 41928, true);
183 OneImage {
184 slots: slots,
185 primaries: primaries,
186 upgrades: upgrades,
187 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700188 Images {
David Brown76101572019-02-28 11:29:03 -0700189 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700190 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700191 images: images,
David Browne5133242019-02-28 11:05:19 -0700192 total_count: None,
193 }
194 }
195
196 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700197 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700198 match device {
199 DeviceName::Stm32f4 => {
200 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700201 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
202 64 * 1024,
203 128 * 1024, 128 * 1024, 128 * 1024],
204 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700205 let dev_id = 0;
206 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700207 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700208 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
209 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
210 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
211
David Brown76101572019-02-28 11:29:03 -0700212 let mut flash = SimMultiFlash::new();
213 flash.insert(dev_id, dev);
214 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700215 }
216 DeviceName::K64f => {
217 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700218 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700219
220 let dev_id = 0;
221 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700222 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700223 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
224 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
225 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
226
David Brown76101572019-02-28 11:29:03 -0700227 let mut flash = SimMultiFlash::new();
228 flash.insert(dev_id, dev);
229 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700230 }
231 DeviceName::K64fBig => {
232 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
233 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700234 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700235
236 let dev_id = 0;
237 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700238 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700239 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
240 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
241 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
242
David Brown76101572019-02-28 11:29:03 -0700243 let mut flash = SimMultiFlash::new();
244 flash.insert(dev_id, dev);
245 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700246 }
247 DeviceName::Nrf52840 => {
248 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
249 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700250 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700251
252 let dev_id = 0;
253 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700254 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700255 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
256 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
257 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
258
David Brown76101572019-02-28 11:29:03 -0700259 let mut flash = SimMultiFlash::new();
260 flash.insert(dev_id, dev);
261 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700262 }
263 DeviceName::Nrf52840SpiFlash => {
264 // Simulate nrf52840 with external SPI flash. The external SPI flash
265 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700266 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
267 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700268
269 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700270 areadesc.add_flash_sectors(0, &dev0);
271 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700272
273 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
274 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
275 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
276
David Brown76101572019-02-28 11:29:03 -0700277 let mut flash = SimMultiFlash::new();
278 flash.insert(0, dev0);
279 flash.insert(1, dev1);
280 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700281 }
282 }
283 }
284}
285
David Brown5c9e0f12019-01-09 16:34:33 -0700286impl Images {
287 /// A simple upgrade without forced failures.
288 ///
289 /// Returns the number of flash operations which can later be used to
290 /// inject failures at chosen steps.
291 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Browndb505822019-03-01 10:04:20 -0700292 let (flash, total_count) = self.try_upgrade(None);
David Brown5c9e0f12019-01-09 16:34:33 -0700293 info!("Total flash operation count={}", total_count);
294
David Brown84b49f72019-03-01 10:58:22 -0700295 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700296 warn!("Image mismatch after first boot");
297 Err(())
298 } else {
299 Ok(total_count)
300 }
301 }
302
David Brown5c9e0f12019-01-09 16:34:33 -0700303 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700304 if Caps::OverwriteUpgrade.present() {
305 return false;
306 }
David Brown5c9e0f12019-01-09 16:34:33 -0700307
David Brown5c9e0f12019-01-09 16:34:33 -0700308 let mut fails = 0;
309
310 // FIXME: this test would also pass if no swap is ever performed???
311 if Caps::SwapUpgrade.present() {
312 for count in 2 .. 5 {
313 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700314 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700315 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700316 error!("Revert failure on count {}", count);
317 fails += 1;
318 }
319 }
320 }
321
322 fails > 0
323 }
324
325 pub fn run_perm_with_fails(&self) -> bool {
326 let mut fails = 0;
327 let total_flash_ops = self.total_count.unwrap();
328
329 // Let's try an image halfway through.
330 for i in 1 .. total_flash_ops {
331 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700332 let (flash, count) = self.try_upgrade(Some(i));
David Brown5c9e0f12019-01-09 16:34:33 -0700333 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700334 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700335 warn!("FAIL at step {} of {}", i, total_flash_ops);
336 fails += 1;
337 }
338
David Brown84b49f72019-03-01 10:58:22 -0700339 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
340 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100341 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700342 fails += 1;
343 }
344
David Brown84b49f72019-03-01 10:58:22 -0700345 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
346 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100347 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700348 fails += 1;
349 }
350
351 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700352 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100353 warn!("Secondary slot FAIL at step {} of {}",
354 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700355 fails += 1;
356 }
357 }
358 }
359
360 if fails > 0 {
361 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
362 fails as f32 * 100.0 / total_flash_ops as f32);
363 }
364
365 fails > 0
366 }
367
368 pub fn run_perm_with_random_fails_5(&self) -> bool {
369 self.run_perm_with_random_fails(5)
370 }
371
372 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
373 let mut fails = 0;
374 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700375 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700376 info!("Random interruptions at reset points={:?}", total_counts);
377
David Brown84b49f72019-03-01 10:58:22 -0700378 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100379 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700380 // TODO: This result is ignored.
381 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700382 } else {
383 true
384 };
David Vincze2d736ad2019-02-18 11:50:22 +0100385 if !primary_slot_ok || !secondary_slot_ok {
386 error!("Image mismatch after random interrupts: primary slot={} \
387 secondary slot={}",
388 if primary_slot_ok { "ok" } else { "fail" },
389 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700390 fails += 1;
391 }
David Brown84b49f72019-03-01 10:58:22 -0700392 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
393 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100394 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700395 fails += 1;
396 }
David Brown84b49f72019-03-01 10:58:22 -0700397 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
398 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100399 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700400 fails += 1;
401 }
402
403 if fails > 0 {
404 error!("Error testing perm upgrade with {} fails", total_fails);
405 }
406
407 fails > 0
408 }
409
David Brown5c9e0f12019-01-09 16:34:33 -0700410 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700411 if Caps::OverwriteUpgrade.present() {
412 return false;
413 }
David Brown5c9e0f12019-01-09 16:34:33 -0700414
David Brown5c9e0f12019-01-09 16:34:33 -0700415 let mut fails = 0;
416
417 if Caps::SwapUpgrade.present() {
418 for i in 1 .. (self.total_count.unwrap() - 1) {
419 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700420 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700421 error!("Revert failed at interruption {}", i);
422 fails += 1;
423 }
424 }
425 }
426
427 fails > 0
428 }
429
David Brown5c9e0f12019-01-09 16:34:33 -0700430 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700431 if Caps::OverwriteUpgrade.present() {
432 return false;
433 }
David Brown5c9e0f12019-01-09 16:34:33 -0700434
David Brown76101572019-02-28 11:29:03 -0700435 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700436 let mut fails = 0;
437
438 info!("Try norevert");
439
440 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700441 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700442 if result != 0 {
443 warn!("Failed first boot");
444 fails += 1;
445 }
446
447 //FIXME: copy_done is written by boot_go, is it ok if no copy
448 // was ever done?
449
David Brown84b49f72019-03-01 10:58:22 -0700450 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100451 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700452 fails += 1;
453 }
David Brown84b49f72019-03-01 10:58:22 -0700454 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
455 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100456 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700457 fails += 1;
458 }
David Brown84b49f72019-03-01 10:58:22 -0700459 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
460 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100461 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700462 fails += 1;
463 }
464
David Vincze2d736ad2019-02-18 11:50:22 +0100465 // Marks image in the primary slot as permanent,
466 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700467 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700468
David Brown84b49f72019-03-01 10:58:22 -0700469 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
470 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100471 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700472 fails += 1;
473 }
474
David Brown76101572019-02-28 11:29:03 -0700475 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700476 if result != 0 {
477 warn!("Failed second boot");
478 fails += 1;
479 }
480
David Brown84b49f72019-03-01 10:58:22 -0700481 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
482 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100483 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700484 fails += 1;
485 }
David Brown84b49f72019-03-01 10:58:22 -0700486 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700487 warn!("Failed image verification");
488 fails += 1;
489 }
490
491 if fails > 0 {
492 error!("Error running upgrade without revert");
493 }
494
495 fails > 0
496 }
497
David Vincze2d736ad2019-02-18 11:50:22 +0100498 // Tests a new image written to the primary slot that already has magic and
499 // image_ok set while there is no image on the secondary slot, so no revert
500 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700501 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700502 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700503 let mut fails = 0;
504
505 info!("Try non-revert on imgtool generated image");
506
David Brown84b49f72019-03-01 10:58:22 -0700507 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700508
David Vincze2d736ad2019-02-18 11:50:22 +0100509 // This simulates writing an image created by imgtool to
510 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700511 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
512 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100513 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700514 fails += 1;
515 }
516
517 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700518 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700519 if result != 0 {
520 warn!("Failed first boot");
521 fails += 1;
522 }
523
524 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700525 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700526 warn!("Failed image verification");
527 fails += 1;
528 }
David Brown84b49f72019-03-01 10:58:22 -0700529 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
530 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100531 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700532 fails += 1;
533 }
David Brown84b49f72019-03-01 10:58:22 -0700534 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
535 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100536 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700537 fails += 1;
538 }
539
540 if fails > 0 {
541 error!("Expected a non revert with new image");
542 }
543
544 fails > 0
545 }
546
David Vincze2d736ad2019-02-18 11:50:22 +0100547 // Tests a new image written to the primary slot that already has magic and
548 // image_ok set while there is no image on the secondary slot, so no revert
549 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700550 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700551 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700552 let mut fails = 0;
553
554 info!("Try upgrade image with bad signature");
555
David Brown84b49f72019-03-01 10:58:22 -0700556 self.mark_upgrades(&mut flash, 0);
557 self.mark_permanent_upgrades(&mut flash, 0);
558 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700559
David Brown84b49f72019-03-01 10:58:22 -0700560 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
561 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100562 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700563 fails += 1;
564 }
565
566 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700567 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700568 if result != 0 {
569 warn!("Failed first boot");
570 fails += 1;
571 }
572
573 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700574 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700575 warn!("Failed image verification");
576 fails += 1;
577 }
David Brown84b49f72019-03-01 10:58:22 -0700578 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
579 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100580 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700581 fails += 1;
582 }
583
584 if fails > 0 {
585 error!("Expected an upgrade failure when image has bad signature");
586 }
587
588 fails > 0
589 }
590
David Brown5c9e0f12019-01-09 16:34:33 -0700591 fn trailer_sz(&self, align: usize) -> usize {
592 c::boot_trailer_sz(align as u8) as usize
593 }
594
595 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700596 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700597 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
598 32
599 } else {
600 0
601 };
David Brown5c9e0f12019-01-09 16:34:33 -0700602
David Brown9930a3e2019-01-11 12:28:26 -0700603 self.trailer_sz(align) - (16 + 24 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700604 }
605
606 /// This test runs a simple upgrade with no fails in the images, but
607 /// allowing for fails in the status area. This should run to the end
608 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700609 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100610 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700611 return false;
612 }
613
David Brown76101572019-02-28 11:29:03 -0700614 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700615 let mut fails = 0;
616
617 info!("Try swap with status fails");
618
David Brown84b49f72019-03-01 10:58:22 -0700619 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700620 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700621
David Brown76101572019-02-28 11:29:03 -0700622 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700623 if result != 0 {
624 warn!("Failed!");
625 fails += 1;
626 }
627
628 // Failed writes to the marked "bad" region don't assert anymore.
629 // Any detected assert() is happening in another part of the code.
630 if asserts != 0 {
631 warn!("At least one assert() was called");
632 fails += 1;
633 }
634
David Brown84b49f72019-03-01 10:58:22 -0700635 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
636 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100637 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700638 fails += 1;
639 }
640
David Brown84b49f72019-03-01 10:58:22 -0700641 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700642 warn!("Failed image verification");
643 fails += 1;
644 }
645
David Vincze2d736ad2019-02-18 11:50:22 +0100646 info!("validate primary slot enabled; \
647 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700648 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700649 if result != 0 {
650 warn!("Failed!");
651 fails += 1;
652 }
653
654 if fails > 0 {
655 error!("Error running upgrade with status write fails");
656 }
657
658 fails > 0
659 }
660
661 /// This test runs a simple upgrade with no fails in the images, but
662 /// allowing for fails in the status area. This should run to the end
663 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700664 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700665 if Caps::OverwriteUpgrade.present() {
666 false
David Vincze2d736ad2019-02-18 11:50:22 +0100667 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700668
David Brown76101572019-02-28 11:29:03 -0700669 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700670 let mut fails = 0;
671 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700672
David Brown85904a82019-01-11 13:45:12 -0700673 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700674
David Brown85904a82019-01-11 13:45:12 -0700675 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700676
David Brown84b49f72019-03-01 10:58:22 -0700677 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700678 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700679
680 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700681 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700682 if asserts != 0 {
683 warn!("At least one assert() was called");
684 fails += 1;
685 }
686
David Brown76101572019-02-28 11:29:03 -0700687 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700688
689 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700690 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700691
692 // This might throw no asserts, for large sector devices, where
693 // a single failure writing is indistinguishable from no failure,
694 // or throw a single assert for small sector devices that fail
695 // multiple times...
696 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100697 warn!("Expected single assert validating the primary slot, \
698 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700699 fails += 1;
700 }
701
702 if fails > 0 {
703 error!("Error running upgrade with status write fails");
704 }
705
706 fails > 0
707 } else {
David Brown76101572019-02-28 11:29:03 -0700708 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700709 let mut fails = 0;
710
711 info!("Try interrupted swap with status fails");
712
David Brown84b49f72019-03-01 10:58:22 -0700713 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700714 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700715
716 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700717 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700718 if asserts == 0 {
719 warn!("No assert() detected");
720 fails += 1;
721 }
722
723 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700724 }
David Brown5c9e0f12019-01-09 16:34:33 -0700725 }
726
727 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700728 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700729 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700730 if Caps::OverwriteUpgrade.present() {
731 return;
732 }
733
David Brown84b49f72019-03-01 10:58:22 -0700734 // Set this for each image.
735 for image in &self.images {
736 let dev_id = &image.slots[slot].dev_id;
737 let dev = flash.get_mut(&dev_id).unwrap();
738 let align = dev.align();
739 let off = &image.slots[0].base_off;
740 let len = &image.slots[0].len;
741 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700742
David Brown84b49f72019-03-01 10:58:22 -0700743 // Mark the status area as a bad area
744 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
745 }
David Brown5c9e0f12019-01-09 16:34:33 -0700746 }
747
David Brown76101572019-02-28 11:29:03 -0700748 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100749 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700750 return;
751 }
752
David Brown84b49f72019-03-01 10:58:22 -0700753 for image in &self.images {
754 let dev_id = &image.slots[slot].dev_id;
755 let dev = flash.get_mut(&dev_id).unwrap();
756 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700757
David Brown84b49f72019-03-01 10:58:22 -0700758 // Disabling write verification the only assert triggered by
759 // boot_go should be checking for integrity of status bytes.
760 dev.set_verify_writes(false);
761 }
David Brown5c9e0f12019-01-09 16:34:33 -0700762 }
763
David Browndb505822019-03-01 10:04:20 -0700764 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
765 /// of the number of flash operations done total.
766 fn try_upgrade(&self, stop: Option<i32>) -> (SimMultiFlash, i32) {
767 // Clone the flash to have a new copy.
768 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700769
David Brown84b49f72019-03-01 10:58:22 -0700770 self.mark_permanent_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700771
David Browndb505822019-03-01 10:04:20 -0700772 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700773
David Browndb505822019-03-01 10:04:20 -0700774 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
775 (-0x13579, _) => (true, stop.unwrap()),
776 (0, _) => (false, -counter),
777 (x, _) => panic!("Unknown return: {}", x),
778 };
David Brown5c9e0f12019-01-09 16:34:33 -0700779
David Browndb505822019-03-01 10:04:20 -0700780 counter = 0;
781 if first_interrupted {
782 // fl.dump();
783 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
784 (-0x13579, _) => panic!("Shouldn't stop again"),
785 (0, _) => (),
786 (x, _) => panic!("Unknown return: {}", x),
787 }
788 }
David Brown5c9e0f12019-01-09 16:34:33 -0700789
David Browndb505822019-03-01 10:04:20 -0700790 (flash, count - counter)
791 }
792
793 fn try_revert(&self, count: usize) -> SimMultiFlash {
794 let mut flash = self.flash.clone();
795
796 // fl.write_file("image0.bin").unwrap();
797 for i in 0 .. count {
798 info!("Running boot pass {}", i + 1);
799 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
800 }
801 flash
802 }
803
804 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
805 let mut flash = self.flash.clone();
806 let mut fails = 0;
807
808 let mut counter = stop;
809 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
810 if x != -0x13579 {
811 warn!("Should have stopped at interruption point");
812 fails += 1;
813 }
814
David Brown84b49f72019-03-01 10:58:22 -0700815 if !self.verify_trailers(&flash, 0, None, None, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700816 warn!("copy_done should be unset");
817 fails += 1;
818 }
819
820 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
821 if x != 0 {
822 warn!("Should have finished upgrade");
823 fails += 1;
824 }
825
David Brown84b49f72019-03-01 10:58:22 -0700826 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700827 warn!("Image in the primary slot before revert is invalid at stop={}",
828 stop);
829 fails += 1;
830 }
David Brown84b49f72019-03-01 10:58:22 -0700831 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700832 warn!("Image in the secondary slot before revert is invalid at stop={}",
833 stop);
834 fails += 1;
835 }
David Brown84b49f72019-03-01 10:58:22 -0700836 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
837 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700838 warn!("Mismatched trailer for the primary slot before revert");
839 fails += 1;
840 }
David Brown84b49f72019-03-01 10:58:22 -0700841 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
842 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700843 warn!("Mismatched trailer for the secondary slot before revert");
844 fails += 1;
845 }
846
847 // Do Revert
848 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
849 if x != 0 {
850 warn!("Should have finished a revert");
851 fails += 1;
852 }
853
David Brown84b49f72019-03-01 10:58:22 -0700854 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700855 warn!("Image in the primary slot after revert is invalid at stop={}",
856 stop);
857 fails += 1;
858 }
David Brown84b49f72019-03-01 10:58:22 -0700859 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700860 warn!("Image in the secondary slot after revert is invalid at stop={}",
861 stop);
862 fails += 1;
863 }
David Brown84b49f72019-03-01 10:58:22 -0700864 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
865 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700866 warn!("Mismatched trailer for the secondary slot after revert");
867 fails += 1;
868 }
David Brown84b49f72019-03-01 10:58:22 -0700869 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
870 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700871 warn!("Mismatched trailer for the secondary slot after revert");
872 fails += 1;
873 }
874
875 fails > 0
876 }
877
878 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
879 let mut flash = self.flash.clone();
880
David Brown84b49f72019-03-01 10:58:22 -0700881 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700882
883 let mut rng = rand::thread_rng();
884 let mut resets = vec![0i32; count];
885 let mut remaining_ops = total_ops;
886 for i in 0 .. count {
887 let ops = Range::new(1, remaining_ops / 2);
888 let reset_counter = ops.ind_sample(&mut rng);
889 let mut counter = reset_counter;
890 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
891 (0, _) | (-0x13579, _) => (),
892 (x, _) => panic!("Unknown return: {}", x),
893 }
894 remaining_ops -= reset_counter;
895 resets[i] = reset_counter;
896 }
897
898 match c::boot_go(&mut flash, &self.areadesc, None, false) {
899 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700900 (0, _) => (),
901 (x, _) => panic!("Unknown return: {}", x),
902 }
David Brown5c9e0f12019-01-09 16:34:33 -0700903
David Browndb505822019-03-01 10:04:20 -0700904 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700905 }
David Brown84b49f72019-03-01 10:58:22 -0700906
907 /// Verify the image in the given flash device, the specified slot
908 /// against the expected image.
909 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
910 for image in &self.images {
911 if !verify_image(flash, &image.slots, slot,
912 match against {
913 0 => &image.primaries,
914 1 => &image.upgrades,
915 _ => panic!("Invalid 'against'"),
916 }) {
917 return false;
918 }
919 }
920 true
921 }
922
923 /// Verify that the trailers of the images have the specified
924 /// values.
925 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
926 magic: Option<u8>, image_ok: Option<u8>,
927 copy_done: Option<u8>) -> bool {
928 for image in &self.images {
929 if !verify_trailer(flash, &image.slots, slot,
930 magic, image_ok, copy_done) {
931 return false;
932 }
933 }
934 true
935 }
936
937 /// Mark each of the images for permanent upgrade.
938 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
939 for image in &self.images {
940 mark_permanent_upgrade(flash, &image.slots[slot]);
941 }
942 }
943
944 /// Mark each of the images for permanent upgrade.
945 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
946 for image in &self.images {
947 mark_upgrade(flash, &image.slots[slot]);
948 }
949 }
David Brown5c9e0f12019-01-09 16:34:33 -0700950}
951
952/// Show the flash layout.
953#[allow(dead_code)]
954fn show_flash(flash: &dyn Flash) {
955 println!("---- Flash configuration ----");
956 for sector in flash.sector_iter() {
957 println!(" {:3}: 0x{:08x}, 0x{:08x}",
958 sector.num, sector.base, sector.size);
959 }
960 println!("");
961}
962
963/// Install a "program" into the given image. This fakes the image header, or at least all of the
964/// fields used by the given code. Returns a copy of the image that was written.
David Brown76101572019-02-28 11:29:03 -0700965fn install_image(flash: &mut SimMultiFlash, slots: &[SlotInfo], slot: usize, len: usize,
David Brownca234692019-02-28 11:22:19 -0700966 bad_sig: bool) -> ImageData {
David Brown5c9e0f12019-01-09 16:34:33 -0700967 let offset = slots[slot].base_off;
968 let slot_len = slots[slot].len;
969 let dev_id = slots[slot].dev_id;
970
David Brown43643dd2019-01-11 15:43:28 -0700971 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -0700972
973 const HDR_SIZE: usize = 32;
974
975 // Generate a boot header. Note that the size doesn't include the header.
976 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -0700977 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -0700978 load_addr: 0,
979 hdr_size: HDR_SIZE as u16,
980 _pad1: 0,
981 img_size: len as u32,
982 flags: tlv.get_flags(),
983 ver: ImageVersion {
984 major: (offset / (128 * 1024)) as u8,
985 minor: 0,
986 revision: 1,
987 build_num: offset as u32,
988 },
989 _pad2: 0,
990 };
991
992 let mut b_header = [0; HDR_SIZE];
993 b_header[..32].clone_from_slice(header.as_raw());
994 assert_eq!(b_header.len(), HDR_SIZE);
995
996 tlv.add_bytes(&b_header);
997
998 // The core of the image itself is just pseudorandom data.
999 let mut b_img = vec![0; len];
1000 splat(&mut b_img, offset);
1001
1002 // TLV signatures work over plain image
1003 tlv.add_bytes(&b_img);
1004
1005 // Generate encrypted images
1006 let flag = TlvFlags::ENCRYPTED as u32;
1007 let is_encrypted = (tlv.get_flags() & flag) == flag;
1008 let mut b_encimg = vec![];
1009 if is_encrypted {
1010 let key = GenericArray::from_slice(AES_SEC_KEY);
1011 let nonce = GenericArray::from_slice(&[0; 16]);
1012 let mut cipher = Aes128Ctr::new(&key, &nonce);
1013 b_encimg = b_img.clone();
1014 cipher.apply_keystream(&mut b_encimg);
1015 }
1016
1017 // Build the TLV itself.
1018 let mut b_tlv = if bad_sig {
1019 let good_sig = &mut tlv.make_tlv();
1020 vec![0; good_sig.len()]
1021 } else {
1022 tlv.make_tlv()
1023 };
1024
1025 // Pad the block to a flash alignment (8 bytes).
1026 while b_tlv.len() % 8 != 0 {
1027 //FIXME: should be erase_val?
1028 b_tlv.push(0xFF);
1029 }
1030
1031 let mut buf = vec![];
1032 buf.append(&mut b_header.to_vec());
1033 buf.append(&mut b_img);
1034 buf.append(&mut b_tlv.clone());
1035
1036 let mut encbuf = vec![];
1037 if is_encrypted {
1038 encbuf.append(&mut b_header.to_vec());
1039 encbuf.append(&mut b_encimg);
1040 encbuf.append(&mut b_tlv);
1041 }
1042
David Vincze2d736ad2019-02-18 11:50:22 +01001043 // Since images are always non-encrypted in the primary slot, we first write
1044 // an encrypted image, re-read to use for verification, erase + flash
1045 // un-encrypted. In the secondary slot the image is written un-encrypted,
1046 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001047
David Brown76101572019-02-28 11:29:03 -07001048 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001049
1050 if slot == 0 {
1051 let enc_copy: Option<Vec<u8>>;
1052
1053 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001054 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001055
1056 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001057 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001058
1059 enc_copy = Some(enc);
1060
David Brown76101572019-02-28 11:29:03 -07001061 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001062 } else {
1063 enc_copy = None;
1064 }
1065
David Brown76101572019-02-28 11:29:03 -07001066 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001067
1068 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001069 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001070
David Brownca234692019-02-28 11:22:19 -07001071 ImageData {
1072 plain: copy,
1073 cipher: enc_copy,
1074 }
David Brown5c9e0f12019-01-09 16:34:33 -07001075 } else {
1076
David Brown76101572019-02-28 11:29:03 -07001077 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001078
1079 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001080 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001081
1082 let enc_copy: Option<Vec<u8>>;
1083
1084 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001085 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001086
David Brown76101572019-02-28 11:29:03 -07001087 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001088
1089 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001090 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001091
1092 enc_copy = Some(enc);
1093 } else {
1094 enc_copy = None;
1095 }
1096
David Brownca234692019-02-28 11:22:19 -07001097 ImageData {
1098 plain: copy,
1099 cipher: enc_copy,
1100 }
David Brown5c9e0f12019-01-09 16:34:33 -07001101 }
David Brown5c9e0f12019-01-09 16:34:33 -07001102}
1103
David Brown5c9e0f12019-01-09 16:34:33 -07001104fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001105 if Caps::EcdsaP224.present() {
1106 panic!("Ecdsa P224 not supported in Simulator");
1107 }
David Brown5c9e0f12019-01-09 16:34:33 -07001108
David Brownb8882112019-01-11 14:04:11 -07001109 if Caps::EncKw.present() {
1110 if Caps::RSA2048.present() {
1111 TlvGen::new_rsa_kw()
1112 } else if Caps::EcdsaP256.present() {
1113 TlvGen::new_ecdsa_kw()
1114 } else {
1115 TlvGen::new_enc_kw()
1116 }
1117 } else if Caps::EncRsa.present() {
1118 if Caps::RSA2048.present() {
1119 TlvGen::new_sig_enc_rsa()
1120 } else {
1121 TlvGen::new_enc_rsa()
1122 }
1123 } else {
1124 // The non-encrypted configuration.
1125 if Caps::RSA2048.present() {
1126 TlvGen::new_rsa_pss()
1127 } else if Caps::EcdsaP256.present() {
1128 TlvGen::new_ecdsa()
1129 } else {
1130 TlvGen::new_hash_only()
1131 }
1132 }
David Brown5c9e0f12019-01-09 16:34:33 -07001133}
1134
David Brownca234692019-02-28 11:22:19 -07001135impl ImageData {
1136 /// Find the image contents for the given slot. This assumes that slot 0
1137 /// is unencrypted, and slot 1 is encrypted.
1138 fn find(&self, slot: usize) -> &Vec<u8> {
1139 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1140 match (encrypted, slot) {
1141 (false, _) => &self.plain,
1142 (true, 0) => &self.plain,
1143 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1144 _ => panic!("Invalid slot requested"),
1145 }
David Brown5c9e0f12019-01-09 16:34:33 -07001146 }
1147}
1148
David Brown5c9e0f12019-01-09 16:34:33 -07001149/// Verify that given image is present in the flash at the given offset.
David Brown76101572019-02-28 11:29:03 -07001150fn verify_image(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brownca234692019-02-28 11:22:19 -07001151 images: &ImageData) -> bool {
1152 let image = images.find(slot);
David Brown5c9e0f12019-01-09 16:34:33 -07001153 let buf = image.as_slice();
1154 let dev_id = slots[slot].dev_id;
1155
1156 let mut copy = vec![0u8; buf.len()];
1157 let offset = slots[slot].base_off;
David Brown76101572019-02-28 11:29:03 -07001158 let dev = flash.get(&dev_id).unwrap();
1159 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001160
1161 if buf != &copy[..] {
1162 for i in 0 .. buf.len() {
1163 if buf[i] != copy[i] {
1164 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1165 slot, offset + i, buf[i], copy[i]);
1166 break;
1167 }
1168 }
1169 false
1170 } else {
1171 true
1172 }
1173}
1174
David Brown76101572019-02-28 11:29:03 -07001175fn verify_trailer(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001176 magic: Option<u8>, image_ok: Option<u8>,
1177 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001178 if Caps::OverwriteUpgrade.present() {
1179 return true;
1180 }
David Brown5c9e0f12019-01-09 16:34:33 -07001181
David Brown5c9e0f12019-01-09 16:34:33 -07001182 let offset = slots[slot].trailer_off;
1183 let dev_id = slots[slot].dev_id;
1184 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1185 let mut failed = false;
1186
David Brown76101572019-02-28 11:29:03 -07001187 let dev = flash.get(&dev_id).unwrap();
1188 let erased_val = dev.erased_val();
1189 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001190
1191 failed |= match magic {
1192 Some(v) => {
1193 if v == 1 && &copy[16..] != MAGIC.unwrap() {
1194 warn!("\"magic\" mismatch at {:#x}", offset);
1195 true
1196 } else if v == 3 {
1197 let expected = [erased_val; 16];
1198 if &copy[16..] != expected {
1199 warn!("\"magic\" mismatch at {:#x}", offset);
1200 true
1201 } else {
1202 false
1203 }
1204 } else {
1205 false
1206 }
1207 },
1208 None => false,
1209 };
1210
1211 failed |= match image_ok {
1212 Some(v) => {
1213 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1214 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1215 true
1216 } else {
1217 false
1218 }
1219 },
1220 None => false,
1221 };
1222
1223 failed |= match copy_done {
1224 Some(v) => {
1225 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1226 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1227 true
1228 } else {
1229 false
1230 }
1231 },
1232 None => false,
1233 };
1234
1235 !failed
1236}
1237
1238/// The image header
1239#[repr(C)]
1240pub struct ImageHeader {
1241 magic: u32,
1242 load_addr: u32,
1243 hdr_size: u16,
1244 _pad1: u16,
1245 img_size: u32,
1246 flags: u32,
1247 ver: ImageVersion,
1248 _pad2: u32,
1249}
1250
1251impl AsRaw for ImageHeader {}
1252
1253#[repr(C)]
1254pub struct ImageVersion {
1255 major: u8,
1256 minor: u8,
1257 revision: u16,
1258 build_num: u32,
1259}
1260
1261#[derive(Clone)]
1262pub struct SlotInfo {
1263 pub base_off: usize,
1264 pub trailer_off: usize,
1265 pub len: usize,
1266 pub dev_id: u8,
1267}
1268
David Brown5c9e0f12019-01-09 16:34:33 -07001269const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1270 0x60, 0xd2, 0xef, 0x7f,
1271 0x35, 0x52, 0x50, 0x0f,
1272 0x2c, 0xb6, 0x79, 0x80]);
1273
1274// Replicates defines found in bootutil.h
1275const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1276const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1277
1278const BOOT_FLAG_SET: Option<u8> = Some(1);
1279const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1280
1281/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001282pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1283 let dev = flash.get_mut(&slot.dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001284 let offset = slot.trailer_off + c::boot_max_align() * 2;
David Brown76101572019-02-28 11:29:03 -07001285 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001286}
1287
1288/// Writes the image_ok flag which, guess what, tells the bootloader
1289/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001290fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1291 let dev = flash.get_mut(&slot.dev_id).unwrap();
1292 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001293 ok[0] = 1u8;
1294 let off = slot.trailer_off + c::boot_max_align();
David Brown76101572019-02-28 11:29:03 -07001295 let align = dev.align();
1296 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001297}
1298
1299// Drop some pseudo-random gibberish onto the data.
1300fn splat(data: &mut [u8], seed: usize) {
1301 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1302 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1303 rng.fill_bytes(data);
1304}
1305
1306/// Return a read-only view into the raw bytes of this object
1307trait AsRaw : Sized {
1308 fn as_raw<'a>(&'a self) -> &'a [u8] {
1309 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1310 mem::size_of::<Self>()) }
1311 }
1312}
1313
1314pub fn show_sizes() {
1315 // This isn't panic safe.
1316 for min in &[1, 2, 4, 8] {
1317 let msize = c::boot_trailer_sz(*min);
1318 println!("{:2}: {} (0x{:x})", min, msize, msize);
1319 }
1320}