blob: 37b58860f0731dbc3c2aaca438432709e2e9ae06 [file] [log] [blame]
David Brown2639e072017-10-11 11:18:44 -06001#[macro_use] extern crate log;
2extern crate ring;
3extern crate env_logger;
4extern crate docopt;
5extern crate libc;
6extern crate pem;
7extern crate rand;
8#[macro_use] extern crate serde_derive;
9extern crate serde;
10extern crate simflash;
11extern crate untrusted;
12extern crate mcuboot_sys;
13
14use docopt::Docopt;
15use rand::{Rng, SeedableRng, XorShiftRng};
16use rand::distributions::{IndependentSample, Range};
17use std::fmt;
18use std::mem;
19use std::process;
20use std::slice;
21
22mod caps;
23mod tlv;
24
25use simflash::{Flash, SimFlash};
26use mcuboot_sys::{c, AreaDesc, FlashId};
27use caps::Caps;
28use tlv::TlvGen;
29
30const USAGE: &'static str = "
31Mcuboot simulator
32
33Usage:
34 bootsim sizes
35 bootsim run --device TYPE [--align SIZE]
36 bootsim runall
37 bootsim (--help | --version)
38
39Options:
40 -h, --help Show this message
41 --version Version
42 --device TYPE MCU to simulate
43 Valid values: stm32f4, k64f
44 --align SIZE Flash write alignment
45";
46
47#[derive(Debug, Deserialize)]
48struct Args {
49 flag_help: bool,
50 flag_version: bool,
51 flag_device: Option<DeviceName>,
52 flag_align: Option<AlignArg>,
53 cmd_sizes: bool,
54 cmd_run: bool,
55 cmd_runall: bool,
56}
57
58#[derive(Copy, Clone, Debug, Deserialize)]
59enum DeviceName { Stm32f4, K64f, K64fBig, Nrf52840 }
60
61static ALL_DEVICES: &'static [DeviceName] = &[
62 DeviceName::Stm32f4,
63 DeviceName::K64f,
64 DeviceName::K64fBig,
65 DeviceName::Nrf52840,
66];
67
68impl fmt::Display for DeviceName {
69 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 let name = match *self {
71 DeviceName::Stm32f4 => "stm32f4",
72 DeviceName::K64f => "k64f",
73 DeviceName::K64fBig => "k64fbig",
74 DeviceName::Nrf52840 => "nrf52840",
75 };
76 f.write_str(name)
77 }
78}
79
80#[derive(Debug)]
81struct AlignArg(u8);
82
83struct AlignArgVisitor;
84
85impl<'de> serde::de::Visitor<'de> for AlignArgVisitor {
86 type Value = AlignArg;
87
88 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
89 formatter.write_str("1, 2, 4 or 8")
90 }
91
92 fn visit_u8<E>(self, n: u8) -> Result<Self::Value, E>
93 where E: serde::de::Error
94 {
95 Ok(match n {
96 1 | 2 | 4 | 8 => AlignArg(n),
97 n => {
98 let err = format!("Could not deserialize '{}' as alignment", n);
99 return Err(E::custom(err));
100 }
101 })
102 }
103}
104
105impl<'de> serde::de::Deserialize<'de> for AlignArg {
106 fn deserialize<D>(d: D) -> Result<AlignArg, D::Error>
107 where D: serde::de::Deserializer<'de>
108 {
109 d.deserialize_u8(AlignArgVisitor)
110 }
111}
112
113pub fn main() {
114 let args: Args = Docopt::new(USAGE)
115 .and_then(|d| d.deserialize())
116 .unwrap_or_else(|e| e.exit());
117 // println!("args: {:#?}", args);
118
119 if args.cmd_sizes {
120 show_sizes();
121 return;
122 }
123
124 let mut status = RunStatus::new();
125 if args.cmd_run {
126
127 let align = args.flag_align.map(|x| x.0).unwrap_or(1);
128
129
130 let device = match args.flag_device {
131 None => panic!("Missing mandatory device argument"),
132 Some(dev) => dev,
133 };
134
135 status.run_single(device, align);
136 }
137
138 if args.cmd_runall {
139 for &dev in ALL_DEVICES {
140 for &align in &[1, 2, 4, 8] {
141 status.run_single(dev, align);
142 }
143 }
144 }
145
146 if status.failures > 0 {
147 error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
148 process::exit(1);
149 } else {
150 error!("{} Tests ran successfully", status.passes);
151 process::exit(0);
152 }
153}
154
155struct RunStatus {
156 failures: usize,
157 passes: usize,
158}
159
160impl RunStatus {
161 fn new() -> RunStatus {
162 RunStatus {
163 failures: 0,
164 passes: 0,
165 }
166 }
167
168 fn run_single(&mut self, device: DeviceName, align: u8) {
169 warn!("Running on device {} with alignment {}", device, align);
170
171 let (mut flash, areadesc) = match device {
172 DeviceName::Stm32f4 => {
173 // STM style flash. Large sectors, with a large scratch area.
174 let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
175 64 * 1024,
176 128 * 1024, 128 * 1024, 128 * 1024],
177 align as usize);
178 let mut areadesc = AreaDesc::new(&flash);
179 areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
180 areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
181 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch);
182 (flash, areadesc)
183 }
184 DeviceName::K64f => {
185 // NXP style flash. Small sectors, one small sector for scratch.
186 let flash = SimFlash::new(vec![4096; 128], align as usize);
187
188 let mut areadesc = AreaDesc::new(&flash);
189 areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
190 areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
191 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch);
192 (flash, areadesc)
193 }
194 DeviceName::K64fBig => {
195 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
196 // uses small sectors, but we tell the bootloader they are large.
197 let flash = SimFlash::new(vec![4096; 128], align as usize);
198
199 let mut areadesc = AreaDesc::new(&flash);
200 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0);
201 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1);
202 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch);
203 (flash, areadesc)
204 }
205 DeviceName::Nrf52840 => {
206 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
207 // does not divide into the image size.
208 let flash = SimFlash::new(vec![4096; 128], align as usize);
209
210 let mut areadesc = AreaDesc::new(&flash);
211 areadesc.add_image(0x008000, 0x034000, FlashId::Image0);
212 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1);
213 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch);
214 (flash, areadesc)
215 }
216 };
217
218 let (slot0_base, slot0_len) = areadesc.find(FlashId::Image0);
219 let (slot1_base, slot1_len) = areadesc.find(FlashId::Image1);
220 let (scratch_base, _) = areadesc.find(FlashId::ImageScratch);
221
222 // Code below assumes that the slots are consecutive.
223 assert_eq!(slot1_base, slot0_base + slot0_len);
224 assert_eq!(scratch_base, slot1_base + slot1_len);
225
226 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
227
228 // println!("Areas: {:#?}", areadesc.get_c());
229
230 // Install the boot trailer signature, so that the code will start an upgrade.
231 // TODO: This must be a multiple of flash alignment, add support for an image that is smaller,
232 // and just gets padded.
233
234 // Create original and upgrade images
235 let slot0 = SlotInfo {
236 base_off: slot0_base as usize,
237 trailer_off: slot1_base - offset_from_end,
238 };
239
240 let slot1 = SlotInfo {
241 base_off: slot1_base as usize,
242 trailer_off: scratch_base - offset_from_end,
243 };
244
245 // Set an alignment, and position the magic value.
246 c::set_sim_flash_align(align);
247
248 let mut failed = false;
249
250 // Creates a badly signed image in slot1 to check that it is not
251 // upgraded to
252 let mut bad_flash = flash.clone();
253 let bad_slot1_image = Images {
254 slot0: &slot0,
255 slot1: &slot1,
256 primary: install_image(&mut bad_flash, slot0_base, 32784, false),
257 upgrade: install_image(&mut bad_flash, slot1_base, 41928, true),
258 };
259
260 failed |= run_signfail_upgrade(&bad_flash, &areadesc, &bad_slot1_image);
261
262 let images = Images {
263 slot0: &slot0,
264 slot1: &slot1,
265 primary: install_image(&mut flash, slot0_base, 32784, false),
266 upgrade: install_image(&mut flash, slot1_base, 41928, false),
267 };
268
269 failed |= run_norevert_newimage(&flash, &areadesc, &images);
270
271 mark_upgrade(&mut flash, &images.slot1);
272
273 // upgrades without fails, counts number of flash operations
274 let total_count = match run_basic_upgrade(&flash, &areadesc, &images) {
275 Ok(v) => v,
276 Err(_) => {
277 self.failures += 1;
278 return;
279 },
280 };
281
282 failed |= run_basic_revert(&flash, &areadesc, &images);
283 failed |= run_revert_with_fails(&flash, &areadesc, &images, total_count);
284 failed |= run_perm_with_fails(&flash, &areadesc, &images, total_count);
285 failed |= run_perm_with_random_fails(&flash, &areadesc, &images,
286 total_count, 5);
287 failed |= run_norevert(&flash, &areadesc, &images);
288
289 //show_flash(&flash);
290
291 if failed {
292 self.failures += 1;
293 } else {
294 self.passes += 1;
295 }
296 }
297}
298
299/// A simple upgrade without forced failures.
300///
301/// Returns the number of flash operations which can later be used to
302/// inject failures at chosen steps.
303fn run_basic_upgrade(flash: &SimFlash, areadesc: &AreaDesc, images: &Images)
304 -> Result<i32, ()> {
305 let (fl, total_count) = try_upgrade(&flash, &areadesc, &images, None);
306 info!("Total flash operation count={}", total_count);
307
308 if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
309 warn!("Image mismatch after first boot");
310 Err(())
311 } else {
312 Ok(total_count)
313 }
314}
315
316#[cfg(feature = "overwrite-only")]
317#[allow(unused_variables)]
318fn run_basic_revert(flash: &SimFlash, areadesc: &AreaDesc, images: &Images) -> bool {
319 false
320}
321
322#[cfg(not(feature = "overwrite-only"))]
323fn run_basic_revert(flash: &SimFlash, areadesc: &AreaDesc, images: &Images) -> bool {
324 let mut fails = 0;
325
326 // FIXME: this test would also pass if no swap is ever performed???
327 if Caps::SwapUpgrade.present() {
328 for count in 2 .. 5 {
329 info!("Try revert: {}", count);
330 let fl = try_revert(&flash, &areadesc, count);
331 if !verify_image(&fl, images.slot0.base_off, &images.primary) {
332 error!("Revert failure on count {}", count);
333 fails += 1;
334 }
335 }
336 }
337
338 fails > 0
339}
340
341fn run_perm_with_fails(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
342 total_flash_ops: i32) -> bool {
343 let mut fails = 0;
344
345 // Let's try an image halfway through.
346 for i in 1 .. total_flash_ops {
347 info!("Try interruption at {}", i);
348 let (fl, count) = try_upgrade(&flash, &areadesc, &images, Some(i));
349 info!("Second boot, count={}", count);
350 if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
351 warn!("FAIL at step {} of {}", i, total_flash_ops);
352 fails += 1;
353 }
354
355 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
356 COPY_DONE) {
357 warn!("Mismatched trailer for Slot 0");
358 fails += 1;
359 }
360
361 if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
362 UNSET) {
363 warn!("Mismatched trailer for Slot 1");
364 fails += 1;
365 }
366
367 if Caps::SwapUpgrade.present() {
368 if !verify_image(&fl, images.slot1.base_off, &images.primary) {
369 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
370 fails += 1;
371 }
372 }
373 }
374
375 if fails > 0 {
376 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
377 fails as f32 * 100.0 / total_flash_ops as f32);
378 }
379
380 fails > 0
381}
382
383fn run_perm_with_random_fails(flash: &SimFlash, areadesc: &AreaDesc,
384 images: &Images, total_flash_ops: i32,
385 total_fails: usize) -> bool {
386 let mut fails = 0;
387 let (fl, total_counts) = try_random_fails(&flash, &areadesc, &images,
388 total_flash_ops, total_fails);
389 info!("Random interruptions at reset points={:?}", total_counts);
390
391 let slot0_ok = verify_image(&fl, images.slot0.base_off, &images.upgrade);
392 let slot1_ok = if Caps::SwapUpgrade.present() {
393 verify_image(&fl, images.slot1.base_off, &images.primary)
394 } else {
395 true
396 };
397 if !slot0_ok || !slot1_ok {
398 error!("Image mismatch after random interrupts: slot0={} slot1={}",
399 if slot0_ok { "ok" } else { "fail" },
400 if slot1_ok { "ok" } else { "fail" });
401 fails += 1;
402 }
403 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
404 COPY_DONE) {
405 error!("Mismatched trailer for Slot 0");
406 fails += 1;
407 }
408 if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
409 UNSET) {
410 error!("Mismatched trailer for Slot 1");
411 fails += 1;
412 }
413
414 if fails > 0 {
415 error!("Error testing perm upgrade with {} fails", total_fails);
416 }
417
418 fails > 0
419}
420
421#[cfg(feature = "overwrite-only")]
422#[allow(unused_variables)]
423fn run_revert_with_fails(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
424 total_count: i32) -> bool {
425 false
426}
427
428#[cfg(not(feature = "overwrite-only"))]
429fn run_revert_with_fails(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
430 total_count: i32) -> bool {
431 let mut fails = 0;
432
433 if Caps::SwapUpgrade.present() {
434 for i in 1 .. (total_count - 1) {
435 info!("Try interruption at {}", i);
436 if try_revert_with_fail_at(&flash, &areadesc, &images, i) {
437 error!("Revert failed at interruption {}", i);
438 fails += 1;
439 }
440 }
441 }
442
443 fails > 0
444}
445
446#[cfg(feature = "overwrite-only")]
447#[allow(unused_variables)]
448fn run_norevert(flash: &SimFlash, areadesc: &AreaDesc, images: &Images) -> bool {
449 false
450}
451
452#[cfg(not(feature = "overwrite-only"))]
453fn run_norevert(flash: &SimFlash, areadesc: &AreaDesc, images: &Images) -> bool {
454 let mut fl = flash.clone();
455 let mut fails = 0;
456
457 info!("Try norevert");
458 c::set_flash_counter(0);
459
460 // First do a normal upgrade...
461 if c::boot_go(&mut fl, &areadesc) != 0 {
462 warn!("Failed first boot");
463 fails += 1;
464 }
465
466 //FIXME: copy_done is written by boot_go, is it ok if no copy
467 // was ever done?
468
469 if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
470 warn!("Slot 0 image verification FAIL");
471 fails += 1;
472 }
473 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, UNSET,
474 COPY_DONE) {
475 warn!("Mismatched trailer for Slot 0");
476 fails += 1;
477 }
478 if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
479 UNSET) {
480 warn!("Mismatched trailer for Slot 1");
481 fails += 1;
482 }
483
484 // Marks image in slot0 as permanent, no revert should happen...
485 mark_permanent_upgrade(&mut fl, &images.slot0);
486
487 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
488 COPY_DONE) {
489 warn!("Mismatched trailer for Slot 0");
490 fails += 1;
491 }
492
493 if c::boot_go(&mut fl, &areadesc) != 0 {
494 warn!("Failed second boot");
495 fails += 1;
496 }
497
498 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
499 COPY_DONE) {
500 warn!("Mismatched trailer for Slot 0");
501 fails += 1;
502 }
503 if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
504 warn!("Failed image verification");
505 fails += 1;
506 }
507
508 if fails > 0 {
509 error!("Error running upgrade without revert");
510 }
511
512 fails > 0
513}
514
515// Tests a new image written to slot0 that already has magic and image_ok set
516// while there is no image on slot1, so no revert should ever happen...
517fn run_norevert_newimage(flash: &SimFlash, areadesc: &AreaDesc,
518 images: &Images) -> bool {
519 let mut fl = flash.clone();
520 let mut fails = 0;
521
522 info!("Try non-revert on imgtool generated image");
523 c::set_flash_counter(0);
524
525 mark_upgrade(&mut fl, &images.slot0);
526
527 // This simulates writing an image created by imgtool to Slot 0
528 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, UNSET, UNSET) {
529 warn!("Mismatched trailer for Slot 0");
530 fails += 1;
531 }
532
533 // Run the bootloader...
534 if c::boot_go(&mut fl, &areadesc) != 0 {
535 warn!("Failed first boot");
536 fails += 1;
537 }
538
539 // State should not have changed
540 if !verify_image(&fl, images.slot0.base_off, &images.primary) {
541 warn!("Failed image verification");
542 fails += 1;
543 }
544 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, UNSET,
545 UNSET) {
546 warn!("Mismatched trailer for Slot 0");
547 fails += 1;
548 }
549 if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
550 UNSET) {
551 warn!("Mismatched trailer for Slot 1");
552 fails += 1;
553 }
554
555 if fails > 0 {
556 error!("Expected a non revert with new image");
557 }
558
559 fails > 0
560}
561
562// Tests a new image written to slot0 that already has magic and image_ok set
563// while there is no image on slot1, so no revert should ever happen...
564fn run_signfail_upgrade(flash: &SimFlash, areadesc: &AreaDesc,
565 images: &Images) -> bool {
566 let mut fl = flash.clone();
567 let mut fails = 0;
568
569 info!("Try upgrade image with bad signature");
570 c::set_flash_counter(0);
571
572 mark_upgrade(&mut fl, &images.slot0);
573 mark_permanent_upgrade(&mut fl, &images.slot0);
574 mark_upgrade(&mut fl, &images.slot1);
575
576 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
577 UNSET) {
578 warn!("Mismatched trailer for Slot 0");
579 fails += 1;
580 }
581
582 // Run the bootloader...
583 if c::boot_go(&mut fl, &areadesc) != 0 {
584 warn!("Failed first boot");
585 fails += 1;
586 }
587
588 // State should not have changed
589 if !verify_image(&fl, images.slot0.base_off, &images.primary) {
590 warn!("Failed image verification");
591 fails += 1;
592 }
593 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
594 UNSET) {
595 warn!("Mismatched trailer for Slot 0");
596 fails += 1;
597 }
598
599 if fails > 0 {
600 error!("Expected an upgrade failure when image has bad signature");
601 }
602
603 fails > 0
604}
605
606/// Test a boot, optionally stopping after 'n' flash options. Returns a count
607/// of the number of flash operations done total.
608fn try_upgrade(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
609 stop: Option<i32>) -> (SimFlash, i32) {
610 // Clone the flash to have a new copy.
611 let mut fl = flash.clone();
612
613 mark_permanent_upgrade(&mut fl, &images.slot1);
614
615 c::set_flash_counter(stop.unwrap_or(0));
616 let (first_interrupted, count) = match c::boot_go(&mut fl, &areadesc) {
617 -0x13579 => (true, stop.unwrap()),
618 0 => (false, -c::get_flash_counter()),
619 x => panic!("Unknown return: {}", x),
620 };
621 c::set_flash_counter(0);
622
623 if first_interrupted {
624 // fl.dump();
625 match c::boot_go(&mut fl, &areadesc) {
626 -0x13579 => panic!("Shouldn't stop again"),
627 0 => (),
628 x => panic!("Unknown return: {}", x),
629 }
630 }
631
632 (fl, count - c::get_flash_counter())
633}
634
635#[cfg(not(feature = "overwrite-only"))]
636fn try_revert(flash: &SimFlash, areadesc: &AreaDesc, count: usize) -> SimFlash {
637 let mut fl = flash.clone();
638 c::set_flash_counter(0);
639
640 // fl.write_file("image0.bin").unwrap();
641 for i in 0 .. count {
642 info!("Running boot pass {}", i + 1);
643 assert_eq!(c::boot_go(&mut fl, &areadesc), 0);
644 }
645 fl
646}
647
648#[cfg(not(feature = "overwrite-only"))]
649fn try_revert_with_fail_at(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
650 stop: i32) -> bool {
651 let mut fl = flash.clone();
652 let mut x: i32;
653 let mut fails = 0;
654
655 c::set_flash_counter(stop);
656 x = c::boot_go(&mut fl, &areadesc);
657 if x != -0x13579 {
658 warn!("Should have stopped at interruption point");
659 fails += 1;
660 }
661
662 if !verify_trailer(&fl, images.slot0.trailer_off, None, None, UNSET) {
663 warn!("copy_done should be unset");
664 fails += 1;
665 }
666
667 c::set_flash_counter(0);
668 x = c::boot_go(&mut fl, &areadesc);
669 if x != 0 {
670 warn!("Should have finished upgrade");
671 fails += 1;
672 }
673
674 if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
675 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
676 fails += 1;
677 }
678 if !verify_image(&fl, images.slot1.base_off, &images.primary) {
679 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
680 fails += 1;
681 }
682 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, UNSET,
683 COPY_DONE) {
684 warn!("Mismatched trailer for Slot 0 before revert");
685 fails += 1;
686 }
687 if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
688 UNSET) {
689 warn!("Mismatched trailer for Slot 1 before revert");
690 fails += 1;
691 }
692
693 // Do Revert
694 c::set_flash_counter(0);
695 x = c::boot_go(&mut fl, &areadesc);
696 if x != 0 {
697 warn!("Should have finished a revert");
698 fails += 1;
699 }
700
701 if !verify_image(&fl, images.slot0.base_off, &images.primary) {
702 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
703 fails += 1;
704 }
705 if !verify_image(&fl, images.slot1.base_off, &images.upgrade) {
706 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
707 fails += 1;
708 }
709 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
710 COPY_DONE) {
711 warn!("Mismatched trailer for Slot 1 after revert");
712 fails += 1;
713 }
714 if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
715 UNSET) {
716 warn!("Mismatched trailer for Slot 1 after revert");
717 fails += 1;
718 }
719
720 fails > 0
721}
722
723fn try_random_fails(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
724 total_ops: i32, count: usize) -> (SimFlash, Vec<i32>) {
725 let mut fl = flash.clone();
726
727 mark_permanent_upgrade(&mut fl, &images.slot1);
728
729 let mut rng = rand::thread_rng();
730 let mut resets = vec![0i32; count];
731 let mut remaining_ops = total_ops;
732 for i in 0 .. count {
733 let ops = Range::new(1, remaining_ops / 2);
734 let reset_counter = ops.ind_sample(&mut rng);
735 c::set_flash_counter(reset_counter);
736 match c::boot_go(&mut fl, &areadesc) {
737 0 | -0x13579 => (),
738 x => panic!("Unknown return: {}", x),
739 }
740 remaining_ops -= reset_counter;
741 resets[i] = reset_counter;
742 }
743
744 c::set_flash_counter(0);
745 match c::boot_go(&mut fl, &areadesc) {
746 -0x13579 => panic!("Should not be have been interrupted!"),
747 0 => (),
748 x => panic!("Unknown return: {}", x),
749 }
750
751 (fl, resets)
752}
753
754/// Show the flash layout.
755#[allow(dead_code)]
756fn show_flash(flash: &Flash) {
757 println!("---- Flash configuration ----");
758 for sector in flash.sector_iter() {
759 println!(" {:3}: 0x{:08x}, 0x{:08x}",
760 sector.num, sector.base, sector.size);
761 }
762 println!("");
763}
764
765/// Install a "program" into the given image. This fakes the image header, or at least all of the
766/// fields used by the given code. Returns a copy of the image that was written.
767fn install_image(flash: &mut Flash, offset: usize, len: usize,
768 bad_sig: bool) -> Vec<u8> {
769 let offset0 = offset;
770
771 let mut tlv = make_tlv();
772
773 // Generate a boot header. Note that the size doesn't include the header.
774 let header = ImageHeader {
775 magic: 0x96f3b83d,
776 tlv_size: tlv.get_size(),
777 _pad1: 0,
778 hdr_size: 32,
779 key_id: 0,
780 _pad2: 0,
781 img_size: len as u32,
782 flags: tlv.get_flags(),
783 ver: ImageVersion {
784 major: (offset / (128 * 1024)) as u8,
785 minor: 0,
786 revision: 1,
787 build_num: offset as u32,
788 },
789 _pad3: 0,
790 };
791
792 let b_header = header.as_raw();
793 tlv.add_bytes(&b_header);
794 /*
795 let b_header = unsafe { slice::from_raw_parts(&header as *const _ as *const u8,
796 mem::size_of::<ImageHeader>()) };
797 */
798 assert_eq!(b_header.len(), 32);
799 flash.write(offset, &b_header).unwrap();
800 let offset = offset + b_header.len();
801
802 // The core of the image itself is just pseudorandom data.
803 let mut buf = vec![0; len];
804 splat(&mut buf, offset);
805 tlv.add_bytes(&buf);
806
807 // Get and append the TLV itself.
808 if bad_sig {
809 let good_sig = &mut tlv.make_tlv();
810 buf.append(&mut vec![0; good_sig.len()]);
811 } else {
812 buf.append(&mut tlv.make_tlv());
813 }
814
815 // Pad the block to a flash alignment (8 bytes).
816 while buf.len() % 8 != 0 {
817 buf.push(0xFF);
818 }
819
820 flash.write(offset, &buf).unwrap();
821 let offset = offset + buf.len();
822
823 // Copy out the image so that we can verify that the image was installed correctly later.
824 let mut copy = vec![0u8; offset - offset0];
825 flash.read(offset0, &mut copy).unwrap();
826
827 copy
828}
829
830// The TLV in use depends on what kind of signature we are verifying.
831#[cfg(feature = "sig-rsa")]
832fn make_tlv() -> TlvGen {
833 TlvGen::new_rsa_pss()
834}
835
836#[cfg(not(feature = "sig-rsa"))]
837fn make_tlv() -> TlvGen {
838 TlvGen::new_hash_only()
839}
840
841/// Verify that given image is present in the flash at the given offset.
842fn verify_image(flash: &Flash, offset: usize, buf: &[u8]) -> bool {
843 let mut copy = vec![0u8; buf.len()];
844 flash.read(offset, &mut copy).unwrap();
845
846 if buf != &copy[..] {
847 for i in 0 .. buf.len() {
848 if buf[i] != copy[i] {
849 info!("First failure at {:#x}", offset + i);
850 break;
851 }
852 }
853 false
854 } else {
855 true
856 }
857}
858
859#[cfg(feature = "overwrite-only")]
860#[allow(unused_variables)]
861// overwrite-only doesn't employ trailer management
862fn verify_trailer(flash: &Flash, offset: usize,
863 magic: Option<&[u8]>, image_ok: Option<u8>,
864 copy_done: Option<u8>) -> bool {
865 true
866}
867
868#[cfg(not(feature = "overwrite-only"))]
869fn verify_trailer(flash: &Flash, offset: usize,
870 magic: Option<&[u8]>, image_ok: Option<u8>,
871 copy_done: Option<u8>) -> bool {
872 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
873 let mut failed = false;
874
875 flash.read(offset, &mut copy).unwrap();
876
877 failed |= match magic {
878 Some(v) => {
879 if &copy[16..] != v {
880 warn!("\"magic\" mismatch at {:#x}", offset);
881 true
882 } else {
883 false
884 }
885 },
886 None => false,
887 };
888
889 failed |= match image_ok {
890 Some(v) => {
891 if copy[8] != v {
892 warn!("\"image_ok\" mismatch at {:#x}", offset);
893 true
894 } else {
895 false
896 }
897 },
898 None => false,
899 };
900
901 failed |= match copy_done {
902 Some(v) => {
903 if copy[0] != v {
904 warn!("\"copy_done\" mismatch at {:#x}", offset);
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 tlv_size: u16,
921 key_id: u8,
922 _pad1: u8,
923 hdr_size: u16,
924 _pad2: u16,
925 img_size: u32,
926 flags: u32,
927 ver: ImageVersion,
928 _pad3: u32,
929}
930
931impl AsRaw for ImageHeader {}
932
933#[repr(C)]
934pub struct ImageVersion {
935 major: u8,
936 minor: u8,
937 revision: u16,
938 build_num: u32,
939}
940
941struct SlotInfo {
942 base_off: usize,
943 trailer_off: usize,
944}
945
946struct Images<'a> {
947 slot0: &'a SlotInfo,
948 slot1: &'a SlotInfo,
949 primary: Vec<u8>,
950 upgrade: Vec<u8>,
951}
952
953const MAGIC_VALID: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
954 0x60, 0xd2, 0xef, 0x7f,
955 0x35, 0x52, 0x50, 0x0f,
956 0x2c, 0xb6, 0x79, 0x80]);
957const MAGIC_UNSET: Option<&[u8]> = Some(&[0xff; 16]);
958
959const COPY_DONE: Option<u8> = Some(1);
960const IMAGE_OK: Option<u8> = Some(1);
961const UNSET: Option<u8> = Some(0xff);
962
963/// Write out the magic so that the loader tries doing an upgrade.
964fn mark_upgrade(flash: &mut Flash, slot: &SlotInfo) {
965 let offset = slot.trailer_off + c::boot_max_align() * 2;
966 flash.write(offset, MAGIC_VALID.unwrap()).unwrap();
967}
968
969/// Writes the image_ok flag which, guess what, tells the bootloader
970/// the this image is ok (not a test, and no revert is to be performed).
971fn mark_permanent_upgrade(flash: &mut Flash, slot: &SlotInfo) {
972 let ok = [1u8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
973 let align = c::get_sim_flash_align() as usize;
974 let off = slot.trailer_off + c::boot_max_align();
975 flash.write(off, &ok[..align]).unwrap();
976}
977
978// Drop some pseudo-random gibberish onto the data.
979fn splat(data: &mut [u8], seed: usize) {
980 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
981 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
982 rng.fill_bytes(data);
983}
984
985/// Return a read-only view into the raw bytes of this object
986trait AsRaw : Sized {
987 fn as_raw<'a>(&'a self) -> &'a [u8] {
988 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
989 mem::size_of::<Self>()) }
990 }
991}
992
993fn show_sizes() {
994 // This isn't panic safe.
995 let old_align = c::get_sim_flash_align();
996 for min in &[1, 2, 4, 8] {
997 c::set_sim_flash_align(*min);
998 let msize = c::boot_trailer_sz();
999 println!("{:2}: {} (0x{:x})", min, msize, msize);
1000 }
1001 c::set_sim_flash_align(old_align);
1002}