blob: b940b6e2d3834ef7473428bcfcba265e0ad24bea [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
19use simflash::{Flash, SimFlashMap};
20use mcuboot_sys::{c, AreaDesc};
21use crate::caps::Caps;
22use crate::tlv::{TlvGen, TlvFlags, AES_SEC_KEY};
23
24impl Images {
25 /// A simple upgrade without forced failures.
26 ///
27 /// Returns the number of flash operations which can later be used to
28 /// inject failures at chosen steps.
29 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
30 let (flashmap, total_count) = try_upgrade(&self.flashmap, &self, None);
31 info!("Total flash operation count={}", total_count);
32
33 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
34 warn!("Image mismatch after first boot");
35 Err(())
36 } else {
37 Ok(total_count)
38 }
39 }
40
David Brown5c9e0f12019-01-09 16:34:33 -070041 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -070042 if Caps::OverwriteUpgrade.present() {
43 return false;
44 }
David Brown5c9e0f12019-01-09 16:34:33 -070045
David Brown5c9e0f12019-01-09 16:34:33 -070046 let mut fails = 0;
47
48 // FIXME: this test would also pass if no swap is ever performed???
49 if Caps::SwapUpgrade.present() {
50 for count in 2 .. 5 {
51 info!("Try revert: {}", count);
52 let flashmap = try_revert(&self.flashmap, &self.areadesc, count);
53 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
54 error!("Revert failure on count {}", count);
55 fails += 1;
56 }
57 }
58 }
59
60 fails > 0
61 }
62
63 pub fn run_perm_with_fails(&self) -> bool {
64 let mut fails = 0;
65 let total_flash_ops = self.total_count.unwrap();
66
67 // Let's try an image halfway through.
68 for i in 1 .. total_flash_ops {
69 info!("Try interruption at {}", i);
70 let (flashmap, count) = try_upgrade(&self.flashmap, &self, Some(i));
71 info!("Second boot, count={}", count);
72 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
73 warn!("FAIL at step {} of {}", i, total_flash_ops);
74 fails += 1;
75 }
76
77 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
78 BOOT_FLAG_SET, BOOT_FLAG_SET) {
79 warn!("Mismatched trailer for Slot 0");
80 fails += 1;
81 }
82
83 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
84 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
85 warn!("Mismatched trailer for Slot 1");
86 fails += 1;
87 }
88
89 if Caps::SwapUpgrade.present() {
90 if !verify_image(&flashmap, &self.slots, 1, &self.primaries) {
91 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
92 fails += 1;
93 }
94 }
95 }
96
97 if fails > 0 {
98 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
99 fails as f32 * 100.0 / total_flash_ops as f32);
100 }
101
102 fails > 0
103 }
104
105 pub fn run_perm_with_random_fails_5(&self) -> bool {
106 self.run_perm_with_random_fails(5)
107 }
108
109 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
110 let mut fails = 0;
111 let total_flash_ops = self.total_count.unwrap();
112 let (flashmap, total_counts) = try_random_fails(&self.flashmap, &self,
113 total_flash_ops, total_fails);
114 info!("Random interruptions at reset points={:?}", total_counts);
115
116 let slot0_ok = verify_image(&flashmap, &self.slots, 0, &self.upgrades);
117 let slot1_ok = if Caps::SwapUpgrade.present() {
118 verify_image(&flashmap, &self.slots, 1, &self.primaries)
119 } else {
120 true
121 };
122 if !slot0_ok || !slot1_ok {
123 error!("Image mismatch after random interrupts: slot0={} slot1={}",
124 if slot0_ok { "ok" } else { "fail" },
125 if slot1_ok { "ok" } else { "fail" });
126 fails += 1;
127 }
128 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
129 BOOT_FLAG_SET, BOOT_FLAG_SET) {
130 error!("Mismatched trailer for Slot 0");
131 fails += 1;
132 }
133 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
134 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
135 error!("Mismatched trailer for Slot 1");
136 fails += 1;
137 }
138
139 if fails > 0 {
140 error!("Error testing perm upgrade with {} fails", total_fails);
141 }
142
143 fails > 0
144 }
145
David Brown5c9e0f12019-01-09 16:34:33 -0700146 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700147 if Caps::OverwriteUpgrade.present() {
148 return false;
149 }
David Brown5c9e0f12019-01-09 16:34:33 -0700150
David Brown5c9e0f12019-01-09 16:34:33 -0700151 let mut fails = 0;
152
153 if Caps::SwapUpgrade.present() {
154 for i in 1 .. (self.total_count.unwrap() - 1) {
155 info!("Try interruption at {}", i);
156 if try_revert_with_fail_at(&self.flashmap, &self, i) {
157 error!("Revert failed at interruption {}", i);
158 fails += 1;
159 }
160 }
161 }
162
163 fails > 0
164 }
165
David Brown5c9e0f12019-01-09 16:34:33 -0700166 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700167 if Caps::OverwriteUpgrade.present() {
168 return false;
169 }
David Brown5c9e0f12019-01-09 16:34:33 -0700170
David Brown5c9e0f12019-01-09 16:34:33 -0700171 let mut flashmap = self.flashmap.clone();
172 let mut fails = 0;
173
174 info!("Try norevert");
175
176 // First do a normal upgrade...
177 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
178 if result != 0 {
179 warn!("Failed first boot");
180 fails += 1;
181 }
182
183 //FIXME: copy_done is written by boot_go, is it ok if no copy
184 // was ever done?
185
186 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
187 warn!("Slot 0 image verification FAIL");
188 fails += 1;
189 }
190 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
191 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
192 warn!("Mismatched trailer for Slot 0");
193 fails += 1;
194 }
195 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
196 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
197 warn!("Mismatched trailer for Slot 1");
198 fails += 1;
199 }
200
201 // Marks image in slot0 as permanent, no revert should happen...
202 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
203
204 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
205 BOOT_FLAG_SET, BOOT_FLAG_SET) {
206 warn!("Mismatched trailer for Slot 0");
207 fails += 1;
208 }
209
210 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
211 if result != 0 {
212 warn!("Failed second boot");
213 fails += 1;
214 }
215
216 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
217 BOOT_FLAG_SET, BOOT_FLAG_SET) {
218 warn!("Mismatched trailer for Slot 0");
219 fails += 1;
220 }
221 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
222 warn!("Failed image verification");
223 fails += 1;
224 }
225
226 if fails > 0 {
227 error!("Error running upgrade without revert");
228 }
229
230 fails > 0
231 }
232
233 // Tests a new image written to slot0 that already has magic and image_ok set
234 // while there is no image on slot1, so no revert should ever happen...
235 pub fn run_norevert_newimage(&self) -> bool {
236 let mut flashmap = self.flashmap.clone();
237 let mut fails = 0;
238
239 info!("Try non-revert on imgtool generated image");
240
241 mark_upgrade(&mut flashmap, &self.slots[0]);
242
243 // This simulates writing an image created by imgtool to Slot 0
244 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
245 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
246 warn!("Mismatched trailer for Slot 0");
247 fails += 1;
248 }
249
250 // Run the bootloader...
251 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
252 if result != 0 {
253 warn!("Failed first boot");
254 fails += 1;
255 }
256
257 // State should not have changed
258 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
259 warn!("Failed image verification");
260 fails += 1;
261 }
262 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
263 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
264 warn!("Mismatched trailer for Slot 0");
265 fails += 1;
266 }
267 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
268 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
269 warn!("Mismatched trailer for Slot 1");
270 fails += 1;
271 }
272
273 if fails > 0 {
274 error!("Expected a non revert with new image");
275 }
276
277 fails > 0
278 }
279
280 // Tests a new image written to slot0 that already has magic and image_ok set
281 // while there is no image on slot1, so no revert should ever happen...
282 pub fn run_signfail_upgrade(&self) -> bool {
283 let mut flashmap = self.flashmap.clone();
284 let mut fails = 0;
285
286 info!("Try upgrade image with bad signature");
287
288 mark_upgrade(&mut flashmap, &self.slots[0]);
289 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
290 mark_upgrade(&mut flashmap, &self.slots[1]);
291
292 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
293 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
294 warn!("Mismatched trailer for Slot 0");
295 fails += 1;
296 }
297
298 // Run the bootloader...
299 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
300 if result != 0 {
301 warn!("Failed first boot");
302 fails += 1;
303 }
304
305 // State should not have changed
306 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
307 warn!("Failed image verification");
308 fails += 1;
309 }
310 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
311 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
312 warn!("Mismatched trailer for Slot 0");
313 fails += 1;
314 }
315
316 if fails > 0 {
317 error!("Expected an upgrade failure when image has bad signature");
318 }
319
320 fails > 0
321 }
322
David Brown5c9e0f12019-01-09 16:34:33 -0700323 fn trailer_sz(&self, align: usize) -> usize {
324 c::boot_trailer_sz(align as u8) as usize
325 }
326
327 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700328 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700329 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
330 32
331 } else {
332 0
333 };
David Brown5c9e0f12019-01-09 16:34:33 -0700334
David Brown9930a3e2019-01-11 12:28:26 -0700335 self.trailer_sz(align) - (16 + 24 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700336 }
337
338 /// This test runs a simple upgrade with no fails in the images, but
339 /// allowing for fails in the status area. This should run to the end
340 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700341 pub fn run_with_status_fails_complete(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700342 if !Caps::ValidateSlot0.present() {
343 return false;
344 }
345
David Brown5c9e0f12019-01-09 16:34:33 -0700346 let mut flashmap = self.flashmap.clone();
347 let mut fails = 0;
348
349 info!("Try swap with status fails");
350
351 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
352 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
353
354 let (result, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
355 if result != 0 {
356 warn!("Failed!");
357 fails += 1;
358 }
359
360 // Failed writes to the marked "bad" region don't assert anymore.
361 // Any detected assert() is happening in another part of the code.
362 if asserts != 0 {
363 warn!("At least one assert() was called");
364 fails += 1;
365 }
366
367 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
368 BOOT_FLAG_SET, BOOT_FLAG_SET) {
369 warn!("Mismatched trailer for Slot 0");
370 fails += 1;
371 }
372
373 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
374 warn!("Failed image verification");
375 fails += 1;
376 }
377
378 info!("validate slot0 enabled; re-run of boot_go should just work");
379 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
380 if result != 0 {
381 warn!("Failed!");
382 fails += 1;
383 }
384
385 if fails > 0 {
386 error!("Error running upgrade with status write fails");
387 }
388
389 fails > 0
390 }
391
392 /// This test runs a simple upgrade with no fails in the images, but
393 /// allowing for fails in the status area. This should run to the end
394 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700395 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700396 if Caps::OverwriteUpgrade.present() {
397 false
398 } else if Caps::ValidateSlot0.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700399
David Brown85904a82019-01-11 13:45:12 -0700400 let mut flashmap = self.flashmap.clone();
401 let mut fails = 0;
402 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700403
David Brown85904a82019-01-11 13:45:12 -0700404 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700405
David Brown85904a82019-01-11 13:45:12 -0700406 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700407
David Brown85904a82019-01-11 13:45:12 -0700408 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
409 self.mark_bad_status_with_rate(&mut flashmap, 0, 0.5);
410
411 // Should not fail, writing to bad regions does not assert
412 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, Some(&mut count), true);
413 if asserts != 0 {
414 warn!("At least one assert() was called");
415 fails += 1;
416 }
417
418 self.reset_bad_status(&mut flashmap, 0);
419
420 info!("Resuming an interrupted swap operation");
421 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
422
423 // This might throw no asserts, for large sector devices, where
424 // a single failure writing is indistinguishable from no failure,
425 // or throw a single assert for small sector devices that fail
426 // multiple times...
427 if asserts > 1 {
428 warn!("Expected single assert validating slot0, more detected {}", asserts);
429 fails += 1;
430 }
431
432 if fails > 0 {
433 error!("Error running upgrade with status write fails");
434 }
435
436 fails > 0
437 } else {
438 let mut flashmap = self.flashmap.clone();
439 let mut fails = 0;
440
441 info!("Try interrupted swap with status fails");
442
443 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
444 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
445
446 // This is expected to fail while writing to bad regions...
447 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
448 if asserts == 0 {
449 warn!("No assert() detected");
450 fails += 1;
451 }
452
453 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700454 }
David Brown5c9e0f12019-01-09 16:34:33 -0700455 }
456
457 /// Adds a new flash area that fails statistically
David Brown5c9e0f12019-01-09 16:34:33 -0700458 fn mark_bad_status_with_rate(&self, flashmap: &mut SimFlashMap, slot: usize,
459 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700460 if Caps::OverwriteUpgrade.present() {
461 return;
462 }
463
David Brown5c9e0f12019-01-09 16:34:33 -0700464 let dev_id = &self.slots[slot].dev_id;
465 let flash = flashmap.get_mut(&dev_id).unwrap();
466 let align = flash.align();
467 let off = &self.slots[0].base_off;
468 let len = &self.slots[0].len;
469 let status_off = off + len - self.trailer_sz(align);
470
471 // Mark the status area as a bad area
472 let _ = flash.add_bad_region(status_off, self.status_sz(align), rate);
473 }
474
David Brown5c9e0f12019-01-09 16:34:33 -0700475 fn reset_bad_status(&self, flashmap: &mut SimFlashMap, slot: usize) {
David Brown85904a82019-01-11 13:45:12 -0700476 if !Caps::ValidateSlot0.present() {
477 return;
478 }
479
David Brown5c9e0f12019-01-09 16:34:33 -0700480 let dev_id = &self.slots[slot].dev_id;
481 let flash = flashmap.get_mut(&dev_id).unwrap();
482 flash.reset_bad_regions();
483
484 // Disabling write verification the only assert triggered by
485 // boot_go should be checking for integrity of status bytes.
486 flash.set_verify_writes(false);
487 }
488
David Brown5c9e0f12019-01-09 16:34:33 -0700489}
490
491/// Test a boot, optionally stopping after 'n' flash options. Returns a count
492/// of the number of flash operations done total.
493fn try_upgrade(flashmap: &SimFlashMap, images: &Images,
494 stop: Option<i32>) -> (SimFlashMap, i32) {
495 // Clone the flash to have a new copy.
496 let mut flashmap = flashmap.clone();
497
498 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
499
500 let mut counter = stop.unwrap_or(0);
501
502 let (first_interrupted, count) = match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
503 (-0x13579, _) => (true, stop.unwrap()),
504 (0, _) => (false, -counter),
505 (x, _) => panic!("Unknown return: {}", x),
506 };
507
508 counter = 0;
509 if first_interrupted {
510 // fl.dump();
511 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
512 (-0x13579, _) => panic!("Shouldn't stop again"),
513 (0, _) => (),
514 (x, _) => panic!("Unknown return: {}", x),
515 }
516 }
517
518 (flashmap, count - counter)
519}
520
David Brown5c9e0f12019-01-09 16:34:33 -0700521fn try_revert(flashmap: &SimFlashMap, areadesc: &AreaDesc, count: usize) -> SimFlashMap {
522 let mut flashmap = flashmap.clone();
523
524 // fl.write_file("image0.bin").unwrap();
525 for i in 0 .. count {
526 info!("Running boot pass {}", i + 1);
527 assert_eq!(c::boot_go(&mut flashmap, &areadesc, None, false), (0, 0));
528 }
529 flashmap
530}
531
David Brown5c9e0f12019-01-09 16:34:33 -0700532fn try_revert_with_fail_at(flashmap: &SimFlashMap, images: &Images,
533 stop: i32) -> bool {
534 let mut flashmap = flashmap.clone();
535 let mut fails = 0;
536
537 let mut counter = stop;
538 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false);
539 if x != -0x13579 {
540 warn!("Should have stopped at interruption point");
541 fails += 1;
542 }
543
544 if !verify_trailer(&flashmap, &images.slots, 0, None, None, BOOT_FLAG_UNSET) {
545 warn!("copy_done should be unset");
546 fails += 1;
547 }
548
549 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
550 if x != 0 {
551 warn!("Should have finished upgrade");
552 fails += 1;
553 }
554
555 if !verify_image(&flashmap, &images.slots, 0, &images.upgrades) {
556 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
557 fails += 1;
558 }
559 if !verify_image(&flashmap, &images.slots, 1, &images.primaries) {
560 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
561 fails += 1;
562 }
563 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
564 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
565 warn!("Mismatched trailer for Slot 0 before revert");
566 fails += 1;
567 }
568 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
569 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
570 warn!("Mismatched trailer for Slot 1 before revert");
571 fails += 1;
572 }
573
574 // Do Revert
575 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
576 if x != 0 {
577 warn!("Should have finished a revert");
578 fails += 1;
579 }
580
581 if !verify_image(&flashmap, &images.slots, 0, &images.primaries) {
582 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
583 fails += 1;
584 }
585 if !verify_image(&flashmap, &images.slots, 1, &images.upgrades) {
586 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
587 fails += 1;
588 }
589 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
590 BOOT_FLAG_SET, BOOT_FLAG_SET) {
591 warn!("Mismatched trailer for Slot 1 after revert");
592 fails += 1;
593 }
594 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
595 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
596 warn!("Mismatched trailer for Slot 1 after revert");
597 fails += 1;
598 }
599
600 fails > 0
601}
602
603fn try_random_fails(flashmap: &SimFlashMap, images: &Images,
604 total_ops: i32, count: usize) -> (SimFlashMap, Vec<i32>) {
605 let mut flashmap = flashmap.clone();
606
607 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
608
609 let mut rng = rand::thread_rng();
610 let mut resets = vec![0i32; count];
611 let mut remaining_ops = total_ops;
612 for i in 0 .. count {
613 let ops = Range::new(1, remaining_ops / 2);
614 let reset_counter = ops.ind_sample(&mut rng);
615 let mut counter = reset_counter;
616 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
617 (0, _) | (-0x13579, _) => (),
618 (x, _) => panic!("Unknown return: {}", x),
619 }
620 remaining_ops -= reset_counter;
621 resets[i] = reset_counter;
622 }
623
624 match c::boot_go(&mut flashmap, &images.areadesc, None, false) {
625 (-0x13579, _) => panic!("Should not be have been interrupted!"),
626 (0, _) => (),
627 (x, _) => panic!("Unknown return: {}", x),
628 }
629
630 (flashmap, resets)
631}
632
633/// Show the flash layout.
634#[allow(dead_code)]
635fn show_flash(flash: &dyn Flash) {
636 println!("---- Flash configuration ----");
637 for sector in flash.sector_iter() {
638 println!(" {:3}: 0x{:08x}, 0x{:08x}",
639 sector.num, sector.base, sector.size);
640 }
641 println!("");
642}
643
644/// Install a "program" into the given image. This fakes the image header, or at least all of the
645/// fields used by the given code. Returns a copy of the image that was written.
646pub fn install_image(flashmap: &mut SimFlashMap, slots: &[SlotInfo], slot: usize, len: usize,
647 bad_sig: bool) -> [Option<Vec<u8>>; 2] {
648 let offset = slots[slot].base_off;
649 let slot_len = slots[slot].len;
650 let dev_id = slots[slot].dev_id;
651
652 let mut tlv = make_tlv();
653
654 const HDR_SIZE: usize = 32;
655
656 // Generate a boot header. Note that the size doesn't include the header.
657 let header = ImageHeader {
658 magic: 0x96f3b83d,
659 load_addr: 0,
660 hdr_size: HDR_SIZE as u16,
661 _pad1: 0,
662 img_size: len as u32,
663 flags: tlv.get_flags(),
664 ver: ImageVersion {
665 major: (offset / (128 * 1024)) as u8,
666 minor: 0,
667 revision: 1,
668 build_num: offset as u32,
669 },
670 _pad2: 0,
671 };
672
673 let mut b_header = [0; HDR_SIZE];
674 b_header[..32].clone_from_slice(header.as_raw());
675 assert_eq!(b_header.len(), HDR_SIZE);
676
677 tlv.add_bytes(&b_header);
678
679 // The core of the image itself is just pseudorandom data.
680 let mut b_img = vec![0; len];
681 splat(&mut b_img, offset);
682
683 // TLV signatures work over plain image
684 tlv.add_bytes(&b_img);
685
686 // Generate encrypted images
687 let flag = TlvFlags::ENCRYPTED as u32;
688 let is_encrypted = (tlv.get_flags() & flag) == flag;
689 let mut b_encimg = vec![];
690 if is_encrypted {
691 let key = GenericArray::from_slice(AES_SEC_KEY);
692 let nonce = GenericArray::from_slice(&[0; 16]);
693 let mut cipher = Aes128Ctr::new(&key, &nonce);
694 b_encimg = b_img.clone();
695 cipher.apply_keystream(&mut b_encimg);
696 }
697
698 // Build the TLV itself.
699 let mut b_tlv = if bad_sig {
700 let good_sig = &mut tlv.make_tlv();
701 vec![0; good_sig.len()]
702 } else {
703 tlv.make_tlv()
704 };
705
706 // Pad the block to a flash alignment (8 bytes).
707 while b_tlv.len() % 8 != 0 {
708 //FIXME: should be erase_val?
709 b_tlv.push(0xFF);
710 }
711
712 let mut buf = vec![];
713 buf.append(&mut b_header.to_vec());
714 buf.append(&mut b_img);
715 buf.append(&mut b_tlv.clone());
716
717 let mut encbuf = vec![];
718 if is_encrypted {
719 encbuf.append(&mut b_header.to_vec());
720 encbuf.append(&mut b_encimg);
721 encbuf.append(&mut b_tlv);
722 }
723
724 let result: [Option<Vec<u8>>; 2];
725
726 // Since images are always non-encrypted in slot0, we first write an
727 // encrypted image, re-read to use for verification, erase + flash
728 // un-encrypted. In slot1 the image is written un-encrypted, and if
729 // encryption is requested, it follows an erase + flash encrypted.
730
731 let flash = flashmap.get_mut(&dev_id).unwrap();
732
733 if slot == 0 {
734 let enc_copy: Option<Vec<u8>>;
735
736 if is_encrypted {
737 flash.write(offset, &encbuf).unwrap();
738
739 let mut enc = vec![0u8; encbuf.len()];
740 flash.read(offset, &mut enc).unwrap();
741
742 enc_copy = Some(enc);
743
744 flash.erase(offset, slot_len).unwrap();
745 } else {
746 enc_copy = None;
747 }
748
749 flash.write(offset, &buf).unwrap();
750
751 let mut copy = vec![0u8; buf.len()];
752 flash.read(offset, &mut copy).unwrap();
753
754 result = [Some(copy), enc_copy];
755 } else {
756
757 flash.write(offset, &buf).unwrap();
758
759 let mut copy = vec![0u8; buf.len()];
760 flash.read(offset, &mut copy).unwrap();
761
762 let enc_copy: Option<Vec<u8>>;
763
764 if is_encrypted {
765 flash.erase(offset, slot_len).unwrap();
766
767 flash.write(offset, &encbuf).unwrap();
768
769 let mut enc = vec![0u8; encbuf.len()];
770 flash.read(offset, &mut enc).unwrap();
771
772 enc_copy = Some(enc);
773 } else {
774 enc_copy = None;
775 }
776
777 result = [Some(copy), enc_copy];
778 }
779
780 result
781}
782
David Brown5c9e0f12019-01-09 16:34:33 -0700783fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -0700784 if Caps::EcdsaP224.present() {
785 panic!("Ecdsa P224 not supported in Simulator");
786 }
David Brown5c9e0f12019-01-09 16:34:33 -0700787
David Brownb8882112019-01-11 14:04:11 -0700788 if Caps::EncKw.present() {
789 if Caps::RSA2048.present() {
790 TlvGen::new_rsa_kw()
791 } else if Caps::EcdsaP256.present() {
792 TlvGen::new_ecdsa_kw()
793 } else {
794 TlvGen::new_enc_kw()
795 }
796 } else if Caps::EncRsa.present() {
797 if Caps::RSA2048.present() {
798 TlvGen::new_sig_enc_rsa()
799 } else {
800 TlvGen::new_enc_rsa()
801 }
802 } else {
803 // The non-encrypted configuration.
804 if Caps::RSA2048.present() {
805 TlvGen::new_rsa_pss()
806 } else if Caps::EcdsaP256.present() {
807 TlvGen::new_ecdsa()
808 } else {
809 TlvGen::new_hash_only()
810 }
811 }
David Brown5c9e0f12019-01-09 16:34:33 -0700812}
813
David Brown5c9e0f12019-01-09 16:34:33 -0700814fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
David Brownf38bc342019-01-11 14:07:58 -0700815 let slot = if Caps::EncRsa.present() || Caps::EncKw.present() {
816 slot
817 } else {
818 0
819 };
David Brown5c9e0f12019-01-09 16:34:33 -0700820
David Brown5c9e0f12019-01-09 16:34:33 -0700821 match &images[slot] {
822 Some(image) => return image,
823 None => panic!("Invalid image"),
824 }
825}
826
David Brown5c9e0f12019-01-09 16:34:33 -0700827/// Verify that given image is present in the flash at the given offset.
828fn verify_image(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
829 images: &[Option<Vec<u8>>; 2]) -> bool {
830 let image = find_image(images, slot);
831 let buf = image.as_slice();
832 let dev_id = slots[slot].dev_id;
833
834 let mut copy = vec![0u8; buf.len()];
835 let offset = slots[slot].base_off;
836 let flash = flashmap.get(&dev_id).unwrap();
837 flash.read(offset, &mut copy).unwrap();
838
839 if buf != &copy[..] {
840 for i in 0 .. buf.len() {
841 if buf[i] != copy[i] {
842 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
843 slot, offset + i, buf[i], copy[i]);
844 break;
845 }
846 }
847 false
848 } else {
849 true
850 }
851}
852
David Brown5c9e0f12019-01-09 16:34:33 -0700853fn verify_trailer(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
854 magic: Option<u8>, image_ok: Option<u8>,
855 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -0700856 if Caps::OverwriteUpgrade.present() {
857 return true;
858 }
David Brown5c9e0f12019-01-09 16:34:33 -0700859
David Brown5c9e0f12019-01-09 16:34:33 -0700860 let offset = slots[slot].trailer_off;
861 let dev_id = slots[slot].dev_id;
862 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
863 let mut failed = false;
864
865 let flash = flashmap.get(&dev_id).unwrap();
866 let erased_val = flash.erased_val();
867 flash.read(offset, &mut copy).unwrap();
868
869 failed |= match magic {
870 Some(v) => {
871 if v == 1 && &copy[16..] != MAGIC.unwrap() {
872 warn!("\"magic\" mismatch at {:#x}", offset);
873 true
874 } else if v == 3 {
875 let expected = [erased_val; 16];
876 if &copy[16..] != expected {
877 warn!("\"magic\" mismatch at {:#x}", offset);
878 true
879 } else {
880 false
881 }
882 } else {
883 false
884 }
885 },
886 None => false,
887 };
888
889 failed |= match image_ok {
890 Some(v) => {
891 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
892 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
893 true
894 } else {
895 false
896 }
897 },
898 None => false,
899 };
900
901 failed |= match copy_done {
902 Some(v) => {
903 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
904 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
905 true
906 } else {
907 false
908 }
909 },
910 None => false,
911 };
912
913 !failed
914}
915
916/// The image header
917#[repr(C)]
918pub struct ImageHeader {
919 magic: u32,
920 load_addr: u32,
921 hdr_size: u16,
922 _pad1: u16,
923 img_size: u32,
924 flags: u32,
925 ver: ImageVersion,
926 _pad2: u32,
927}
928
929impl AsRaw for ImageHeader {}
930
931#[repr(C)]
932pub struct ImageVersion {
933 major: u8,
934 minor: u8,
935 revision: u16,
936 build_num: u32,
937}
938
939#[derive(Clone)]
940pub struct SlotInfo {
941 pub base_off: usize,
942 pub trailer_off: usize,
943 pub len: usize,
944 pub dev_id: u8,
945}
946
947pub struct Images {
948 pub flashmap: SimFlashMap,
949 pub areadesc: AreaDesc,
950 pub slots: [SlotInfo; 2],
951 pub primaries: [Option<Vec<u8>>; 2],
952 pub upgrades: [Option<Vec<u8>>; 2],
953 pub total_count: Option<i32>,
954}
955
956const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
957 0x60, 0xd2, 0xef, 0x7f,
958 0x35, 0x52, 0x50, 0x0f,
959 0x2c, 0xb6, 0x79, 0x80]);
960
961// Replicates defines found in bootutil.h
962const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
963const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
964
965const BOOT_FLAG_SET: Option<u8> = Some(1);
966const BOOT_FLAG_UNSET: Option<u8> = Some(3);
967
968/// Write out the magic so that the loader tries doing an upgrade.
969pub fn mark_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
970 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
971 let offset = slot.trailer_off + c::boot_max_align() * 2;
972 flash.write(offset, MAGIC.unwrap()).unwrap();
973}
974
975/// Writes the image_ok flag which, guess what, tells the bootloader
976/// the this image is ok (not a test, and no revert is to be performed).
977fn mark_permanent_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
978 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
979 let mut ok = [flash.erased_val(); 8];
980 ok[0] = 1u8;
981 let off = slot.trailer_off + c::boot_max_align();
982 let align = flash.align();
983 flash.write(off, &ok[..align]).unwrap();
984}
985
986// Drop some pseudo-random gibberish onto the data.
987fn splat(data: &mut [u8], seed: usize) {
988 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
989 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
990 rng.fill_bytes(data);
991}
992
993/// Return a read-only view into the raw bytes of this object
994trait AsRaw : Sized {
995 fn as_raw<'a>(&'a self) -> &'a [u8] {
996 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
997 mem::size_of::<Self>()) }
998 }
999}
1000
1001pub fn show_sizes() {
1002 // This isn't panic safe.
1003 for min in &[1, 2, 4, 8] {
1004 let msize = c::boot_trailer_sz(*min);
1005 println!("{:2}: {} (0x{:x})", min, msize, msize);
1006 }
1007}