blob: 1e8ba8a508d4b040dd88afaaf984938c85b4c40b [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
Fabio Utzigea0290b2018-08-09 14:23:01 -0300136 status.run_single(device, align, 0xff);
David Brown2639e072017-10-11 11:18:44 -0600137 }
138
139 if args.cmd_runall {
140 for &dev in ALL_DEVICES {
141 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300142 for &erased_val in &[0, 0xff] {
143 status.run_single(dev, align, erased_val);
144 }
David Brown2639e072017-10-11 11:18:44 -0600145 }
146 }
147 }
148
149 if status.failures > 0 {
150 error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
151 process::exit(1);
152 } else {
153 error!("{} Tests ran successfully", status.passes);
154 process::exit(0);
155 }
156}
157
David Browndb9a3952017-11-06 13:16:15 -0700158/// A test run, intended to be run from "cargo test", so panics on failure.
159pub struct Run {
160 flash: SimFlash,
161 areadesc: AreaDesc,
162 slots: [SlotInfo; 2],
163 align: u8,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300164 erased_val: u8,
David Browndb9a3952017-11-06 13:16:15 -0700165}
166
167impl Run {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300168 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Run {
169 let (flash, areadesc) = make_device(device, align, erased_val);
David Browndb9a3952017-11-06 13:16:15 -0700170
171 let (slot0_base, slot0_len) = areadesc.find(FlashId::Image0);
172 let (slot1_base, slot1_len) = areadesc.find(FlashId::Image1);
173 let (scratch_base, _) = areadesc.find(FlashId::ImageScratch);
174
175 // The code assumes that the slots are consecutive.
176 assert_eq!(slot1_base, slot0_base + slot0_len);
177 assert_eq!(scratch_base, slot1_base + slot1_len);
178
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200179 // NOTE: not accounting "swap_size" because it is not used by sim...
David Browndb9a3952017-11-06 13:16:15 -0700180 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
181
182 // Construct a primary image.
183 let slot0 = SlotInfo {
184 base_off: slot0_base as usize,
185 trailer_off: slot1_base - offset_from_end,
186 };
187
188 // And an upgrade image.
189 let slot1 = SlotInfo {
190 base_off: slot1_base as usize,
191 trailer_off: scratch_base - offset_from_end,
192 };
193
194 Run {
195 flash: flash,
196 areadesc: areadesc,
197 slots: [slot0, slot1],
198 align: align,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300199 erased_val: erased_val,
David Browndb9a3952017-11-06 13:16:15 -0700200 }
201 }
202
203 pub fn each_device<F>(f: F)
204 where F: Fn(&mut Run)
205 {
206 for &dev in ALL_DEVICES {
207 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300208 for &erased_val in &[0, 0xff] {
209 let mut run = Run::new(dev, align, erased_val);
210 f(&mut run);
211 }
David Browndb9a3952017-11-06 13:16:15 -0700212 }
213 }
214 }
David Brownf48b9502017-11-06 14:00:26 -0700215
216 /// Construct an `Images` that doesn't expect an upgrade to happen.
217 pub fn make_no_upgrade_image(&self) -> Images {
218 let mut flash = self.flash.clone();
219 let primary = install_image(&mut flash, self.slots[0].base_off, 32784, false);
220 let upgrade = install_image(&mut flash, self.slots[1].base_off, 41928, false);
221 Images {
222 flash: flash,
223 areadesc: self.areadesc.clone(),
224 slot0: self.slots[0].clone(),
225 slot1: self.slots[1].clone(),
226 primary: primary,
227 upgrade: upgrade,
David Brownc49811e2017-11-06 14:20:45 -0700228 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700229 align: self.align,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300230 erased_val: self.erased_val,
David Brownf48b9502017-11-06 14:00:26 -0700231 }
232 }
233
234 /// Construct an `Images` for normal testing.
235 pub fn make_image(&self) -> Images {
236 let mut images = self.make_no_upgrade_image();
237 mark_upgrade(&mut images.flash, &images.slot1);
David Brownc49811e2017-11-06 14:20:45 -0700238
239 // upgrades without fails, counts number of flash operations
240 let total_count = match images.run_basic_upgrade() {
241 Ok(v) => v,
242 Err(_) => {
243 panic!("Unable to perform basic upgrade");
244 },
245 };
246
247 images.total_count = Some(total_count);
David Brownf48b9502017-11-06 14:00:26 -0700248 images
249 }
250
251 pub fn make_bad_slot1_image(&self) -> Images {
252 let mut bad_flash = self.flash.clone();
253 let primary = install_image(&mut bad_flash, self.slots[0].base_off, 32784, false);
254 let upgrade = install_image(&mut bad_flash, self.slots[1].base_off, 41928, true);
255 Images {
256 flash: bad_flash,
257 areadesc: self.areadesc.clone(),
258 slot0: self.slots[0].clone(),
259 slot1: self.slots[1].clone(),
260 primary: primary,
261 upgrade: upgrade,
David Brownc49811e2017-11-06 14:20:45 -0700262 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700263 align: self.align,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300264 erased_val: self.erased_val,
David Brownf48b9502017-11-06 14:00:26 -0700265 }
266 }
David Brownc49811e2017-11-06 14:20:45 -0700267
David Browndb9a3952017-11-06 13:16:15 -0700268}
269
David Browndd2b1182017-11-02 15:39:21 -0600270pub struct RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600271 failures: usize,
272 passes: usize,
273}
274
275impl RunStatus {
David Browndd2b1182017-11-02 15:39:21 -0600276 pub fn new() -> RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600277 RunStatus {
278 failures: 0,
279 passes: 0,
280 }
281 }
282
Fabio Utzigea0290b2018-08-09 14:23:01 -0300283 pub fn run_single(&mut self, device: DeviceName, align: u8, erased_val: u8) {
David Brown2639e072017-10-11 11:18:44 -0600284 warn!("Running on device {} with alignment {}", device, align);
285
Fabio Utzigea0290b2018-08-09 14:23:01 -0300286 let run = Run::new(device, align, erased_val);
David Brown2639e072017-10-11 11:18:44 -0600287
David Brown2639e072017-10-11 11:18:44 -0600288 let mut failed = false;
289
290 // Creates a badly signed image in slot1 to check that it is not
291 // upgraded to
David Brownf48b9502017-11-06 14:00:26 -0700292 let bad_slot1_image = run.make_bad_slot1_image();
David Brown2639e072017-10-11 11:18:44 -0600293
David Brown5f7ec2b2017-11-06 13:54:02 -0700294 failed |= bad_slot1_image.run_signfail_upgrade();
David Brown2639e072017-10-11 11:18:44 -0600295
David Brownf48b9502017-11-06 14:00:26 -0700296 let images = run.make_no_upgrade_image();
David Brown5f7ec2b2017-11-06 13:54:02 -0700297 failed |= images.run_norevert_newimage();
David Brown2639e072017-10-11 11:18:44 -0600298
David Brownf48b9502017-11-06 14:00:26 -0700299 let images = run.make_image();
David Brown2639e072017-10-11 11:18:44 -0600300
David Brown5f7ec2b2017-11-06 13:54:02 -0700301 failed |= images.run_basic_revert();
David Brownc49811e2017-11-06 14:20:45 -0700302 failed |= images.run_revert_with_fails();
303 failed |= images.run_perm_with_fails();
304 failed |= images.run_perm_with_random_fails(5);
David Brown5f7ec2b2017-11-06 13:54:02 -0700305 failed |= images.run_norevert();
David Brown2639e072017-10-11 11:18:44 -0600306
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200307 failed |= images.run_with_status_fails_complete();
Fabio Utzigeedcc452017-11-24 10:48:52 -0200308 failed |= images.run_with_status_fails_with_reset();
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200309
David Brown2639e072017-10-11 11:18:44 -0600310 //show_flash(&flash);
311
312 if failed {
313 self.failures += 1;
314 } else {
315 self.passes += 1;
316 }
317 }
David Browndd2b1182017-11-02 15:39:21 -0600318
319 pub fn failures(&self) -> usize {
320 self.failures
321 }
David Brown2639e072017-10-11 11:18:44 -0600322}
323
David Browndecbd042017-10-19 10:43:17 -0600324/// Build the Flash and area descriptor for a given device.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300325pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimFlash, AreaDesc) {
David Browndecbd042017-10-19 10:43:17 -0600326 match device {
327 DeviceName::Stm32f4 => {
328 // STM style flash. Large sectors, with a large scratch area.
329 let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
330 64 * 1024,
331 128 * 1024, 128 * 1024, 128 * 1024],
Fabio Utzigea0290b2018-08-09 14:23:01 -0300332 align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600333 let mut areadesc = AreaDesc::new(&flash);
334 areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
335 areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
336 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch);
337 (flash, areadesc)
338 }
339 DeviceName::K64f => {
340 // NXP style flash. Small sectors, one small sector for scratch.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300341 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600342
343 let mut areadesc = AreaDesc::new(&flash);
344 areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
345 areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
346 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch);
347 (flash, areadesc)
348 }
349 DeviceName::K64fBig => {
350 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
351 // uses small sectors, but we tell the bootloader they are large.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300352 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600353
354 let mut areadesc = AreaDesc::new(&flash);
355 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0);
356 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1);
357 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch);
358 (flash, areadesc)
359 }
360 DeviceName::Nrf52840 => {
361 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
362 // does not divide into the image size.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300363 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600364
365 let mut areadesc = AreaDesc::new(&flash);
366 areadesc.add_image(0x008000, 0x034000, FlashId::Image0);
367 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1);
368 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch);
369 (flash, areadesc)
370 }
371 }
372}
373
David Brown5f7ec2b2017-11-06 13:54:02 -0700374impl Images {
375 /// A simple upgrade without forced failures.
376 ///
377 /// Returns the number of flash operations which can later be used to
378 /// inject failures at chosen steps.
David Brownc49811e2017-11-06 14:20:45 -0700379 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Brown5f7ec2b2017-11-06 13:54:02 -0700380 let (fl, total_count) = try_upgrade(&self.flash, &self, None);
381 info!("Total flash operation count={}", total_count);
David Brown2639e072017-10-11 11:18:44 -0600382
David Brown5f7ec2b2017-11-06 13:54:02 -0700383 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
384 warn!("Image mismatch after first boot");
385 Err(())
386 } else {
387 Ok(total_count)
David Brown2639e072017-10-11 11:18:44 -0600388 }
389 }
390
David Brown5f7ec2b2017-11-06 13:54:02 -0700391 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700392 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700393 false
394 }
David Brown2639e072017-10-11 11:18:44 -0600395
David Brown5f7ec2b2017-11-06 13:54:02 -0700396 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700397 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700398 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600399
David Brown5f7ec2b2017-11-06 13:54:02 -0700400 // FIXME: this test would also pass if no swap is ever performed???
401 if Caps::SwapUpgrade.present() {
402 for count in 2 .. 5 {
403 info!("Try revert: {}", count);
404 let fl = try_revert(&self.flash, &self.areadesc, count, self.align);
405 if !verify_image(&fl, self.slot0.base_off, &self.primary) {
406 error!("Revert failure on count {}", count);
407 fails += 1;
408 }
409 }
410 }
411
412 fails > 0
413 }
414
David Browna4167ef2017-11-06 14:30:05 -0700415 pub fn run_perm_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700416 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700417 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700418
419 // Let's try an image halfway through.
420 for i in 1 .. total_flash_ops {
421 info!("Try interruption at {}", i);
422 let (fl, count) = try_upgrade(&self.flash, &self, Some(i));
423 info!("Second boot, count={}", count);
424 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
425 warn!("FAIL at step {} of {}", i, total_flash_ops);
426 fails += 1;
427 }
428
Fabio Utzigea0290b2018-08-09 14:23:01 -0300429 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
430 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700431 warn!("Mismatched trailer for Slot 0");
432 fails += 1;
433 }
434
Fabio Utzigea0290b2018-08-09 14:23:01 -0300435 if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
436 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700437 warn!("Mismatched trailer for Slot 1");
438 fails += 1;
439 }
440
441 if Caps::SwapUpgrade.present() {
442 if !verify_image(&fl, self.slot1.base_off, &self.primary) {
443 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
444 fails += 1;
445 }
446 }
447 }
448
449 if fails > 0 {
450 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
451 fails as f32 * 100.0 / total_flash_ops as f32);
452 }
453
454 fails > 0
455 }
456
David Browna4167ef2017-11-06 14:30:05 -0700457 pub fn run_perm_with_random_fails_5(&self) -> bool {
458 self.run_perm_with_random_fails(5)
459 }
460
David Brownc49811e2017-11-06 14:20:45 -0700461 fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700462 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700463 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700464 let (fl, total_counts) = try_random_fails(&self.flash, &self,
465 total_flash_ops, total_fails);
466 info!("Random interruptions at reset points={:?}", total_counts);
467
468 let slot0_ok = verify_image(&fl, self.slot0.base_off, &self.upgrade);
469 let slot1_ok = if Caps::SwapUpgrade.present() {
470 verify_image(&fl, self.slot1.base_off, &self.primary)
471 } else {
472 true
473 };
474 if !slot0_ok || !slot1_ok {
475 error!("Image mismatch after random interrupts: slot0={} slot1={}",
476 if slot0_ok { "ok" } else { "fail" },
477 if slot1_ok { "ok" } else { "fail" });
478 fails += 1;
479 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300480 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
481 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700482 error!("Mismatched trailer for Slot 0");
483 fails += 1;
484 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300485 if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
486 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700487 error!("Mismatched trailer for Slot 1");
David Brown2639e072017-10-11 11:18:44 -0600488 fails += 1;
489 }
490
David Brown5f7ec2b2017-11-06 13:54:02 -0700491 if fails > 0 {
492 error!("Error testing perm upgrade with {} fails", total_fails);
493 }
494
495 fails > 0
496 }
497
498 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700499 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700500 false
501 }
502
503 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700504 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700505 let mut fails = 0;
506
507 if Caps::SwapUpgrade.present() {
David Brownc49811e2017-11-06 14:20:45 -0700508 for i in 1 .. (self.total_count.unwrap() - 1) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700509 info!("Try interruption at {}", i);
510 if try_revert_with_fail_at(&self.flash, &self, i) {
511 error!("Revert failed at interruption {}", i);
512 fails += 1;
513 }
514 }
515 }
516
517 fails > 0
518 }
519
520 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700521 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700522 false
523 }
524
525 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700526 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700527 let mut fl = self.flash.clone();
528 let mut fails = 0;
529
530 info!("Try norevert");
531
532 // First do a normal upgrade...
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200533 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
534 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700535 warn!("Failed first boot");
536 fails += 1;
537 }
538
539 //FIXME: copy_done is written by boot_go, is it ok if no copy
540 // was ever done?
541
542 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
543 warn!("Slot 0 image verification FAIL");
544 fails += 1;
545 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300546 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
547 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600548 warn!("Mismatched trailer for Slot 0");
549 fails += 1;
550 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300551 if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
552 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600553 warn!("Mismatched trailer for Slot 1");
554 fails += 1;
555 }
556
David Brown5f7ec2b2017-11-06 13:54:02 -0700557 // Marks image in slot0 as permanent, no revert should happen...
Fabio Utzigea0290b2018-08-09 14:23:01 -0300558 mark_permanent_upgrade(&mut fl, &self.slot0, self.align, self.erased_val);
David Brown5f7ec2b2017-11-06 13:54:02 -0700559
Fabio Utzigea0290b2018-08-09 14:23:01 -0300560 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
561 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700562 warn!("Mismatched trailer for Slot 0");
563 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600564 }
David Brown2639e072017-10-11 11:18:44 -0600565
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200566 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
567 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700568 warn!("Failed second boot");
569 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600570 }
David Brown5f7ec2b2017-11-06 13:54:02 -0700571
Fabio Utzigea0290b2018-08-09 14:23:01 -0300572 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
573 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700574 warn!("Mismatched trailer for Slot 0");
575 fails += 1;
576 }
577 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
578 warn!("Failed image verification");
579 fails += 1;
580 }
581
582 if fails > 0 {
583 error!("Error running upgrade without revert");
584 }
585
586 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600587 }
588
David Brown5f7ec2b2017-11-06 13:54:02 -0700589 // Tests a new image written to slot0 that already has magic and image_ok set
590 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700591 pub fn run_norevert_newimage(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700592 let mut fl = self.flash.clone();
593 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600594
David Brown5f7ec2b2017-11-06 13:54:02 -0700595 info!("Try non-revert on imgtool generated image");
David Brown2639e072017-10-11 11:18:44 -0600596
David Brown5f7ec2b2017-11-06 13:54:02 -0700597 mark_upgrade(&mut fl, &self.slot0);
David Brown2639e072017-10-11 11:18:44 -0600598
David Brown5f7ec2b2017-11-06 13:54:02 -0700599 // This simulates writing an image created by imgtool to Slot 0
Fabio Utzigea0290b2018-08-09 14:23:01 -0300600 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
601 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700602 warn!("Mismatched trailer for Slot 0");
603 fails += 1;
604 }
David Brown2639e072017-10-11 11:18:44 -0600605
David Brown5f7ec2b2017-11-06 13:54:02 -0700606 // Run the bootloader...
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200607 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
608 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700609 warn!("Failed first boot");
610 fails += 1;
611 }
612
613 // State should not have changed
614 if !verify_image(&fl, self.slot0.base_off, &self.primary) {
615 warn!("Failed image verification");
616 fails += 1;
617 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300618 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
619 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700620 warn!("Mismatched trailer for Slot 0");
621 fails += 1;
622 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300623 if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
624 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700625 warn!("Mismatched trailer for Slot 1");
626 fails += 1;
627 }
628
629 if fails > 0 {
630 error!("Expected a non revert with new image");
631 }
632
633 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600634 }
635
David Brown5f7ec2b2017-11-06 13:54:02 -0700636 // Tests a new image written to slot0 that already has magic and image_ok set
637 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700638 pub fn run_signfail_upgrade(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700639 let mut fl = self.flash.clone();
640 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600641
David Brown5f7ec2b2017-11-06 13:54:02 -0700642 info!("Try upgrade image with bad signature");
643
644 mark_upgrade(&mut fl, &self.slot0);
Fabio Utzigea0290b2018-08-09 14:23:01 -0300645 mark_permanent_upgrade(&mut fl, &self.slot0, self.align, self.erased_val);
David Brown5f7ec2b2017-11-06 13:54:02 -0700646 mark_upgrade(&mut fl, &self.slot1);
647
Fabio Utzigea0290b2018-08-09 14:23:01 -0300648 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
649 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700650 warn!("Mismatched trailer for Slot 0");
651 fails += 1;
652 }
653
654 // Run the bootloader...
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200655 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
656 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700657 warn!("Failed first boot");
658 fails += 1;
659 }
660
661 // State should not have changed
662 if !verify_image(&fl, self.slot0.base_off, &self.primary) {
663 warn!("Failed image verification");
664 fails += 1;
665 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300666 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
667 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700668 warn!("Mismatched trailer for Slot 0");
669 fails += 1;
670 }
671
672 if fails > 0 {
673 error!("Expected an upgrade failure when image has bad signature");
674 }
675
676 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600677 }
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200678
Fabio Utziga91c6262017-12-06 09:01:12 -0200679 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200680 fn trailer_sz(&self) -> usize {
681 c::boot_trailer_sz(self.align) as usize
682 }
683
684 // FIXME: could get status sz from bootloader
Fabio Utziga91c6262017-12-06 09:01:12 -0200685 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200686 fn status_sz(&self) -> usize {
687 self.trailer_sz() - (16 + 24)
688 }
689
690 /// This test runs a simple upgrade with no fails in the images, but
691 /// allowing for fails in the status area. This should run to the end
692 /// and warn that write fails were detected...
693 #[cfg(not(feature = "validate-slot0"))]
694 pub fn run_with_status_fails_complete(&self) -> bool { false }
695
696 #[cfg(feature = "validate-slot0")]
697 pub fn run_with_status_fails_complete(&self) -> bool {
698 let mut fl = self.flash.clone();
699 let mut fails = 0;
700
701 info!("Try swap with status fails");
702
Fabio Utzigea0290b2018-08-09 14:23:01 -0300703 mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200704
705 let status_off = self.slot1.base_off - self.trailer_sz();
706
707 // Always fail writes to status area...
708 let _ = fl.add_bad_region(status_off, self.status_sz(), 1.0);
709
710 let (result, asserts) = c::boot_go(&mut fl, &self.areadesc, None, self.align, true);
711 if result != 0 {
712 warn!("Failed!");
713 fails += 1;
714 }
715
716 // Failed writes to the marked "bad" region don't assert anymore.
717 // Any detected assert() is happening in another part of the code.
718 if asserts != 0 {
719 warn!("At least one assert() was called");
720 fails += 1;
721 }
722
Fabio Utzigea0290b2018-08-09 14:23:01 -0300723 if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
724 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200725 warn!("Mismatched trailer for Slot 0");
726 fails += 1;
727 }
728
729 if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
730 warn!("Failed image verification");
731 fails += 1;
732 }
733
734 info!("validate slot0 enabled; re-run of boot_go should just work");
735 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, self.align, false);
736 if result != 0 {
737 warn!("Failed!");
738 fails += 1;
739 }
740
741 if fails > 0 {
742 error!("Error running upgrade with status write fails");
743 }
744
745 fails > 0
746 }
747
748 /// This test runs a simple upgrade with no fails in the images, but
749 /// allowing for fails in the status area. This should run to the end
750 /// and warn that write fails were detected...
751 #[cfg(feature = "validate-slot0")]
752 pub fn run_with_status_fails_with_reset(&self) -> bool {
753 let mut fl = self.flash.clone();
754 let mut fails = 0;
755 let mut count = self.total_count.unwrap() / 2;
756
757 //info!("count={}\n", count);
758
759 info!("Try interrupted swap with status fails");
760
Fabio Utzigea0290b2018-08-09 14:23:01 -0300761 mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200762
763 let status_off = self.slot1.base_off - self.trailer_sz();
764
765 // Mark the status area as a bad area
766 let _ = fl.add_bad_region(status_off, self.status_sz(), 0.5);
767
768 // Should not fail, writing to bad regions does not assert
769 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, Some(&mut count), self.align, true);
770 if asserts != 0 {
771 warn!("At least one assert() was called");
772 fails += 1;
773 }
774
775 fl.reset_bad_regions();
776
777 // Disabling write verification the only assert triggered by
778 // boot_go should be checking for integrity of status bytes.
779 fl.set_verify_writes(false);
780
781 info!("Resuming an interrupted swap operation");
782 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, None, self.align, true);
783
784 // This might throw no asserts, for large sector devices, where
785 // a single failure writing is indistinguishable from no failure,
786 // or throw a single assert for small sector devices that fail
787 // multiple times...
788 if asserts > 1 {
789 warn!("Expected single assert validating slot0, more detected {}", asserts);
790 fails += 1;
791 }
792
793 if fails > 0 {
794 error!("Error running upgrade with status write fails");
795 }
796
797 fails > 0
798 }
799
800 #[cfg(not(feature = "validate-slot0"))]
801 #[cfg(not(feature = "overwrite-only"))]
802 pub fn run_with_status_fails_with_reset(&self) -> bool {
803 let mut fl = self.flash.clone();
804 let mut fails = 0;
805
806 info!("Try interrupted swap with status fails");
807
Fabio Utzigea0290b2018-08-09 14:23:01 -0300808 mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200809
810 let status_off = self.slot1.base_off - self.trailer_sz();
811
812 // Mark the status area as a bad area
813 let _ = fl.add_bad_region(status_off, self.status_sz(), 1.0);
814
815 // This is expected to fail while writing to bad regions...
816 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, None, self.align, true);
817 if asserts == 0 {
818 warn!("No assert() detected");
819 fails += 1;
820 }
821
822 fails > 0
823 }
824
825 #[cfg(feature = "overwrite-only")]
826 pub fn run_with_status_fails_with_reset(&self) -> bool {
827 false
828 }
David Brown2639e072017-10-11 11:18:44 -0600829}
830
831/// Test a boot, optionally stopping after 'n' flash options. Returns a count
832/// of the number of flash operations done total.
David Brown3f687dc2017-11-06 13:41:18 -0700833fn try_upgrade(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600834 stop: Option<i32>) -> (SimFlash, i32) {
835 // Clone the flash to have a new copy.
836 let mut fl = flash.clone();
837
Fabio Utzigea0290b2018-08-09 14:23:01 -0300838 mark_permanent_upgrade(&mut fl, &images.slot1, images.align, images.erased_val);
David Brown2639e072017-10-11 11:18:44 -0600839
David Brownee61c832017-11-06 11:13:25 -0700840 let mut counter = stop.unwrap_or(0);
841
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200842 let (first_interrupted, count) = match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), images.align, false) {
843 (-0x13579, _) => (true, stop.unwrap()),
844 (0, _) => (false, -counter),
845 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600846 };
David Brown2639e072017-10-11 11:18:44 -0600847
David Brownee61c832017-11-06 11:13:25 -0700848 counter = 0;
David Brown2639e072017-10-11 11:18:44 -0600849 if first_interrupted {
850 // fl.dump();
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200851 match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), images.align, false) {
852 (-0x13579, _) => panic!("Shouldn't stop again"),
853 (0, _) => (),
854 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600855 }
856 }
857
David Brownee61c832017-11-06 11:13:25 -0700858 (fl, count - counter)
David Brown2639e072017-10-11 11:18:44 -0600859}
860
861#[cfg(not(feature = "overwrite-only"))]
David Brown541860c2017-11-06 11:25:42 -0700862fn try_revert(flash: &SimFlash, areadesc: &AreaDesc, count: usize, align: u8) -> SimFlash {
David Brown2639e072017-10-11 11:18:44 -0600863 let mut fl = flash.clone();
David Brown2639e072017-10-11 11:18:44 -0600864
865 // fl.write_file("image0.bin").unwrap();
866 for i in 0 .. count {
867 info!("Running boot pass {}", i + 1);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200868 assert_eq!(c::boot_go(&mut fl, &areadesc, None, align, false), (0, 0));
David Brown2639e072017-10-11 11:18:44 -0600869 }
870 fl
871}
872
873#[cfg(not(feature = "overwrite-only"))]
David Brown3f687dc2017-11-06 13:41:18 -0700874fn try_revert_with_fail_at(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600875 stop: i32) -> bool {
876 let mut fl = flash.clone();
David Brown2639e072017-10-11 11:18:44 -0600877 let mut fails = 0;
878
David Brownee61c832017-11-06 11:13:25 -0700879 let mut counter = stop;
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200880 let (x, _) = c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), images.align, false);
David Brown2639e072017-10-11 11:18:44 -0600881 if x != -0x13579 {
882 warn!("Should have stopped at interruption point");
883 fails += 1;
884 }
885
Fabio Utzigea0290b2018-08-09 14:23:01 -0300886 if !verify_trailer(&fl, images.slot0.trailer_off, None, None, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600887 warn!("copy_done should be unset");
888 fails += 1;
889 }
890
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200891 let (x, _) = c::boot_go(&mut fl, &images.areadesc, None, images.align, false);
David Brown2639e072017-10-11 11:18:44 -0600892 if x != 0 {
893 warn!("Should have finished upgrade");
894 fails += 1;
895 }
896
897 if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
898 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
899 fails += 1;
900 }
901 if !verify_image(&fl, images.slot1.base_off, &images.primary) {
902 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
903 fails += 1;
904 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300905 if !verify_trailer(&fl, images.slot0.trailer_off, BOOT_MAGIC_GOOD,
906 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600907 warn!("Mismatched trailer for Slot 0 before revert");
908 fails += 1;
909 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300910 if !verify_trailer(&fl, images.slot1.trailer_off, BOOT_MAGIC_UNSET,
911 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600912 warn!("Mismatched trailer for Slot 1 before revert");
913 fails += 1;
914 }
915
916 // Do Revert
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200917 let (x, _) = c::boot_go(&mut fl, &images.areadesc, None, images.align, false);
David Brown2639e072017-10-11 11:18:44 -0600918 if x != 0 {
919 warn!("Should have finished a revert");
920 fails += 1;
921 }
922
923 if !verify_image(&fl, images.slot0.base_off, &images.primary) {
924 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
925 fails += 1;
926 }
927 if !verify_image(&fl, images.slot1.base_off, &images.upgrade) {
928 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
929 fails += 1;
930 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300931 if !verify_trailer(&fl, images.slot0.trailer_off, BOOT_MAGIC_GOOD,
932 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600933 warn!("Mismatched trailer for Slot 1 after revert");
934 fails += 1;
935 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300936 if !verify_trailer(&fl, images.slot1.trailer_off, BOOT_MAGIC_UNSET,
937 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600938 warn!("Mismatched trailer for Slot 1 after revert");
939 fails += 1;
940 }
941
942 fails > 0
943}
944
David Brown3f687dc2017-11-06 13:41:18 -0700945fn try_random_fails(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600946 total_ops: i32, count: usize) -> (SimFlash, Vec<i32>) {
947 let mut fl = flash.clone();
948
Fabio Utzigea0290b2018-08-09 14:23:01 -0300949 mark_permanent_upgrade(&mut fl, &images.slot1, images.align, images.erased_val);
David Brown2639e072017-10-11 11:18:44 -0600950
951 let mut rng = rand::thread_rng();
952 let mut resets = vec![0i32; count];
953 let mut remaining_ops = total_ops;
954 for i in 0 .. count {
955 let ops = Range::new(1, remaining_ops / 2);
956 let reset_counter = ops.ind_sample(&mut rng);
David Brownee61c832017-11-06 11:13:25 -0700957 let mut counter = reset_counter;
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200958 match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), images.align, false) {
959 (0, _) | (-0x13579, _) => (),
960 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600961 }
962 remaining_ops -= reset_counter;
963 resets[i] = reset_counter;
964 }
965
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200966 match c::boot_go(&mut fl, &images.areadesc, None, images.align, false) {
967 (-0x13579, _) => panic!("Should not be have been interrupted!"),
968 (0, _) => (),
969 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600970 }
971
972 (fl, resets)
973}
974
975/// Show the flash layout.
976#[allow(dead_code)]
977fn show_flash(flash: &Flash) {
978 println!("---- Flash configuration ----");
979 for sector in flash.sector_iter() {
980 println!(" {:3}: 0x{:08x}, 0x{:08x}",
981 sector.num, sector.base, sector.size);
982 }
983 println!("");
984}
985
986/// Install a "program" into the given image. This fakes the image header, or at least all of the
987/// fields used by the given code. Returns a copy of the image that was written.
988fn install_image(flash: &mut Flash, offset: usize, len: usize,
989 bad_sig: bool) -> Vec<u8> {
990 let offset0 = offset;
991
992 let mut tlv = make_tlv();
993
994 // Generate a boot header. Note that the size doesn't include the header.
995 let header = ImageHeader {
996 magic: 0x96f3b83d,
997 tlv_size: tlv.get_size(),
998 _pad1: 0,
999 hdr_size: 32,
1000 key_id: 0,
1001 _pad2: 0,
1002 img_size: len as u32,
1003 flags: tlv.get_flags(),
1004 ver: ImageVersion {
1005 major: (offset / (128 * 1024)) as u8,
1006 minor: 0,
1007 revision: 1,
1008 build_num: offset as u32,
1009 },
1010 _pad3: 0,
1011 };
1012
1013 let b_header = header.as_raw();
1014 tlv.add_bytes(&b_header);
1015 /*
1016 let b_header = unsafe { slice::from_raw_parts(&header as *const _ as *const u8,
1017 mem::size_of::<ImageHeader>()) };
1018 */
1019 assert_eq!(b_header.len(), 32);
1020 flash.write(offset, &b_header).unwrap();
1021 let offset = offset + b_header.len();
1022
1023 // The core of the image itself is just pseudorandom data.
1024 let mut buf = vec![0; len];
1025 splat(&mut buf, offset);
1026 tlv.add_bytes(&buf);
1027
1028 // Get and append the TLV itself.
1029 if bad_sig {
1030 let good_sig = &mut tlv.make_tlv();
1031 buf.append(&mut vec![0; good_sig.len()]);
1032 } else {
1033 buf.append(&mut tlv.make_tlv());
1034 }
1035
1036 // Pad the block to a flash alignment (8 bytes).
1037 while buf.len() % 8 != 0 {
1038 buf.push(0xFF);
1039 }
1040
1041 flash.write(offset, &buf).unwrap();
1042 let offset = offset + buf.len();
1043
1044 // Copy out the image so that we can verify that the image was installed correctly later.
1045 let mut copy = vec![0u8; offset - offset0];
1046 flash.read(offset0, &mut copy).unwrap();
1047
1048 copy
1049}
1050
1051// The TLV in use depends on what kind of signature we are verifying.
1052#[cfg(feature = "sig-rsa")]
1053fn make_tlv() -> TlvGen {
1054 TlvGen::new_rsa_pss()
1055}
1056
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001057#[cfg(feature = "sig-ecdsa")]
1058fn make_tlv() -> TlvGen {
1059 TlvGen::new_ecdsa()
1060}
1061
David Brown2639e072017-10-11 11:18:44 -06001062#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001063#[cfg(not(feature = "sig-ecdsa"))]
David Brown2639e072017-10-11 11:18:44 -06001064fn make_tlv() -> TlvGen {
1065 TlvGen::new_hash_only()
1066}
1067
1068/// Verify that given image is present in the flash at the given offset.
1069fn verify_image(flash: &Flash, offset: usize, buf: &[u8]) -> bool {
1070 let mut copy = vec![0u8; buf.len()];
1071 flash.read(offset, &mut copy).unwrap();
1072
1073 if buf != &copy[..] {
1074 for i in 0 .. buf.len() {
1075 if buf[i] != copy[i] {
1076 info!("First failure at {:#x}", offset + i);
1077 break;
1078 }
1079 }
1080 false
1081 } else {
1082 true
1083 }
1084}
1085
1086#[cfg(feature = "overwrite-only")]
1087#[allow(unused_variables)]
1088// overwrite-only doesn't employ trailer management
1089fn verify_trailer(flash: &Flash, offset: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001090 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001091 copy_done: Option<u8>) -> bool {
1092 true
1093}
1094
1095#[cfg(not(feature = "overwrite-only"))]
1096fn verify_trailer(flash: &Flash, offset: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001097 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001098 copy_done: Option<u8>) -> bool {
1099 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1100 let mut failed = false;
Fabio Utzigea0290b2018-08-09 14:23:01 -03001101 let erased_val = flash.erased_val();
David Brown2639e072017-10-11 11:18:44 -06001102
1103 flash.read(offset, &mut copy).unwrap();
1104
1105 failed |= match magic {
1106 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001107 if v == 1 && &copy[16..] != MAGIC.unwrap() {
David Brown2639e072017-10-11 11:18:44 -06001108 warn!("\"magic\" mismatch at {:#x}", offset);
1109 true
Fabio Utzigea0290b2018-08-09 14:23:01 -03001110 } else if v == 3 {
1111 let expected = [erased_val; 16];
1112 if &copy[16..] != expected {
1113 warn!("\"magic\" mismatch at {:#x}", offset);
1114 true
1115 } else {
1116 false
1117 }
David Brown2639e072017-10-11 11:18:44 -06001118 } else {
1119 false
1120 }
1121 },
1122 None => false,
1123 };
1124
1125 failed |= match image_ok {
1126 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001127 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1128 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
David Brown2639e072017-10-11 11:18:44 -06001129 true
1130 } else {
1131 false
1132 }
1133 },
1134 None => false,
1135 };
1136
1137 failed |= match copy_done {
1138 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001139 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1140 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
David Brown2639e072017-10-11 11:18:44 -06001141 true
1142 } else {
1143 false
1144 }
1145 },
1146 None => false,
1147 };
1148
1149 !failed
1150}
1151
1152/// The image header
1153#[repr(C)]
1154pub struct ImageHeader {
1155 magic: u32,
1156 tlv_size: u16,
1157 key_id: u8,
1158 _pad1: u8,
1159 hdr_size: u16,
1160 _pad2: u16,
1161 img_size: u32,
1162 flags: u32,
1163 ver: ImageVersion,
1164 _pad3: u32,
1165}
1166
1167impl AsRaw for ImageHeader {}
1168
1169#[repr(C)]
1170pub struct ImageVersion {
1171 major: u8,
1172 minor: u8,
1173 revision: u16,
1174 build_num: u32,
1175}
1176
David Brownd5e632c2017-10-19 10:49:46 -06001177#[derive(Clone)]
David Brown2639e072017-10-11 11:18:44 -06001178struct SlotInfo {
1179 base_off: usize,
1180 trailer_off: usize,
1181}
1182
David Brownf48b9502017-11-06 14:00:26 -07001183pub struct Images {
David Browndc9cba12017-11-06 13:31:42 -07001184 flash: SimFlash,
David Brown3f687dc2017-11-06 13:41:18 -07001185 areadesc: AreaDesc,
David Brownd5e632c2017-10-19 10:49:46 -06001186 slot0: SlotInfo,
1187 slot1: SlotInfo,
David Brown2639e072017-10-11 11:18:44 -06001188 primary: Vec<u8>,
1189 upgrade: Vec<u8>,
David Brownc49811e2017-11-06 14:20:45 -07001190 total_count: Option<i32>,
David Brown541860c2017-11-06 11:25:42 -07001191 align: u8,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001192 erased_val: u8,
David Brown2639e072017-10-11 11:18:44 -06001193}
1194
Fabio Utzigea0290b2018-08-09 14:23:01 -03001195const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1196 0x60, 0xd2, 0xef, 0x7f,
1197 0x35, 0x52, 0x50, 0x0f,
1198 0x2c, 0xb6, 0x79, 0x80]);
David Brown2639e072017-10-11 11:18:44 -06001199
Fabio Utzigea0290b2018-08-09 14:23:01 -03001200// Replicates defines found in bootutil.h
1201const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1202const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1203
1204const BOOT_FLAG_SET: Option<u8> = Some(1);
1205const BOOT_FLAG_UNSET: Option<u8> = Some(3);
David Brown2639e072017-10-11 11:18:44 -06001206
1207/// Write out the magic so that the loader tries doing an upgrade.
1208fn mark_upgrade(flash: &mut Flash, slot: &SlotInfo) {
1209 let offset = slot.trailer_off + c::boot_max_align() * 2;
Fabio Utzigea0290b2018-08-09 14:23:01 -03001210 flash.write(offset, MAGIC.unwrap()).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001211}
1212
1213/// Writes the image_ok flag which, guess what, tells the bootloader
1214/// the this image is ok (not a test, and no revert is to be performed).
Fabio Utzigea0290b2018-08-09 14:23:01 -03001215fn mark_permanent_upgrade(flash: &mut Flash, slot: &SlotInfo, align: u8, erased_val: u8) {
1216 let mut ok = [erased_val; 8];
1217 ok[0] = 1u8;
David Brown2639e072017-10-11 11:18:44 -06001218 let off = slot.trailer_off + c::boot_max_align();
David Brown541860c2017-11-06 11:25:42 -07001219 flash.write(off, &ok[..align as usize]).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001220}
1221
1222// Drop some pseudo-random gibberish onto the data.
1223fn splat(data: &mut [u8], seed: usize) {
1224 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1225 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1226 rng.fill_bytes(data);
1227}
1228
1229/// Return a read-only view into the raw bytes of this object
1230trait AsRaw : Sized {
1231 fn as_raw<'a>(&'a self) -> &'a [u8] {
1232 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1233 mem::size_of::<Self>()) }
1234 }
1235}
1236
1237fn show_sizes() {
1238 // This isn't panic safe.
David Brown2639e072017-10-11 11:18:44 -06001239 for min in &[1, 2, 4, 8] {
David Brown541860c2017-11-06 11:25:42 -07001240 let msize = c::boot_trailer_sz(*min);
David Brown2639e072017-10-11 11:18:44 -06001241 println!("{:2}: {} (0x{:x})", min, msize, msize);
1242 }
David Brown2639e072017-10-11 11:18:44 -06001243}