blob: 90d3a77b33419bd0bc5b72f701423dbe93ace781 [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
Christopher Collinsa1c12042019-05-23 14:00:28 -070096 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 4;
David Browne5133242019-02-28 11:05:19 -070097
David Brown06ef06e2019-03-05 12:28:10 -070098 // Construct a primary image.
99 let primary = SlotInfo {
100 base_off: primary_base as usize,
101 trailer_off: primary_base + primary_len - offset_from_end,
102 len: primary_len as usize,
103 dev_id: primary_dev_id,
104 };
105
106 // And an upgrade image.
107 let secondary = SlotInfo {
108 base_off: secondary_base as usize,
109 trailer_off: secondary_base + secondary_len - offset_from_end,
110 len: secondary_len as usize,
111 dev_id: secondary_dev_id,
112 };
113
114 slots.push([primary, secondary]);
115 }
David Browne5133242019-02-28 11:05:19 -0700116
David Brown5bc62c62019-03-05 12:11:48 -0700117 Some(ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -0700118 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700119 areadesc: areadesc,
David Brown06ef06e2019-03-05 12:28:10 -0700120 slots: slots,
David Brown5bc62c62019-03-05 12:11:48 -0700121 })
David Browne5133242019-02-28 11:05:19 -0700122 }
123
124 pub fn each_device<F>(f: F)
125 where F: Fn(Self)
126 {
127 for &dev in ALL_DEVICES {
128 for &align in &[1, 2, 4, 8] {
129 for &erased_val in &[0, 0xff] {
David Brown5bc62c62019-03-05 12:11:48 -0700130 match Self::new(dev, align, erased_val) {
131 Some(run) => f(run),
132 None => warn!("Skipping {:?}, insufficient partitions", dev),
133 }
David Browne5133242019-02-28 11:05:19 -0700134 }
135 }
136 }
137 }
138
139 /// Construct an `Images` that doesn't expect an upgrade to happen.
140 pub fn make_no_upgrade_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700141 let mut flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700142 let images = self.slots.into_iter().map(|slots| {
Fabio Utzig28d012c2019-05-17 10:14:27 -0700143 let primaries = install_image(&mut flash, &slots, 0, 42784, false);
144 let upgrades = install_image(&mut flash, &slots, 1, 46928, false);
David Brown84b49f72019-03-01 10:58:22 -0700145 OneImage {
146 slots: slots,
147 primaries: primaries,
148 upgrades: upgrades,
149 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700150 Images {
David Brown76101572019-02-28 11:29:03 -0700151 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700152 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700153 images: images,
David Browne5133242019-02-28 11:05:19 -0700154 total_count: None,
155 }
156 }
157
Fabio Utziged4a5362019-07-30 12:43:23 -0300158 fn make_image_with_permanent(self, permanent: bool) -> Images {
David Browne5133242019-02-28 11:05:19 -0700159 let mut images = self.make_no_upgrade_image();
David Brown84b49f72019-03-01 10:58:22 -0700160 for image in &images.images {
161 mark_upgrade(&mut images.flash, &image.slots[1]);
162 }
David Browne5133242019-02-28 11:05:19 -0700163
164 // upgrades without fails, counts number of flash operations
Fabio Utziged4a5362019-07-30 12:43:23 -0300165 let total_count = match images.run_basic_upgrade(permanent) {
David Browne5133242019-02-28 11:05:19 -0700166 Ok(v) => v,
167 Err(_) => {
168 panic!("Unable to perform basic upgrade");
169 },
170 };
171
172 images.total_count = Some(total_count);
173 images
174 }
175
Fabio Utziged4a5362019-07-30 12:43:23 -0300176 /// Construct an `Images` for normal testing with perm upgrade.
177 pub fn make_image(self) -> Images {
178 self.make_image_with_permanent(true)
179 }
180
181 /// Construct an `Images` for normal testing with test upgrade.
182 pub fn make_non_permanent_image(self) -> Images {
183 self.make_image_with_permanent(false)
184 }
185
David Browne5133242019-02-28 11:05:19 -0700186 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700187 let mut bad_flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700188 let images = self.slots.into_iter().map(|slots| {
189 let primaries = install_image(&mut bad_flash, &slots, 0, 32784, false);
190 let upgrades = install_image(&mut bad_flash, &slots, 1, 41928, true);
191 OneImage {
192 slots: slots,
193 primaries: primaries,
194 upgrades: upgrades,
195 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700196 Images {
David Brown76101572019-02-28 11:29:03 -0700197 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700198 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700199 images: images,
David Browne5133242019-02-28 11:05:19 -0700200 total_count: None,
201 }
202 }
203
204 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700205 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700206 match device {
207 DeviceName::Stm32f4 => {
208 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700209 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
210 64 * 1024,
211 128 * 1024, 128 * 1024, 128 * 1024],
212 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700213 let dev_id = 0;
214 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700215 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700216 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
217 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
218 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
219
David Brown76101572019-02-28 11:29:03 -0700220 let mut flash = SimMultiFlash::new();
221 flash.insert(dev_id, dev);
222 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700223 }
224 DeviceName::K64f => {
225 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700226 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700227
228 let dev_id = 0;
229 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700230 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700231 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
232 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
233 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
234
David Brown76101572019-02-28 11:29:03 -0700235 let mut flash = SimMultiFlash::new();
236 flash.insert(dev_id, dev);
237 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700238 }
239 DeviceName::K64fBig => {
240 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
241 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700242 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700243
244 let dev_id = 0;
245 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700246 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700247 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
248 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
249 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
250
David Brown76101572019-02-28 11:29:03 -0700251 let mut flash = SimMultiFlash::new();
252 flash.insert(dev_id, dev);
253 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700254 }
255 DeviceName::Nrf52840 => {
256 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
257 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700258 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700259
260 let dev_id = 0;
261 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700262 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700263 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
264 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
265 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
266
David Brown76101572019-02-28 11:29:03 -0700267 let mut flash = SimMultiFlash::new();
268 flash.insert(dev_id, dev);
269 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700270 }
271 DeviceName::Nrf52840SpiFlash => {
272 // Simulate nrf52840 with external SPI flash. The external SPI flash
273 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700274 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
275 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700276
277 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700278 areadesc.add_flash_sectors(0, &dev0);
279 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700280
281 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
282 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
283 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
284
David Brown76101572019-02-28 11:29:03 -0700285 let mut flash = SimMultiFlash::new();
286 flash.insert(0, dev0);
287 flash.insert(1, dev1);
288 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700289 }
David Brown2bff6472019-03-05 13:58:35 -0700290 DeviceName::K64fMulti => {
291 // NXP style flash, but larger, to support multiple images.
292 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
293
294 let dev_id = 0;
295 let mut areadesc = AreaDesc::new();
296 areadesc.add_flash_sectors(dev_id, &dev);
297 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
298 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
299 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
300 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
301 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
302
303 let mut flash = SimMultiFlash::new();
304 flash.insert(dev_id, dev);
305 (flash, areadesc)
306 }
David Browne5133242019-02-28 11:05:19 -0700307 }
308 }
309}
310
David Brown5c9e0f12019-01-09 16:34:33 -0700311impl Images {
312 /// A simple upgrade without forced failures.
313 ///
314 /// Returns the number of flash operations which can later be used to
315 /// inject failures at chosen steps.
Fabio Utziged4a5362019-07-30 12:43:23 -0300316 pub fn run_basic_upgrade(&self, permanent: bool) -> Result<i32, ()> {
317 let (flash, total_count) = self.try_upgrade(None, permanent);
David Brown5c9e0f12019-01-09 16:34:33 -0700318 info!("Total flash operation count={}", total_count);
319
David Brown84b49f72019-03-01 10:58:22 -0700320 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700321 warn!("Image mismatch after first boot");
322 Err(())
323 } else {
324 Ok(total_count)
325 }
326 }
327
David Brown5c9e0f12019-01-09 16:34:33 -0700328 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700329 if Caps::OverwriteUpgrade.present() {
330 return false;
331 }
David Brown5c9e0f12019-01-09 16:34:33 -0700332
David Brown5c9e0f12019-01-09 16:34:33 -0700333 let mut fails = 0;
334
335 // FIXME: this test would also pass if no swap is ever performed???
336 if Caps::SwapUpgrade.present() {
337 for count in 2 .. 5 {
338 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700339 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700340 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700341 error!("Revert failure on count {}", count);
342 fails += 1;
343 }
344 }
345 }
346
347 fails > 0
348 }
349
350 pub fn run_perm_with_fails(&self) -> bool {
351 let mut fails = 0;
352 let total_flash_ops = self.total_count.unwrap();
353
354 // Let's try an image halfway through.
355 for i in 1 .. total_flash_ops {
356 info!("Try interruption at {}", i);
Fabio Utziged4a5362019-07-30 12:43:23 -0300357 let (flash, count) = self.try_upgrade(Some(i), true);
David Brown5c9e0f12019-01-09 16:34:33 -0700358 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700359 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700360 warn!("FAIL at step {} of {}", i, total_flash_ops);
361 fails += 1;
362 }
363
David Brown84b49f72019-03-01 10:58:22 -0700364 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
365 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100366 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700367 fails += 1;
368 }
369
David Brown84b49f72019-03-01 10:58:22 -0700370 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
371 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100372 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700373 fails += 1;
374 }
375
376 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700377 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100378 warn!("Secondary slot FAIL at step {} of {}",
379 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700380 fails += 1;
381 }
382 }
383 }
384
385 if fails > 0 {
386 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
387 fails as f32 * 100.0 / total_flash_ops as f32);
388 }
389
390 fails > 0
391 }
392
393 pub fn run_perm_with_random_fails_5(&self) -> bool {
394 self.run_perm_with_random_fails(5)
395 }
396
397 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
398 let mut fails = 0;
399 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700400 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700401 info!("Random interruptions at reset points={:?}", total_counts);
402
David Brown84b49f72019-03-01 10:58:22 -0700403 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100404 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700405 // TODO: This result is ignored.
406 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700407 } else {
408 true
409 };
David Vincze2d736ad2019-02-18 11:50:22 +0100410 if !primary_slot_ok || !secondary_slot_ok {
411 error!("Image mismatch after random interrupts: primary slot={} \
412 secondary slot={}",
413 if primary_slot_ok { "ok" } else { "fail" },
414 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700415 fails += 1;
416 }
David Brown84b49f72019-03-01 10:58:22 -0700417 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
418 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100419 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700420 fails += 1;
421 }
David Brown84b49f72019-03-01 10:58:22 -0700422 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
423 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100424 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700425 fails += 1;
426 }
427
428 if fails > 0 {
429 error!("Error testing perm upgrade with {} fails", total_fails);
430 }
431
432 fails > 0
433 }
434
David Brown5c9e0f12019-01-09 16:34:33 -0700435 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700436 if Caps::OverwriteUpgrade.present() {
437 return false;
438 }
David Brown5c9e0f12019-01-09 16:34:33 -0700439
David Brown5c9e0f12019-01-09 16:34:33 -0700440 let mut fails = 0;
441
442 if Caps::SwapUpgrade.present() {
Fabio Utziged4a5362019-07-30 12:43:23 -0300443 for i in 1 .. self.total_count.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -0700444 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700445 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700446 error!("Revert failed at interruption {}", i);
447 fails += 1;
448 }
449 }
450 }
451
452 fails > 0
453 }
454
David Brown5c9e0f12019-01-09 16:34:33 -0700455 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700456 if Caps::OverwriteUpgrade.present() {
457 return false;
458 }
David Brown5c9e0f12019-01-09 16:34:33 -0700459
David Brown76101572019-02-28 11:29:03 -0700460 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700461 let mut fails = 0;
462
463 info!("Try norevert");
464
465 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700466 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700467 if result != 0 {
468 warn!("Failed first boot");
469 fails += 1;
470 }
471
472 //FIXME: copy_done is written by boot_go, is it ok if no copy
473 // was ever done?
474
David Brown84b49f72019-03-01 10:58:22 -0700475 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100476 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700477 fails += 1;
478 }
David Brown84b49f72019-03-01 10:58:22 -0700479 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
480 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100481 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700482 fails += 1;
483 }
David Brown84b49f72019-03-01 10:58:22 -0700484 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
485 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100486 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700487 fails += 1;
488 }
489
David Vincze2d736ad2019-02-18 11:50:22 +0100490 // Marks image in the primary slot as permanent,
491 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700492 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700493
David Brown84b49f72019-03-01 10:58:22 -0700494 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
495 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100496 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700497 fails += 1;
498 }
499
David Brown76101572019-02-28 11:29:03 -0700500 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700501 if result != 0 {
502 warn!("Failed second boot");
503 fails += 1;
504 }
505
David Brown84b49f72019-03-01 10:58:22 -0700506 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
507 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100508 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700509 fails += 1;
510 }
David Brown84b49f72019-03-01 10:58:22 -0700511 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700512 warn!("Failed image verification");
513 fails += 1;
514 }
515
516 if fails > 0 {
517 error!("Error running upgrade without revert");
518 }
519
520 fails > 0
521 }
522
David Vincze2d736ad2019-02-18 11:50:22 +0100523 // Tests a new image written to the primary slot that already has magic and
524 // image_ok set while there is no image on the secondary slot, so no revert
525 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700526 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700527 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700528 let mut fails = 0;
529
530 info!("Try non-revert on imgtool generated image");
531
David Brown84b49f72019-03-01 10:58:22 -0700532 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700533
David Vincze2d736ad2019-02-18 11:50:22 +0100534 // This simulates writing an image created by imgtool to
535 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700536 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
537 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100538 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700539 fails += 1;
540 }
541
542 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700543 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700544 if result != 0 {
545 warn!("Failed first boot");
546 fails += 1;
547 }
548
549 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700550 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700551 warn!("Failed image verification");
552 fails += 1;
553 }
David Brown84b49f72019-03-01 10:58:22 -0700554 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
555 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100556 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700557 fails += 1;
558 }
David Brown84b49f72019-03-01 10:58:22 -0700559 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
560 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100561 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700562 fails += 1;
563 }
564
565 if fails > 0 {
566 error!("Expected a non revert with new image");
567 }
568
569 fails > 0
570 }
571
David Vincze2d736ad2019-02-18 11:50:22 +0100572 // Tests a new image written to the primary slot that already has magic and
573 // image_ok set while there is no image on the secondary slot, so no revert
574 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700575 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700576 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700577 let mut fails = 0;
578
579 info!("Try upgrade image with bad signature");
580
David Brown84b49f72019-03-01 10:58:22 -0700581 self.mark_upgrades(&mut flash, 0);
582 self.mark_permanent_upgrades(&mut flash, 0);
583 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700584
David Brown84b49f72019-03-01 10:58:22 -0700585 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
586 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100587 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700588 fails += 1;
589 }
590
591 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700592 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700593 if result != 0 {
594 warn!("Failed first boot");
595 fails += 1;
596 }
597
598 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700599 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700600 warn!("Failed image verification");
601 fails += 1;
602 }
David Brown84b49f72019-03-01 10:58:22 -0700603 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
604 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100605 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700606 fails += 1;
607 }
608
609 if fails > 0 {
610 error!("Expected an upgrade failure when image has bad signature");
611 }
612
613 fails > 0
614 }
615
David Brown5c9e0f12019-01-09 16:34:33 -0700616 fn trailer_sz(&self, align: usize) -> usize {
617 c::boot_trailer_sz(align as u8) as usize
618 }
619
620 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700621 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700622 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
623 32
624 } else {
625 0
626 };
David Brown5c9e0f12019-01-09 16:34:33 -0700627
Christopher Collinsa1c12042019-05-23 14:00:28 -0700628 self.trailer_sz(align) - (16 + 32 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700629 }
630
631 /// This test runs a simple upgrade with no fails in the images, but
632 /// allowing for fails in the status area. This should run to the end
633 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700634 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100635 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700636 return false;
637 }
638
David Brown76101572019-02-28 11:29:03 -0700639 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700640 let mut fails = 0;
641
642 info!("Try swap with status fails");
643
David Brown84b49f72019-03-01 10:58:22 -0700644 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700645 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700646
David Brown76101572019-02-28 11:29:03 -0700647 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700648 if result != 0 {
649 warn!("Failed!");
650 fails += 1;
651 }
652
653 // Failed writes to the marked "bad" region don't assert anymore.
654 // Any detected assert() is happening in another part of the code.
655 if asserts != 0 {
656 warn!("At least one assert() was called");
657 fails += 1;
658 }
659
David Brown84b49f72019-03-01 10:58:22 -0700660 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
661 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100662 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700663 fails += 1;
664 }
665
David Brown84b49f72019-03-01 10:58:22 -0700666 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700667 warn!("Failed image verification");
668 fails += 1;
669 }
670
David Vincze2d736ad2019-02-18 11:50:22 +0100671 info!("validate primary slot enabled; \
672 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700673 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700674 if result != 0 {
675 warn!("Failed!");
676 fails += 1;
677 }
678
679 if fails > 0 {
680 error!("Error running upgrade with status write fails");
681 }
682
683 fails > 0
684 }
685
686 /// This test runs a simple upgrade with no fails in the images, but
687 /// allowing for fails in the status area. This should run to the end
688 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700689 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700690 if Caps::OverwriteUpgrade.present() {
691 false
David Vincze2d736ad2019-02-18 11:50:22 +0100692 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700693
David Brown76101572019-02-28 11:29:03 -0700694 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700695 let mut fails = 0;
696 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700697
David Brown85904a82019-01-11 13:45:12 -0700698 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700699
David Brown85904a82019-01-11 13:45:12 -0700700 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700701
David Brown84b49f72019-03-01 10:58:22 -0700702 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700703 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700704
705 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700706 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700707 if asserts != 0 {
708 warn!("At least one assert() was called");
709 fails += 1;
710 }
711
David Brown76101572019-02-28 11:29:03 -0700712 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700713
714 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700715 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700716
717 // This might throw no asserts, for large sector devices, where
718 // a single failure writing is indistinguishable from no failure,
719 // or throw a single assert for small sector devices that fail
720 // multiple times...
721 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100722 warn!("Expected single assert validating the primary slot, \
723 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700724 fails += 1;
725 }
726
727 if fails > 0 {
728 error!("Error running upgrade with status write fails");
729 }
730
731 fails > 0
732 } else {
David Brown76101572019-02-28 11:29:03 -0700733 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700734 let mut fails = 0;
735
736 info!("Try interrupted swap with status fails");
737
David Brown84b49f72019-03-01 10:58:22 -0700738 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700739 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700740
741 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700742 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700743 if asserts == 0 {
744 warn!("No assert() detected");
745 fails += 1;
746 }
747
748 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700749 }
David Brown5c9e0f12019-01-09 16:34:33 -0700750 }
751
752 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700753 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700754 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700755 if Caps::OverwriteUpgrade.present() {
756 return;
757 }
758
David Brown84b49f72019-03-01 10:58:22 -0700759 // Set this for each image.
760 for image in &self.images {
761 let dev_id = &image.slots[slot].dev_id;
762 let dev = flash.get_mut(&dev_id).unwrap();
763 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -0700764 let off = &image.slots[slot].base_off;
765 let len = &image.slots[slot].len;
David Brown84b49f72019-03-01 10:58:22 -0700766 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700767
David Brown84b49f72019-03-01 10:58:22 -0700768 // Mark the status area as a bad area
769 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
770 }
David Brown5c9e0f12019-01-09 16:34:33 -0700771 }
772
David Brown76101572019-02-28 11:29:03 -0700773 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100774 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700775 return;
776 }
777
David Brown84b49f72019-03-01 10:58:22 -0700778 for image in &self.images {
779 let dev_id = &image.slots[slot].dev_id;
780 let dev = flash.get_mut(&dev_id).unwrap();
781 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700782
David Brown84b49f72019-03-01 10:58:22 -0700783 // Disabling write verification the only assert triggered by
784 // boot_go should be checking for integrity of status bytes.
785 dev.set_verify_writes(false);
786 }
David Brown5c9e0f12019-01-09 16:34:33 -0700787 }
788
David Browndb505822019-03-01 10:04:20 -0700789 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
790 /// of the number of flash operations done total.
Fabio Utziged4a5362019-07-30 12:43:23 -0300791 fn try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32) {
David Browndb505822019-03-01 10:04:20 -0700792 // Clone the flash to have a new copy.
793 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700794
Fabio Utziged4a5362019-07-30 12:43:23 -0300795 if permanent {
796 self.mark_permanent_upgrades(&mut flash, 1);
797 }
David Brown5c9e0f12019-01-09 16:34:33 -0700798
David Browndb505822019-03-01 10:04:20 -0700799 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700800
David Browndb505822019-03-01 10:04:20 -0700801 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
802 (-0x13579, _) => (true, stop.unwrap()),
803 (0, _) => (false, -counter),
804 (x, _) => panic!("Unknown return: {}", x),
805 };
David Brown5c9e0f12019-01-09 16:34:33 -0700806
David Browndb505822019-03-01 10:04:20 -0700807 counter = 0;
808 if first_interrupted {
809 // fl.dump();
810 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
811 (-0x13579, _) => panic!("Shouldn't stop again"),
812 (0, _) => (),
813 (x, _) => panic!("Unknown return: {}", x),
814 }
815 }
David Brown5c9e0f12019-01-09 16:34:33 -0700816
David Browndb505822019-03-01 10:04:20 -0700817 (flash, count - counter)
818 }
819
820 fn try_revert(&self, count: usize) -> SimMultiFlash {
821 let mut flash = self.flash.clone();
822
823 // fl.write_file("image0.bin").unwrap();
824 for i in 0 .. count {
825 info!("Running boot pass {}", i + 1);
826 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
827 }
828 flash
829 }
830
831 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
832 let mut flash = self.flash.clone();
833 let mut fails = 0;
834
835 let mut counter = stop;
836 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
837 if x != -0x13579 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700838 warn!("Should have stopped test at interruption point");
David Browndb505822019-03-01 10:04:20 -0700839 fails += 1;
840 }
841
Fabio Utzig8af7f792019-07-30 12:40:01 -0300842 // In a multi-image setup, copy done might be set if any number of
843 // images was already successfully swapped.
844 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
845 warn!("copy_done should be unset");
846 fails += 1;
847 }
848
David Browndb505822019-03-01 10:04:20 -0700849 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
850 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700851 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -0700852 fails += 1;
853 }
854
David Brown84b49f72019-03-01 10:58:22 -0700855 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700856 warn!("Image in the primary slot before revert is invalid at stop={}",
857 stop);
858 fails += 1;
859 }
David Brown84b49f72019-03-01 10:58:22 -0700860 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700861 warn!("Image in the secondary slot before revert is invalid at stop={}",
862 stop);
863 fails += 1;
864 }
David Brown84b49f72019-03-01 10:58:22 -0700865 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
866 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700867 warn!("Mismatched trailer for the primary slot before revert");
868 fails += 1;
869 }
David Brown84b49f72019-03-01 10:58:22 -0700870 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
871 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700872 warn!("Mismatched trailer for the secondary slot before revert");
873 fails += 1;
874 }
875
876 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700877 let mut counter = stop;
878 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
879 if x != -0x13579 {
880 warn!("Should have stopped revert at interruption point");
881 fails += 1;
882 }
883
David Browndb505822019-03-01 10:04:20 -0700884 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
885 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700886 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -0700887 fails += 1;
888 }
889
David Brown84b49f72019-03-01 10:58:22 -0700890 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700891 warn!("Image in the primary slot after revert is invalid at stop={}",
892 stop);
893 fails += 1;
894 }
David Brown84b49f72019-03-01 10:58:22 -0700895 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700896 warn!("Image in the secondary slot after revert is invalid at stop={}",
897 stop);
898 fails += 1;
899 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700900
David Brown84b49f72019-03-01 10:58:22 -0700901 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
902 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700903 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -0700904 fails += 1;
905 }
David Brown84b49f72019-03-01 10:58:22 -0700906 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
907 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700908 warn!("Mismatched trailer for the secondary slot after revert");
909 fails += 1;
910 }
911
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700912 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
913 if x != 0 {
914 warn!("Should have finished 3rd boot");
915 fails += 1;
916 }
917
918 if !self.verify_images(&flash, 0, 0) {
919 warn!("Image in the primary slot is invalid on 1st boot after revert");
920 fails += 1;
921 }
922 if !self.verify_images(&flash, 1, 1) {
923 warn!("Image in the secondary slot is invalid on 1st boot after revert");
924 fails += 1;
925 }
926
David Browndb505822019-03-01 10:04:20 -0700927 fails > 0
928 }
929
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700930
David Browndb505822019-03-01 10:04:20 -0700931 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
932 let mut flash = self.flash.clone();
933
David Brown84b49f72019-03-01 10:58:22 -0700934 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700935
936 let mut rng = rand::thread_rng();
937 let mut resets = vec![0i32; count];
938 let mut remaining_ops = total_ops;
939 for i in 0 .. count {
940 let ops = Range::new(1, remaining_ops / 2);
941 let reset_counter = ops.ind_sample(&mut rng);
942 let mut counter = reset_counter;
943 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
944 (0, _) | (-0x13579, _) => (),
945 (x, _) => panic!("Unknown return: {}", x),
946 }
947 remaining_ops -= reset_counter;
948 resets[i] = reset_counter;
949 }
950
951 match c::boot_go(&mut flash, &self.areadesc, None, false) {
952 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700953 (0, _) => (),
954 (x, _) => panic!("Unknown return: {}", x),
955 }
David Brown5c9e0f12019-01-09 16:34:33 -0700956
David Browndb505822019-03-01 10:04:20 -0700957 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700958 }
David Brown84b49f72019-03-01 10:58:22 -0700959
960 /// Verify the image in the given flash device, the specified slot
961 /// against the expected image.
962 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
963 for image in &self.images {
964 if !verify_image(flash, &image.slots, slot,
965 match against {
966 0 => &image.primaries,
967 1 => &image.upgrades,
968 _ => panic!("Invalid 'against'"),
969 }) {
970 return false;
971 }
972 }
973 true
974 }
975
Fabio Utzig8af7f792019-07-30 12:40:01 -0300976 /// Verify that at least one of the trailers of the images have the
977 /// specified values.
978 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
979 magic: Option<u8>, image_ok: Option<u8>,
980 copy_done: Option<u8>) -> bool {
981 for image in &self.images {
982 if verify_trailer(flash, &image.slots, slot,
983 magic, image_ok, copy_done) {
984 return true;
985 }
986 }
987 false
988 }
989
David Brown84b49f72019-03-01 10:58:22 -0700990 /// Verify that the trailers of the images have the specified
991 /// values.
992 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
993 magic: Option<u8>, image_ok: Option<u8>,
994 copy_done: Option<u8>) -> bool {
995 for image in &self.images {
996 if !verify_trailer(flash, &image.slots, slot,
997 magic, image_ok, copy_done) {
998 return false;
999 }
1000 }
1001 true
1002 }
1003
1004 /// Mark each of the images for permanent upgrade.
1005 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1006 for image in &self.images {
1007 mark_permanent_upgrade(flash, &image.slots[slot]);
1008 }
1009 }
1010
1011 /// Mark each of the images for permanent upgrade.
1012 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1013 for image in &self.images {
1014 mark_upgrade(flash, &image.slots[slot]);
1015 }
1016 }
David Brown5c9e0f12019-01-09 16:34:33 -07001017}
1018
1019/// Show the flash layout.
1020#[allow(dead_code)]
1021fn show_flash(flash: &dyn Flash) {
1022 println!("---- Flash configuration ----");
1023 for sector in flash.sector_iter() {
1024 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1025 sector.num, sector.base, sector.size);
1026 }
1027 println!("");
1028}
1029
1030/// Install a "program" into the given image. This fakes the image header, or at least all of the
1031/// fields used by the given code. Returns a copy of the image that was written.
David Brown76101572019-02-28 11:29:03 -07001032fn install_image(flash: &mut SimMultiFlash, slots: &[SlotInfo], slot: usize, len: usize,
David Brownca234692019-02-28 11:22:19 -07001033 bad_sig: bool) -> ImageData {
David Brown5c9e0f12019-01-09 16:34:33 -07001034 let offset = slots[slot].base_off;
1035 let slot_len = slots[slot].len;
1036 let dev_id = slots[slot].dev_id;
1037
David Brown43643dd2019-01-11 15:43:28 -07001038 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001039
1040 const HDR_SIZE: usize = 32;
1041
1042 // Generate a boot header. Note that the size doesn't include the header.
1043 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001044 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001045 load_addr: 0,
1046 hdr_size: HDR_SIZE as u16,
1047 _pad1: 0,
1048 img_size: len as u32,
1049 flags: tlv.get_flags(),
1050 ver: ImageVersion {
1051 major: (offset / (128 * 1024)) as u8,
1052 minor: 0,
1053 revision: 1,
1054 build_num: offset as u32,
1055 },
1056 _pad2: 0,
1057 };
1058
1059 let mut b_header = [0; HDR_SIZE];
1060 b_header[..32].clone_from_slice(header.as_raw());
1061 assert_eq!(b_header.len(), HDR_SIZE);
1062
1063 tlv.add_bytes(&b_header);
1064
1065 // The core of the image itself is just pseudorandom data.
1066 let mut b_img = vec![0; len];
1067 splat(&mut b_img, offset);
1068
1069 // TLV signatures work over plain image
1070 tlv.add_bytes(&b_img);
1071
1072 // Generate encrypted images
1073 let flag = TlvFlags::ENCRYPTED as u32;
1074 let is_encrypted = (tlv.get_flags() & flag) == flag;
1075 let mut b_encimg = vec![];
1076 if is_encrypted {
1077 let key = GenericArray::from_slice(AES_SEC_KEY);
1078 let nonce = GenericArray::from_slice(&[0; 16]);
1079 let mut cipher = Aes128Ctr::new(&key, &nonce);
1080 b_encimg = b_img.clone();
1081 cipher.apply_keystream(&mut b_encimg);
1082 }
1083
1084 // Build the TLV itself.
1085 let mut b_tlv = if bad_sig {
1086 let good_sig = &mut tlv.make_tlv();
1087 vec![0; good_sig.len()]
1088 } else {
1089 tlv.make_tlv()
1090 };
1091
1092 // Pad the block to a flash alignment (8 bytes).
1093 while b_tlv.len() % 8 != 0 {
1094 //FIXME: should be erase_val?
1095 b_tlv.push(0xFF);
1096 }
1097
1098 let mut buf = vec![];
1099 buf.append(&mut b_header.to_vec());
1100 buf.append(&mut b_img);
1101 buf.append(&mut b_tlv.clone());
1102
1103 let mut encbuf = vec![];
1104 if is_encrypted {
1105 encbuf.append(&mut b_header.to_vec());
1106 encbuf.append(&mut b_encimg);
1107 encbuf.append(&mut b_tlv);
1108 }
1109
David Vincze2d736ad2019-02-18 11:50:22 +01001110 // Since images are always non-encrypted in the primary slot, we first write
1111 // an encrypted image, re-read to use for verification, erase + flash
1112 // un-encrypted. In the secondary slot the image is written un-encrypted,
1113 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001114
David Brown76101572019-02-28 11:29:03 -07001115 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001116
1117 if slot == 0 {
1118 let enc_copy: Option<Vec<u8>>;
1119
1120 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001121 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001122
1123 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001124 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001125
1126 enc_copy = Some(enc);
1127
David Brown76101572019-02-28 11:29:03 -07001128 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001129 } else {
1130 enc_copy = None;
1131 }
1132
David Brown76101572019-02-28 11:29:03 -07001133 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001134
1135 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001136 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001137
David Brownca234692019-02-28 11:22:19 -07001138 ImageData {
1139 plain: copy,
1140 cipher: enc_copy,
1141 }
David Brown5c9e0f12019-01-09 16:34:33 -07001142 } else {
1143
David Brown76101572019-02-28 11:29:03 -07001144 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001145
1146 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001147 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001148
1149 let enc_copy: Option<Vec<u8>>;
1150
1151 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001152 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001153
David Brown76101572019-02-28 11:29:03 -07001154 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001155
1156 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001157 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001158
1159 enc_copy = Some(enc);
1160 } else {
1161 enc_copy = None;
1162 }
1163
David Brownca234692019-02-28 11:22:19 -07001164 ImageData {
1165 plain: copy,
1166 cipher: enc_copy,
1167 }
David Brown5c9e0f12019-01-09 16:34:33 -07001168 }
David Brown5c9e0f12019-01-09 16:34:33 -07001169}
1170
David Brown5c9e0f12019-01-09 16:34:33 -07001171fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001172 if Caps::EcdsaP224.present() {
1173 panic!("Ecdsa P224 not supported in Simulator");
1174 }
David Brown5c9e0f12019-01-09 16:34:33 -07001175
David Brownb8882112019-01-11 14:04:11 -07001176 if Caps::EncKw.present() {
1177 if Caps::RSA2048.present() {
1178 TlvGen::new_rsa_kw()
1179 } else if Caps::EcdsaP256.present() {
1180 TlvGen::new_ecdsa_kw()
1181 } else {
1182 TlvGen::new_enc_kw()
1183 }
1184 } else if Caps::EncRsa.present() {
1185 if Caps::RSA2048.present() {
1186 TlvGen::new_sig_enc_rsa()
1187 } else {
1188 TlvGen::new_enc_rsa()
1189 }
1190 } else {
1191 // The non-encrypted configuration.
1192 if Caps::RSA2048.present() {
1193 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001194 } else if Caps::RSA3072.present() {
1195 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001196 } else if Caps::EcdsaP256.present() {
1197 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001198 } else if Caps::Ed25519.present() {
1199 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001200 } else {
1201 TlvGen::new_hash_only()
1202 }
1203 }
David Brown5c9e0f12019-01-09 16:34:33 -07001204}
1205
David Brownca234692019-02-28 11:22:19 -07001206impl ImageData {
1207 /// Find the image contents for the given slot. This assumes that slot 0
1208 /// is unencrypted, and slot 1 is encrypted.
1209 fn find(&self, slot: usize) -> &Vec<u8> {
1210 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1211 match (encrypted, slot) {
1212 (false, _) => &self.plain,
1213 (true, 0) => &self.plain,
1214 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1215 _ => panic!("Invalid slot requested"),
1216 }
David Brown5c9e0f12019-01-09 16:34:33 -07001217 }
1218}
1219
David Brown5c9e0f12019-01-09 16:34:33 -07001220/// Verify that given image is present in the flash at the given offset.
David Brown76101572019-02-28 11:29:03 -07001221fn verify_image(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brownca234692019-02-28 11:22:19 -07001222 images: &ImageData) -> bool {
1223 let image = images.find(slot);
David Brown5c9e0f12019-01-09 16:34:33 -07001224 let buf = image.as_slice();
1225 let dev_id = slots[slot].dev_id;
1226
1227 let mut copy = vec![0u8; buf.len()];
1228 let offset = slots[slot].base_off;
David Brown76101572019-02-28 11:29:03 -07001229 let dev = flash.get(&dev_id).unwrap();
1230 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001231
1232 if buf != &copy[..] {
1233 for i in 0 .. buf.len() {
1234 if buf[i] != copy[i] {
1235 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1236 slot, offset + i, buf[i], copy[i]);
1237 break;
1238 }
1239 }
1240 false
1241 } else {
1242 true
1243 }
1244}
1245
David Brown76101572019-02-28 11:29:03 -07001246fn verify_trailer(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001247 magic: Option<u8>, image_ok: Option<u8>,
1248 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001249 if Caps::OverwriteUpgrade.present() {
1250 return true;
1251 }
David Brown5c9e0f12019-01-09 16:34:33 -07001252
Christopher Collinsa1c12042019-05-23 14:00:28 -07001253 let offset = slots[slot].trailer_off + c::boot_max_align();
David Brown5c9e0f12019-01-09 16:34:33 -07001254 let dev_id = slots[slot].dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001255 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001256 let mut failed = false;
1257
David Brown76101572019-02-28 11:29:03 -07001258 let dev = flash.get(&dev_id).unwrap();
1259 let erased_val = dev.erased_val();
1260 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001261
1262 failed |= match magic {
1263 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001264 if v == 1 && &copy[24..] != MAGIC.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -07001265 warn!("\"magic\" mismatch at {:#x}", offset);
1266 true
1267 } else if v == 3 {
1268 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001269 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001270 warn!("\"magic\" mismatch at {:#x}", offset);
1271 true
1272 } else {
1273 false
1274 }
1275 } else {
1276 false
1277 }
1278 },
1279 None => false,
1280 };
1281
1282 failed |= match image_ok {
1283 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001284 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001285 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1286 true
1287 } else {
1288 false
1289 }
1290 },
1291 None => false,
1292 };
1293
1294 failed |= match copy_done {
1295 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001296 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001297 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1298 true
1299 } else {
1300 false
1301 }
1302 },
1303 None => false,
1304 };
1305
1306 !failed
1307}
1308
1309/// The image header
1310#[repr(C)]
1311pub struct ImageHeader {
1312 magic: u32,
1313 load_addr: u32,
1314 hdr_size: u16,
1315 _pad1: u16,
1316 img_size: u32,
1317 flags: u32,
1318 ver: ImageVersion,
1319 _pad2: u32,
1320}
1321
1322impl AsRaw for ImageHeader {}
1323
1324#[repr(C)]
1325pub struct ImageVersion {
1326 major: u8,
1327 minor: u8,
1328 revision: u16,
1329 build_num: u32,
1330}
1331
1332#[derive(Clone)]
1333pub struct SlotInfo {
1334 pub base_off: usize,
1335 pub trailer_off: usize,
1336 pub len: usize,
1337 pub dev_id: u8,
1338}
1339
David Brown5c9e0f12019-01-09 16:34:33 -07001340const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1341 0x60, 0xd2, 0xef, 0x7f,
1342 0x35, 0x52, 0x50, 0x0f,
1343 0x2c, 0xb6, 0x79, 0x80]);
1344
1345// Replicates defines found in bootutil.h
1346const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1347const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1348
1349const BOOT_FLAG_SET: Option<u8> = Some(1);
1350const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1351
1352/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001353pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1354 let dev = flash.get_mut(&slot.dev_id).unwrap();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001355 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown76101572019-02-28 11:29:03 -07001356 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001357}
1358
1359/// Writes the image_ok flag which, guess what, tells the bootloader
1360/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001361fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1362 let dev = flash.get_mut(&slot.dev_id).unwrap();
1363 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001364 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001365 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001366 let align = dev.align();
1367 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001368}
1369
1370// Drop some pseudo-random gibberish onto the data.
1371fn splat(data: &mut [u8], seed: usize) {
1372 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1373 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1374 rng.fill_bytes(data);
1375}
1376
1377/// Return a read-only view into the raw bytes of this object
1378trait AsRaw : Sized {
1379 fn as_raw<'a>(&'a self) -> &'a [u8] {
1380 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1381 mem::size_of::<Self>()) }
1382 }
1383}
1384
1385pub fn show_sizes() {
1386 // This isn't panic safe.
1387 for min in &[1, 2, 4, 8] {
1388 let msize = c::boot_trailer_sz(*min);
1389 println!("{:2}: {} (0x{:x})", min, msize, msize);
1390 }
1391}