blob: 92df421f684727df298e3390a601c90363a58df1 [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 {
65 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Self {
David Brown76101572019-02-28 11:29:03 -070066 let (flash, areadesc) = Self::make_device(device, align, erased_val);
David Browne5133242019-02-28 11:05:19 -070067
68 let (slot0_base, slot0_len, slot0_dev_id) = areadesc.find(FlashId::Image0);
69 let (slot1_base, slot1_len, slot1_dev_id) = areadesc.find(FlashId::Image1);
70
71 // NOTE: not accounting "swap_size" because it is not used by sim...
72 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
73
74 // Construct a primary image.
75 let slot0 = SlotInfo {
76 base_off: slot0_base as usize,
77 trailer_off: slot0_base + slot0_len - offset_from_end,
78 len: slot0_len as usize,
79 dev_id: slot0_dev_id,
80 };
81
82 // And an upgrade image.
83 let slot1 = SlotInfo {
84 base_off: slot1_base as usize,
85 trailer_off: slot1_base + slot1_len - offset_from_end,
86 len: slot1_len as usize,
87 dev_id: slot1_dev_id,
88 };
89
90 ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070091 flash: flash,
David Browne5133242019-02-28 11:05:19 -070092 areadesc: areadesc,
David Brown84b49f72019-03-01 10:58:22 -070093 slots: vec![[slot0, slot1]],
David Browne5133242019-02-28 11:05:19 -070094 }
95 }
96
97 pub fn each_device<F>(f: F)
98 where F: Fn(Self)
99 {
100 for &dev in ALL_DEVICES {
101 for &align in &[1, 2, 4, 8] {
102 for &erased_val in &[0, 0xff] {
103 let run = Self::new(dev, align, erased_val);
104 f(run);
105 }
106 }
107 }
108 }
109
110 /// Construct an `Images` that doesn't expect an upgrade to happen.
111 pub fn make_no_upgrade_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700112 let mut flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700113 let images = self.slots.into_iter().map(|slots| {
114 let primaries = install_image(&mut flash, &slots, 0, 32784, false);
115 let upgrades = install_image(&mut flash, &slots, 1, 41928, false);
116 OneImage {
117 slots: slots,
118 primaries: primaries,
119 upgrades: upgrades,
120 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700121 Images {
David Brown76101572019-02-28 11:29:03 -0700122 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700123 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700124 images: images,
David Browne5133242019-02-28 11:05:19 -0700125 total_count: None,
126 }
127 }
128
129 /// Construct an `Images` for normal testing.
130 pub fn make_image(self) -> Images {
131 let mut images = self.make_no_upgrade_image();
David Brown84b49f72019-03-01 10:58:22 -0700132 for image in &images.images {
133 mark_upgrade(&mut images.flash, &image.slots[1]);
134 }
David Browne5133242019-02-28 11:05:19 -0700135
136 // upgrades without fails, counts number of flash operations
137 let total_count = match images.run_basic_upgrade() {
138 Ok(v) => v,
139 Err(_) => {
140 panic!("Unable to perform basic upgrade");
141 },
142 };
143
144 images.total_count = Some(total_count);
145 images
146 }
147
148 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700149 let mut bad_flash = self.flash;
David Brown84b49f72019-03-01 10:58:22 -0700150 let images = self.slots.into_iter().map(|slots| {
151 let primaries = install_image(&mut bad_flash, &slots, 0, 32784, false);
152 let upgrades = install_image(&mut bad_flash, &slots, 1, 41928, true);
153 OneImage {
154 slots: slots,
155 primaries: primaries,
156 upgrades: upgrades,
157 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700158 Images {
David Brown76101572019-02-28 11:29:03 -0700159 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700160 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700161 images: images,
David Browne5133242019-02-28 11:05:19 -0700162 total_count: None,
163 }
164 }
165
166 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700167 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700168 match device {
169 DeviceName::Stm32f4 => {
170 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700171 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
172 64 * 1024,
173 128 * 1024, 128 * 1024, 128 * 1024],
174 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700175 let dev_id = 0;
176 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700177 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700178 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
179 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
180 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
181
David Brown76101572019-02-28 11:29:03 -0700182 let mut flash = SimMultiFlash::new();
183 flash.insert(dev_id, dev);
184 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700185 }
186 DeviceName::K64f => {
187 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700188 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700189
190 let dev_id = 0;
191 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700192 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700193 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
194 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
195 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
196
David Brown76101572019-02-28 11:29:03 -0700197 let mut flash = SimMultiFlash::new();
198 flash.insert(dev_id, dev);
199 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700200 }
201 DeviceName::K64fBig => {
202 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
203 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700204 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700205
206 let dev_id = 0;
207 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700208 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700209 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
210 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
211 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
212
David Brown76101572019-02-28 11:29:03 -0700213 let mut flash = SimMultiFlash::new();
214 flash.insert(dev_id, dev);
215 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700216 }
217 DeviceName::Nrf52840 => {
218 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
219 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700220 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700221
222 let dev_id = 0;
223 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700224 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700225 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
226 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
227 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
228
David Brown76101572019-02-28 11:29:03 -0700229 let mut flash = SimMultiFlash::new();
230 flash.insert(dev_id, dev);
231 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700232 }
233 DeviceName::Nrf52840SpiFlash => {
234 // Simulate nrf52840 with external SPI flash. The external SPI flash
235 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700236 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
237 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700238
239 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700240 areadesc.add_flash_sectors(0, &dev0);
241 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700242
243 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
244 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
245 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
246
David Brown76101572019-02-28 11:29:03 -0700247 let mut flash = SimMultiFlash::new();
248 flash.insert(0, dev0);
249 flash.insert(1, dev1);
250 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700251 }
252 }
253 }
254}
255
David Brown5c9e0f12019-01-09 16:34:33 -0700256impl Images {
257 /// A simple upgrade without forced failures.
258 ///
259 /// Returns the number of flash operations which can later be used to
260 /// inject failures at chosen steps.
261 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Browndb505822019-03-01 10:04:20 -0700262 let (flash, total_count) = self.try_upgrade(None);
David Brown5c9e0f12019-01-09 16:34:33 -0700263 info!("Total flash operation count={}", total_count);
264
David Brown84b49f72019-03-01 10:58:22 -0700265 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700266 warn!("Image mismatch after first boot");
267 Err(())
268 } else {
269 Ok(total_count)
270 }
271 }
272
David Brown5c9e0f12019-01-09 16:34:33 -0700273 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700274 if Caps::OverwriteUpgrade.present() {
275 return false;
276 }
David Brown5c9e0f12019-01-09 16:34:33 -0700277
David Brown5c9e0f12019-01-09 16:34:33 -0700278 let mut fails = 0;
279
280 // FIXME: this test would also pass if no swap is ever performed???
281 if Caps::SwapUpgrade.present() {
282 for count in 2 .. 5 {
283 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700284 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700285 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700286 error!("Revert failure on count {}", count);
287 fails += 1;
288 }
289 }
290 }
291
292 fails > 0
293 }
294
295 pub fn run_perm_with_fails(&self) -> bool {
296 let mut fails = 0;
297 let total_flash_ops = self.total_count.unwrap();
298
299 // Let's try an image halfway through.
300 for i in 1 .. total_flash_ops {
301 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700302 let (flash, count) = self.try_upgrade(Some(i));
David Brown5c9e0f12019-01-09 16:34:33 -0700303 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700304 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700305 warn!("FAIL at step {} of {}", i, total_flash_ops);
306 fails += 1;
307 }
308
David Brown84b49f72019-03-01 10:58:22 -0700309 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
310 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100311 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700312 fails += 1;
313 }
314
David Brown84b49f72019-03-01 10:58:22 -0700315 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
316 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100317 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700318 fails += 1;
319 }
320
321 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700322 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100323 warn!("Secondary slot FAIL at step {} of {}",
324 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700325 fails += 1;
326 }
327 }
328 }
329
330 if fails > 0 {
331 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
332 fails as f32 * 100.0 / total_flash_ops as f32);
333 }
334
335 fails > 0
336 }
337
338 pub fn run_perm_with_random_fails_5(&self) -> bool {
339 self.run_perm_with_random_fails(5)
340 }
341
342 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
343 let mut fails = 0;
344 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700345 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700346 info!("Random interruptions at reset points={:?}", total_counts);
347
David Brown84b49f72019-03-01 10:58:22 -0700348 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100349 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700350 // TODO: This result is ignored.
351 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700352 } else {
353 true
354 };
David Vincze2d736ad2019-02-18 11:50:22 +0100355 if !primary_slot_ok || !secondary_slot_ok {
356 error!("Image mismatch after random interrupts: primary slot={} \
357 secondary slot={}",
358 if primary_slot_ok { "ok" } else { "fail" },
359 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700360 fails += 1;
361 }
David Brown84b49f72019-03-01 10:58:22 -0700362 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
363 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100364 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700365 fails += 1;
366 }
David Brown84b49f72019-03-01 10:58:22 -0700367 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
368 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100369 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700370 fails += 1;
371 }
372
373 if fails > 0 {
374 error!("Error testing perm upgrade with {} fails", total_fails);
375 }
376
377 fails > 0
378 }
379
David Brown5c9e0f12019-01-09 16:34:33 -0700380 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700381 if Caps::OverwriteUpgrade.present() {
382 return false;
383 }
David Brown5c9e0f12019-01-09 16:34:33 -0700384
David Brown5c9e0f12019-01-09 16:34:33 -0700385 let mut fails = 0;
386
387 if Caps::SwapUpgrade.present() {
388 for i in 1 .. (self.total_count.unwrap() - 1) {
389 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700390 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700391 error!("Revert failed at interruption {}", i);
392 fails += 1;
393 }
394 }
395 }
396
397 fails > 0
398 }
399
David Brown5c9e0f12019-01-09 16:34:33 -0700400 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700401 if Caps::OverwriteUpgrade.present() {
402 return false;
403 }
David Brown5c9e0f12019-01-09 16:34:33 -0700404
David Brown76101572019-02-28 11:29:03 -0700405 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700406 let mut fails = 0;
407
408 info!("Try norevert");
409
410 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700411 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700412 if result != 0 {
413 warn!("Failed first boot");
414 fails += 1;
415 }
416
417 //FIXME: copy_done is written by boot_go, is it ok if no copy
418 // was ever done?
419
David Brown84b49f72019-03-01 10:58:22 -0700420 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100421 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700422 fails += 1;
423 }
David Brown84b49f72019-03-01 10:58:22 -0700424 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
425 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100426 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700427 fails += 1;
428 }
David Brown84b49f72019-03-01 10:58:22 -0700429 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
430 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100431 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700432 fails += 1;
433 }
434
David Vincze2d736ad2019-02-18 11:50:22 +0100435 // Marks image in the primary slot as permanent,
436 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700437 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700438
David Brown84b49f72019-03-01 10:58:22 -0700439 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
440 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100441 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700442 fails += 1;
443 }
444
David Brown76101572019-02-28 11:29:03 -0700445 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700446 if result != 0 {
447 warn!("Failed second boot");
448 fails += 1;
449 }
450
David Brown84b49f72019-03-01 10:58:22 -0700451 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
452 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100453 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700454 fails += 1;
455 }
David Brown84b49f72019-03-01 10:58:22 -0700456 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700457 warn!("Failed image verification");
458 fails += 1;
459 }
460
461 if fails > 0 {
462 error!("Error running upgrade without revert");
463 }
464
465 fails > 0
466 }
467
David Vincze2d736ad2019-02-18 11:50:22 +0100468 // Tests a new image written to the primary slot that already has magic and
469 // image_ok set while there is no image on the secondary slot, so no revert
470 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700471 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700472 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700473 let mut fails = 0;
474
475 info!("Try non-revert on imgtool generated image");
476
David Brown84b49f72019-03-01 10:58:22 -0700477 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700478
David Vincze2d736ad2019-02-18 11:50:22 +0100479 // This simulates writing an image created by imgtool to
480 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700481 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
482 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100483 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700484 fails += 1;
485 }
486
487 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700488 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700489 if result != 0 {
490 warn!("Failed first boot");
491 fails += 1;
492 }
493
494 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700495 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700496 warn!("Failed image verification");
497 fails += 1;
498 }
David Brown84b49f72019-03-01 10:58:22 -0700499 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
500 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100501 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700502 fails += 1;
503 }
David Brown84b49f72019-03-01 10:58:22 -0700504 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
505 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100506 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700507 fails += 1;
508 }
509
510 if fails > 0 {
511 error!("Expected a non revert with new image");
512 }
513
514 fails > 0
515 }
516
David Vincze2d736ad2019-02-18 11:50:22 +0100517 // Tests a new image written to the primary slot that already has magic and
518 // image_ok set while there is no image on the secondary slot, so no revert
519 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700520 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700521 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700522 let mut fails = 0;
523
524 info!("Try upgrade image with bad signature");
525
David Brown84b49f72019-03-01 10:58:22 -0700526 self.mark_upgrades(&mut flash, 0);
527 self.mark_permanent_upgrades(&mut flash, 0);
528 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700529
David Brown84b49f72019-03-01 10:58:22 -0700530 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
531 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100532 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700533 fails += 1;
534 }
535
536 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700537 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700538 if result != 0 {
539 warn!("Failed first boot");
540 fails += 1;
541 }
542
543 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700544 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700545 warn!("Failed image verification");
546 fails += 1;
547 }
David Brown84b49f72019-03-01 10:58:22 -0700548 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
549 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100550 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700551 fails += 1;
552 }
553
554 if fails > 0 {
555 error!("Expected an upgrade failure when image has bad signature");
556 }
557
558 fails > 0
559 }
560
David Brown5c9e0f12019-01-09 16:34:33 -0700561 fn trailer_sz(&self, align: usize) -> usize {
562 c::boot_trailer_sz(align as u8) as usize
563 }
564
565 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700566 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700567 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
568 32
569 } else {
570 0
571 };
David Brown5c9e0f12019-01-09 16:34:33 -0700572
David Brown9930a3e2019-01-11 12:28:26 -0700573 self.trailer_sz(align) - (16 + 24 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700574 }
575
576 /// This test runs a simple upgrade with no fails in the images, but
577 /// allowing for fails in the status area. This should run to the end
578 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700579 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100580 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700581 return false;
582 }
583
David Brown76101572019-02-28 11:29:03 -0700584 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700585 let mut fails = 0;
586
587 info!("Try swap with status fails");
588
David Brown84b49f72019-03-01 10:58:22 -0700589 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700590 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700591
David Brown76101572019-02-28 11:29:03 -0700592 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700593 if result != 0 {
594 warn!("Failed!");
595 fails += 1;
596 }
597
598 // Failed writes to the marked "bad" region don't assert anymore.
599 // Any detected assert() is happening in another part of the code.
600 if asserts != 0 {
601 warn!("At least one assert() was called");
602 fails += 1;
603 }
604
David Brown84b49f72019-03-01 10:58:22 -0700605 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
606 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100607 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700608 fails += 1;
609 }
610
David Brown84b49f72019-03-01 10:58:22 -0700611 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700612 warn!("Failed image verification");
613 fails += 1;
614 }
615
David Vincze2d736ad2019-02-18 11:50:22 +0100616 info!("validate primary slot enabled; \
617 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700618 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700619 if result != 0 {
620 warn!("Failed!");
621 fails += 1;
622 }
623
624 if fails > 0 {
625 error!("Error running upgrade with status write fails");
626 }
627
628 fails > 0
629 }
630
631 /// This test runs a simple upgrade with no fails in the images, but
632 /// allowing for fails in the status area. This should run to the end
633 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700634 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700635 if Caps::OverwriteUpgrade.present() {
636 false
David Vincze2d736ad2019-02-18 11:50:22 +0100637 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700638
David Brown76101572019-02-28 11:29:03 -0700639 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700640 let mut fails = 0;
641 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700642
David Brown85904a82019-01-11 13:45:12 -0700643 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700644
David Brown85904a82019-01-11 13:45:12 -0700645 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700646
David Brown84b49f72019-03-01 10:58:22 -0700647 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700648 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700649
650 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700651 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700652 if asserts != 0 {
653 warn!("At least one assert() was called");
654 fails += 1;
655 }
656
David Brown76101572019-02-28 11:29:03 -0700657 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700658
659 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700660 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700661
662 // This might throw no asserts, for large sector devices, where
663 // a single failure writing is indistinguishable from no failure,
664 // or throw a single assert for small sector devices that fail
665 // multiple times...
666 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100667 warn!("Expected single assert validating the primary slot, \
668 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700669 fails += 1;
670 }
671
672 if fails > 0 {
673 error!("Error running upgrade with status write fails");
674 }
675
676 fails > 0
677 } else {
David Brown76101572019-02-28 11:29:03 -0700678 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700679 let mut fails = 0;
680
681 info!("Try interrupted swap with status fails");
682
David Brown84b49f72019-03-01 10:58:22 -0700683 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700684 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700685
686 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700687 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700688 if asserts == 0 {
689 warn!("No assert() detected");
690 fails += 1;
691 }
692
693 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700694 }
David Brown5c9e0f12019-01-09 16:34:33 -0700695 }
696
697 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700698 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700699 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700700 if Caps::OverwriteUpgrade.present() {
701 return;
702 }
703
David Brown84b49f72019-03-01 10:58:22 -0700704 // Set this for each image.
705 for image in &self.images {
706 let dev_id = &image.slots[slot].dev_id;
707 let dev = flash.get_mut(&dev_id).unwrap();
708 let align = dev.align();
709 let off = &image.slots[0].base_off;
710 let len = &image.slots[0].len;
711 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700712
David Brown84b49f72019-03-01 10:58:22 -0700713 // Mark the status area as a bad area
714 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
715 }
David Brown5c9e0f12019-01-09 16:34:33 -0700716 }
717
David Brown76101572019-02-28 11:29:03 -0700718 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100719 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700720 return;
721 }
722
David Brown84b49f72019-03-01 10:58:22 -0700723 for image in &self.images {
724 let dev_id = &image.slots[slot].dev_id;
725 let dev = flash.get_mut(&dev_id).unwrap();
726 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700727
David Brown84b49f72019-03-01 10:58:22 -0700728 // Disabling write verification the only assert triggered by
729 // boot_go should be checking for integrity of status bytes.
730 dev.set_verify_writes(false);
731 }
David Brown5c9e0f12019-01-09 16:34:33 -0700732 }
733
David Browndb505822019-03-01 10:04:20 -0700734 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
735 /// of the number of flash operations done total.
736 fn try_upgrade(&self, stop: Option<i32>) -> (SimMultiFlash, i32) {
737 // Clone the flash to have a new copy.
738 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700739
David Brown84b49f72019-03-01 10:58:22 -0700740 self.mark_permanent_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700741
David Browndb505822019-03-01 10:04:20 -0700742 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700743
David Browndb505822019-03-01 10:04:20 -0700744 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
745 (-0x13579, _) => (true, stop.unwrap()),
746 (0, _) => (false, -counter),
747 (x, _) => panic!("Unknown return: {}", x),
748 };
David Brown5c9e0f12019-01-09 16:34:33 -0700749
David Browndb505822019-03-01 10:04:20 -0700750 counter = 0;
751 if first_interrupted {
752 // fl.dump();
753 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
754 (-0x13579, _) => panic!("Shouldn't stop again"),
755 (0, _) => (),
756 (x, _) => panic!("Unknown return: {}", x),
757 }
758 }
David Brown5c9e0f12019-01-09 16:34:33 -0700759
David Browndb505822019-03-01 10:04:20 -0700760 (flash, count - counter)
761 }
762
763 fn try_revert(&self, count: usize) -> SimMultiFlash {
764 let mut flash = self.flash.clone();
765
766 // fl.write_file("image0.bin").unwrap();
767 for i in 0 .. count {
768 info!("Running boot pass {}", i + 1);
769 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
770 }
771 flash
772 }
773
774 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
775 let mut flash = self.flash.clone();
776 let mut fails = 0;
777
778 let mut counter = stop;
779 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
780 if x != -0x13579 {
781 warn!("Should have stopped at interruption point");
782 fails += 1;
783 }
784
David Brown84b49f72019-03-01 10:58:22 -0700785 if !self.verify_trailers(&flash, 0, None, None, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700786 warn!("copy_done should be unset");
787 fails += 1;
788 }
789
790 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
791 if x != 0 {
792 warn!("Should have finished upgrade");
793 fails += 1;
794 }
795
David Brown84b49f72019-03-01 10:58:22 -0700796 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700797 warn!("Image in the primary slot before revert is invalid at stop={}",
798 stop);
799 fails += 1;
800 }
David Brown84b49f72019-03-01 10:58:22 -0700801 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700802 warn!("Image in the secondary slot before revert is invalid at stop={}",
803 stop);
804 fails += 1;
805 }
David Brown84b49f72019-03-01 10:58:22 -0700806 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
807 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700808 warn!("Mismatched trailer for the primary slot before revert");
809 fails += 1;
810 }
David Brown84b49f72019-03-01 10:58:22 -0700811 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
812 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700813 warn!("Mismatched trailer for the secondary slot before revert");
814 fails += 1;
815 }
816
817 // Do Revert
818 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
819 if x != 0 {
820 warn!("Should have finished a revert");
821 fails += 1;
822 }
823
David Brown84b49f72019-03-01 10:58:22 -0700824 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700825 warn!("Image in the primary slot after revert is invalid at stop={}",
826 stop);
827 fails += 1;
828 }
David Brown84b49f72019-03-01 10:58:22 -0700829 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700830 warn!("Image in the secondary slot after revert is invalid at stop={}",
831 stop);
832 fails += 1;
833 }
David Brown84b49f72019-03-01 10:58:22 -0700834 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
835 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700836 warn!("Mismatched trailer for the secondary slot after revert");
837 fails += 1;
838 }
David Brown84b49f72019-03-01 10:58:22 -0700839 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
840 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700841 warn!("Mismatched trailer for the secondary slot after revert");
842 fails += 1;
843 }
844
845 fails > 0
846 }
847
848 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
849 let mut flash = self.flash.clone();
850
David Brown84b49f72019-03-01 10:58:22 -0700851 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700852
853 let mut rng = rand::thread_rng();
854 let mut resets = vec![0i32; count];
855 let mut remaining_ops = total_ops;
856 for i in 0 .. count {
857 let ops = Range::new(1, remaining_ops / 2);
858 let reset_counter = ops.ind_sample(&mut rng);
859 let mut counter = reset_counter;
860 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
861 (0, _) | (-0x13579, _) => (),
862 (x, _) => panic!("Unknown return: {}", x),
863 }
864 remaining_ops -= reset_counter;
865 resets[i] = reset_counter;
866 }
867
868 match c::boot_go(&mut flash, &self.areadesc, None, false) {
869 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700870 (0, _) => (),
871 (x, _) => panic!("Unknown return: {}", x),
872 }
David Brown5c9e0f12019-01-09 16:34:33 -0700873
David Browndb505822019-03-01 10:04:20 -0700874 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700875 }
David Brown84b49f72019-03-01 10:58:22 -0700876
877 /// Verify the image in the given flash device, the specified slot
878 /// against the expected image.
879 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
880 for image in &self.images {
881 if !verify_image(flash, &image.slots, slot,
882 match against {
883 0 => &image.primaries,
884 1 => &image.upgrades,
885 _ => panic!("Invalid 'against'"),
886 }) {
887 return false;
888 }
889 }
890 true
891 }
892
893 /// Verify that the trailers of the images have the specified
894 /// values.
895 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
896 magic: Option<u8>, image_ok: Option<u8>,
897 copy_done: Option<u8>) -> bool {
898 for image in &self.images {
899 if !verify_trailer(flash, &image.slots, slot,
900 magic, image_ok, copy_done) {
901 return false;
902 }
903 }
904 true
905 }
906
907 /// Mark each of the images for permanent upgrade.
908 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
909 for image in &self.images {
910 mark_permanent_upgrade(flash, &image.slots[slot]);
911 }
912 }
913
914 /// Mark each of the images for permanent upgrade.
915 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
916 for image in &self.images {
917 mark_upgrade(flash, &image.slots[slot]);
918 }
919 }
David Brown5c9e0f12019-01-09 16:34:33 -0700920}
921
922/// Show the flash layout.
923#[allow(dead_code)]
924fn show_flash(flash: &dyn Flash) {
925 println!("---- Flash configuration ----");
926 for sector in flash.sector_iter() {
927 println!(" {:3}: 0x{:08x}, 0x{:08x}",
928 sector.num, sector.base, sector.size);
929 }
930 println!("");
931}
932
933/// Install a "program" into the given image. This fakes the image header, or at least all of the
934/// fields used by the given code. Returns a copy of the image that was written.
David Brown76101572019-02-28 11:29:03 -0700935fn install_image(flash: &mut SimMultiFlash, slots: &[SlotInfo], slot: usize, len: usize,
David Brownca234692019-02-28 11:22:19 -0700936 bad_sig: bool) -> ImageData {
David Brown5c9e0f12019-01-09 16:34:33 -0700937 let offset = slots[slot].base_off;
938 let slot_len = slots[slot].len;
939 let dev_id = slots[slot].dev_id;
940
David Brown43643dd2019-01-11 15:43:28 -0700941 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -0700942
943 const HDR_SIZE: usize = 32;
944
945 // Generate a boot header. Note that the size doesn't include the header.
946 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -0700947 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -0700948 load_addr: 0,
949 hdr_size: HDR_SIZE as u16,
950 _pad1: 0,
951 img_size: len as u32,
952 flags: tlv.get_flags(),
953 ver: ImageVersion {
954 major: (offset / (128 * 1024)) as u8,
955 minor: 0,
956 revision: 1,
957 build_num: offset as u32,
958 },
959 _pad2: 0,
960 };
961
962 let mut b_header = [0; HDR_SIZE];
963 b_header[..32].clone_from_slice(header.as_raw());
964 assert_eq!(b_header.len(), HDR_SIZE);
965
966 tlv.add_bytes(&b_header);
967
968 // The core of the image itself is just pseudorandom data.
969 let mut b_img = vec![0; len];
970 splat(&mut b_img, offset);
971
972 // TLV signatures work over plain image
973 tlv.add_bytes(&b_img);
974
975 // Generate encrypted images
976 let flag = TlvFlags::ENCRYPTED as u32;
977 let is_encrypted = (tlv.get_flags() & flag) == flag;
978 let mut b_encimg = vec![];
979 if is_encrypted {
980 let key = GenericArray::from_slice(AES_SEC_KEY);
981 let nonce = GenericArray::from_slice(&[0; 16]);
982 let mut cipher = Aes128Ctr::new(&key, &nonce);
983 b_encimg = b_img.clone();
984 cipher.apply_keystream(&mut b_encimg);
985 }
986
987 // Build the TLV itself.
988 let mut b_tlv = if bad_sig {
989 let good_sig = &mut tlv.make_tlv();
990 vec![0; good_sig.len()]
991 } else {
992 tlv.make_tlv()
993 };
994
995 // Pad the block to a flash alignment (8 bytes).
996 while b_tlv.len() % 8 != 0 {
997 //FIXME: should be erase_val?
998 b_tlv.push(0xFF);
999 }
1000
1001 let mut buf = vec![];
1002 buf.append(&mut b_header.to_vec());
1003 buf.append(&mut b_img);
1004 buf.append(&mut b_tlv.clone());
1005
1006 let mut encbuf = vec![];
1007 if is_encrypted {
1008 encbuf.append(&mut b_header.to_vec());
1009 encbuf.append(&mut b_encimg);
1010 encbuf.append(&mut b_tlv);
1011 }
1012
David Vincze2d736ad2019-02-18 11:50:22 +01001013 // Since images are always non-encrypted in the primary slot, we first write
1014 // an encrypted image, re-read to use for verification, erase + flash
1015 // un-encrypted. In the secondary slot the image is written un-encrypted,
1016 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001017
David Brown76101572019-02-28 11:29:03 -07001018 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001019
1020 if slot == 0 {
1021 let enc_copy: Option<Vec<u8>>;
1022
1023 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001024 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001025
1026 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001027 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001028
1029 enc_copy = Some(enc);
1030
David Brown76101572019-02-28 11:29:03 -07001031 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001032 } else {
1033 enc_copy = None;
1034 }
1035
David Brown76101572019-02-28 11:29:03 -07001036 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001037
1038 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001039 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001040
David Brownca234692019-02-28 11:22:19 -07001041 ImageData {
1042 plain: copy,
1043 cipher: enc_copy,
1044 }
David Brown5c9e0f12019-01-09 16:34:33 -07001045 } else {
1046
David Brown76101572019-02-28 11:29:03 -07001047 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001048
1049 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001050 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001051
1052 let enc_copy: Option<Vec<u8>>;
1053
1054 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001055 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001056
David Brown76101572019-02-28 11:29:03 -07001057 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001058
1059 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001060 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001061
1062 enc_copy = Some(enc);
1063 } else {
1064 enc_copy = None;
1065 }
1066
David Brownca234692019-02-28 11:22:19 -07001067 ImageData {
1068 plain: copy,
1069 cipher: enc_copy,
1070 }
David Brown5c9e0f12019-01-09 16:34:33 -07001071 }
David Brown5c9e0f12019-01-09 16:34:33 -07001072}
1073
David Brown5c9e0f12019-01-09 16:34:33 -07001074fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001075 if Caps::EcdsaP224.present() {
1076 panic!("Ecdsa P224 not supported in Simulator");
1077 }
David Brown5c9e0f12019-01-09 16:34:33 -07001078
David Brownb8882112019-01-11 14:04:11 -07001079 if Caps::EncKw.present() {
1080 if Caps::RSA2048.present() {
1081 TlvGen::new_rsa_kw()
1082 } else if Caps::EcdsaP256.present() {
1083 TlvGen::new_ecdsa_kw()
1084 } else {
1085 TlvGen::new_enc_kw()
1086 }
1087 } else if Caps::EncRsa.present() {
1088 if Caps::RSA2048.present() {
1089 TlvGen::new_sig_enc_rsa()
1090 } else {
1091 TlvGen::new_enc_rsa()
1092 }
1093 } else {
1094 // The non-encrypted configuration.
1095 if Caps::RSA2048.present() {
1096 TlvGen::new_rsa_pss()
1097 } else if Caps::EcdsaP256.present() {
1098 TlvGen::new_ecdsa()
1099 } else {
1100 TlvGen::new_hash_only()
1101 }
1102 }
David Brown5c9e0f12019-01-09 16:34:33 -07001103}
1104
David Brownca234692019-02-28 11:22:19 -07001105impl ImageData {
1106 /// Find the image contents for the given slot. This assumes that slot 0
1107 /// is unencrypted, and slot 1 is encrypted.
1108 fn find(&self, slot: usize) -> &Vec<u8> {
1109 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1110 match (encrypted, slot) {
1111 (false, _) => &self.plain,
1112 (true, 0) => &self.plain,
1113 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1114 _ => panic!("Invalid slot requested"),
1115 }
David Brown5c9e0f12019-01-09 16:34:33 -07001116 }
1117}
1118
David Brown5c9e0f12019-01-09 16:34:33 -07001119/// Verify that given image is present in the flash at the given offset.
David Brown76101572019-02-28 11:29:03 -07001120fn verify_image(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brownca234692019-02-28 11:22:19 -07001121 images: &ImageData) -> bool {
1122 let image = images.find(slot);
David Brown5c9e0f12019-01-09 16:34:33 -07001123 let buf = image.as_slice();
1124 let dev_id = slots[slot].dev_id;
1125
1126 let mut copy = vec![0u8; buf.len()];
1127 let offset = slots[slot].base_off;
David Brown76101572019-02-28 11:29:03 -07001128 let dev = flash.get(&dev_id).unwrap();
1129 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001130
1131 if buf != &copy[..] {
1132 for i in 0 .. buf.len() {
1133 if buf[i] != copy[i] {
1134 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1135 slot, offset + i, buf[i], copy[i]);
1136 break;
1137 }
1138 }
1139 false
1140 } else {
1141 true
1142 }
1143}
1144
David Brown76101572019-02-28 11:29:03 -07001145fn verify_trailer(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001146 magic: Option<u8>, image_ok: Option<u8>,
1147 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001148 if Caps::OverwriteUpgrade.present() {
1149 return true;
1150 }
David Brown5c9e0f12019-01-09 16:34:33 -07001151
David Brown5c9e0f12019-01-09 16:34:33 -07001152 let offset = slots[slot].trailer_off;
1153 let dev_id = slots[slot].dev_id;
1154 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1155 let mut failed = false;
1156
David Brown76101572019-02-28 11:29:03 -07001157 let dev = flash.get(&dev_id).unwrap();
1158 let erased_val = dev.erased_val();
1159 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001160
1161 failed |= match magic {
1162 Some(v) => {
1163 if v == 1 && &copy[16..] != MAGIC.unwrap() {
1164 warn!("\"magic\" mismatch at {:#x}", offset);
1165 true
1166 } else if v == 3 {
1167 let expected = [erased_val; 16];
1168 if &copy[16..] != expected {
1169 warn!("\"magic\" mismatch at {:#x}", offset);
1170 true
1171 } else {
1172 false
1173 }
1174 } else {
1175 false
1176 }
1177 },
1178 None => false,
1179 };
1180
1181 failed |= match image_ok {
1182 Some(v) => {
1183 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1184 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1185 true
1186 } else {
1187 false
1188 }
1189 },
1190 None => false,
1191 };
1192
1193 failed |= match copy_done {
1194 Some(v) => {
1195 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1196 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1197 true
1198 } else {
1199 false
1200 }
1201 },
1202 None => false,
1203 };
1204
1205 !failed
1206}
1207
1208/// The image header
1209#[repr(C)]
1210pub struct ImageHeader {
1211 magic: u32,
1212 load_addr: u32,
1213 hdr_size: u16,
1214 _pad1: u16,
1215 img_size: u32,
1216 flags: u32,
1217 ver: ImageVersion,
1218 _pad2: u32,
1219}
1220
1221impl AsRaw for ImageHeader {}
1222
1223#[repr(C)]
1224pub struct ImageVersion {
1225 major: u8,
1226 minor: u8,
1227 revision: u16,
1228 build_num: u32,
1229}
1230
1231#[derive(Clone)]
1232pub struct SlotInfo {
1233 pub base_off: usize,
1234 pub trailer_off: usize,
1235 pub len: usize,
1236 pub dev_id: u8,
1237}
1238
David Brown5c9e0f12019-01-09 16:34:33 -07001239const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1240 0x60, 0xd2, 0xef, 0x7f,
1241 0x35, 0x52, 0x50, 0x0f,
1242 0x2c, 0xb6, 0x79, 0x80]);
1243
1244// Replicates defines found in bootutil.h
1245const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1246const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1247
1248const BOOT_FLAG_SET: Option<u8> = Some(1);
1249const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1250
1251/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001252pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1253 let dev = flash.get_mut(&slot.dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001254 let offset = slot.trailer_off + c::boot_max_align() * 2;
David Brown76101572019-02-28 11:29:03 -07001255 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001256}
1257
1258/// Writes the image_ok flag which, guess what, tells the bootloader
1259/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001260fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1261 let dev = flash.get_mut(&slot.dev_id).unwrap();
1262 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001263 ok[0] = 1u8;
1264 let off = slot.trailer_off + c::boot_max_align();
David Brown76101572019-02-28 11:29:03 -07001265 let align = dev.align();
1266 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001267}
1268
1269// Drop some pseudo-random gibberish onto the data.
1270fn splat(data: &mut [u8], seed: usize) {
1271 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1272 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1273 rng.fill_bytes(data);
1274}
1275
1276/// Return a read-only view into the raw bytes of this object
1277trait AsRaw : Sized {
1278 fn as_raw<'a>(&'a self) -> &'a [u8] {
1279 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1280 mem::size_of::<Self>()) }
1281 }
1282}
1283
1284pub fn show_sizes() {
1285 // This isn't panic safe.
1286 for min in &[1, 2, 4, 8] {
1287 let msize = c::boot_trailer_sz(*min);
1288 println!("{:2}: {} (0x{:x})", min, msize, msize);
1289 }
1290}