blob: 899989caeb0393163adf04665d5fd39b66a0dd59 [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
71 let (slot0_base, slot0_len, slot0_dev_id) = areadesc.find(FlashId::Image0);
72 let (slot1_base, slot1_len, slot1_dev_id) = areadesc.find(FlashId::Image1);
73
74 // NOTE: not accounting "swap_size" because it is not used by sim...
75 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
76
77 // Construct a primary image.
78 let slot0 = SlotInfo {
79 base_off: slot0_base as usize,
80 trailer_off: slot0_base + slot0_len - offset_from_end,
81 len: slot0_len as usize,
82 dev_id: slot0_dev_id,
83 };
84
85 // And an upgrade image.
86 let slot1 = SlotInfo {
87 base_off: slot1_base as usize,
88 trailer_off: slot1_base + slot1_len - offset_from_end,
89 len: slot1_len as usize,
90 dev_id: slot1_dev_id,
91 };
92
David Brown5bc62c62019-03-05 12:11:48 -070093 Some(ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070094 flash: flash,
David Browne5133242019-02-28 11:05:19 -070095 areadesc: areadesc,
David Brown84b49f72019-03-01 10:58:22 -070096 slots: vec![[slot0, slot1]],
David Brown5bc62c62019-03-05 12:11:48 -070097 })
David Browne5133242019-02-28 11:05:19 -070098 }
99
100 pub fn each_device<F>(f: F)
101 where F: Fn(Self)
102 {
103 for &dev in ALL_DEVICES {
104 for &align in &[1, 2, 4, 8] {
105 for &erased_val in &[0, 0xff] {
David Brown5bc62c62019-03-05 12:11:48 -0700106 match Self::new(dev, align, erased_val) {
107 Some(run) => f(run),
108 None => warn!("Skipping {:?}, insufficient partitions", dev),
109 }
David Browne5133242019-02-28 11:05:19 -0700110 }
111 }
112 }
113 }
114
115 /// Construct an `Images` that doesn't expect an upgrade to happen.
116 pub fn make_no_upgrade_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700117 let mut flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700118 let images = self.slots.into_iter().map(|slots| {
119 let primaries = install_image(&mut flash, &slots, 0, 32784, false);
120 let upgrades = install_image(&mut flash, &slots, 1, 41928, false);
121 OneImage {
122 slots: slots,
123 primaries: primaries,
124 upgrades: upgrades,
125 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700126 Images {
David Brown76101572019-02-28 11:29:03 -0700127 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700128 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700129 images: images,
David Browne5133242019-02-28 11:05:19 -0700130 total_count: None,
131 }
132 }
133
134 /// Construct an `Images` for normal testing.
135 pub fn make_image(self) -> Images {
136 let mut images = self.make_no_upgrade_image();
David Brown84b49f72019-03-01 10:58:22 -0700137 for image in &images.images {
138 mark_upgrade(&mut images.flash, &image.slots[1]);
139 }
David Browne5133242019-02-28 11:05:19 -0700140
141 // upgrades without fails, counts number of flash operations
142 let total_count = match images.run_basic_upgrade() {
143 Ok(v) => v,
144 Err(_) => {
145 panic!("Unable to perform basic upgrade");
146 },
147 };
148
149 images.total_count = Some(total_count);
150 images
151 }
152
153 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700154 let mut bad_flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700155 let images = self.slots.into_iter().map(|slots| {
156 let primaries = install_image(&mut bad_flash, &slots, 0, 32784, false);
157 let upgrades = install_image(&mut bad_flash, &slots, 1, 41928, true);
158 OneImage {
159 slots: slots,
160 primaries: primaries,
161 upgrades: upgrades,
162 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700163 Images {
David Brown76101572019-02-28 11:29:03 -0700164 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700165 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700166 images: images,
David Browne5133242019-02-28 11:05:19 -0700167 total_count: None,
168 }
169 }
170
171 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700172 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700173 match device {
174 DeviceName::Stm32f4 => {
175 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700176 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
177 64 * 1024,
178 128 * 1024, 128 * 1024, 128 * 1024],
179 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700180 let dev_id = 0;
181 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700182 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700183 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
184 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
185 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
186
David Brown76101572019-02-28 11:29:03 -0700187 let mut flash = SimMultiFlash::new();
188 flash.insert(dev_id, dev);
189 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700190 }
191 DeviceName::K64f => {
192 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700193 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700194
195 let dev_id = 0;
196 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700197 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700198 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
199 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
200 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
201
David Brown76101572019-02-28 11:29:03 -0700202 let mut flash = SimMultiFlash::new();
203 flash.insert(dev_id, dev);
204 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700205 }
206 DeviceName::K64fBig => {
207 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
208 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700209 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700210
211 let dev_id = 0;
212 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700213 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700214 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
215 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
216 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
217
David Brown76101572019-02-28 11:29:03 -0700218 let mut flash = SimMultiFlash::new();
219 flash.insert(dev_id, dev);
220 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700221 }
222 DeviceName::Nrf52840 => {
223 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
224 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700225 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700226
227 let dev_id = 0;
228 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700229 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700230 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
231 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
232 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
233
David Brown76101572019-02-28 11:29:03 -0700234 let mut flash = SimMultiFlash::new();
235 flash.insert(dev_id, dev);
236 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700237 }
238 DeviceName::Nrf52840SpiFlash => {
239 // Simulate nrf52840 with external SPI flash. The external SPI flash
240 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700241 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
242 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700243
244 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700245 areadesc.add_flash_sectors(0, &dev0);
246 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700247
248 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
249 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
250 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
251
David Brown76101572019-02-28 11:29:03 -0700252 let mut flash = SimMultiFlash::new();
253 flash.insert(0, dev0);
254 flash.insert(1, dev1);
255 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700256 }
257 }
258 }
259}
260
David Brown5c9e0f12019-01-09 16:34:33 -0700261impl Images {
262 /// A simple upgrade without forced failures.
263 ///
264 /// Returns the number of flash operations which can later be used to
265 /// inject failures at chosen steps.
266 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Browndb505822019-03-01 10:04:20 -0700267 let (flash, total_count) = self.try_upgrade(None);
David Brown5c9e0f12019-01-09 16:34:33 -0700268 info!("Total flash operation count={}", total_count);
269
David Brown84b49f72019-03-01 10:58:22 -0700270 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700271 warn!("Image mismatch after first boot");
272 Err(())
273 } else {
274 Ok(total_count)
275 }
276 }
277
David Brown5c9e0f12019-01-09 16:34:33 -0700278 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700279 if Caps::OverwriteUpgrade.present() {
280 return false;
281 }
David Brown5c9e0f12019-01-09 16:34:33 -0700282
David Brown5c9e0f12019-01-09 16:34:33 -0700283 let mut fails = 0;
284
285 // FIXME: this test would also pass if no swap is ever performed???
286 if Caps::SwapUpgrade.present() {
287 for count in 2 .. 5 {
288 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700289 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700290 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700291 error!("Revert failure on count {}", count);
292 fails += 1;
293 }
294 }
295 }
296
297 fails > 0
298 }
299
300 pub fn run_perm_with_fails(&self) -> bool {
301 let mut fails = 0;
302 let total_flash_ops = self.total_count.unwrap();
303
304 // Let's try an image halfway through.
305 for i in 1 .. total_flash_ops {
306 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700307 let (flash, count) = self.try_upgrade(Some(i));
David Brown5c9e0f12019-01-09 16:34:33 -0700308 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700309 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700310 warn!("FAIL at step {} of {}", i, total_flash_ops);
311 fails += 1;
312 }
313
David Brown84b49f72019-03-01 10:58:22 -0700314 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
315 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100316 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700317 fails += 1;
318 }
319
David Brown84b49f72019-03-01 10:58:22 -0700320 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
321 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100322 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700323 fails += 1;
324 }
325
326 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700327 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100328 warn!("Secondary slot FAIL at step {} of {}",
329 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700330 fails += 1;
331 }
332 }
333 }
334
335 if fails > 0 {
336 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
337 fails as f32 * 100.0 / total_flash_ops as f32);
338 }
339
340 fails > 0
341 }
342
343 pub fn run_perm_with_random_fails_5(&self) -> bool {
344 self.run_perm_with_random_fails(5)
345 }
346
347 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
348 let mut fails = 0;
349 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700350 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700351 info!("Random interruptions at reset points={:?}", total_counts);
352
David Brown84b49f72019-03-01 10:58:22 -0700353 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100354 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700355 // TODO: This result is ignored.
356 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700357 } else {
358 true
359 };
David Vincze2d736ad2019-02-18 11:50:22 +0100360 if !primary_slot_ok || !secondary_slot_ok {
361 error!("Image mismatch after random interrupts: primary slot={} \
362 secondary slot={}",
363 if primary_slot_ok { "ok" } else { "fail" },
364 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700365 fails += 1;
366 }
David Brown84b49f72019-03-01 10:58:22 -0700367 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
368 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100369 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700370 fails += 1;
371 }
David Brown84b49f72019-03-01 10:58:22 -0700372 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
373 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100374 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700375 fails += 1;
376 }
377
378 if fails > 0 {
379 error!("Error testing perm upgrade with {} fails", total_fails);
380 }
381
382 fails > 0
383 }
384
David Brown5c9e0f12019-01-09 16:34:33 -0700385 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700386 if Caps::OverwriteUpgrade.present() {
387 return false;
388 }
David Brown5c9e0f12019-01-09 16:34:33 -0700389
David Brown5c9e0f12019-01-09 16:34:33 -0700390 let mut fails = 0;
391
392 if Caps::SwapUpgrade.present() {
393 for i in 1 .. (self.total_count.unwrap() - 1) {
394 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700395 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700396 error!("Revert failed at interruption {}", i);
397 fails += 1;
398 }
399 }
400 }
401
402 fails > 0
403 }
404
David Brown5c9e0f12019-01-09 16:34:33 -0700405 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700406 if Caps::OverwriteUpgrade.present() {
407 return false;
408 }
David Brown5c9e0f12019-01-09 16:34:33 -0700409
David Brown76101572019-02-28 11:29:03 -0700410 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700411 let mut fails = 0;
412
413 info!("Try norevert");
414
415 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700416 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700417 if result != 0 {
418 warn!("Failed first boot");
419 fails += 1;
420 }
421
422 //FIXME: copy_done is written by boot_go, is it ok if no copy
423 // was ever done?
424
David Brown84b49f72019-03-01 10:58:22 -0700425 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100426 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700427 fails += 1;
428 }
David Brown84b49f72019-03-01 10:58:22 -0700429 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
430 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100431 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700432 fails += 1;
433 }
David Brown84b49f72019-03-01 10:58:22 -0700434 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
435 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100436 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700437 fails += 1;
438 }
439
David Vincze2d736ad2019-02-18 11:50:22 +0100440 // Marks image in the primary slot as permanent,
441 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700442 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700443
David Brown84b49f72019-03-01 10:58:22 -0700444 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
445 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100446 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700447 fails += 1;
448 }
449
David Brown76101572019-02-28 11:29:03 -0700450 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700451 if result != 0 {
452 warn!("Failed second boot");
453 fails += 1;
454 }
455
David Brown84b49f72019-03-01 10:58:22 -0700456 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
457 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100458 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700459 fails += 1;
460 }
David Brown84b49f72019-03-01 10:58:22 -0700461 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700462 warn!("Failed image verification");
463 fails += 1;
464 }
465
466 if fails > 0 {
467 error!("Error running upgrade without revert");
468 }
469
470 fails > 0
471 }
472
David Vincze2d736ad2019-02-18 11:50:22 +0100473 // Tests a new image written to the primary slot that already has magic and
474 // image_ok set while there is no image on the secondary slot, so no revert
475 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700476 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700477 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700478 let mut fails = 0;
479
480 info!("Try non-revert on imgtool generated image");
481
David Brown84b49f72019-03-01 10:58:22 -0700482 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700483
David Vincze2d736ad2019-02-18 11:50:22 +0100484 // This simulates writing an image created by imgtool to
485 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700486 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
487 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100488 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700489 fails += 1;
490 }
491
492 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700493 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700494 if result != 0 {
495 warn!("Failed first boot");
496 fails += 1;
497 }
498
499 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700500 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700501 warn!("Failed image verification");
502 fails += 1;
503 }
David Brown84b49f72019-03-01 10:58:22 -0700504 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
505 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100506 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700507 fails += 1;
508 }
David Brown84b49f72019-03-01 10:58:22 -0700509 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
510 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100511 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700512 fails += 1;
513 }
514
515 if fails > 0 {
516 error!("Expected a non revert with new image");
517 }
518
519 fails > 0
520 }
521
David Vincze2d736ad2019-02-18 11:50:22 +0100522 // Tests a new image written to the primary slot that already has magic and
523 // image_ok set while there is no image on the secondary slot, so no revert
524 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700525 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700526 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700527 let mut fails = 0;
528
529 info!("Try upgrade image with bad signature");
530
David Brown84b49f72019-03-01 10:58:22 -0700531 self.mark_upgrades(&mut flash, 0);
532 self.mark_permanent_upgrades(&mut flash, 0);
533 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700534
David Brown84b49f72019-03-01 10:58:22 -0700535 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
536 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100537 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700538 fails += 1;
539 }
540
541 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700542 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700543 if result != 0 {
544 warn!("Failed first boot");
545 fails += 1;
546 }
547
548 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700549 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700550 warn!("Failed image verification");
551 fails += 1;
552 }
David Brown84b49f72019-03-01 10:58:22 -0700553 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
554 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100555 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700556 fails += 1;
557 }
558
559 if fails > 0 {
560 error!("Expected an upgrade failure when image has bad signature");
561 }
562
563 fails > 0
564 }
565
David Brown5c9e0f12019-01-09 16:34:33 -0700566 fn trailer_sz(&self, align: usize) -> usize {
567 c::boot_trailer_sz(align as u8) as usize
568 }
569
570 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700571 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700572 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
573 32
574 } else {
575 0
576 };
David Brown5c9e0f12019-01-09 16:34:33 -0700577
David Brown9930a3e2019-01-11 12:28:26 -0700578 self.trailer_sz(align) - (16 + 24 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700579 }
580
581 /// This test runs a simple upgrade with no fails in the images, but
582 /// allowing for fails in the status area. This should run to the end
583 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700584 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100585 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700586 return false;
587 }
588
David Brown76101572019-02-28 11:29:03 -0700589 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700590 let mut fails = 0;
591
592 info!("Try swap with status fails");
593
David Brown84b49f72019-03-01 10:58:22 -0700594 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700595 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700596
David Brown76101572019-02-28 11:29:03 -0700597 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700598 if result != 0 {
599 warn!("Failed!");
600 fails += 1;
601 }
602
603 // Failed writes to the marked "bad" region don't assert anymore.
604 // Any detected assert() is happening in another part of the code.
605 if asserts != 0 {
606 warn!("At least one assert() was called");
607 fails += 1;
608 }
609
David Brown84b49f72019-03-01 10:58:22 -0700610 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
611 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100612 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700613 fails += 1;
614 }
615
David Brown84b49f72019-03-01 10:58:22 -0700616 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700617 warn!("Failed image verification");
618 fails += 1;
619 }
620
David Vincze2d736ad2019-02-18 11:50:22 +0100621 info!("validate primary slot enabled; \
622 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700623 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700624 if result != 0 {
625 warn!("Failed!");
626 fails += 1;
627 }
628
629 if fails > 0 {
630 error!("Error running upgrade with status write fails");
631 }
632
633 fails > 0
634 }
635
636 /// This test runs a simple upgrade with no fails in the images, but
637 /// allowing for fails in the status area. This should run to the end
638 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700639 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700640 if Caps::OverwriteUpgrade.present() {
641 false
David Vincze2d736ad2019-02-18 11:50:22 +0100642 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700643
David Brown76101572019-02-28 11:29:03 -0700644 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700645 let mut fails = 0;
646 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700647
David Brown85904a82019-01-11 13:45:12 -0700648 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700649
David Brown85904a82019-01-11 13:45:12 -0700650 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700651
David Brown84b49f72019-03-01 10:58:22 -0700652 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700653 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700654
655 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700656 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700657 if asserts != 0 {
658 warn!("At least one assert() was called");
659 fails += 1;
660 }
661
David Brown76101572019-02-28 11:29:03 -0700662 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700663
664 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700665 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700666
667 // This might throw no asserts, for large sector devices, where
668 // a single failure writing is indistinguishable from no failure,
669 // or throw a single assert for small sector devices that fail
670 // multiple times...
671 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100672 warn!("Expected single assert validating the primary slot, \
673 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700674 fails += 1;
675 }
676
677 if fails > 0 {
678 error!("Error running upgrade with status write fails");
679 }
680
681 fails > 0
682 } else {
David Brown76101572019-02-28 11:29:03 -0700683 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700684 let mut fails = 0;
685
686 info!("Try interrupted swap with status fails");
687
David Brown84b49f72019-03-01 10:58:22 -0700688 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700689 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700690
691 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700692 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700693 if asserts == 0 {
694 warn!("No assert() detected");
695 fails += 1;
696 }
697
698 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700699 }
David Brown5c9e0f12019-01-09 16:34:33 -0700700 }
701
702 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700703 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700704 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700705 if Caps::OverwriteUpgrade.present() {
706 return;
707 }
708
David Brown84b49f72019-03-01 10:58:22 -0700709 // Set this for each image.
710 for image in &self.images {
711 let dev_id = &image.slots[slot].dev_id;
712 let dev = flash.get_mut(&dev_id).unwrap();
713 let align = dev.align();
714 let off = &image.slots[0].base_off;
715 let len = &image.slots[0].len;
716 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700717
David Brown84b49f72019-03-01 10:58:22 -0700718 // Mark the status area as a bad area
719 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
720 }
David Brown5c9e0f12019-01-09 16:34:33 -0700721 }
722
David Brown76101572019-02-28 11:29:03 -0700723 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100724 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700725 return;
726 }
727
David Brown84b49f72019-03-01 10:58:22 -0700728 for image in &self.images {
729 let dev_id = &image.slots[slot].dev_id;
730 let dev = flash.get_mut(&dev_id).unwrap();
731 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700732
David Brown84b49f72019-03-01 10:58:22 -0700733 // Disabling write verification the only assert triggered by
734 // boot_go should be checking for integrity of status bytes.
735 dev.set_verify_writes(false);
736 }
David Brown5c9e0f12019-01-09 16:34:33 -0700737 }
738
David Browndb505822019-03-01 10:04:20 -0700739 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
740 /// of the number of flash operations done total.
741 fn try_upgrade(&self, stop: Option<i32>) -> (SimMultiFlash, i32) {
742 // Clone the flash to have a new copy.
743 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700744
David Brown84b49f72019-03-01 10:58:22 -0700745 self.mark_permanent_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700746
David Browndb505822019-03-01 10:04:20 -0700747 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700748
David Browndb505822019-03-01 10:04:20 -0700749 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
750 (-0x13579, _) => (true, stop.unwrap()),
751 (0, _) => (false, -counter),
752 (x, _) => panic!("Unknown return: {}", x),
753 };
David Brown5c9e0f12019-01-09 16:34:33 -0700754
David Browndb505822019-03-01 10:04:20 -0700755 counter = 0;
756 if first_interrupted {
757 // fl.dump();
758 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
759 (-0x13579, _) => panic!("Shouldn't stop again"),
760 (0, _) => (),
761 (x, _) => panic!("Unknown return: {}", x),
762 }
763 }
David Brown5c9e0f12019-01-09 16:34:33 -0700764
David Browndb505822019-03-01 10:04:20 -0700765 (flash, count - counter)
766 }
767
768 fn try_revert(&self, count: usize) -> SimMultiFlash {
769 let mut flash = self.flash.clone();
770
771 // fl.write_file("image0.bin").unwrap();
772 for i in 0 .. count {
773 info!("Running boot pass {}", i + 1);
774 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
775 }
776 flash
777 }
778
779 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
780 let mut flash = self.flash.clone();
781 let mut fails = 0;
782
783 let mut counter = stop;
784 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
785 if x != -0x13579 {
786 warn!("Should have stopped at interruption point");
787 fails += 1;
788 }
789
David Brown84b49f72019-03-01 10:58:22 -0700790 if !self.verify_trailers(&flash, 0, None, None, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700791 warn!("copy_done should be unset");
792 fails += 1;
793 }
794
795 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
796 if x != 0 {
797 warn!("Should have finished upgrade");
798 fails += 1;
799 }
800
David Brown84b49f72019-03-01 10:58:22 -0700801 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700802 warn!("Image in the primary slot before revert is invalid at stop={}",
803 stop);
804 fails += 1;
805 }
David Brown84b49f72019-03-01 10:58:22 -0700806 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700807 warn!("Image in the secondary slot before revert is invalid at stop={}",
808 stop);
809 fails += 1;
810 }
David Brown84b49f72019-03-01 10:58:22 -0700811 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
812 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700813 warn!("Mismatched trailer for the primary slot before revert");
814 fails += 1;
815 }
David Brown84b49f72019-03-01 10:58:22 -0700816 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
817 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700818 warn!("Mismatched trailer for the secondary slot before revert");
819 fails += 1;
820 }
821
822 // Do Revert
823 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
824 if x != 0 {
825 warn!("Should have finished a revert");
826 fails += 1;
827 }
828
David Brown84b49f72019-03-01 10:58:22 -0700829 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700830 warn!("Image in the primary slot after revert is invalid at stop={}",
831 stop);
832 fails += 1;
833 }
David Brown84b49f72019-03-01 10:58:22 -0700834 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700835 warn!("Image in the secondary slot after revert is invalid at stop={}",
836 stop);
837 fails += 1;
838 }
David Brown84b49f72019-03-01 10:58:22 -0700839 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
840 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700841 warn!("Mismatched trailer for the secondary slot after revert");
842 fails += 1;
843 }
David Brown84b49f72019-03-01 10:58:22 -0700844 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
845 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700846 warn!("Mismatched trailer for the secondary slot after revert");
847 fails += 1;
848 }
849
850 fails > 0
851 }
852
853 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
854 let mut flash = self.flash.clone();
855
David Brown84b49f72019-03-01 10:58:22 -0700856 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700857
858 let mut rng = rand::thread_rng();
859 let mut resets = vec![0i32; count];
860 let mut remaining_ops = total_ops;
861 for i in 0 .. count {
862 let ops = Range::new(1, remaining_ops / 2);
863 let reset_counter = ops.ind_sample(&mut rng);
864 let mut counter = reset_counter;
865 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
866 (0, _) | (-0x13579, _) => (),
867 (x, _) => panic!("Unknown return: {}", x),
868 }
869 remaining_ops -= reset_counter;
870 resets[i] = reset_counter;
871 }
872
873 match c::boot_go(&mut flash, &self.areadesc, None, false) {
874 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700875 (0, _) => (),
876 (x, _) => panic!("Unknown return: {}", x),
877 }
David Brown5c9e0f12019-01-09 16:34:33 -0700878
David Browndb505822019-03-01 10:04:20 -0700879 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700880 }
David Brown84b49f72019-03-01 10:58:22 -0700881
882 /// Verify the image in the given flash device, the specified slot
883 /// against the expected image.
884 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
885 for image in &self.images {
886 if !verify_image(flash, &image.slots, slot,
887 match against {
888 0 => &image.primaries,
889 1 => &image.upgrades,
890 _ => panic!("Invalid 'against'"),
891 }) {
892 return false;
893 }
894 }
895 true
896 }
897
898 /// Verify that the trailers of the images have the specified
899 /// values.
900 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
901 magic: Option<u8>, image_ok: Option<u8>,
902 copy_done: Option<u8>) -> bool {
903 for image in &self.images {
904 if !verify_trailer(flash, &image.slots, slot,
905 magic, image_ok, copy_done) {
906 return false;
907 }
908 }
909 true
910 }
911
912 /// Mark each of the images for permanent upgrade.
913 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
914 for image in &self.images {
915 mark_permanent_upgrade(flash, &image.slots[slot]);
916 }
917 }
918
919 /// Mark each of the images for permanent upgrade.
920 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
921 for image in &self.images {
922 mark_upgrade(flash, &image.slots[slot]);
923 }
924 }
David Brown5c9e0f12019-01-09 16:34:33 -0700925}
926
927/// Show the flash layout.
928#[allow(dead_code)]
929fn show_flash(flash: &dyn Flash) {
930 println!("---- Flash configuration ----");
931 for sector in flash.sector_iter() {
932 println!(" {:3}: 0x{:08x}, 0x{:08x}",
933 sector.num, sector.base, sector.size);
934 }
935 println!("");
936}
937
938/// Install a "program" into the given image. This fakes the image header, or at least all of the
939/// fields used by the given code. Returns a copy of the image that was written.
David Brown76101572019-02-28 11:29:03 -0700940fn install_image(flash: &mut SimMultiFlash, slots: &[SlotInfo], slot: usize, len: usize,
David Brownca234692019-02-28 11:22:19 -0700941 bad_sig: bool) -> ImageData {
David Brown5c9e0f12019-01-09 16:34:33 -0700942 let offset = slots[slot].base_off;
943 let slot_len = slots[slot].len;
944 let dev_id = slots[slot].dev_id;
945
David Brown43643dd2019-01-11 15:43:28 -0700946 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -0700947
948 const HDR_SIZE: usize = 32;
949
950 // Generate a boot header. Note that the size doesn't include the header.
951 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -0700952 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -0700953 load_addr: 0,
954 hdr_size: HDR_SIZE as u16,
955 _pad1: 0,
956 img_size: len as u32,
957 flags: tlv.get_flags(),
958 ver: ImageVersion {
959 major: (offset / (128 * 1024)) as u8,
960 minor: 0,
961 revision: 1,
962 build_num: offset as u32,
963 },
964 _pad2: 0,
965 };
966
967 let mut b_header = [0; HDR_SIZE];
968 b_header[..32].clone_from_slice(header.as_raw());
969 assert_eq!(b_header.len(), HDR_SIZE);
970
971 tlv.add_bytes(&b_header);
972
973 // The core of the image itself is just pseudorandom data.
974 let mut b_img = vec![0; len];
975 splat(&mut b_img, offset);
976
977 // TLV signatures work over plain image
978 tlv.add_bytes(&b_img);
979
980 // Generate encrypted images
981 let flag = TlvFlags::ENCRYPTED as u32;
982 let is_encrypted = (tlv.get_flags() & flag) == flag;
983 let mut b_encimg = vec![];
984 if is_encrypted {
985 let key = GenericArray::from_slice(AES_SEC_KEY);
986 let nonce = GenericArray::from_slice(&[0; 16]);
987 let mut cipher = Aes128Ctr::new(&key, &nonce);
988 b_encimg = b_img.clone();
989 cipher.apply_keystream(&mut b_encimg);
990 }
991
992 // Build the TLV itself.
993 let mut b_tlv = if bad_sig {
994 let good_sig = &mut tlv.make_tlv();
995 vec![0; good_sig.len()]
996 } else {
997 tlv.make_tlv()
998 };
999
1000 // Pad the block to a flash alignment (8 bytes).
1001 while b_tlv.len() % 8 != 0 {
1002 //FIXME: should be erase_val?
1003 b_tlv.push(0xFF);
1004 }
1005
1006 let mut buf = vec![];
1007 buf.append(&mut b_header.to_vec());
1008 buf.append(&mut b_img);
1009 buf.append(&mut b_tlv.clone());
1010
1011 let mut encbuf = vec![];
1012 if is_encrypted {
1013 encbuf.append(&mut b_header.to_vec());
1014 encbuf.append(&mut b_encimg);
1015 encbuf.append(&mut b_tlv);
1016 }
1017
David Vincze2d736ad2019-02-18 11:50:22 +01001018 // Since images are always non-encrypted in the primary slot, we first write
1019 // an encrypted image, re-read to use for verification, erase + flash
1020 // un-encrypted. In the secondary slot the image is written un-encrypted,
1021 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001022
David Brown76101572019-02-28 11:29:03 -07001023 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001024
1025 if slot == 0 {
1026 let enc_copy: Option<Vec<u8>>;
1027
1028 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001029 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001030
1031 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001032 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001033
1034 enc_copy = Some(enc);
1035
David Brown76101572019-02-28 11:29:03 -07001036 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001037 } else {
1038 enc_copy = None;
1039 }
1040
David Brown76101572019-02-28 11:29:03 -07001041 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001042
1043 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001044 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001045
David Brownca234692019-02-28 11:22:19 -07001046 ImageData {
1047 plain: copy,
1048 cipher: enc_copy,
1049 }
David Brown5c9e0f12019-01-09 16:34:33 -07001050 } else {
1051
David Brown76101572019-02-28 11:29:03 -07001052 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001053
1054 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001055 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001056
1057 let enc_copy: Option<Vec<u8>>;
1058
1059 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001060 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001061
David Brown76101572019-02-28 11:29:03 -07001062 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001063
1064 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001065 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001066
1067 enc_copy = Some(enc);
1068 } else {
1069 enc_copy = None;
1070 }
1071
David Brownca234692019-02-28 11:22:19 -07001072 ImageData {
1073 plain: copy,
1074 cipher: enc_copy,
1075 }
David Brown5c9e0f12019-01-09 16:34:33 -07001076 }
David Brown5c9e0f12019-01-09 16:34:33 -07001077}
1078
David Brown5c9e0f12019-01-09 16:34:33 -07001079fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001080 if Caps::EcdsaP224.present() {
1081 panic!("Ecdsa P224 not supported in Simulator");
1082 }
David Brown5c9e0f12019-01-09 16:34:33 -07001083
David Brownb8882112019-01-11 14:04:11 -07001084 if Caps::EncKw.present() {
1085 if Caps::RSA2048.present() {
1086 TlvGen::new_rsa_kw()
1087 } else if Caps::EcdsaP256.present() {
1088 TlvGen::new_ecdsa_kw()
1089 } else {
1090 TlvGen::new_enc_kw()
1091 }
1092 } else if Caps::EncRsa.present() {
1093 if Caps::RSA2048.present() {
1094 TlvGen::new_sig_enc_rsa()
1095 } else {
1096 TlvGen::new_enc_rsa()
1097 }
1098 } else {
1099 // The non-encrypted configuration.
1100 if Caps::RSA2048.present() {
1101 TlvGen::new_rsa_pss()
1102 } else if Caps::EcdsaP256.present() {
1103 TlvGen::new_ecdsa()
1104 } else {
1105 TlvGen::new_hash_only()
1106 }
1107 }
David Brown5c9e0f12019-01-09 16:34:33 -07001108}
1109
David Brownca234692019-02-28 11:22:19 -07001110impl ImageData {
1111 /// Find the image contents for the given slot. This assumes that slot 0
1112 /// is unencrypted, and slot 1 is encrypted.
1113 fn find(&self, slot: usize) -> &Vec<u8> {
1114 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1115 match (encrypted, slot) {
1116 (false, _) => &self.plain,
1117 (true, 0) => &self.plain,
1118 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1119 _ => panic!("Invalid slot requested"),
1120 }
David Brown5c9e0f12019-01-09 16:34:33 -07001121 }
1122}
1123
David Brown5c9e0f12019-01-09 16:34:33 -07001124/// Verify that given image is present in the flash at the given offset.
David Brown76101572019-02-28 11:29:03 -07001125fn verify_image(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brownca234692019-02-28 11:22:19 -07001126 images: &ImageData) -> bool {
1127 let image = images.find(slot);
David Brown5c9e0f12019-01-09 16:34:33 -07001128 let buf = image.as_slice();
1129 let dev_id = slots[slot].dev_id;
1130
1131 let mut copy = vec![0u8; buf.len()];
1132 let offset = slots[slot].base_off;
David Brown76101572019-02-28 11:29:03 -07001133 let dev = flash.get(&dev_id).unwrap();
1134 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001135
1136 if buf != &copy[..] {
1137 for i in 0 .. buf.len() {
1138 if buf[i] != copy[i] {
1139 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1140 slot, offset + i, buf[i], copy[i]);
1141 break;
1142 }
1143 }
1144 false
1145 } else {
1146 true
1147 }
1148}
1149
David Brown76101572019-02-28 11:29:03 -07001150fn verify_trailer(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001151 magic: Option<u8>, image_ok: Option<u8>,
1152 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001153 if Caps::OverwriteUpgrade.present() {
1154 return true;
1155 }
David Brown5c9e0f12019-01-09 16:34:33 -07001156
David Brown5c9e0f12019-01-09 16:34:33 -07001157 let offset = slots[slot].trailer_off;
1158 let dev_id = slots[slot].dev_id;
1159 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1160 let mut failed = false;
1161
David Brown76101572019-02-28 11:29:03 -07001162 let dev = flash.get(&dev_id).unwrap();
1163 let erased_val = dev.erased_val();
1164 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001165
1166 failed |= match magic {
1167 Some(v) => {
1168 if v == 1 && &copy[16..] != MAGIC.unwrap() {
1169 warn!("\"magic\" mismatch at {:#x}", offset);
1170 true
1171 } else if v == 3 {
1172 let expected = [erased_val; 16];
1173 if &copy[16..] != expected {
1174 warn!("\"magic\" mismatch at {:#x}", offset);
1175 true
1176 } else {
1177 false
1178 }
1179 } else {
1180 false
1181 }
1182 },
1183 None => false,
1184 };
1185
1186 failed |= match image_ok {
1187 Some(v) => {
1188 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1189 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1190 true
1191 } else {
1192 false
1193 }
1194 },
1195 None => false,
1196 };
1197
1198 failed |= match copy_done {
1199 Some(v) => {
1200 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1201 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1202 true
1203 } else {
1204 false
1205 }
1206 },
1207 None => false,
1208 };
1209
1210 !failed
1211}
1212
1213/// The image header
1214#[repr(C)]
1215pub struct ImageHeader {
1216 magic: u32,
1217 load_addr: u32,
1218 hdr_size: u16,
1219 _pad1: u16,
1220 img_size: u32,
1221 flags: u32,
1222 ver: ImageVersion,
1223 _pad2: u32,
1224}
1225
1226impl AsRaw for ImageHeader {}
1227
1228#[repr(C)]
1229pub struct ImageVersion {
1230 major: u8,
1231 minor: u8,
1232 revision: u16,
1233 build_num: u32,
1234}
1235
1236#[derive(Clone)]
1237pub struct SlotInfo {
1238 pub base_off: usize,
1239 pub trailer_off: usize,
1240 pub len: usize,
1241 pub dev_id: u8,
1242}
1243
David Brown5c9e0f12019-01-09 16:34:33 -07001244const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1245 0x60, 0xd2, 0xef, 0x7f,
1246 0x35, 0x52, 0x50, 0x0f,
1247 0x2c, 0xb6, 0x79, 0x80]);
1248
1249// Replicates defines found in bootutil.h
1250const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1251const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1252
1253const BOOT_FLAG_SET: Option<u8> = Some(1);
1254const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1255
1256/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001257pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1258 let dev = flash.get_mut(&slot.dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001259 let offset = slot.trailer_off + c::boot_max_align() * 2;
David Brown76101572019-02-28 11:29:03 -07001260 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001261}
1262
1263/// Writes the image_ok flag which, guess what, tells the bootloader
1264/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001265fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1266 let dev = flash.get_mut(&slot.dev_id).unwrap();
1267 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001268 ok[0] = 1u8;
1269 let off = slot.trailer_off + c::boot_max_align();
David Brown76101572019-02-28 11:29:03 -07001270 let align = dev.align();
1271 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001272}
1273
1274// Drop some pseudo-random gibberish onto the data.
1275fn splat(data: &mut [u8], seed: usize) {
1276 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1277 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1278 rng.fill_bytes(data);
1279}
1280
1281/// Return a read-only view into the raw bytes of this object
1282trait AsRaw : Sized {
1283 fn as_raw<'a>(&'a self) -> &'a [u8] {
1284 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1285 mem::size_of::<Self>()) }
1286 }
1287}
1288
1289pub fn show_sizes() {
1290 // This isn't panic safe.
1291 for min in &[1, 2, 4, 8] {
1292 let msize = c::boot_trailer_sz(*min);
1293 println!("{:2}: {} (0x{:x})", min, msize, msize);
1294 }
1295}