blob: 564e3312cb9069bd37ac6b152a267a9ed6cb074b [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
David Browndb505822019-03-01 10:04:20 -0700831 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
832 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700833 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -0700834 fails += 1;
835 }
836
David Brown84b49f72019-03-01 10:58:22 -0700837 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700838 warn!("Image in the primary slot before revert is invalid at stop={}",
839 stop);
840 fails += 1;
841 }
David Brown84b49f72019-03-01 10:58:22 -0700842 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700843 warn!("Image in the secondary slot before revert is invalid at stop={}",
844 stop);
845 fails += 1;
846 }
David Brown84b49f72019-03-01 10:58:22 -0700847 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
848 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700849 warn!("Mismatched trailer for the primary slot before revert");
850 fails += 1;
851 }
David Brown84b49f72019-03-01 10:58:22 -0700852 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
853 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700854 warn!("Mismatched trailer for the secondary slot before revert");
855 fails += 1;
856 }
857
858 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700859 let mut counter = stop;
860 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
861 if x != -0x13579 {
862 warn!("Should have stopped revert at interruption point");
863 fails += 1;
864 }
865
David Browndb505822019-03-01 10:04:20 -0700866 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
867 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700868 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -0700869 fails += 1;
870 }
871
David Brown84b49f72019-03-01 10:58:22 -0700872 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700873 warn!("Image in the primary slot after revert is invalid at stop={}",
874 stop);
875 fails += 1;
876 }
David Brown84b49f72019-03-01 10:58:22 -0700877 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700878 warn!("Image in the secondary slot after revert is invalid at stop={}",
879 stop);
880 fails += 1;
881 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700882
David Brown84b49f72019-03-01 10:58:22 -0700883 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
884 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700885 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -0700886 fails += 1;
887 }
David Brown84b49f72019-03-01 10:58:22 -0700888 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
889 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700890 warn!("Mismatched trailer for the secondary slot after revert");
891 fails += 1;
892 }
893
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700894 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
895 if x != 0 {
896 warn!("Should have finished 3rd boot");
897 fails += 1;
898 }
899
900 if !self.verify_images(&flash, 0, 0) {
901 warn!("Image in the primary slot is invalid on 1st boot after revert");
902 fails += 1;
903 }
904 if !self.verify_images(&flash, 1, 1) {
905 warn!("Image in the secondary slot is invalid on 1st boot after revert");
906 fails += 1;
907 }
908
David Browndb505822019-03-01 10:04:20 -0700909 fails > 0
910 }
911
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700912
David Browndb505822019-03-01 10:04:20 -0700913 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
914 let mut flash = self.flash.clone();
915
David Brown84b49f72019-03-01 10:58:22 -0700916 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700917
918 let mut rng = rand::thread_rng();
919 let mut resets = vec![0i32; count];
920 let mut remaining_ops = total_ops;
921 for i in 0 .. count {
922 let ops = Range::new(1, remaining_ops / 2);
923 let reset_counter = ops.ind_sample(&mut rng);
924 let mut counter = reset_counter;
925 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
926 (0, _) | (-0x13579, _) => (),
927 (x, _) => panic!("Unknown return: {}", x),
928 }
929 remaining_ops -= reset_counter;
930 resets[i] = reset_counter;
931 }
932
933 match c::boot_go(&mut flash, &self.areadesc, None, false) {
934 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700935 (0, _) => (),
936 (x, _) => panic!("Unknown return: {}", x),
937 }
David Brown5c9e0f12019-01-09 16:34:33 -0700938
David Browndb505822019-03-01 10:04:20 -0700939 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700940 }
David Brown84b49f72019-03-01 10:58:22 -0700941
942 /// Verify the image in the given flash device, the specified slot
943 /// against the expected image.
944 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
945 for image in &self.images {
946 if !verify_image(flash, &image.slots, slot,
947 match against {
948 0 => &image.primaries,
949 1 => &image.upgrades,
950 _ => panic!("Invalid 'against'"),
951 }) {
952 return false;
953 }
954 }
955 true
956 }
957
958 /// Verify that the trailers of the images have the specified
959 /// values.
960 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
961 magic: Option<u8>, image_ok: Option<u8>,
962 copy_done: Option<u8>) -> bool {
963 for image in &self.images {
964 if !verify_trailer(flash, &image.slots, slot,
965 magic, image_ok, copy_done) {
966 return false;
967 }
968 }
969 true
970 }
971
972 /// Mark each of the images for permanent upgrade.
973 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
974 for image in &self.images {
975 mark_permanent_upgrade(flash, &image.slots[slot]);
976 }
977 }
978
979 /// Mark each of the images for permanent upgrade.
980 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
981 for image in &self.images {
982 mark_upgrade(flash, &image.slots[slot]);
983 }
984 }
David Brown5c9e0f12019-01-09 16:34:33 -0700985}
986
987/// Show the flash layout.
988#[allow(dead_code)]
989fn show_flash(flash: &dyn Flash) {
990 println!("---- Flash configuration ----");
991 for sector in flash.sector_iter() {
992 println!(" {:3}: 0x{:08x}, 0x{:08x}",
993 sector.num, sector.base, sector.size);
994 }
995 println!("");
996}
997
998/// Install a "program" into the given image. This fakes the image header, or at least all of the
999/// fields used by the given code. Returns a copy of the image that was written.
David Brown76101572019-02-28 11:29:03 -07001000fn install_image(flash: &mut SimMultiFlash, slots: &[SlotInfo], slot: usize, len: usize,
David Brownca234692019-02-28 11:22:19 -07001001 bad_sig: bool) -> ImageData {
David Brown5c9e0f12019-01-09 16:34:33 -07001002 let offset = slots[slot].base_off;
1003 let slot_len = slots[slot].len;
1004 let dev_id = slots[slot].dev_id;
1005
David Brown43643dd2019-01-11 15:43:28 -07001006 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001007
1008 const HDR_SIZE: usize = 32;
1009
1010 // Generate a boot header. Note that the size doesn't include the header.
1011 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001012 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001013 load_addr: 0,
1014 hdr_size: HDR_SIZE as u16,
1015 _pad1: 0,
1016 img_size: len as u32,
1017 flags: tlv.get_flags(),
1018 ver: ImageVersion {
1019 major: (offset / (128 * 1024)) as u8,
1020 minor: 0,
1021 revision: 1,
1022 build_num: offset as u32,
1023 },
1024 _pad2: 0,
1025 };
1026
1027 let mut b_header = [0; HDR_SIZE];
1028 b_header[..32].clone_from_slice(header.as_raw());
1029 assert_eq!(b_header.len(), HDR_SIZE);
1030
1031 tlv.add_bytes(&b_header);
1032
1033 // The core of the image itself is just pseudorandom data.
1034 let mut b_img = vec![0; len];
1035 splat(&mut b_img, offset);
1036
1037 // TLV signatures work over plain image
1038 tlv.add_bytes(&b_img);
1039
1040 // Generate encrypted images
1041 let flag = TlvFlags::ENCRYPTED as u32;
1042 let is_encrypted = (tlv.get_flags() & flag) == flag;
1043 let mut b_encimg = vec![];
1044 if is_encrypted {
1045 let key = GenericArray::from_slice(AES_SEC_KEY);
1046 let nonce = GenericArray::from_slice(&[0; 16]);
1047 let mut cipher = Aes128Ctr::new(&key, &nonce);
1048 b_encimg = b_img.clone();
1049 cipher.apply_keystream(&mut b_encimg);
1050 }
1051
1052 // Build the TLV itself.
1053 let mut b_tlv = if bad_sig {
1054 let good_sig = &mut tlv.make_tlv();
1055 vec![0; good_sig.len()]
1056 } else {
1057 tlv.make_tlv()
1058 };
1059
1060 // Pad the block to a flash alignment (8 bytes).
1061 while b_tlv.len() % 8 != 0 {
1062 //FIXME: should be erase_val?
1063 b_tlv.push(0xFF);
1064 }
1065
1066 let mut buf = vec![];
1067 buf.append(&mut b_header.to_vec());
1068 buf.append(&mut b_img);
1069 buf.append(&mut b_tlv.clone());
1070
1071 let mut encbuf = vec![];
1072 if is_encrypted {
1073 encbuf.append(&mut b_header.to_vec());
1074 encbuf.append(&mut b_encimg);
1075 encbuf.append(&mut b_tlv);
1076 }
1077
David Vincze2d736ad2019-02-18 11:50:22 +01001078 // Since images are always non-encrypted in the primary slot, we first write
1079 // an encrypted image, re-read to use for verification, erase + flash
1080 // un-encrypted. In the secondary slot the image is written un-encrypted,
1081 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001082
David Brown76101572019-02-28 11:29:03 -07001083 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001084
1085 if slot == 0 {
1086 let enc_copy: Option<Vec<u8>>;
1087
1088 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001089 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001090
1091 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001092 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001093
1094 enc_copy = Some(enc);
1095
David Brown76101572019-02-28 11:29:03 -07001096 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001097 } else {
1098 enc_copy = None;
1099 }
1100
David Brown76101572019-02-28 11:29:03 -07001101 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001102
1103 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001104 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001105
David Brownca234692019-02-28 11:22:19 -07001106 ImageData {
1107 plain: copy,
1108 cipher: enc_copy,
1109 }
David Brown5c9e0f12019-01-09 16:34:33 -07001110 } else {
1111
David Brown76101572019-02-28 11:29:03 -07001112 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001113
1114 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001115 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001116
1117 let enc_copy: Option<Vec<u8>>;
1118
1119 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001120 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001121
David Brown76101572019-02-28 11:29:03 -07001122 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001123
1124 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001125 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001126
1127 enc_copy = Some(enc);
1128 } else {
1129 enc_copy = None;
1130 }
1131
David Brownca234692019-02-28 11:22:19 -07001132 ImageData {
1133 plain: copy,
1134 cipher: enc_copy,
1135 }
David Brown5c9e0f12019-01-09 16:34:33 -07001136 }
David Brown5c9e0f12019-01-09 16:34:33 -07001137}
1138
David Brown5c9e0f12019-01-09 16:34:33 -07001139fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001140 if Caps::EcdsaP224.present() {
1141 panic!("Ecdsa P224 not supported in Simulator");
1142 }
David Brown5c9e0f12019-01-09 16:34:33 -07001143
David Brownb8882112019-01-11 14:04:11 -07001144 if Caps::EncKw.present() {
1145 if Caps::RSA2048.present() {
1146 TlvGen::new_rsa_kw()
1147 } else if Caps::EcdsaP256.present() {
1148 TlvGen::new_ecdsa_kw()
1149 } else {
1150 TlvGen::new_enc_kw()
1151 }
1152 } else if Caps::EncRsa.present() {
1153 if Caps::RSA2048.present() {
1154 TlvGen::new_sig_enc_rsa()
1155 } else {
1156 TlvGen::new_enc_rsa()
1157 }
1158 } else {
1159 // The non-encrypted configuration.
1160 if Caps::RSA2048.present() {
1161 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001162 } else if Caps::RSA3072.present() {
1163 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001164 } else if Caps::EcdsaP256.present() {
1165 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001166 } else if Caps::Ed25519.present() {
1167 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001168 } else {
1169 TlvGen::new_hash_only()
1170 }
1171 }
David Brown5c9e0f12019-01-09 16:34:33 -07001172}
1173
David Brownca234692019-02-28 11:22:19 -07001174impl ImageData {
1175 /// Find the image contents for the given slot. This assumes that slot 0
1176 /// is unencrypted, and slot 1 is encrypted.
1177 fn find(&self, slot: usize) -> &Vec<u8> {
1178 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1179 match (encrypted, slot) {
1180 (false, _) => &self.plain,
1181 (true, 0) => &self.plain,
1182 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1183 _ => panic!("Invalid slot requested"),
1184 }
David Brown5c9e0f12019-01-09 16:34:33 -07001185 }
1186}
1187
David Brown5c9e0f12019-01-09 16:34:33 -07001188/// Verify that given image is present in the flash at the given offset.
David Brown76101572019-02-28 11:29:03 -07001189fn verify_image(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brownca234692019-02-28 11:22:19 -07001190 images: &ImageData) -> bool {
1191 let image = images.find(slot);
David Brown5c9e0f12019-01-09 16:34:33 -07001192 let buf = image.as_slice();
1193 let dev_id = slots[slot].dev_id;
1194
1195 let mut copy = vec![0u8; buf.len()];
1196 let offset = slots[slot].base_off;
David Brown76101572019-02-28 11:29:03 -07001197 let dev = flash.get(&dev_id).unwrap();
1198 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001199
1200 if buf != &copy[..] {
1201 for i in 0 .. buf.len() {
1202 if buf[i] != copy[i] {
1203 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1204 slot, offset + i, buf[i], copy[i]);
1205 break;
1206 }
1207 }
1208 false
1209 } else {
1210 true
1211 }
1212}
1213
David Brown76101572019-02-28 11:29:03 -07001214fn verify_trailer(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001215 magic: Option<u8>, image_ok: Option<u8>,
1216 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001217 if Caps::OverwriteUpgrade.present() {
1218 return true;
1219 }
David Brown5c9e0f12019-01-09 16:34:33 -07001220
Christopher Collinsa1c12042019-05-23 14:00:28 -07001221 let offset = slots[slot].trailer_off + c::boot_max_align();
David Brown5c9e0f12019-01-09 16:34:33 -07001222 let dev_id = slots[slot].dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001223 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001224 let mut failed = false;
1225
David Brown76101572019-02-28 11:29:03 -07001226 let dev = flash.get(&dev_id).unwrap();
1227 let erased_val = dev.erased_val();
1228 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001229
1230 failed |= match magic {
1231 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001232 if v == 1 && &copy[24..] != MAGIC.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -07001233 warn!("\"magic\" mismatch at {:#x}", offset);
1234 true
1235 } else if v == 3 {
1236 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001237 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001238 warn!("\"magic\" mismatch at {:#x}", offset);
1239 true
1240 } else {
1241 false
1242 }
1243 } else {
1244 false
1245 }
1246 },
1247 None => false,
1248 };
1249
1250 failed |= match image_ok {
1251 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001252 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001253 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1254 true
1255 } else {
1256 false
1257 }
1258 },
1259 None => false,
1260 };
1261
1262 failed |= match copy_done {
1263 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001264 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001265 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1266 true
1267 } else {
1268 false
1269 }
1270 },
1271 None => false,
1272 };
1273
1274 !failed
1275}
1276
1277/// The image header
1278#[repr(C)]
1279pub struct ImageHeader {
1280 magic: u32,
1281 load_addr: u32,
1282 hdr_size: u16,
1283 _pad1: u16,
1284 img_size: u32,
1285 flags: u32,
1286 ver: ImageVersion,
1287 _pad2: u32,
1288}
1289
1290impl AsRaw for ImageHeader {}
1291
1292#[repr(C)]
1293pub struct ImageVersion {
1294 major: u8,
1295 minor: u8,
1296 revision: u16,
1297 build_num: u32,
1298}
1299
1300#[derive(Clone)]
1301pub struct SlotInfo {
1302 pub base_off: usize,
1303 pub trailer_off: usize,
1304 pub len: usize,
1305 pub dev_id: u8,
1306}
1307
David Brown5c9e0f12019-01-09 16:34:33 -07001308const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1309 0x60, 0xd2, 0xef, 0x7f,
1310 0x35, 0x52, 0x50, 0x0f,
1311 0x2c, 0xb6, 0x79, 0x80]);
1312
1313// Replicates defines found in bootutil.h
1314const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1315const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1316
1317const BOOT_FLAG_SET: Option<u8> = Some(1);
1318const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1319
1320/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001321pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1322 let dev = flash.get_mut(&slot.dev_id).unwrap();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001323 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown76101572019-02-28 11:29:03 -07001324 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001325}
1326
1327/// Writes the image_ok flag which, guess what, tells the bootloader
1328/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001329fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1330 let dev = flash.get_mut(&slot.dev_id).unwrap();
1331 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001332 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001333 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001334 let align = dev.align();
1335 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001336}
1337
1338// Drop some pseudo-random gibberish onto the data.
1339fn splat(data: &mut [u8], seed: usize) {
1340 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1341 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1342 rng.fill_bytes(data);
1343}
1344
1345/// Return a read-only view into the raw bytes of this object
1346trait AsRaw : Sized {
1347 fn as_raw<'a>(&'a self) -> &'a [u8] {
1348 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1349 mem::size_of::<Self>()) }
1350 }
1351}
1352
1353pub fn show_sizes() {
1354 // This isn't panic safe.
1355 for min in &[1, 2, 4, 8] {
1356 let msize = c::boot_trailer_sz(*min);
1357 println!("{:2}: {} (0x{:x})", min, msize, msize);
1358 }
1359}