blob: becd2c4f29269c58e2a2387bfdbd7c7a8da3e196 [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
David Browneebf5022019-07-30 15:01:07 -0600158 pub fn make_image(self, permanent: bool) -> Images {
David Browne5133242019-02-28 11:05:19 -0700159 let mut images = self.make_no_upgrade_image();
David Brown84b49f72019-03-01 10:58:22 -0700160 for image in &images.images {
161 mark_upgrade(&mut images.flash, &image.slots[1]);
162 }
David Browne5133242019-02-28 11:05:19 -0700163
164 // upgrades without fails, counts number of flash operations
Fabio Utziged4a5362019-07-30 12:43:23 -0300165 let total_count = match images.run_basic_upgrade(permanent) {
David Browne5133242019-02-28 11:05:19 -0700166 Ok(v) => v,
167 Err(_) => {
168 panic!("Unable to perform basic upgrade");
169 },
170 };
171
172 images.total_count = Some(total_count);
173 images
174 }
175
176 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700177 let mut bad_flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700178 let images = self.slots.into_iter().map(|slots| {
179 let primaries = install_image(&mut bad_flash, &slots, 0, 32784, false);
180 let upgrades = install_image(&mut bad_flash, &slots, 1, 41928, true);
181 OneImage {
182 slots: slots,
183 primaries: primaries,
184 upgrades: upgrades,
185 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700186 Images {
David Brown76101572019-02-28 11:29:03 -0700187 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700188 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700189 images: images,
David Browne5133242019-02-28 11:05:19 -0700190 total_count: None,
191 }
192 }
193
194 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700195 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700196 match device {
197 DeviceName::Stm32f4 => {
198 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700199 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
200 64 * 1024,
201 128 * 1024, 128 * 1024, 128 * 1024],
202 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700203 let dev_id = 0;
204 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700205 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700206 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
207 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
208 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
209
David Brown76101572019-02-28 11:29:03 -0700210 let mut flash = SimMultiFlash::new();
211 flash.insert(dev_id, dev);
212 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700213 }
214 DeviceName::K64f => {
215 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700216 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700217
218 let dev_id = 0;
219 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700220 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700221 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
222 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
223 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
224
David Brown76101572019-02-28 11:29:03 -0700225 let mut flash = SimMultiFlash::new();
226 flash.insert(dev_id, dev);
227 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700228 }
229 DeviceName::K64fBig => {
230 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
231 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700232 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700233
234 let dev_id = 0;
235 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700236 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700237 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
238 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
239 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
240
David Brown76101572019-02-28 11:29:03 -0700241 let mut flash = SimMultiFlash::new();
242 flash.insert(dev_id, dev);
243 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700244 }
245 DeviceName::Nrf52840 => {
246 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
247 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700248 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700249
250 let dev_id = 0;
251 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700252 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700253 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
254 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
255 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
256
David Brown76101572019-02-28 11:29:03 -0700257 let mut flash = SimMultiFlash::new();
258 flash.insert(dev_id, dev);
259 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700260 }
261 DeviceName::Nrf52840SpiFlash => {
262 // Simulate nrf52840 with external SPI flash. The external SPI flash
263 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700264 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
265 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700266
267 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700268 areadesc.add_flash_sectors(0, &dev0);
269 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700270
271 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
272 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
273 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
274
David Brown76101572019-02-28 11:29:03 -0700275 let mut flash = SimMultiFlash::new();
276 flash.insert(0, dev0);
277 flash.insert(1, dev1);
278 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700279 }
David Brown2bff6472019-03-05 13:58:35 -0700280 DeviceName::K64fMulti => {
281 // NXP style flash, but larger, to support multiple images.
282 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
283
284 let dev_id = 0;
285 let mut areadesc = AreaDesc::new();
286 areadesc.add_flash_sectors(dev_id, &dev);
287 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
288 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
289 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
290 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
291 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
292
293 let mut flash = SimMultiFlash::new();
294 flash.insert(dev_id, dev);
295 (flash, areadesc)
296 }
David Browne5133242019-02-28 11:05:19 -0700297 }
298 }
299}
300
David Brown5c9e0f12019-01-09 16:34:33 -0700301impl Images {
302 /// A simple upgrade without forced failures.
303 ///
304 /// Returns the number of flash operations which can later be used to
305 /// inject failures at chosen steps.
Fabio Utziged4a5362019-07-30 12:43:23 -0300306 pub fn run_basic_upgrade(&self, permanent: bool) -> Result<i32, ()> {
307 let (flash, total_count) = self.try_upgrade(None, permanent);
David Brown5c9e0f12019-01-09 16:34:33 -0700308 info!("Total flash operation count={}", total_count);
309
David Brown84b49f72019-03-01 10:58:22 -0700310 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700311 warn!("Image mismatch after first boot");
312 Err(())
313 } else {
314 Ok(total_count)
315 }
316 }
317
David Brown5c9e0f12019-01-09 16:34:33 -0700318 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700319 if Caps::OverwriteUpgrade.present() {
320 return false;
321 }
David Brown5c9e0f12019-01-09 16:34:33 -0700322
David Brown5c9e0f12019-01-09 16:34:33 -0700323 let mut fails = 0;
324
325 // FIXME: this test would also pass if no swap is ever performed???
326 if Caps::SwapUpgrade.present() {
327 for count in 2 .. 5 {
328 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700329 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700330 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700331 error!("Revert failure on count {}", count);
332 fails += 1;
333 }
334 }
335 }
336
337 fails > 0
338 }
339
340 pub fn run_perm_with_fails(&self) -> bool {
341 let mut fails = 0;
342 let total_flash_ops = self.total_count.unwrap();
343
344 // Let's try an image halfway through.
345 for i in 1 .. total_flash_ops {
346 info!("Try interruption at {}", i);
Fabio Utziged4a5362019-07-30 12:43:23 -0300347 let (flash, count) = self.try_upgrade(Some(i), true);
David Brown5c9e0f12019-01-09 16:34:33 -0700348 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700349 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700350 warn!("FAIL at step {} of {}", i, total_flash_ops);
351 fails += 1;
352 }
353
David Brown84b49f72019-03-01 10:58:22 -0700354 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
355 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100356 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700357 fails += 1;
358 }
359
David Brown84b49f72019-03-01 10:58:22 -0700360 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
361 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100362 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700363 fails += 1;
364 }
365
366 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700367 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100368 warn!("Secondary slot FAIL at step {} of {}",
369 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700370 fails += 1;
371 }
372 }
373 }
374
375 if fails > 0 {
376 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
377 fails as f32 * 100.0 / total_flash_ops as f32);
378 }
379
380 fails > 0
381 }
382
David Brown5c9e0f12019-01-09 16:34:33 -0700383 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
384 let mut fails = 0;
385 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700386 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700387 info!("Random interruptions at reset points={:?}", total_counts);
388
David Brown84b49f72019-03-01 10:58:22 -0700389 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100390 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700391 // TODO: This result is ignored.
392 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700393 } else {
394 true
395 };
David Vincze2d736ad2019-02-18 11:50:22 +0100396 if !primary_slot_ok || !secondary_slot_ok {
397 error!("Image mismatch after random interrupts: primary slot={} \
398 secondary slot={}",
399 if primary_slot_ok { "ok" } else { "fail" },
400 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700401 fails += 1;
402 }
David Brown84b49f72019-03-01 10:58:22 -0700403 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
404 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100405 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700406 fails += 1;
407 }
David Brown84b49f72019-03-01 10:58:22 -0700408 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
409 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100410 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700411 fails += 1;
412 }
413
414 if fails > 0 {
415 error!("Error testing perm upgrade with {} fails", total_fails);
416 }
417
418 fails > 0
419 }
420
David Brown5c9e0f12019-01-09 16:34:33 -0700421 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700422 if Caps::OverwriteUpgrade.present() {
423 return false;
424 }
David Brown5c9e0f12019-01-09 16:34:33 -0700425
David Brown5c9e0f12019-01-09 16:34:33 -0700426 let mut fails = 0;
427
428 if Caps::SwapUpgrade.present() {
Fabio Utziged4a5362019-07-30 12:43:23 -0300429 for i in 1 .. self.total_count.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -0700430 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700431 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700432 error!("Revert failed at interruption {}", i);
433 fails += 1;
434 }
435 }
436 }
437
438 fails > 0
439 }
440
David Brown5c9e0f12019-01-09 16:34:33 -0700441 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700442 if Caps::OverwriteUpgrade.present() {
443 return false;
444 }
David Brown5c9e0f12019-01-09 16:34:33 -0700445
David Brown76101572019-02-28 11:29:03 -0700446 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700447 let mut fails = 0;
448
449 info!("Try norevert");
450
451 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700452 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700453 if result != 0 {
454 warn!("Failed first boot");
455 fails += 1;
456 }
457
458 //FIXME: copy_done is written by boot_go, is it ok if no copy
459 // was ever done?
460
David Brown84b49f72019-03-01 10:58:22 -0700461 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100462 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700463 fails += 1;
464 }
David Brown84b49f72019-03-01 10:58:22 -0700465 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
466 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100467 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700468 fails += 1;
469 }
David Brown84b49f72019-03-01 10:58:22 -0700470 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
471 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100472 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700473 fails += 1;
474 }
475
David Vincze2d736ad2019-02-18 11:50:22 +0100476 // Marks image in the primary slot as permanent,
477 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700478 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700479
David Brown84b49f72019-03-01 10:58:22 -0700480 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
481 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100482 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700483 fails += 1;
484 }
485
David Brown76101572019-02-28 11:29:03 -0700486 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700487 if result != 0 {
488 warn!("Failed second boot");
489 fails += 1;
490 }
491
David Brown84b49f72019-03-01 10:58:22 -0700492 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
493 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100494 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700495 fails += 1;
496 }
David Brown84b49f72019-03-01 10:58:22 -0700497 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700498 warn!("Failed image verification");
499 fails += 1;
500 }
501
502 if fails > 0 {
503 error!("Error running upgrade without revert");
504 }
505
506 fails > 0
507 }
508
David Vincze2d736ad2019-02-18 11:50:22 +0100509 // Tests a new image written to the primary slot that already has magic and
510 // image_ok set while there is no image on the secondary slot, so no revert
511 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700512 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700513 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700514 let mut fails = 0;
515
516 info!("Try non-revert on imgtool generated image");
517
David Brown84b49f72019-03-01 10:58:22 -0700518 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700519
David Vincze2d736ad2019-02-18 11:50:22 +0100520 // This simulates writing an image created by imgtool to
521 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700522 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
523 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100524 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700525 fails += 1;
526 }
527
528 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700529 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700530 if result != 0 {
531 warn!("Failed first boot");
532 fails += 1;
533 }
534
535 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700536 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700537 warn!("Failed image verification");
538 fails += 1;
539 }
David Brown84b49f72019-03-01 10:58:22 -0700540 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
541 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100542 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700543 fails += 1;
544 }
David Brown84b49f72019-03-01 10:58:22 -0700545 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
546 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100547 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700548 fails += 1;
549 }
550
551 if fails > 0 {
552 error!("Expected a non revert with new image");
553 }
554
555 fails > 0
556 }
557
David Vincze2d736ad2019-02-18 11:50:22 +0100558 // Tests a new image written to the primary slot that already has magic and
559 // image_ok set while there is no image on the secondary slot, so no revert
560 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700561 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700562 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700563 let mut fails = 0;
564
565 info!("Try upgrade image with bad signature");
566
David Brown84b49f72019-03-01 10:58:22 -0700567 self.mark_upgrades(&mut flash, 0);
568 self.mark_permanent_upgrades(&mut flash, 0);
569 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700570
David Brown84b49f72019-03-01 10:58:22 -0700571 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
572 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100573 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700574 fails += 1;
575 }
576
577 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700578 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700579 if result != 0 {
580 warn!("Failed first boot");
581 fails += 1;
582 }
583
584 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700585 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700586 warn!("Failed image verification");
587 fails += 1;
588 }
David Brown84b49f72019-03-01 10:58:22 -0700589 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
590 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100591 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700592 fails += 1;
593 }
594
595 if fails > 0 {
596 error!("Expected an upgrade failure when image has bad signature");
597 }
598
599 fails > 0
600 }
601
David Brown5c9e0f12019-01-09 16:34:33 -0700602 fn trailer_sz(&self, align: usize) -> usize {
603 c::boot_trailer_sz(align as u8) as usize
604 }
605
606 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700607 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700608 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
609 32
610 } else {
611 0
612 };
David Brown5c9e0f12019-01-09 16:34:33 -0700613
Christopher Collinsa1c12042019-05-23 14:00:28 -0700614 self.trailer_sz(align) - (16 + 32 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700615 }
616
617 /// This test runs a simple upgrade with no fails in the images, but
618 /// allowing for fails in the status area. This should run to the end
619 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700620 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100621 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700622 return false;
623 }
624
David Brown76101572019-02-28 11:29:03 -0700625 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700626 let mut fails = 0;
627
628 info!("Try swap with status fails");
629
David Brown84b49f72019-03-01 10:58:22 -0700630 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700631 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700632
David Brown76101572019-02-28 11:29:03 -0700633 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700634 if result != 0 {
635 warn!("Failed!");
636 fails += 1;
637 }
638
639 // Failed writes to the marked "bad" region don't assert anymore.
640 // Any detected assert() is happening in another part of the code.
641 if asserts != 0 {
642 warn!("At least one assert() was called");
643 fails += 1;
644 }
645
David Brown84b49f72019-03-01 10:58:22 -0700646 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
647 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100648 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700649 fails += 1;
650 }
651
David Brown84b49f72019-03-01 10:58:22 -0700652 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700653 warn!("Failed image verification");
654 fails += 1;
655 }
656
David Vincze2d736ad2019-02-18 11:50:22 +0100657 info!("validate primary slot enabled; \
658 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700659 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700660 if result != 0 {
661 warn!("Failed!");
662 fails += 1;
663 }
664
665 if fails > 0 {
666 error!("Error running upgrade with status write fails");
667 }
668
669 fails > 0
670 }
671
672 /// This test runs a simple upgrade with no fails in the images, but
673 /// allowing for fails in the status area. This should run to the end
674 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700675 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700676 if Caps::OverwriteUpgrade.present() {
677 false
David Vincze2d736ad2019-02-18 11:50:22 +0100678 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700679
David Brown76101572019-02-28 11:29:03 -0700680 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700681 let mut fails = 0;
682 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700683
David Brown85904a82019-01-11 13:45:12 -0700684 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700685
David Brown85904a82019-01-11 13:45:12 -0700686 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700687
David Brown84b49f72019-03-01 10:58:22 -0700688 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700689 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700690
691 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700692 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700693 if asserts != 0 {
694 warn!("At least one assert() was called");
695 fails += 1;
696 }
697
David Brown76101572019-02-28 11:29:03 -0700698 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700699
700 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700701 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700702
703 // This might throw no asserts, for large sector devices, where
704 // a single failure writing is indistinguishable from no failure,
705 // or throw a single assert for small sector devices that fail
706 // multiple times...
707 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100708 warn!("Expected single assert validating the primary slot, \
709 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700710 fails += 1;
711 }
712
713 if fails > 0 {
714 error!("Error running upgrade with status write fails");
715 }
716
717 fails > 0
718 } else {
David Brown76101572019-02-28 11:29:03 -0700719 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700720 let mut fails = 0;
721
722 info!("Try interrupted swap with status fails");
723
David Brown84b49f72019-03-01 10:58:22 -0700724 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700725 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700726
727 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700728 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700729 if asserts == 0 {
730 warn!("No assert() detected");
731 fails += 1;
732 }
733
734 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700735 }
David Brown5c9e0f12019-01-09 16:34:33 -0700736 }
737
738 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700739 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700740 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700741 if Caps::OverwriteUpgrade.present() {
742 return;
743 }
744
David Brown84b49f72019-03-01 10:58:22 -0700745 // Set this for each image.
746 for image in &self.images {
747 let dev_id = &image.slots[slot].dev_id;
748 let dev = flash.get_mut(&dev_id).unwrap();
749 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -0700750 let off = &image.slots[slot].base_off;
751 let len = &image.slots[slot].len;
David Brown84b49f72019-03-01 10:58:22 -0700752 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700753
David Brown84b49f72019-03-01 10:58:22 -0700754 // Mark the status area as a bad area
755 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
756 }
David Brown5c9e0f12019-01-09 16:34:33 -0700757 }
758
David Brown76101572019-02-28 11:29:03 -0700759 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100760 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700761 return;
762 }
763
David Brown84b49f72019-03-01 10:58:22 -0700764 for image in &self.images {
765 let dev_id = &image.slots[slot].dev_id;
766 let dev = flash.get_mut(&dev_id).unwrap();
767 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700768
David Brown84b49f72019-03-01 10:58:22 -0700769 // Disabling write verification the only assert triggered by
770 // boot_go should be checking for integrity of status bytes.
771 dev.set_verify_writes(false);
772 }
David Brown5c9e0f12019-01-09 16:34:33 -0700773 }
774
David Browndb505822019-03-01 10:04:20 -0700775 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
776 /// of the number of flash operations done total.
Fabio Utziged4a5362019-07-30 12:43:23 -0300777 fn try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32) {
David Browndb505822019-03-01 10:04:20 -0700778 // Clone the flash to have a new copy.
779 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700780
Fabio Utziged4a5362019-07-30 12:43:23 -0300781 if permanent {
782 self.mark_permanent_upgrades(&mut flash, 1);
783 }
David Brown5c9e0f12019-01-09 16:34:33 -0700784
David Browndb505822019-03-01 10:04:20 -0700785 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700786
David Browndb505822019-03-01 10:04:20 -0700787 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
788 (-0x13579, _) => (true, stop.unwrap()),
789 (0, _) => (false, -counter),
790 (x, _) => panic!("Unknown return: {}", x),
791 };
David Brown5c9e0f12019-01-09 16:34:33 -0700792
David Browndb505822019-03-01 10:04:20 -0700793 counter = 0;
794 if first_interrupted {
795 // fl.dump();
796 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
797 (-0x13579, _) => panic!("Shouldn't stop again"),
798 (0, _) => (),
799 (x, _) => panic!("Unknown return: {}", x),
800 }
801 }
David Brown5c9e0f12019-01-09 16:34:33 -0700802
David Browndb505822019-03-01 10:04:20 -0700803 (flash, count - counter)
804 }
805
806 fn try_revert(&self, count: usize) -> SimMultiFlash {
807 let mut flash = self.flash.clone();
808
809 // fl.write_file("image0.bin").unwrap();
810 for i in 0 .. count {
811 info!("Running boot pass {}", i + 1);
812 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
813 }
814 flash
815 }
816
817 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
818 let mut flash = self.flash.clone();
819 let mut fails = 0;
820
821 let mut counter = stop;
822 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
823 if x != -0x13579 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700824 warn!("Should have stopped test at interruption point");
David Browndb505822019-03-01 10:04:20 -0700825 fails += 1;
826 }
827
Fabio Utzig8af7f792019-07-30 12:40:01 -0300828 // In a multi-image setup, copy done might be set if any number of
829 // images was already successfully swapped.
830 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
831 warn!("copy_done should be unset");
832 fails += 1;
833 }
834
David Browndb505822019-03-01 10:04:20 -0700835 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
836 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700837 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -0700838 fails += 1;
839 }
840
David Brown84b49f72019-03-01 10:58:22 -0700841 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700842 warn!("Image in the primary slot before revert is invalid at stop={}",
843 stop);
844 fails += 1;
845 }
David Brown84b49f72019-03-01 10:58:22 -0700846 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700847 warn!("Image in the secondary slot before revert is invalid at stop={}",
848 stop);
849 fails += 1;
850 }
David Brown84b49f72019-03-01 10:58:22 -0700851 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
852 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700853 warn!("Mismatched trailer for the primary slot before revert");
854 fails += 1;
855 }
David Brown84b49f72019-03-01 10:58:22 -0700856 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
857 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700858 warn!("Mismatched trailer for the secondary slot before revert");
859 fails += 1;
860 }
861
862 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700863 let mut counter = stop;
864 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
865 if x != -0x13579 {
866 warn!("Should have stopped revert at interruption point");
867 fails += 1;
868 }
869
David Browndb505822019-03-01 10:04:20 -0700870 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
871 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700872 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -0700873 fails += 1;
874 }
875
David Brown84b49f72019-03-01 10:58:22 -0700876 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700877 warn!("Image in the primary slot after revert is invalid at stop={}",
878 stop);
879 fails += 1;
880 }
David Brown84b49f72019-03-01 10:58:22 -0700881 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700882 warn!("Image in the secondary slot after revert is invalid at stop={}",
883 stop);
884 fails += 1;
885 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700886
David Brown84b49f72019-03-01 10:58:22 -0700887 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
888 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700889 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -0700890 fails += 1;
891 }
David Brown84b49f72019-03-01 10:58:22 -0700892 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
893 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700894 warn!("Mismatched trailer for the secondary slot after revert");
895 fails += 1;
896 }
897
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700898 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
899 if x != 0 {
900 warn!("Should have finished 3rd boot");
901 fails += 1;
902 }
903
904 if !self.verify_images(&flash, 0, 0) {
905 warn!("Image in the primary slot is invalid on 1st boot after revert");
906 fails += 1;
907 }
908 if !self.verify_images(&flash, 1, 1) {
909 warn!("Image in the secondary slot is invalid on 1st boot after revert");
910 fails += 1;
911 }
912
David Browndb505822019-03-01 10:04:20 -0700913 fails > 0
914 }
915
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700916
David Browndb505822019-03-01 10:04:20 -0700917 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
918 let mut flash = self.flash.clone();
919
David Brown84b49f72019-03-01 10:58:22 -0700920 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700921
922 let mut rng = rand::thread_rng();
923 let mut resets = vec![0i32; count];
924 let mut remaining_ops = total_ops;
925 for i in 0 .. count {
926 let ops = Range::new(1, remaining_ops / 2);
927 let reset_counter = ops.ind_sample(&mut rng);
928 let mut counter = reset_counter;
929 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
930 (0, _) | (-0x13579, _) => (),
931 (x, _) => panic!("Unknown return: {}", x),
932 }
933 remaining_ops -= reset_counter;
934 resets[i] = reset_counter;
935 }
936
937 match c::boot_go(&mut flash, &self.areadesc, None, false) {
938 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700939 (0, _) => (),
940 (x, _) => panic!("Unknown return: {}", x),
941 }
David Brown5c9e0f12019-01-09 16:34:33 -0700942
David Browndb505822019-03-01 10:04:20 -0700943 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700944 }
David Brown84b49f72019-03-01 10:58:22 -0700945
946 /// Verify the image in the given flash device, the specified slot
947 /// against the expected image.
948 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
949 for image in &self.images {
950 if !verify_image(flash, &image.slots, slot,
951 match against {
952 0 => &image.primaries,
953 1 => &image.upgrades,
954 _ => panic!("Invalid 'against'"),
955 }) {
956 return false;
957 }
958 }
959 true
960 }
961
Fabio Utzig8af7f792019-07-30 12:40:01 -0300962 /// Verify that at least one of the trailers of the images have the
963 /// specified values.
964 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
965 magic: Option<u8>, image_ok: Option<u8>,
966 copy_done: Option<u8>) -> bool {
967 for image in &self.images {
968 if verify_trailer(flash, &image.slots, slot,
969 magic, image_ok, copy_done) {
970 return true;
971 }
972 }
973 false
974 }
975
David Brown84b49f72019-03-01 10:58:22 -0700976 /// Verify that the trailers of the images have the specified
977 /// values.
978 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
979 magic: Option<u8>, image_ok: Option<u8>,
980 copy_done: Option<u8>) -> bool {
981 for image in &self.images {
982 if !verify_trailer(flash, &image.slots, slot,
983 magic, image_ok, copy_done) {
984 return false;
985 }
986 }
987 true
988 }
989
990 /// Mark each of the images for permanent upgrade.
991 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
992 for image in &self.images {
993 mark_permanent_upgrade(flash, &image.slots[slot]);
994 }
995 }
996
997 /// Mark each of the images for permanent upgrade.
998 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
999 for image in &self.images {
1000 mark_upgrade(flash, &image.slots[slot]);
1001 }
1002 }
David Brown5c9e0f12019-01-09 16:34:33 -07001003}
1004
1005/// Show the flash layout.
1006#[allow(dead_code)]
1007fn show_flash(flash: &dyn Flash) {
1008 println!("---- Flash configuration ----");
1009 for sector in flash.sector_iter() {
1010 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1011 sector.num, sector.base, sector.size);
1012 }
1013 println!("");
1014}
1015
1016/// Install a "program" into the given image. This fakes the image header, or at least all of the
1017/// fields used by the given code. Returns a copy of the image that was written.
David Brown76101572019-02-28 11:29:03 -07001018fn install_image(flash: &mut SimMultiFlash, slots: &[SlotInfo], slot: usize, len: usize,
David Brownca234692019-02-28 11:22:19 -07001019 bad_sig: bool) -> ImageData {
David Brown5c9e0f12019-01-09 16:34:33 -07001020 let offset = slots[slot].base_off;
1021 let slot_len = slots[slot].len;
1022 let dev_id = slots[slot].dev_id;
1023
David Brown43643dd2019-01-11 15:43:28 -07001024 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001025
1026 const HDR_SIZE: usize = 32;
1027
1028 // Generate a boot header. Note that the size doesn't include the header.
1029 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001030 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001031 load_addr: 0,
1032 hdr_size: HDR_SIZE as u16,
1033 _pad1: 0,
1034 img_size: len as u32,
1035 flags: tlv.get_flags(),
1036 ver: ImageVersion {
1037 major: (offset / (128 * 1024)) as u8,
1038 minor: 0,
1039 revision: 1,
1040 build_num: offset as u32,
1041 },
1042 _pad2: 0,
1043 };
1044
1045 let mut b_header = [0; HDR_SIZE];
1046 b_header[..32].clone_from_slice(header.as_raw());
1047 assert_eq!(b_header.len(), HDR_SIZE);
1048
1049 tlv.add_bytes(&b_header);
1050
1051 // The core of the image itself is just pseudorandom data.
1052 let mut b_img = vec![0; len];
1053 splat(&mut b_img, offset);
1054
1055 // TLV signatures work over plain image
1056 tlv.add_bytes(&b_img);
1057
1058 // Generate encrypted images
1059 let flag = TlvFlags::ENCRYPTED as u32;
1060 let is_encrypted = (tlv.get_flags() & flag) == flag;
1061 let mut b_encimg = vec![];
1062 if is_encrypted {
1063 let key = GenericArray::from_slice(AES_SEC_KEY);
1064 let nonce = GenericArray::from_slice(&[0; 16]);
1065 let mut cipher = Aes128Ctr::new(&key, &nonce);
1066 b_encimg = b_img.clone();
1067 cipher.apply_keystream(&mut b_encimg);
1068 }
1069
1070 // Build the TLV itself.
1071 let mut b_tlv = if bad_sig {
1072 let good_sig = &mut tlv.make_tlv();
1073 vec![0; good_sig.len()]
1074 } else {
1075 tlv.make_tlv()
1076 };
1077
1078 // Pad the block to a flash alignment (8 bytes).
1079 while b_tlv.len() % 8 != 0 {
1080 //FIXME: should be erase_val?
1081 b_tlv.push(0xFF);
1082 }
1083
1084 let mut buf = vec![];
1085 buf.append(&mut b_header.to_vec());
1086 buf.append(&mut b_img);
1087 buf.append(&mut b_tlv.clone());
1088
1089 let mut encbuf = vec![];
1090 if is_encrypted {
1091 encbuf.append(&mut b_header.to_vec());
1092 encbuf.append(&mut b_encimg);
1093 encbuf.append(&mut b_tlv);
1094 }
1095
David Vincze2d736ad2019-02-18 11:50:22 +01001096 // Since images are always non-encrypted in the primary slot, we first write
1097 // an encrypted image, re-read to use for verification, erase + flash
1098 // un-encrypted. In the secondary slot the image is written un-encrypted,
1099 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001100
David Brown76101572019-02-28 11:29:03 -07001101 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001102
1103 if slot == 0 {
1104 let enc_copy: Option<Vec<u8>>;
1105
1106 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001107 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001108
1109 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001110 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001111
1112 enc_copy = Some(enc);
1113
David Brown76101572019-02-28 11:29:03 -07001114 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001115 } else {
1116 enc_copy = None;
1117 }
1118
David Brown76101572019-02-28 11:29:03 -07001119 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001120
1121 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001122 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001123
David Brownca234692019-02-28 11:22:19 -07001124 ImageData {
1125 plain: copy,
1126 cipher: enc_copy,
1127 }
David Brown5c9e0f12019-01-09 16:34:33 -07001128 } else {
1129
David Brown76101572019-02-28 11:29:03 -07001130 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001131
1132 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001133 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001134
1135 let enc_copy: Option<Vec<u8>>;
1136
1137 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001138 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001139
David Brown76101572019-02-28 11:29:03 -07001140 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001141
1142 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001143 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001144
1145 enc_copy = Some(enc);
1146 } else {
1147 enc_copy = None;
1148 }
1149
David Brownca234692019-02-28 11:22:19 -07001150 ImageData {
1151 plain: copy,
1152 cipher: enc_copy,
1153 }
David Brown5c9e0f12019-01-09 16:34:33 -07001154 }
David Brown5c9e0f12019-01-09 16:34:33 -07001155}
1156
David Brown5c9e0f12019-01-09 16:34:33 -07001157fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001158 if Caps::EcdsaP224.present() {
1159 panic!("Ecdsa P224 not supported in Simulator");
1160 }
David Brown5c9e0f12019-01-09 16:34:33 -07001161
David Brownb8882112019-01-11 14:04:11 -07001162 if Caps::EncKw.present() {
1163 if Caps::RSA2048.present() {
1164 TlvGen::new_rsa_kw()
1165 } else if Caps::EcdsaP256.present() {
1166 TlvGen::new_ecdsa_kw()
1167 } else {
1168 TlvGen::new_enc_kw()
1169 }
1170 } else if Caps::EncRsa.present() {
1171 if Caps::RSA2048.present() {
1172 TlvGen::new_sig_enc_rsa()
1173 } else {
1174 TlvGen::new_enc_rsa()
1175 }
1176 } else {
1177 // The non-encrypted configuration.
1178 if Caps::RSA2048.present() {
1179 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001180 } else if Caps::RSA3072.present() {
1181 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001182 } else if Caps::EcdsaP256.present() {
1183 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001184 } else if Caps::Ed25519.present() {
1185 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001186 } else {
1187 TlvGen::new_hash_only()
1188 }
1189 }
David Brown5c9e0f12019-01-09 16:34:33 -07001190}
1191
David Brownca234692019-02-28 11:22:19 -07001192impl ImageData {
1193 /// Find the image contents for the given slot. This assumes that slot 0
1194 /// is unencrypted, and slot 1 is encrypted.
1195 fn find(&self, slot: usize) -> &Vec<u8> {
1196 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1197 match (encrypted, slot) {
1198 (false, _) => &self.plain,
1199 (true, 0) => &self.plain,
1200 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1201 _ => panic!("Invalid slot requested"),
1202 }
David Brown5c9e0f12019-01-09 16:34:33 -07001203 }
1204}
1205
David Brown5c9e0f12019-01-09 16:34:33 -07001206/// Verify that given image is present in the flash at the given offset.
David Brown76101572019-02-28 11:29:03 -07001207fn verify_image(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brownca234692019-02-28 11:22:19 -07001208 images: &ImageData) -> bool {
1209 let image = images.find(slot);
David Brown5c9e0f12019-01-09 16:34:33 -07001210 let buf = image.as_slice();
1211 let dev_id = slots[slot].dev_id;
1212
1213 let mut copy = vec![0u8; buf.len()];
1214 let offset = slots[slot].base_off;
David Brown76101572019-02-28 11:29:03 -07001215 let dev = flash.get(&dev_id).unwrap();
1216 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001217
1218 if buf != &copy[..] {
1219 for i in 0 .. buf.len() {
1220 if buf[i] != copy[i] {
1221 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1222 slot, offset + i, buf[i], copy[i]);
1223 break;
1224 }
1225 }
1226 false
1227 } else {
1228 true
1229 }
1230}
1231
David Brown76101572019-02-28 11:29:03 -07001232fn verify_trailer(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001233 magic: Option<u8>, image_ok: Option<u8>,
1234 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001235 if Caps::OverwriteUpgrade.present() {
1236 return true;
1237 }
David Brown5c9e0f12019-01-09 16:34:33 -07001238
Christopher Collinsa1c12042019-05-23 14:00:28 -07001239 let offset = slots[slot].trailer_off + c::boot_max_align();
David Brown5c9e0f12019-01-09 16:34:33 -07001240 let dev_id = slots[slot].dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001241 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001242 let mut failed = false;
1243
David Brown76101572019-02-28 11:29:03 -07001244 let dev = flash.get(&dev_id).unwrap();
1245 let erased_val = dev.erased_val();
1246 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001247
1248 failed |= match magic {
1249 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001250 if v == 1 && &copy[24..] != MAGIC.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -07001251 warn!("\"magic\" mismatch at {:#x}", offset);
1252 true
1253 } else if v == 3 {
1254 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001255 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001256 warn!("\"magic\" mismatch at {:#x}", offset);
1257 true
1258 } else {
1259 false
1260 }
1261 } else {
1262 false
1263 }
1264 },
1265 None => false,
1266 };
1267
1268 failed |= match image_ok {
1269 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001270 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001271 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1272 true
1273 } else {
1274 false
1275 }
1276 },
1277 None => false,
1278 };
1279
1280 failed |= match copy_done {
1281 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001282 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001283 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1284 true
1285 } else {
1286 false
1287 }
1288 },
1289 None => false,
1290 };
1291
1292 !failed
1293}
1294
1295/// The image header
1296#[repr(C)]
1297pub struct ImageHeader {
1298 magic: u32,
1299 load_addr: u32,
1300 hdr_size: u16,
1301 _pad1: u16,
1302 img_size: u32,
1303 flags: u32,
1304 ver: ImageVersion,
1305 _pad2: u32,
1306}
1307
1308impl AsRaw for ImageHeader {}
1309
1310#[repr(C)]
1311pub struct ImageVersion {
1312 major: u8,
1313 minor: u8,
1314 revision: u16,
1315 build_num: u32,
1316}
1317
1318#[derive(Clone)]
1319pub struct SlotInfo {
1320 pub base_off: usize,
1321 pub trailer_off: usize,
1322 pub len: usize,
1323 pub dev_id: u8,
1324}
1325
David Brown5c9e0f12019-01-09 16:34:33 -07001326const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1327 0x60, 0xd2, 0xef, 0x7f,
1328 0x35, 0x52, 0x50, 0x0f,
1329 0x2c, 0xb6, 0x79, 0x80]);
1330
1331// Replicates defines found in bootutil.h
1332const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1333const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1334
1335const BOOT_FLAG_SET: Option<u8> = Some(1);
1336const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1337
1338/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001339pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1340 let dev = flash.get_mut(&slot.dev_id).unwrap();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001341 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown76101572019-02-28 11:29:03 -07001342 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001343}
1344
1345/// Writes the image_ok flag which, guess what, tells the bootloader
1346/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001347fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1348 let dev = flash.get_mut(&slot.dev_id).unwrap();
1349 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001350 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001351 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001352 let align = dev.align();
1353 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001354}
1355
1356// Drop some pseudo-random gibberish onto the data.
1357fn splat(data: &mut [u8], seed: usize) {
1358 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1359 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1360 rng.fill_bytes(data);
1361}
1362
1363/// Return a read-only view into the raw bytes of this object
1364trait AsRaw : Sized {
1365 fn as_raw<'a>(&'a self) -> &'a [u8] {
1366 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1367 mem::size_of::<Self>()) }
1368 }
1369}
1370
1371pub fn show_sizes() {
1372 // This isn't panic safe.
1373 for min in &[1, 2, 4, 8] {
1374 let msize = c::boot_trailer_sz(*min);
1375 println!("{:2}: {} (0x{:x})", min, msize, msize);
1376 }
1377}