blob: e22984e80ef3a0a6b9f828ae6190a6453ace9ce7 [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;
David Brownca7b5d32017-11-03 08:37:38 -060024pub mod testlog;
David Brown2639e072017-10-11 11:18:44 -060025
26use simflash::{Flash, SimFlash};
27use mcuboot_sys::{c, AreaDesc, FlashId};
28use caps::Caps;
29use tlv::TlvGen;
30
31const USAGE: &'static str = "
32Mcuboot simulator
33
34Usage:
35 bootsim sizes
36 bootsim run --device TYPE [--align SIZE]
37 bootsim runall
38 bootsim (--help | --version)
39
40Options:
41 -h, --help Show this message
42 --version Version
43 --device TYPE MCU to simulate
44 Valid values: stm32f4, k64f
45 --align SIZE Flash write alignment
46";
47
48#[derive(Debug, Deserialize)]
49struct Args {
50 flag_help: bool,
51 flag_version: bool,
52 flag_device: Option<DeviceName>,
53 flag_align: Option<AlignArg>,
54 cmd_sizes: bool,
55 cmd_run: bool,
56 cmd_runall: bool,
57}
58
59#[derive(Copy, Clone, Debug, Deserialize)]
David Browndecbd042017-10-19 10:43:17 -060060pub enum DeviceName { Stm32f4, K64f, K64fBig, Nrf52840 }
David Brown2639e072017-10-11 11:18:44 -060061
David Browndd2b1182017-11-02 15:39:21 -060062pub static ALL_DEVICES: &'static [DeviceName] = &[
David Brown2639e072017-10-11 11:18:44 -060063 DeviceName::Stm32f4,
64 DeviceName::K64f,
65 DeviceName::K64fBig,
66 DeviceName::Nrf52840,
67];
68
69impl fmt::Display for DeviceName {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 let name = match *self {
72 DeviceName::Stm32f4 => "stm32f4",
73 DeviceName::K64f => "k64f",
74 DeviceName::K64fBig => "k64fbig",
75 DeviceName::Nrf52840 => "nrf52840",
76 };
77 f.write_str(name)
78 }
79}
80
81#[derive(Debug)]
82struct AlignArg(u8);
83
84struct AlignArgVisitor;
85
86impl<'de> serde::de::Visitor<'de> for AlignArgVisitor {
87 type Value = AlignArg;
88
89 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
90 formatter.write_str("1, 2, 4 or 8")
91 }
92
93 fn visit_u8<E>(self, n: u8) -> Result<Self::Value, E>
94 where E: serde::de::Error
95 {
96 Ok(match n {
97 1 | 2 | 4 | 8 => AlignArg(n),
98 n => {
99 let err = format!("Could not deserialize '{}' as alignment", n);
100 return Err(E::custom(err));
101 }
102 })
103 }
104}
105
106impl<'de> serde::de::Deserialize<'de> for AlignArg {
107 fn deserialize<D>(d: D) -> Result<AlignArg, D::Error>
108 where D: serde::de::Deserializer<'de>
109 {
110 d.deserialize_u8(AlignArgVisitor)
111 }
112}
113
114pub fn main() {
115 let args: Args = Docopt::new(USAGE)
116 .and_then(|d| d.deserialize())
117 .unwrap_or_else(|e| e.exit());
118 // println!("args: {:#?}", args);
119
120 if args.cmd_sizes {
121 show_sizes();
122 return;
123 }
124
125 let mut status = RunStatus::new();
126 if args.cmd_run {
127
128 let align = args.flag_align.map(|x| x.0).unwrap_or(1);
129
130
131 let device = match args.flag_device {
132 None => panic!("Missing mandatory device argument"),
133 Some(dev) => dev,
134 };
135
136 status.run_single(device, align);
137 }
138
139 if args.cmd_runall {
140 for &dev in ALL_DEVICES {
141 for &align in &[1, 2, 4, 8] {
142 status.run_single(dev, align);
143 }
144 }
145 }
146
147 if status.failures > 0 {
148 error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
149 process::exit(1);
150 } else {
151 error!("{} Tests ran successfully", status.passes);
152 process::exit(0);
153 }
154}
155
David Browndb9a3952017-11-06 13:16:15 -0700156/// A test run, intended to be run from "cargo test", so panics on failure.
157pub struct Run {
158 flash: SimFlash,
159 areadesc: AreaDesc,
160 slots: [SlotInfo; 2],
161 align: u8,
162}
163
164impl Run {
165 pub fn new(device: DeviceName, align: u8) -> Run {
166 let (flash, areadesc) = make_device(device, align);
167
168 let (slot0_base, slot0_len) = areadesc.find(FlashId::Image0);
169 let (slot1_base, slot1_len) = areadesc.find(FlashId::Image1);
170 let (scratch_base, _) = areadesc.find(FlashId::ImageScratch);
171
172 // The code assumes that the slots are consecutive.
173 assert_eq!(slot1_base, slot0_base + slot0_len);
174 assert_eq!(scratch_base, slot1_base + slot1_len);
175
176 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
177
178 // Construct a primary image.
179 let slot0 = SlotInfo {
180 base_off: slot0_base as usize,
181 trailer_off: slot1_base - offset_from_end,
182 };
183
184 // And an upgrade image.
185 let slot1 = SlotInfo {
186 base_off: slot1_base as usize,
187 trailer_off: scratch_base - offset_from_end,
188 };
189
190 Run {
191 flash: flash,
192 areadesc: areadesc,
193 slots: [slot0, slot1],
194 align: align,
195 }
196 }
197
198 pub fn each_device<F>(f: F)
199 where F: Fn(&mut Run)
200 {
201 for &dev in ALL_DEVICES {
202 for &align in &[1, 2, 4, 8] {
203 let mut run = Run::new(dev, align);
204 f(&mut run);
205 }
206 }
207 }
David Brownf48b9502017-11-06 14:00:26 -0700208
209 /// Construct an `Images` that doesn't expect an upgrade to happen.
210 pub fn make_no_upgrade_image(&self) -> Images {
211 let mut flash = self.flash.clone();
212 let primary = install_image(&mut flash, self.slots[0].base_off, 32784, false);
213 let upgrade = install_image(&mut flash, self.slots[1].base_off, 41928, false);
214 Images {
215 flash: flash,
216 areadesc: self.areadesc.clone(),
217 slot0: self.slots[0].clone(),
218 slot1: self.slots[1].clone(),
219 primary: primary,
220 upgrade: upgrade,
David Brownc49811e2017-11-06 14:20:45 -0700221 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700222 align: self.align,
223 }
224 }
225
226 /// Construct an `Images` for normal testing.
227 pub fn make_image(&self) -> Images {
228 let mut images = self.make_no_upgrade_image();
229 mark_upgrade(&mut images.flash, &images.slot1);
David Brownc49811e2017-11-06 14:20:45 -0700230
231 // upgrades without fails, counts number of flash operations
232 let total_count = match images.run_basic_upgrade() {
233 Ok(v) => v,
234 Err(_) => {
235 panic!("Unable to perform basic upgrade");
236 },
237 };
238
239 images.total_count = Some(total_count);
David Brownf48b9502017-11-06 14:00:26 -0700240 images
241 }
242
243 pub fn make_bad_slot1_image(&self) -> Images {
244 let mut bad_flash = self.flash.clone();
245 let primary = install_image(&mut bad_flash, self.slots[0].base_off, 32784, false);
246 let upgrade = install_image(&mut bad_flash, self.slots[1].base_off, 41928, true);
247 Images {
248 flash: bad_flash,
249 areadesc: self.areadesc.clone(),
250 slot0: self.slots[0].clone(),
251 slot1: self.slots[1].clone(),
252 primary: primary,
253 upgrade: upgrade,
David Brownc49811e2017-11-06 14:20:45 -0700254 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700255 align: self.align,
256 }
257 }
David Brownc49811e2017-11-06 14:20:45 -0700258
David Browndb9a3952017-11-06 13:16:15 -0700259}
260
David Browndd2b1182017-11-02 15:39:21 -0600261pub struct RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600262 failures: usize,
263 passes: usize,
264}
265
266impl RunStatus {
David Browndd2b1182017-11-02 15:39:21 -0600267 pub fn new() -> RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600268 RunStatus {
269 failures: 0,
270 passes: 0,
271 }
272 }
273
David Browndd2b1182017-11-02 15:39:21 -0600274 pub fn run_single(&mut self, device: DeviceName, align: u8) {
David Brown2639e072017-10-11 11:18:44 -0600275 warn!("Running on device {} with alignment {}", device, align);
276
David Browndc9cba12017-11-06 13:31:42 -0700277 let run = Run::new(device, align);
David Brown2639e072017-10-11 11:18:44 -0600278
David Brown2639e072017-10-11 11:18:44 -0600279 let mut failed = false;
280
281 // Creates a badly signed image in slot1 to check that it is not
282 // upgraded to
David Brownf48b9502017-11-06 14:00:26 -0700283 let bad_slot1_image = run.make_bad_slot1_image();
David Brown2639e072017-10-11 11:18:44 -0600284
David Brown5f7ec2b2017-11-06 13:54:02 -0700285 failed |= bad_slot1_image.run_signfail_upgrade();
David Brown2639e072017-10-11 11:18:44 -0600286
David Brownf48b9502017-11-06 14:00:26 -0700287 let images = run.make_no_upgrade_image();
David Brown5f7ec2b2017-11-06 13:54:02 -0700288 failed |= images.run_norevert_newimage();
David Brown2639e072017-10-11 11:18:44 -0600289
David Brownf48b9502017-11-06 14:00:26 -0700290 let images = run.make_image();
David Brown2639e072017-10-11 11:18:44 -0600291
David Brown5f7ec2b2017-11-06 13:54:02 -0700292 failed |= images.run_basic_revert();
David Brownc49811e2017-11-06 14:20:45 -0700293 failed |= images.run_revert_with_fails();
294 failed |= images.run_perm_with_fails();
295 failed |= images.run_perm_with_random_fails(5);
David Brown5f7ec2b2017-11-06 13:54:02 -0700296 failed |= images.run_norevert();
David Brown2639e072017-10-11 11:18:44 -0600297
298 //show_flash(&flash);
299
300 if failed {
301 self.failures += 1;
302 } else {
303 self.passes += 1;
304 }
305 }
David Browndd2b1182017-11-02 15:39:21 -0600306
307 pub fn failures(&self) -> usize {
308 self.failures
309 }
David Brown2639e072017-10-11 11:18:44 -0600310}
311
David Browndecbd042017-10-19 10:43:17 -0600312/// Build the Flash and area descriptor for a given device.
313pub fn make_device(device: DeviceName, align: u8) -> (SimFlash, AreaDesc) {
314 match device {
315 DeviceName::Stm32f4 => {
316 // STM style flash. Large sectors, with a large scratch area.
317 let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
318 64 * 1024,
319 128 * 1024, 128 * 1024, 128 * 1024],
320 align as usize);
321 let mut areadesc = AreaDesc::new(&flash);
322 areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
323 areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
324 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch);
325 (flash, areadesc)
326 }
327 DeviceName::K64f => {
328 // NXP style flash. Small sectors, one small sector for scratch.
329 let flash = SimFlash::new(vec![4096; 128], align as usize);
330
331 let mut areadesc = AreaDesc::new(&flash);
332 areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
333 areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
334 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch);
335 (flash, areadesc)
336 }
337 DeviceName::K64fBig => {
338 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
339 // uses small sectors, but we tell the bootloader they are large.
340 let flash = SimFlash::new(vec![4096; 128], align as usize);
341
342 let mut areadesc = AreaDesc::new(&flash);
343 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0);
344 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1);
345 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch);
346 (flash, areadesc)
347 }
348 DeviceName::Nrf52840 => {
349 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
350 // does not divide into the image size.
351 let flash = SimFlash::new(vec![4096; 128], align as usize);
352
353 let mut areadesc = AreaDesc::new(&flash);
354 areadesc.add_image(0x008000, 0x034000, FlashId::Image0);
355 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1);
356 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch);
357 (flash, areadesc)
358 }
359 }
360}
361
David Brown5f7ec2b2017-11-06 13:54:02 -0700362impl Images {
363 /// A simple upgrade without forced failures.
364 ///
365 /// Returns the number of flash operations which can later be used to
366 /// inject failures at chosen steps.
David Brownc49811e2017-11-06 14:20:45 -0700367 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Brown5f7ec2b2017-11-06 13:54:02 -0700368 let (fl, total_count) = try_upgrade(&self.flash, &self, None);
369 info!("Total flash operation count={}", total_count);
David Brown2639e072017-10-11 11:18:44 -0600370
David Brown5f7ec2b2017-11-06 13:54:02 -0700371 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
372 warn!("Image mismatch after first boot");
373 Err(())
374 } else {
375 Ok(total_count)
David Brown2639e072017-10-11 11:18:44 -0600376 }
377 }
378
David Brown5f7ec2b2017-11-06 13:54:02 -0700379 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700380 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700381 false
382 }
David Brown2639e072017-10-11 11:18:44 -0600383
David Brown5f7ec2b2017-11-06 13:54:02 -0700384 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700385 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700386 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600387
David Brown5f7ec2b2017-11-06 13:54:02 -0700388 // FIXME: this test would also pass if no swap is ever performed???
389 if Caps::SwapUpgrade.present() {
390 for count in 2 .. 5 {
391 info!("Try revert: {}", count);
392 let fl = try_revert(&self.flash, &self.areadesc, count, self.align);
393 if !verify_image(&fl, self.slot0.base_off, &self.primary) {
394 error!("Revert failure on count {}", count);
395 fails += 1;
396 }
397 }
398 }
399
400 fails > 0
401 }
402
David Browna4167ef2017-11-06 14:30:05 -0700403 pub fn run_perm_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700404 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700405 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700406
407 // Let's try an image halfway through.
408 for i in 1 .. total_flash_ops {
409 info!("Try interruption at {}", i);
410 let (fl, count) = try_upgrade(&self.flash, &self, Some(i));
411 info!("Second boot, count={}", count);
412 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
413 warn!("FAIL at step {} of {}", i, total_flash_ops);
414 fails += 1;
415 }
416
417 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
418 COPY_DONE) {
419 warn!("Mismatched trailer for Slot 0");
420 fails += 1;
421 }
422
423 if !verify_trailer(&fl, self.slot1.trailer_off, MAGIC_UNSET, UNSET,
424 UNSET) {
425 warn!("Mismatched trailer for Slot 1");
426 fails += 1;
427 }
428
429 if Caps::SwapUpgrade.present() {
430 if !verify_image(&fl, self.slot1.base_off, &self.primary) {
431 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
432 fails += 1;
433 }
434 }
435 }
436
437 if fails > 0 {
438 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
439 fails as f32 * 100.0 / total_flash_ops as f32);
440 }
441
442 fails > 0
443 }
444
David Browna4167ef2017-11-06 14:30:05 -0700445 pub fn run_perm_with_random_fails_5(&self) -> bool {
446 self.run_perm_with_random_fails(5)
447 }
448
David Brownc49811e2017-11-06 14:20:45 -0700449 fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700450 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700451 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700452 let (fl, total_counts) = try_random_fails(&self.flash, &self,
453 total_flash_ops, total_fails);
454 info!("Random interruptions at reset points={:?}", total_counts);
455
456 let slot0_ok = verify_image(&fl, self.slot0.base_off, &self.upgrade);
457 let slot1_ok = if Caps::SwapUpgrade.present() {
458 verify_image(&fl, self.slot1.base_off, &self.primary)
459 } else {
460 true
461 };
462 if !slot0_ok || !slot1_ok {
463 error!("Image mismatch after random interrupts: slot0={} slot1={}",
464 if slot0_ok { "ok" } else { "fail" },
465 if slot1_ok { "ok" } else { "fail" });
466 fails += 1;
467 }
468 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
469 COPY_DONE) {
470 error!("Mismatched trailer for Slot 0");
471 fails += 1;
472 }
473 if !verify_trailer(&fl, self.slot1.trailer_off, MAGIC_UNSET, UNSET,
474 UNSET) {
475 error!("Mismatched trailer for Slot 1");
David Brown2639e072017-10-11 11:18:44 -0600476 fails += 1;
477 }
478
David Brown5f7ec2b2017-11-06 13:54:02 -0700479 if fails > 0 {
480 error!("Error testing perm upgrade with {} fails", total_fails);
481 }
482
483 fails > 0
484 }
485
486 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700487 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700488 false
489 }
490
491 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700492 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700493 let mut fails = 0;
494
495 if Caps::SwapUpgrade.present() {
David Brownc49811e2017-11-06 14:20:45 -0700496 for i in 1 .. (self.total_count.unwrap() - 1) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700497 info!("Try interruption at {}", i);
498 if try_revert_with_fail_at(&self.flash, &self, i) {
499 error!("Revert failed at interruption {}", i);
500 fails += 1;
501 }
502 }
503 }
504
505 fails > 0
506 }
507
508 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700509 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700510 false
511 }
512
513 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700514 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700515 let mut fl = self.flash.clone();
516 let mut fails = 0;
517
518 info!("Try norevert");
519
520 // First do a normal upgrade...
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200521 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
522 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700523 warn!("Failed first boot");
524 fails += 1;
525 }
526
527 //FIXME: copy_done is written by boot_go, is it ok if no copy
528 // was ever done?
529
530 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
531 warn!("Slot 0 image verification FAIL");
532 fails += 1;
533 }
534 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, UNSET,
David Brown2639e072017-10-11 11:18:44 -0600535 COPY_DONE) {
536 warn!("Mismatched trailer for Slot 0");
537 fails += 1;
538 }
David Brown5f7ec2b2017-11-06 13:54:02 -0700539 if !verify_trailer(&fl, self.slot1.trailer_off, MAGIC_UNSET, UNSET,
David Brown2639e072017-10-11 11:18:44 -0600540 UNSET) {
541 warn!("Mismatched trailer for Slot 1");
542 fails += 1;
543 }
544
David Brown5f7ec2b2017-11-06 13:54:02 -0700545 // Marks image in slot0 as permanent, no revert should happen...
546 mark_permanent_upgrade(&mut fl, &self.slot0, self.align);
547
548 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
549 COPY_DONE) {
550 warn!("Mismatched trailer for Slot 0");
551 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600552 }
David Brown2639e072017-10-11 11:18:44 -0600553
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200554 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
555 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700556 warn!("Failed second boot");
557 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600558 }
David Brown5f7ec2b2017-11-06 13:54:02 -0700559
560 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
561 COPY_DONE) {
562 warn!("Mismatched trailer for Slot 0");
563 fails += 1;
564 }
565 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
566 warn!("Failed image verification");
567 fails += 1;
568 }
569
570 if fails > 0 {
571 error!("Error running upgrade without revert");
572 }
573
574 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600575 }
576
David Brown5f7ec2b2017-11-06 13:54:02 -0700577 // Tests a new image written to slot0 that already has magic and image_ok set
578 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700579 pub fn run_norevert_newimage(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700580 let mut fl = self.flash.clone();
581 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600582
David Brown5f7ec2b2017-11-06 13:54:02 -0700583 info!("Try non-revert on imgtool generated image");
David Brown2639e072017-10-11 11:18:44 -0600584
David Brown5f7ec2b2017-11-06 13:54:02 -0700585 mark_upgrade(&mut fl, &self.slot0);
David Brown2639e072017-10-11 11:18:44 -0600586
David Brown5f7ec2b2017-11-06 13:54:02 -0700587 // This simulates writing an image created by imgtool to Slot 0
588 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, UNSET, UNSET) {
589 warn!("Mismatched trailer for Slot 0");
590 fails += 1;
591 }
David Brown2639e072017-10-11 11:18:44 -0600592
David Brown5f7ec2b2017-11-06 13:54:02 -0700593 // Run the bootloader...
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200594 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
595 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700596 warn!("Failed first boot");
597 fails += 1;
598 }
599
600 // State should not have changed
601 if !verify_image(&fl, self.slot0.base_off, &self.primary) {
602 warn!("Failed image verification");
603 fails += 1;
604 }
605 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, UNSET,
606 UNSET) {
607 warn!("Mismatched trailer for Slot 0");
608 fails += 1;
609 }
610 if !verify_trailer(&fl, self.slot1.trailer_off, MAGIC_UNSET, UNSET,
611 UNSET) {
612 warn!("Mismatched trailer for Slot 1");
613 fails += 1;
614 }
615
616 if fails > 0 {
617 error!("Expected a non revert with new image");
618 }
619
620 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600621 }
622
David Brown5f7ec2b2017-11-06 13:54:02 -0700623 // Tests a new image written to slot0 that already has magic and image_ok set
624 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700625 pub fn run_signfail_upgrade(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700626 let mut fl = self.flash.clone();
627 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600628
David Brown5f7ec2b2017-11-06 13:54:02 -0700629 info!("Try upgrade image with bad signature");
630
631 mark_upgrade(&mut fl, &self.slot0);
632 mark_permanent_upgrade(&mut fl, &self.slot0, self.align);
633 mark_upgrade(&mut fl, &self.slot1);
634
635 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
636 UNSET) {
637 warn!("Mismatched trailer for Slot 0");
638 fails += 1;
639 }
640
641 // Run the bootloader...
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200642 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
643 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700644 warn!("Failed first boot");
645 fails += 1;
646 }
647
648 // State should not have changed
649 if !verify_image(&fl, self.slot0.base_off, &self.primary) {
650 warn!("Failed image verification");
651 fails += 1;
652 }
653 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
654 UNSET) {
655 warn!("Mismatched trailer for Slot 0");
656 fails += 1;
657 }
658
659 if fails > 0 {
660 error!("Expected an upgrade failure when image has bad signature");
661 }
662
663 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600664 }
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200665
666 fn trailer_sz(&self) -> usize {
667 c::boot_trailer_sz(self.align) as usize
668 }
669
670 // FIXME: could get status sz from bootloader
671 fn status_sz(&self) -> usize {
672 self.trailer_sz() - (16 + 24)
673 }
674
675 /// This test runs a simple upgrade with no fails in the images, but
676 /// allowing for fails in the status area. This should run to the end
677 /// and warn that write fails were detected...
678 #[cfg(not(feature = "validate-slot0"))]
679 pub fn run_with_status_fails_complete(&self) -> bool { false }
680
681 #[cfg(feature = "validate-slot0")]
682 pub fn run_with_status_fails_complete(&self) -> bool {
683 let mut fl = self.flash.clone();
684 let mut fails = 0;
685
686 info!("Try swap with status fails");
687
688 mark_permanent_upgrade(&mut fl, &self.slot1, self.align);
689
690 let status_off = self.slot1.base_off - self.trailer_sz();
691
692 // Always fail writes to status area...
693 let _ = fl.add_bad_region(status_off, self.status_sz(), 1.0);
694
695 let (result, asserts) = c::boot_go(&mut fl, &self.areadesc, None, self.align, true);
696 if result != 0 {
697 warn!("Failed!");
698 fails += 1;
699 }
700
701 // Failed writes to the marked "bad" region don't assert anymore.
702 // Any detected assert() is happening in another part of the code.
703 if asserts != 0 {
704 warn!("At least one assert() was called");
705 fails += 1;
706 }
707
708 if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
709 COPY_DONE) {
710 warn!("Mismatched trailer for Slot 0");
711 fails += 1;
712 }
713
714 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
715 warn!("Failed image verification");
716 fails += 1;
717 }
718
719 info!("validate slot0 enabled; re-run of boot_go should just work");
720 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
721 if result != 0 {
722 warn!("Failed!");
723 fails += 1;
724 }
725
726 if fails > 0 {
727 error!("Error running upgrade with status write fails");
728 }
729
730 fails > 0
731 }
732
733 /// This test runs a simple upgrade with no fails in the images, but
734 /// allowing for fails in the status area. This should run to the end
735 /// and warn that write fails were detected...
736 #[cfg(feature = "validate-slot0")]
737 pub fn run_with_status_fails_with_reset(&self) -> bool {
738 let mut fl = self.flash.clone();
739 let mut fails = 0;
740 let mut count = self.total_count.unwrap() / 2;
741
742 //info!("count={}\n", count);
743
744 info!("Try interrupted swap with status fails");
745
746 mark_permanent_upgrade(&mut fl, &self.slot1, self.align);
747
748 let status_off = self.slot1.base_off - self.trailer_sz();
749
750 // Mark the status area as a bad area
751 let _ = fl.add_bad_region(status_off, self.status_sz(), 0.5);
752
753 // Should not fail, writing to bad regions does not assert
754 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, Some(&mut count), self.align, true);
755 if asserts != 0 {
756 warn!("At least one assert() was called");
757 fails += 1;
758 }
759
760 fl.reset_bad_regions();
761
762 // Disabling write verification the only assert triggered by
763 // boot_go should be checking for integrity of status bytes.
764 fl.set_verify_writes(false);
765
766 info!("Resuming an interrupted swap operation");
767 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, None, self.align, true);
768
769 // This might throw no asserts, for large sector devices, where
770 // a single failure writing is indistinguishable from no failure,
771 // or throw a single assert for small sector devices that fail
772 // multiple times...
773 if asserts > 1 {
774 warn!("Expected single assert validating slot0, more detected {}", asserts);
775 fails += 1;
776 }
777
778 if fails > 0 {
779 error!("Error running upgrade with status write fails");
780 }
781
782 fails > 0
783 }
784
785 #[cfg(not(feature = "validate-slot0"))]
786 #[cfg(not(feature = "overwrite-only"))]
787 pub fn run_with_status_fails_with_reset(&self) -> bool {
788 let mut fl = self.flash.clone();
789 let mut fails = 0;
790
791 info!("Try interrupted swap with status fails");
792
793 mark_permanent_upgrade(&mut fl, &self.slot1, self.align);
794
795 let status_off = self.slot1.base_off - self.trailer_sz();
796
797 // Mark the status area as a bad area
798 let _ = fl.add_bad_region(status_off, self.status_sz(), 1.0);
799
800 // This is expected to fail while writing to bad regions...
801 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, None, self.align, true);
802 if asserts == 0 {
803 warn!("No assert() detected");
804 fails += 1;
805 }
806
807 fails > 0
808 }
809
810 #[cfg(feature = "overwrite-only")]
811 pub fn run_with_status_fails_with_reset(&self) -> bool {
812 false
813 }
David Brown2639e072017-10-11 11:18:44 -0600814}
815
816/// Test a boot, optionally stopping after 'n' flash options. Returns a count
817/// of the number of flash operations done total.
David Brown3f687dc2017-11-06 13:41:18 -0700818fn try_upgrade(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600819 stop: Option<i32>) -> (SimFlash, i32) {
820 // Clone the flash to have a new copy.
821 let mut fl = flash.clone();
822
David Brown541860c2017-11-06 11:25:42 -0700823 mark_permanent_upgrade(&mut fl, &images.slot1, images.align);
David Brown2639e072017-10-11 11:18:44 -0600824
David Brownee61c832017-11-06 11:13:25 -0700825 let mut counter = stop.unwrap_or(0);
826
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200827 let (first_interrupted, count) = match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), images.align, false) {
828 (-0x13579, _) => (true, stop.unwrap()),
829 (0, _) => (false, -counter),
830 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600831 };
David Brown2639e072017-10-11 11:18:44 -0600832
David Brownee61c832017-11-06 11:13:25 -0700833 counter = 0;
David Brown2639e072017-10-11 11:18:44 -0600834 if first_interrupted {
835 // fl.dump();
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200836 match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), images.align, false) {
837 (-0x13579, _) => panic!("Shouldn't stop again"),
838 (0, _) => (),
839 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600840 }
841 }
842
David Brownee61c832017-11-06 11:13:25 -0700843 (fl, count - counter)
David Brown2639e072017-10-11 11:18:44 -0600844}
845
846#[cfg(not(feature = "overwrite-only"))]
David Brown541860c2017-11-06 11:25:42 -0700847fn try_revert(flash: &SimFlash, areadesc: &AreaDesc, count: usize, align: u8) -> SimFlash {
David Brown2639e072017-10-11 11:18:44 -0600848 let mut fl = flash.clone();
David Brown2639e072017-10-11 11:18:44 -0600849
850 // fl.write_file("image0.bin").unwrap();
851 for i in 0 .. count {
852 info!("Running boot pass {}", i + 1);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200853 assert_eq!(c::boot_go(&mut fl, &areadesc, None, align, false), (0, 0));
David Brown2639e072017-10-11 11:18:44 -0600854 }
855 fl
856}
857
858#[cfg(not(feature = "overwrite-only"))]
David Brown3f687dc2017-11-06 13:41:18 -0700859fn try_revert_with_fail_at(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600860 stop: i32) -> bool {
861 let mut fl = flash.clone();
David Brown2639e072017-10-11 11:18:44 -0600862 let mut fails = 0;
863
David Brownee61c832017-11-06 11:13:25 -0700864 let mut counter = stop;
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200865 let (x, _) = c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), images.align, false);
David Brown2639e072017-10-11 11:18:44 -0600866 if x != -0x13579 {
867 warn!("Should have stopped at interruption point");
868 fails += 1;
869 }
870
871 if !verify_trailer(&fl, images.slot0.trailer_off, None, None, UNSET) {
872 warn!("copy_done should be unset");
873 fails += 1;
874 }
875
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200876 let (x, _) = c::boot_go(&mut fl, &images.areadesc, None, images.align, false);
David Brown2639e072017-10-11 11:18:44 -0600877 if x != 0 {
878 warn!("Should have finished upgrade");
879 fails += 1;
880 }
881
882 if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
883 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
884 fails += 1;
885 }
886 if !verify_image(&fl, images.slot1.base_off, &images.primary) {
887 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
888 fails += 1;
889 }
890 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, UNSET,
891 COPY_DONE) {
892 warn!("Mismatched trailer for Slot 0 before revert");
893 fails += 1;
894 }
895 if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
896 UNSET) {
897 warn!("Mismatched trailer for Slot 1 before revert");
898 fails += 1;
899 }
900
901 // Do Revert
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200902 let (x, _) = c::boot_go(&mut fl, &images.areadesc, None, images.align, false);
David Brown2639e072017-10-11 11:18:44 -0600903 if x != 0 {
904 warn!("Should have finished a revert");
905 fails += 1;
906 }
907
908 if !verify_image(&fl, images.slot0.base_off, &images.primary) {
909 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
910 fails += 1;
911 }
912 if !verify_image(&fl, images.slot1.base_off, &images.upgrade) {
913 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
914 fails += 1;
915 }
916 if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
917 COPY_DONE) {
918 warn!("Mismatched trailer for Slot 1 after revert");
919 fails += 1;
920 }
921 if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
922 UNSET) {
923 warn!("Mismatched trailer for Slot 1 after revert");
924 fails += 1;
925 }
926
927 fails > 0
928}
929
David Brown3f687dc2017-11-06 13:41:18 -0700930fn try_random_fails(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600931 total_ops: i32, count: usize) -> (SimFlash, Vec<i32>) {
932 let mut fl = flash.clone();
933
David Brown541860c2017-11-06 11:25:42 -0700934 mark_permanent_upgrade(&mut fl, &images.slot1, images.align);
David Brown2639e072017-10-11 11:18:44 -0600935
936 let mut rng = rand::thread_rng();
937 let mut resets = vec![0i32; count];
938 let mut remaining_ops = total_ops;
939 for i in 0 .. count {
940 let ops = Range::new(1, remaining_ops / 2);
941 let reset_counter = ops.ind_sample(&mut rng);
David Brownee61c832017-11-06 11:13:25 -0700942 let mut counter = reset_counter;
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200943 match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), images.align, false) {
944 (0, _) | (-0x13579, _) => (),
945 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600946 }
947 remaining_ops -= reset_counter;
948 resets[i] = reset_counter;
949 }
950
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200951 match c::boot_go(&mut fl, &images.areadesc, None, images.align, false) {
952 (-0x13579, _) => panic!("Should not be have been interrupted!"),
953 (0, _) => (),
954 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600955 }
956
957 (fl, resets)
958}
959
960/// Show the flash layout.
961#[allow(dead_code)]
962fn show_flash(flash: &Flash) {
963 println!("---- Flash configuration ----");
964 for sector in flash.sector_iter() {
965 println!(" {:3}: 0x{:08x}, 0x{:08x}",
966 sector.num, sector.base, sector.size);
967 }
968 println!("");
969}
970
971/// Install a "program" into the given image. This fakes the image header, or at least all of the
972/// fields used by the given code. Returns a copy of the image that was written.
973fn install_image(flash: &mut Flash, offset: usize, len: usize,
974 bad_sig: bool) -> Vec<u8> {
975 let offset0 = offset;
976
977 let mut tlv = make_tlv();
978
979 // Generate a boot header. Note that the size doesn't include the header.
980 let header = ImageHeader {
981 magic: 0x96f3b83d,
982 tlv_size: tlv.get_size(),
983 _pad1: 0,
984 hdr_size: 32,
985 key_id: 0,
986 _pad2: 0,
987 img_size: len as u32,
988 flags: tlv.get_flags(),
989 ver: ImageVersion {
990 major: (offset / (128 * 1024)) as u8,
991 minor: 0,
992 revision: 1,
993 build_num: offset as u32,
994 },
995 _pad3: 0,
996 };
997
998 let b_header = header.as_raw();
999 tlv.add_bytes(&b_header);
1000 /*
1001 let b_header = unsafe { slice::from_raw_parts(&header as *const _ as *const u8,
1002 mem::size_of::<ImageHeader>()) };
1003 */
1004 assert_eq!(b_header.len(), 32);
1005 flash.write(offset, &b_header).unwrap();
1006 let offset = offset + b_header.len();
1007
1008 // The core of the image itself is just pseudorandom data.
1009 let mut buf = vec![0; len];
1010 splat(&mut buf, offset);
1011 tlv.add_bytes(&buf);
1012
1013 // Get and append the TLV itself.
1014 if bad_sig {
1015 let good_sig = &mut tlv.make_tlv();
1016 buf.append(&mut vec![0; good_sig.len()]);
1017 } else {
1018 buf.append(&mut tlv.make_tlv());
1019 }
1020
1021 // Pad the block to a flash alignment (8 bytes).
1022 while buf.len() % 8 != 0 {
1023 buf.push(0xFF);
1024 }
1025
1026 flash.write(offset, &buf).unwrap();
1027 let offset = offset + buf.len();
1028
1029 // Copy out the image so that we can verify that the image was installed correctly later.
1030 let mut copy = vec![0u8; offset - offset0];
1031 flash.read(offset0, &mut copy).unwrap();
1032
1033 copy
1034}
1035
1036// The TLV in use depends on what kind of signature we are verifying.
1037#[cfg(feature = "sig-rsa")]
1038fn make_tlv() -> TlvGen {
1039 TlvGen::new_rsa_pss()
1040}
1041
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001042#[cfg(feature = "sig-ecdsa")]
1043fn make_tlv() -> TlvGen {
1044 TlvGen::new_ecdsa()
1045}
1046
David Brown2639e072017-10-11 11:18:44 -06001047#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001048#[cfg(not(feature = "sig-ecdsa"))]
David Brown2639e072017-10-11 11:18:44 -06001049fn make_tlv() -> TlvGen {
1050 TlvGen::new_hash_only()
1051}
1052
1053/// Verify that given image is present in the flash at the given offset.
1054fn verify_image(flash: &Flash, offset: usize, buf: &[u8]) -> bool {
1055 let mut copy = vec![0u8; buf.len()];
1056 flash.read(offset, &mut copy).unwrap();
1057
1058 if buf != &copy[..] {
1059 for i in 0 .. buf.len() {
1060 if buf[i] != copy[i] {
1061 info!("First failure at {:#x}", offset + i);
1062 break;
1063 }
1064 }
1065 false
1066 } else {
1067 true
1068 }
1069}
1070
1071#[cfg(feature = "overwrite-only")]
1072#[allow(unused_variables)]
1073// overwrite-only doesn't employ trailer management
1074fn verify_trailer(flash: &Flash, offset: usize,
1075 magic: Option<&[u8]>, image_ok: Option<u8>,
1076 copy_done: Option<u8>) -> bool {
1077 true
1078}
1079
1080#[cfg(not(feature = "overwrite-only"))]
1081fn verify_trailer(flash: &Flash, offset: usize,
1082 magic: Option<&[u8]>, image_ok: Option<u8>,
1083 copy_done: Option<u8>) -> bool {
1084 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1085 let mut failed = false;
1086
1087 flash.read(offset, &mut copy).unwrap();
1088
1089 failed |= match magic {
1090 Some(v) => {
1091 if &copy[16..] != v {
1092 warn!("\"magic\" mismatch at {:#x}", offset);
1093 true
1094 } else {
1095 false
1096 }
1097 },
1098 None => false,
1099 };
1100
1101 failed |= match image_ok {
1102 Some(v) => {
1103 if copy[8] != v {
1104 warn!("\"image_ok\" mismatch at {:#x}", offset);
1105 true
1106 } else {
1107 false
1108 }
1109 },
1110 None => false,
1111 };
1112
1113 failed |= match copy_done {
1114 Some(v) => {
1115 if copy[0] != v {
1116 warn!("\"copy_done\" mismatch at {:#x}", offset);
1117 true
1118 } else {
1119 false
1120 }
1121 },
1122 None => false,
1123 };
1124
1125 !failed
1126}
1127
1128/// The image header
1129#[repr(C)]
1130pub struct ImageHeader {
1131 magic: u32,
1132 tlv_size: u16,
1133 key_id: u8,
1134 _pad1: u8,
1135 hdr_size: u16,
1136 _pad2: u16,
1137 img_size: u32,
1138 flags: u32,
1139 ver: ImageVersion,
1140 _pad3: u32,
1141}
1142
1143impl AsRaw for ImageHeader {}
1144
1145#[repr(C)]
1146pub struct ImageVersion {
1147 major: u8,
1148 minor: u8,
1149 revision: u16,
1150 build_num: u32,
1151}
1152
David Brownd5e632c2017-10-19 10:49:46 -06001153#[derive(Clone)]
David Brown2639e072017-10-11 11:18:44 -06001154struct SlotInfo {
1155 base_off: usize,
1156 trailer_off: usize,
1157}
1158
David Brownf48b9502017-11-06 14:00:26 -07001159pub struct Images {
David Browndc9cba12017-11-06 13:31:42 -07001160 flash: SimFlash,
David Brown3f687dc2017-11-06 13:41:18 -07001161 areadesc: AreaDesc,
David Brownd5e632c2017-10-19 10:49:46 -06001162 slot0: SlotInfo,
1163 slot1: SlotInfo,
David Brown2639e072017-10-11 11:18:44 -06001164 primary: Vec<u8>,
1165 upgrade: Vec<u8>,
David Brownc49811e2017-11-06 14:20:45 -07001166 total_count: Option<i32>,
David Brown541860c2017-11-06 11:25:42 -07001167 align: u8,
David Brown2639e072017-10-11 11:18:44 -06001168}
1169
1170const MAGIC_VALID: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1171 0x60, 0xd2, 0xef, 0x7f,
1172 0x35, 0x52, 0x50, 0x0f,
1173 0x2c, 0xb6, 0x79, 0x80]);
1174const MAGIC_UNSET: Option<&[u8]> = Some(&[0xff; 16]);
1175
1176const COPY_DONE: Option<u8> = Some(1);
1177const IMAGE_OK: Option<u8> = Some(1);
1178const UNSET: Option<u8> = Some(0xff);
1179
1180/// Write out the magic so that the loader tries doing an upgrade.
1181fn mark_upgrade(flash: &mut Flash, slot: &SlotInfo) {
1182 let offset = slot.trailer_off + c::boot_max_align() * 2;
1183 flash.write(offset, MAGIC_VALID.unwrap()).unwrap();
1184}
1185
1186/// Writes the image_ok flag which, guess what, tells the bootloader
1187/// the this image is ok (not a test, and no revert is to be performed).
David Brown541860c2017-11-06 11:25:42 -07001188fn mark_permanent_upgrade(flash: &mut Flash, slot: &SlotInfo, align: u8) {
David Brown2639e072017-10-11 11:18:44 -06001189 let ok = [1u8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
David Brown2639e072017-10-11 11:18:44 -06001190 let off = slot.trailer_off + c::boot_max_align();
David Brown541860c2017-11-06 11:25:42 -07001191 flash.write(off, &ok[..align as usize]).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001192}
1193
1194// Drop some pseudo-random gibberish onto the data.
1195fn splat(data: &mut [u8], seed: usize) {
1196 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1197 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1198 rng.fill_bytes(data);
1199}
1200
1201/// Return a read-only view into the raw bytes of this object
1202trait AsRaw : Sized {
1203 fn as_raw<'a>(&'a self) -> &'a [u8] {
1204 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1205 mem::size_of::<Self>()) }
1206 }
1207}
1208
1209fn show_sizes() {
1210 // This isn't panic safe.
David Brown2639e072017-10-11 11:18:44 -06001211 for min in &[1, 2, 4, 8] {
David Brown541860c2017-11-06 11:25:42 -07001212 let msize = c::boot_trailer_sz(*min);
David Brown2639e072017-10-11 11:18:44 -06001213 println!("{:2}: {} (0x{:x})", min, msize, msize);
1214 }
David Brown2639e072017-10-11 11:18:44 -06001215}