blob: 44cfaaad11c805950aefd01ad163809039cea6dc [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
158 /// Construct an `Images` for normal testing.
159 pub fn make_image(self) -> Images {
160 let mut images = self.make_no_upgrade_image();
David Brown84b49f72019-03-01 10:58:22 -0700161 for image in &images.images {
162 mark_upgrade(&mut images.flash, &image.slots[1]);
163 }
David Browne5133242019-02-28 11:05:19 -0700164
165 // upgrades without fails, counts number of flash operations
166 let total_count = match images.run_basic_upgrade() {
167 Ok(v) => v,
168 Err(_) => {
169 panic!("Unable to perform basic upgrade");
170 },
171 };
172
173 images.total_count = Some(total_count);
174 images
175 }
176
177 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700178 let mut bad_flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700179 let images = self.slots.into_iter().map(|slots| {
180 let primaries = install_image(&mut bad_flash, &slots, 0, 32784, false);
181 let upgrades = install_image(&mut bad_flash, &slots, 1, 41928, true);
182 OneImage {
183 slots: slots,
184 primaries: primaries,
185 upgrades: upgrades,
186 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700187 Images {
David Brown76101572019-02-28 11:29:03 -0700188 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700189 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700190 images: images,
David Browne5133242019-02-28 11:05:19 -0700191 total_count: None,
192 }
193 }
194
195 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700196 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700197 match device {
198 DeviceName::Stm32f4 => {
199 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700200 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
201 64 * 1024,
202 128 * 1024, 128 * 1024, 128 * 1024],
203 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700204 let dev_id = 0;
205 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700206 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700207 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
208 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
209 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
210
David Brown76101572019-02-28 11:29:03 -0700211 let mut flash = SimMultiFlash::new();
212 flash.insert(dev_id, dev);
213 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700214 }
215 DeviceName::K64f => {
216 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700217 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700218
219 let dev_id = 0;
220 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700221 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700222 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
223 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
224 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
225
David Brown76101572019-02-28 11:29:03 -0700226 let mut flash = SimMultiFlash::new();
227 flash.insert(dev_id, dev);
228 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700229 }
230 DeviceName::K64fBig => {
231 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
232 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700233 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700234
235 let dev_id = 0;
236 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700237 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700238 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
239 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
240 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
241
David Brown76101572019-02-28 11:29:03 -0700242 let mut flash = SimMultiFlash::new();
243 flash.insert(dev_id, dev);
244 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700245 }
246 DeviceName::Nrf52840 => {
247 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
248 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700249 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700250
251 let dev_id = 0;
252 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700253 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700254 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
255 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
256 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
257
David Brown76101572019-02-28 11:29:03 -0700258 let mut flash = SimMultiFlash::new();
259 flash.insert(dev_id, dev);
260 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700261 }
262 DeviceName::Nrf52840SpiFlash => {
263 // Simulate nrf52840 with external SPI flash. The external SPI flash
264 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700265 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
266 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700267
268 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700269 areadesc.add_flash_sectors(0, &dev0);
270 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700271
272 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
273 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
274 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
275
David Brown76101572019-02-28 11:29:03 -0700276 let mut flash = SimMultiFlash::new();
277 flash.insert(0, dev0);
278 flash.insert(1, dev1);
279 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700280 }
David Brown2bff6472019-03-05 13:58:35 -0700281 DeviceName::K64fMulti => {
282 // NXP style flash, but larger, to support multiple images.
283 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
284
285 let dev_id = 0;
286 let mut areadesc = AreaDesc::new();
287 areadesc.add_flash_sectors(dev_id, &dev);
288 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
289 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
290 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
291 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
292 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
293
294 let mut flash = SimMultiFlash::new();
295 flash.insert(dev_id, dev);
296 (flash, areadesc)
297 }
David Browne5133242019-02-28 11:05:19 -0700298 }
299 }
300}
301
David Brown5c9e0f12019-01-09 16:34:33 -0700302impl Images {
303 /// A simple upgrade without forced failures.
304 ///
305 /// Returns the number of flash operations which can later be used to
306 /// inject failures at chosen steps.
307 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Browndb505822019-03-01 10:04:20 -0700308 let (flash, total_count) = self.try_upgrade(None);
David Brown5c9e0f12019-01-09 16:34:33 -0700309 info!("Total flash operation count={}", total_count);
310
David Brown84b49f72019-03-01 10:58:22 -0700311 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700312 warn!("Image mismatch after first boot");
313 Err(())
314 } else {
315 Ok(total_count)
316 }
317 }
318
David Brown5c9e0f12019-01-09 16:34:33 -0700319 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700320 if Caps::OverwriteUpgrade.present() {
321 return false;
322 }
David Brown5c9e0f12019-01-09 16:34:33 -0700323
David Brown5c9e0f12019-01-09 16:34:33 -0700324 let mut fails = 0;
325
326 // FIXME: this test would also pass if no swap is ever performed???
327 if Caps::SwapUpgrade.present() {
328 for count in 2 .. 5 {
329 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700330 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700331 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700332 error!("Revert failure on count {}", count);
333 fails += 1;
334 }
335 }
336 }
337
338 fails > 0
339 }
340
341 pub fn run_perm_with_fails(&self) -> bool {
342 let mut fails = 0;
343 let total_flash_ops = self.total_count.unwrap();
344
345 // Let's try an image halfway through.
346 for i in 1 .. total_flash_ops {
347 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700348 let (flash, count) = self.try_upgrade(Some(i));
David Brown5c9e0f12019-01-09 16:34:33 -0700349 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700350 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700351 warn!("FAIL at step {} of {}", i, total_flash_ops);
352 fails += 1;
353 }
354
David Brown84b49f72019-03-01 10:58:22 -0700355 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
356 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100357 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700358 fails += 1;
359 }
360
David Brown84b49f72019-03-01 10:58:22 -0700361 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
362 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100363 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700364 fails += 1;
365 }
366
367 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700368 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100369 warn!("Secondary slot FAIL at step {} of {}",
370 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700371 fails += 1;
372 }
373 }
374 }
375
376 if fails > 0 {
377 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
378 fails as f32 * 100.0 / total_flash_ops as f32);
379 }
380
381 fails > 0
382 }
383
384 pub fn run_perm_with_random_fails_5(&self) -> bool {
385 self.run_perm_with_random_fails(5)
386 }
387
388 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
389 let mut fails = 0;
390 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700391 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700392 info!("Random interruptions at reset points={:?}", total_counts);
393
David Brown84b49f72019-03-01 10:58:22 -0700394 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100395 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700396 // TODO: This result is ignored.
397 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700398 } else {
399 true
400 };
David Vincze2d736ad2019-02-18 11:50:22 +0100401 if !primary_slot_ok || !secondary_slot_ok {
402 error!("Image mismatch after random interrupts: primary slot={} \
403 secondary slot={}",
404 if primary_slot_ok { "ok" } else { "fail" },
405 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700406 fails += 1;
407 }
David Brown84b49f72019-03-01 10:58:22 -0700408 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
409 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100410 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700411 fails += 1;
412 }
David Brown84b49f72019-03-01 10:58:22 -0700413 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
414 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100415 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700416 fails += 1;
417 }
418
419 if fails > 0 {
420 error!("Error testing perm upgrade with {} fails", total_fails);
421 }
422
423 fails > 0
424 }
425
David Brown5c9e0f12019-01-09 16:34:33 -0700426 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700427 if Caps::OverwriteUpgrade.present() {
428 return false;
429 }
David Brown5c9e0f12019-01-09 16:34:33 -0700430
David Brown5c9e0f12019-01-09 16:34:33 -0700431 let mut fails = 0;
432
433 if Caps::SwapUpgrade.present() {
434 for i in 1 .. (self.total_count.unwrap() - 1) {
435 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700436 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700437 error!("Revert failed at interruption {}", i);
438 fails += 1;
439 }
440 }
441 }
442
443 fails > 0
444 }
445
David Brown5c9e0f12019-01-09 16:34:33 -0700446 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700447 if Caps::OverwriteUpgrade.present() {
448 return false;
449 }
David Brown5c9e0f12019-01-09 16:34:33 -0700450
David Brown76101572019-02-28 11:29:03 -0700451 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700452 let mut fails = 0;
453
454 info!("Try norevert");
455
456 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700457 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700458 if result != 0 {
459 warn!("Failed first boot");
460 fails += 1;
461 }
462
463 //FIXME: copy_done is written by boot_go, is it ok if no copy
464 // was ever done?
465
David Brown84b49f72019-03-01 10:58:22 -0700466 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100467 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700468 fails += 1;
469 }
David Brown84b49f72019-03-01 10:58:22 -0700470 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
471 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100472 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700473 fails += 1;
474 }
David Brown84b49f72019-03-01 10:58:22 -0700475 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
476 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100477 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700478 fails += 1;
479 }
480
David Vincze2d736ad2019-02-18 11:50:22 +0100481 // Marks image in the primary slot as permanent,
482 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700483 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700484
David Brown84b49f72019-03-01 10:58:22 -0700485 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
486 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100487 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700488 fails += 1;
489 }
490
David Brown76101572019-02-28 11:29:03 -0700491 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700492 if result != 0 {
493 warn!("Failed second boot");
494 fails += 1;
495 }
496
David Brown84b49f72019-03-01 10:58:22 -0700497 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
498 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100499 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700500 fails += 1;
501 }
David Brown84b49f72019-03-01 10:58:22 -0700502 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700503 warn!("Failed image verification");
504 fails += 1;
505 }
506
507 if fails > 0 {
508 error!("Error running upgrade without revert");
509 }
510
511 fails > 0
512 }
513
David Vincze2d736ad2019-02-18 11:50:22 +0100514 // Tests a new image written to the primary slot that already has magic and
515 // image_ok set while there is no image on the secondary slot, so no revert
516 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700517 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700518 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700519 let mut fails = 0;
520
521 info!("Try non-revert on imgtool generated image");
522
David Brown84b49f72019-03-01 10:58:22 -0700523 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700524
David Vincze2d736ad2019-02-18 11:50:22 +0100525 // This simulates writing an image created by imgtool to
526 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700527 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
528 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100529 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700530 fails += 1;
531 }
532
533 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700534 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700535 if result != 0 {
536 warn!("Failed first boot");
537 fails += 1;
538 }
539
540 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700541 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700542 warn!("Failed image verification");
543 fails += 1;
544 }
David Brown84b49f72019-03-01 10:58:22 -0700545 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
546 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100547 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700548 fails += 1;
549 }
David Brown84b49f72019-03-01 10:58:22 -0700550 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
551 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100552 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700553 fails += 1;
554 }
555
556 if fails > 0 {
557 error!("Expected a non revert with new image");
558 }
559
560 fails > 0
561 }
562
David Vincze2d736ad2019-02-18 11:50:22 +0100563 // Tests a new image written to the primary slot that already has magic and
564 // image_ok set while there is no image on the secondary slot, so no revert
565 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700566 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700567 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700568 let mut fails = 0;
569
570 info!("Try upgrade image with bad signature");
571
David Brown84b49f72019-03-01 10:58:22 -0700572 self.mark_upgrades(&mut flash, 0);
573 self.mark_permanent_upgrades(&mut flash, 0);
574 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700575
David Brown84b49f72019-03-01 10:58:22 -0700576 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
577 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100578 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700579 fails += 1;
580 }
581
582 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700583 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700584 if result != 0 {
585 warn!("Failed first boot");
586 fails += 1;
587 }
588
589 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700590 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700591 warn!("Failed image verification");
592 fails += 1;
593 }
David Brown84b49f72019-03-01 10:58:22 -0700594 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
595 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100596 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700597 fails += 1;
598 }
599
600 if fails > 0 {
601 error!("Expected an upgrade failure when image has bad signature");
602 }
603
604 fails > 0
605 }
606
David Brown5c9e0f12019-01-09 16:34:33 -0700607 fn trailer_sz(&self, align: usize) -> usize {
608 c::boot_trailer_sz(align as u8) as usize
609 }
610
611 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700612 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700613 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
614 32
615 } else {
616 0
617 };
David Brown5c9e0f12019-01-09 16:34:33 -0700618
Christopher Collinsa1c12042019-05-23 14:00:28 -0700619 self.trailer_sz(align) - (16 + 32 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700620 }
621
622 /// This test runs a simple upgrade with no fails in the images, but
623 /// allowing for fails in the status area. This should run to the end
624 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700625 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100626 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700627 return false;
628 }
629
David Brown76101572019-02-28 11:29:03 -0700630 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700631 let mut fails = 0;
632
633 info!("Try swap with status fails");
634
David Brown84b49f72019-03-01 10:58:22 -0700635 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700636 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700637
David Brown76101572019-02-28 11:29:03 -0700638 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700639 if result != 0 {
640 warn!("Failed!");
641 fails += 1;
642 }
643
644 // Failed writes to the marked "bad" region don't assert anymore.
645 // Any detected assert() is happening in another part of the code.
646 if asserts != 0 {
647 warn!("At least one assert() was called");
648 fails += 1;
649 }
650
David Brown84b49f72019-03-01 10:58:22 -0700651 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
652 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100653 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700654 fails += 1;
655 }
656
David Brown84b49f72019-03-01 10:58:22 -0700657 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700658 warn!("Failed image verification");
659 fails += 1;
660 }
661
David Vincze2d736ad2019-02-18 11:50:22 +0100662 info!("validate primary slot enabled; \
663 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700664 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700665 if result != 0 {
666 warn!("Failed!");
667 fails += 1;
668 }
669
670 if fails > 0 {
671 error!("Error running upgrade with status write fails");
672 }
673
674 fails > 0
675 }
676
677 /// This test runs a simple upgrade with no fails in the images, but
678 /// allowing for fails in the status area. This should run to the end
679 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700680 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700681 if Caps::OverwriteUpgrade.present() {
682 false
David Vincze2d736ad2019-02-18 11:50:22 +0100683 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700684
David Brown76101572019-02-28 11:29:03 -0700685 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700686 let mut fails = 0;
687 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700688
David Brown85904a82019-01-11 13:45:12 -0700689 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700690
David Brown85904a82019-01-11 13:45:12 -0700691 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700692
David Brown84b49f72019-03-01 10:58:22 -0700693 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700694 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700695
696 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700697 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700698 if asserts != 0 {
699 warn!("At least one assert() was called");
700 fails += 1;
701 }
702
David Brown76101572019-02-28 11:29:03 -0700703 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700704
705 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700706 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700707
708 // This might throw no asserts, for large sector devices, where
709 // a single failure writing is indistinguishable from no failure,
710 // or throw a single assert for small sector devices that fail
711 // multiple times...
712 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100713 warn!("Expected single assert validating the primary slot, \
714 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700715 fails += 1;
716 }
717
718 if fails > 0 {
719 error!("Error running upgrade with status write fails");
720 }
721
722 fails > 0
723 } else {
David Brown76101572019-02-28 11:29:03 -0700724 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700725 let mut fails = 0;
726
727 info!("Try interrupted swap with status fails");
728
David Brown84b49f72019-03-01 10:58:22 -0700729 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700730 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700731
732 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700733 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700734 if asserts == 0 {
735 warn!("No assert() detected");
736 fails += 1;
737 }
738
739 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700740 }
David Brown5c9e0f12019-01-09 16:34:33 -0700741 }
742
743 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700744 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700745 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700746 if Caps::OverwriteUpgrade.present() {
747 return;
748 }
749
David Brown84b49f72019-03-01 10:58:22 -0700750 // Set this for each image.
751 for image in &self.images {
752 let dev_id = &image.slots[slot].dev_id;
753 let dev = flash.get_mut(&dev_id).unwrap();
754 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -0700755 let off = &image.slots[slot].base_off;
756 let len = &image.slots[slot].len;
David Brown84b49f72019-03-01 10:58:22 -0700757 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700758
David Brown84b49f72019-03-01 10:58:22 -0700759 // Mark the status area as a bad area
760 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
761 }
David Brown5c9e0f12019-01-09 16:34:33 -0700762 }
763
David Brown76101572019-02-28 11:29:03 -0700764 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100765 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700766 return;
767 }
768
David Brown84b49f72019-03-01 10:58:22 -0700769 for image in &self.images {
770 let dev_id = &image.slots[slot].dev_id;
771 let dev = flash.get_mut(&dev_id).unwrap();
772 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700773
David Brown84b49f72019-03-01 10:58:22 -0700774 // Disabling write verification the only assert triggered by
775 // boot_go should be checking for integrity of status bytes.
776 dev.set_verify_writes(false);
777 }
David Brown5c9e0f12019-01-09 16:34:33 -0700778 }
779
David Browndb505822019-03-01 10:04:20 -0700780 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
781 /// of the number of flash operations done total.
782 fn try_upgrade(&self, stop: Option<i32>) -> (SimMultiFlash, i32) {
783 // Clone the flash to have a new copy.
784 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700785
David Brown84b49f72019-03-01 10:58:22 -0700786 self.mark_permanent_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700787
David Browndb505822019-03-01 10:04:20 -0700788 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700789
David Browndb505822019-03-01 10:04:20 -0700790 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
791 (-0x13579, _) => (true, stop.unwrap()),
792 (0, _) => (false, -counter),
793 (x, _) => panic!("Unknown return: {}", x),
794 };
David Brown5c9e0f12019-01-09 16:34:33 -0700795
David Browndb505822019-03-01 10:04:20 -0700796 counter = 0;
797 if first_interrupted {
798 // fl.dump();
799 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
800 (-0x13579, _) => panic!("Shouldn't stop again"),
801 (0, _) => (),
802 (x, _) => panic!("Unknown return: {}", x),
803 }
804 }
David Brown5c9e0f12019-01-09 16:34:33 -0700805
David Browndb505822019-03-01 10:04:20 -0700806 (flash, count - counter)
807 }
808
809 fn try_revert(&self, count: usize) -> SimMultiFlash {
810 let mut flash = self.flash.clone();
811
812 // fl.write_file("image0.bin").unwrap();
813 for i in 0 .. count {
814 info!("Running boot pass {}", i + 1);
815 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
816 }
817 flash
818 }
819
820 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
821 let mut flash = self.flash.clone();
822 let mut fails = 0;
823
824 let mut counter = stop;
825 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
826 if x != -0x13579 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700827 warn!("Should have stopped test at interruption point");
David Browndb505822019-03-01 10:04:20 -0700828 fails += 1;
829 }
830
Fabio Utzig8af7f792019-07-30 12:40:01 -0300831 // In a multi-image setup, copy done might be set if any number of
832 // images was already successfully swapped.
833 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
834 warn!("copy_done should be unset");
835 fails += 1;
836 }
837
David Browndb505822019-03-01 10:04:20 -0700838 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
839 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700840 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -0700841 fails += 1;
842 }
843
David Brown84b49f72019-03-01 10:58:22 -0700844 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700845 warn!("Image in the primary slot before revert is invalid at stop={}",
846 stop);
847 fails += 1;
848 }
David Brown84b49f72019-03-01 10:58:22 -0700849 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700850 warn!("Image in the secondary slot before revert is invalid at stop={}",
851 stop);
852 fails += 1;
853 }
David Brown84b49f72019-03-01 10:58:22 -0700854 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
855 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700856 warn!("Mismatched trailer for the primary slot before revert");
857 fails += 1;
858 }
David Brown84b49f72019-03-01 10:58:22 -0700859 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
860 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700861 warn!("Mismatched trailer for the secondary slot before revert");
862 fails += 1;
863 }
864
865 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700866 let mut counter = stop;
867 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
868 if x != -0x13579 {
869 warn!("Should have stopped revert at interruption point");
870 fails += 1;
871 }
872
David Browndb505822019-03-01 10:04:20 -0700873 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
874 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700875 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -0700876 fails += 1;
877 }
878
David Brown84b49f72019-03-01 10:58:22 -0700879 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700880 warn!("Image in the primary slot after revert is invalid at stop={}",
881 stop);
882 fails += 1;
883 }
David Brown84b49f72019-03-01 10:58:22 -0700884 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700885 warn!("Image in the secondary slot after revert is invalid at stop={}",
886 stop);
887 fails += 1;
888 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700889
David Brown84b49f72019-03-01 10:58:22 -0700890 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
891 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700892 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -0700893 fails += 1;
894 }
David Brown84b49f72019-03-01 10:58:22 -0700895 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
896 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700897 warn!("Mismatched trailer for the secondary slot after revert");
898 fails += 1;
899 }
900
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700901 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
902 if x != 0 {
903 warn!("Should have finished 3rd boot");
904 fails += 1;
905 }
906
907 if !self.verify_images(&flash, 0, 0) {
908 warn!("Image in the primary slot is invalid on 1st boot after revert");
909 fails += 1;
910 }
911 if !self.verify_images(&flash, 1, 1) {
912 warn!("Image in the secondary slot is invalid on 1st boot after revert");
913 fails += 1;
914 }
915
David Browndb505822019-03-01 10:04:20 -0700916 fails > 0
917 }
918
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700919
David Browndb505822019-03-01 10:04:20 -0700920 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
921 let mut flash = self.flash.clone();
922
David Brown84b49f72019-03-01 10:58:22 -0700923 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700924
925 let mut rng = rand::thread_rng();
926 let mut resets = vec![0i32; count];
927 let mut remaining_ops = total_ops;
928 for i in 0 .. count {
929 let ops = Range::new(1, remaining_ops / 2);
930 let reset_counter = ops.ind_sample(&mut rng);
931 let mut counter = reset_counter;
932 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
933 (0, _) | (-0x13579, _) => (),
934 (x, _) => panic!("Unknown return: {}", x),
935 }
936 remaining_ops -= reset_counter;
937 resets[i] = reset_counter;
938 }
939
940 match c::boot_go(&mut flash, &self.areadesc, None, false) {
941 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700942 (0, _) => (),
943 (x, _) => panic!("Unknown return: {}", x),
944 }
David Brown5c9e0f12019-01-09 16:34:33 -0700945
David Browndb505822019-03-01 10:04:20 -0700946 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700947 }
David Brown84b49f72019-03-01 10:58:22 -0700948
949 /// Verify the image in the given flash device, the specified slot
950 /// against the expected image.
951 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
952 for image in &self.images {
953 if !verify_image(flash, &image.slots, slot,
954 match against {
955 0 => &image.primaries,
956 1 => &image.upgrades,
957 _ => panic!("Invalid 'against'"),
958 }) {
959 return false;
960 }
961 }
962 true
963 }
964
Fabio Utzig8af7f792019-07-30 12:40:01 -0300965 /// Verify that at least one of the trailers of the images have the
966 /// specified values.
967 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
968 magic: Option<u8>, image_ok: Option<u8>,
969 copy_done: Option<u8>) -> bool {
970 for image in &self.images {
971 if verify_trailer(flash, &image.slots, slot,
972 magic, image_ok, copy_done) {
973 return true;
974 }
975 }
976 false
977 }
978
David Brown84b49f72019-03-01 10:58:22 -0700979 /// Verify that the trailers of the images have the specified
980 /// values.
981 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
982 magic: Option<u8>, image_ok: Option<u8>,
983 copy_done: Option<u8>) -> bool {
984 for image in &self.images {
985 if !verify_trailer(flash, &image.slots, slot,
986 magic, image_ok, copy_done) {
987 return false;
988 }
989 }
990 true
991 }
992
993 /// Mark each of the images for permanent upgrade.
994 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
995 for image in &self.images {
996 mark_permanent_upgrade(flash, &image.slots[slot]);
997 }
998 }
999
1000 /// Mark each of the images for permanent upgrade.
1001 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1002 for image in &self.images {
1003 mark_upgrade(flash, &image.slots[slot]);
1004 }
1005 }
David Brown5c9e0f12019-01-09 16:34:33 -07001006}
1007
1008/// Show the flash layout.
1009#[allow(dead_code)]
1010fn show_flash(flash: &dyn Flash) {
1011 println!("---- Flash configuration ----");
1012 for sector in flash.sector_iter() {
1013 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1014 sector.num, sector.base, sector.size);
1015 }
1016 println!("");
1017}
1018
1019/// Install a "program" into the given image. This fakes the image header, or at least all of the
1020/// fields used by the given code. Returns a copy of the image that was written.
David Brown76101572019-02-28 11:29:03 -07001021fn install_image(flash: &mut SimMultiFlash, slots: &[SlotInfo], slot: usize, len: usize,
David Brownca234692019-02-28 11:22:19 -07001022 bad_sig: bool) -> ImageData {
David Brown5c9e0f12019-01-09 16:34:33 -07001023 let offset = slots[slot].base_off;
1024 let slot_len = slots[slot].len;
1025 let dev_id = slots[slot].dev_id;
1026
David Brown43643dd2019-01-11 15:43:28 -07001027 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001028
1029 const HDR_SIZE: usize = 32;
1030
1031 // Generate a boot header. Note that the size doesn't include the header.
1032 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001033 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001034 load_addr: 0,
1035 hdr_size: HDR_SIZE as u16,
1036 _pad1: 0,
1037 img_size: len as u32,
1038 flags: tlv.get_flags(),
1039 ver: ImageVersion {
1040 major: (offset / (128 * 1024)) as u8,
1041 minor: 0,
1042 revision: 1,
1043 build_num: offset as u32,
1044 },
1045 _pad2: 0,
1046 };
1047
1048 let mut b_header = [0; HDR_SIZE];
1049 b_header[..32].clone_from_slice(header.as_raw());
1050 assert_eq!(b_header.len(), HDR_SIZE);
1051
1052 tlv.add_bytes(&b_header);
1053
1054 // The core of the image itself is just pseudorandom data.
1055 let mut b_img = vec![0; len];
1056 splat(&mut b_img, offset);
1057
1058 // TLV signatures work over plain image
1059 tlv.add_bytes(&b_img);
1060
1061 // Generate encrypted images
1062 let flag = TlvFlags::ENCRYPTED as u32;
1063 let is_encrypted = (tlv.get_flags() & flag) == flag;
1064 let mut b_encimg = vec![];
1065 if is_encrypted {
1066 let key = GenericArray::from_slice(AES_SEC_KEY);
1067 let nonce = GenericArray::from_slice(&[0; 16]);
1068 let mut cipher = Aes128Ctr::new(&key, &nonce);
1069 b_encimg = b_img.clone();
1070 cipher.apply_keystream(&mut b_encimg);
1071 }
1072
1073 // Build the TLV itself.
1074 let mut b_tlv = if bad_sig {
1075 let good_sig = &mut tlv.make_tlv();
1076 vec![0; good_sig.len()]
1077 } else {
1078 tlv.make_tlv()
1079 };
1080
1081 // Pad the block to a flash alignment (8 bytes).
1082 while b_tlv.len() % 8 != 0 {
1083 //FIXME: should be erase_val?
1084 b_tlv.push(0xFF);
1085 }
1086
1087 let mut buf = vec![];
1088 buf.append(&mut b_header.to_vec());
1089 buf.append(&mut b_img);
1090 buf.append(&mut b_tlv.clone());
1091
1092 let mut encbuf = vec![];
1093 if is_encrypted {
1094 encbuf.append(&mut b_header.to_vec());
1095 encbuf.append(&mut b_encimg);
1096 encbuf.append(&mut b_tlv);
1097 }
1098
David Vincze2d736ad2019-02-18 11:50:22 +01001099 // Since images are always non-encrypted in the primary slot, we first write
1100 // an encrypted image, re-read to use for verification, erase + flash
1101 // un-encrypted. In the secondary slot the image is written un-encrypted,
1102 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001103
David Brown76101572019-02-28 11:29:03 -07001104 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001105
1106 if slot == 0 {
1107 let enc_copy: Option<Vec<u8>>;
1108
1109 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001110 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001111
1112 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001113 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001114
1115 enc_copy = Some(enc);
1116
David Brown76101572019-02-28 11:29:03 -07001117 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001118 } else {
1119 enc_copy = None;
1120 }
1121
David Brown76101572019-02-28 11:29:03 -07001122 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001123
1124 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001125 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001126
David Brownca234692019-02-28 11:22:19 -07001127 ImageData {
1128 plain: copy,
1129 cipher: enc_copy,
1130 }
David Brown5c9e0f12019-01-09 16:34:33 -07001131 } else {
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
1138 let enc_copy: Option<Vec<u8>>;
1139
1140 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001141 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001142
David Brown76101572019-02-28 11:29:03 -07001143 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001144
1145 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001146 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001147
1148 enc_copy = Some(enc);
1149 } else {
1150 enc_copy = None;
1151 }
1152
David Brownca234692019-02-28 11:22:19 -07001153 ImageData {
1154 plain: copy,
1155 cipher: enc_copy,
1156 }
David Brown5c9e0f12019-01-09 16:34:33 -07001157 }
David Brown5c9e0f12019-01-09 16:34:33 -07001158}
1159
David Brown5c9e0f12019-01-09 16:34:33 -07001160fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001161 if Caps::EcdsaP224.present() {
1162 panic!("Ecdsa P224 not supported in Simulator");
1163 }
David Brown5c9e0f12019-01-09 16:34:33 -07001164
David Brownb8882112019-01-11 14:04:11 -07001165 if Caps::EncKw.present() {
1166 if Caps::RSA2048.present() {
1167 TlvGen::new_rsa_kw()
1168 } else if Caps::EcdsaP256.present() {
1169 TlvGen::new_ecdsa_kw()
1170 } else {
1171 TlvGen::new_enc_kw()
1172 }
1173 } else if Caps::EncRsa.present() {
1174 if Caps::RSA2048.present() {
1175 TlvGen::new_sig_enc_rsa()
1176 } else {
1177 TlvGen::new_enc_rsa()
1178 }
1179 } else {
1180 // The non-encrypted configuration.
1181 if Caps::RSA2048.present() {
1182 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001183 } else if Caps::RSA3072.present() {
1184 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001185 } else if Caps::EcdsaP256.present() {
1186 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001187 } else if Caps::Ed25519.present() {
1188 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001189 } else {
1190 TlvGen::new_hash_only()
1191 }
1192 }
David Brown5c9e0f12019-01-09 16:34:33 -07001193}
1194
David Brownca234692019-02-28 11:22:19 -07001195impl ImageData {
1196 /// Find the image contents for the given slot. This assumes that slot 0
1197 /// is unencrypted, and slot 1 is encrypted.
1198 fn find(&self, slot: usize) -> &Vec<u8> {
1199 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1200 match (encrypted, slot) {
1201 (false, _) => &self.plain,
1202 (true, 0) => &self.plain,
1203 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1204 _ => panic!("Invalid slot requested"),
1205 }
David Brown5c9e0f12019-01-09 16:34:33 -07001206 }
1207}
1208
David Brown5c9e0f12019-01-09 16:34:33 -07001209/// Verify that given image is present in the flash at the given offset.
David Brown76101572019-02-28 11:29:03 -07001210fn verify_image(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brownca234692019-02-28 11:22:19 -07001211 images: &ImageData) -> bool {
1212 let image = images.find(slot);
David Brown5c9e0f12019-01-09 16:34:33 -07001213 let buf = image.as_slice();
1214 let dev_id = slots[slot].dev_id;
1215
1216 let mut copy = vec![0u8; buf.len()];
1217 let offset = slots[slot].base_off;
David Brown76101572019-02-28 11:29:03 -07001218 let dev = flash.get(&dev_id).unwrap();
1219 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001220
1221 if buf != &copy[..] {
1222 for i in 0 .. buf.len() {
1223 if buf[i] != copy[i] {
1224 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1225 slot, offset + i, buf[i], copy[i]);
1226 break;
1227 }
1228 }
1229 false
1230 } else {
1231 true
1232 }
1233}
1234
David Brown76101572019-02-28 11:29:03 -07001235fn verify_trailer(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001236 magic: Option<u8>, image_ok: Option<u8>,
1237 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001238 if Caps::OverwriteUpgrade.present() {
1239 return true;
1240 }
David Brown5c9e0f12019-01-09 16:34:33 -07001241
Christopher Collinsa1c12042019-05-23 14:00:28 -07001242 let offset = slots[slot].trailer_off + c::boot_max_align();
David Brown5c9e0f12019-01-09 16:34:33 -07001243 let dev_id = slots[slot].dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001244 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001245 let mut failed = false;
1246
David Brown76101572019-02-28 11:29:03 -07001247 let dev = flash.get(&dev_id).unwrap();
1248 let erased_val = dev.erased_val();
1249 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001250
1251 failed |= match magic {
1252 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001253 if v == 1 && &copy[24..] != MAGIC.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -07001254 warn!("\"magic\" mismatch at {:#x}", offset);
1255 true
1256 } else if v == 3 {
1257 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001258 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001259 warn!("\"magic\" mismatch at {:#x}", offset);
1260 true
1261 } else {
1262 false
1263 }
1264 } else {
1265 false
1266 }
1267 },
1268 None => false,
1269 };
1270
1271 failed |= match image_ok {
1272 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001273 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001274 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1275 true
1276 } else {
1277 false
1278 }
1279 },
1280 None => false,
1281 };
1282
1283 failed |= match copy_done {
1284 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001285 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001286 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1287 true
1288 } else {
1289 false
1290 }
1291 },
1292 None => false,
1293 };
1294
1295 !failed
1296}
1297
1298/// The image header
1299#[repr(C)]
1300pub struct ImageHeader {
1301 magic: u32,
1302 load_addr: u32,
1303 hdr_size: u16,
1304 _pad1: u16,
1305 img_size: u32,
1306 flags: u32,
1307 ver: ImageVersion,
1308 _pad2: u32,
1309}
1310
1311impl AsRaw for ImageHeader {}
1312
1313#[repr(C)]
1314pub struct ImageVersion {
1315 major: u8,
1316 minor: u8,
1317 revision: u16,
1318 build_num: u32,
1319}
1320
1321#[derive(Clone)]
1322pub struct SlotInfo {
1323 pub base_off: usize,
1324 pub trailer_off: usize,
1325 pub len: usize,
1326 pub dev_id: u8,
1327}
1328
David Brown5c9e0f12019-01-09 16:34:33 -07001329const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1330 0x60, 0xd2, 0xef, 0x7f,
1331 0x35, 0x52, 0x50, 0x0f,
1332 0x2c, 0xb6, 0x79, 0x80]);
1333
1334// Replicates defines found in bootutil.h
1335const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1336const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1337
1338const BOOT_FLAG_SET: Option<u8> = Some(1);
1339const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1340
1341/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001342pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1343 let dev = flash.get_mut(&slot.dev_id).unwrap();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001344 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown76101572019-02-28 11:29:03 -07001345 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001346}
1347
1348/// Writes the image_ok flag which, guess what, tells the bootloader
1349/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001350fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1351 let dev = flash.get_mut(&slot.dev_id).unwrap();
1352 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001353 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001354 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001355 let align = dev.align();
1356 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001357}
1358
1359// Drop some pseudo-random gibberish onto the data.
1360fn splat(data: &mut [u8], seed: usize) {
1361 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1362 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1363 rng.fill_bytes(data);
1364}
1365
1366/// Return a read-only view into the raw bytes of this object
1367trait AsRaw : Sized {
1368 fn as_raw<'a>(&'a self) -> &'a [u8] {
1369 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1370 mem::size_of::<Self>()) }
1371 }
1372}
1373
1374pub fn show_sizes() {
1375 // This isn't panic safe.
1376 for min in &[1, 2, 4, 8] {
1377 let msize = c::boot_trailer_sz(*min);
1378 println!("{:2}: {} (0x{:x})", min, msize, msize);
1379 }
1380}