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