blob: 992dcee9aa296ebbecbd9c073f903c19ae870bf0 [file] [log] [blame]
David Brown2639e072017-10-11 11:18:44 -06001#[macro_use] extern crate log;
2extern crate ring;
Fabio Utzig1e48b912018-09-18 09:04:18 -03003extern crate aes_ctr;
4extern crate base64;
David Brown2639e072017-10-11 11:18:44 -06005extern crate env_logger;
6extern crate docopt;
7extern crate libc;
8extern crate pem;
9extern crate rand;
10#[macro_use] extern crate serde_derive;
11extern crate serde;
12extern crate simflash;
13extern crate untrusted;
14extern crate mcuboot_sys;
15
16use docopt::Docopt;
17use rand::{Rng, SeedableRng, XorShiftRng};
18use rand::distributions::{IndependentSample, Range};
19use std::fmt;
20use std::mem;
21use std::process;
22use std::slice;
Fabio Utzig1e48b912018-09-18 09:04:18 -030023use aes_ctr::Aes128Ctr;
24use aes_ctr::stream_cipher::generic_array::GenericArray;
25use aes_ctr::stream_cipher::{NewFixStreamCipher, StreamCipherCore};
David Brown2639e072017-10-11 11:18:44 -060026
27mod caps;
28mod tlv;
David Brownca7b5d32017-11-03 08:37:38 -060029pub mod testlog;
David Brown2639e072017-10-11 11:18:44 -060030
31use simflash::{Flash, SimFlash};
32use mcuboot_sys::{c, AreaDesc, FlashId};
33use caps::Caps;
Fabio Utzig1e48b912018-09-18 09:04:18 -030034use tlv::{TlvGen, TlvFlags, AES_SEC_KEY};
David Brown2639e072017-10-11 11:18:44 -060035
36const USAGE: &'static str = "
37Mcuboot simulator
38
39Usage:
40 bootsim sizes
41 bootsim run --device TYPE [--align SIZE]
42 bootsim runall
43 bootsim (--help | --version)
44
45Options:
46 -h, --help Show this message
47 --version Version
48 --device TYPE MCU to simulate
49 Valid values: stm32f4, k64f
50 --align SIZE Flash write alignment
51";
52
53#[derive(Debug, Deserialize)]
54struct Args {
55 flag_help: bool,
56 flag_version: bool,
57 flag_device: Option<DeviceName>,
58 flag_align: Option<AlignArg>,
59 cmd_sizes: bool,
60 cmd_run: bool,
61 cmd_runall: bool,
62}
63
64#[derive(Copy, Clone, Debug, Deserialize)]
David Browndecbd042017-10-19 10:43:17 -060065pub enum DeviceName { Stm32f4, K64f, K64fBig, Nrf52840 }
David Brown2639e072017-10-11 11:18:44 -060066
David Browndd2b1182017-11-02 15:39:21 -060067pub static ALL_DEVICES: &'static [DeviceName] = &[
David Brown2639e072017-10-11 11:18:44 -060068 DeviceName::Stm32f4,
69 DeviceName::K64f,
70 DeviceName::K64fBig,
71 DeviceName::Nrf52840,
72];
73
74impl fmt::Display for DeviceName {
75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76 let name = match *self {
77 DeviceName::Stm32f4 => "stm32f4",
78 DeviceName::K64f => "k64f",
79 DeviceName::K64fBig => "k64fbig",
80 DeviceName::Nrf52840 => "nrf52840",
81 };
82 f.write_str(name)
83 }
84}
85
86#[derive(Debug)]
87struct AlignArg(u8);
88
89struct AlignArgVisitor;
90
91impl<'de> serde::de::Visitor<'de> for AlignArgVisitor {
92 type Value = AlignArg;
93
94 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
95 formatter.write_str("1, 2, 4 or 8")
96 }
97
98 fn visit_u8<E>(self, n: u8) -> Result<Self::Value, E>
99 where E: serde::de::Error
100 {
101 Ok(match n {
102 1 | 2 | 4 | 8 => AlignArg(n),
103 n => {
104 let err = format!("Could not deserialize '{}' as alignment", n);
105 return Err(E::custom(err));
106 }
107 })
108 }
109}
110
111impl<'de> serde::de::Deserialize<'de> for AlignArg {
112 fn deserialize<D>(d: D) -> Result<AlignArg, D::Error>
113 where D: serde::de::Deserializer<'de>
114 {
115 d.deserialize_u8(AlignArgVisitor)
116 }
117}
118
119pub fn main() {
120 let args: Args = Docopt::new(USAGE)
121 .and_then(|d| d.deserialize())
122 .unwrap_or_else(|e| e.exit());
123 // println!("args: {:#?}", args);
124
125 if args.cmd_sizes {
126 show_sizes();
127 return;
128 }
129
130 let mut status = RunStatus::new();
131 if args.cmd_run {
132
133 let align = args.flag_align.map(|x| x.0).unwrap_or(1);
134
135
136 let device = match args.flag_device {
137 None => panic!("Missing mandatory device argument"),
138 Some(dev) => dev,
139 };
140
Fabio Utzigea0290b2018-08-09 14:23:01 -0300141 status.run_single(device, align, 0xff);
David Brown2639e072017-10-11 11:18:44 -0600142 }
143
144 if args.cmd_runall {
145 for &dev in ALL_DEVICES {
146 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300147 for &erased_val in &[0, 0xff] {
148 status.run_single(dev, align, erased_val);
149 }
David Brown2639e072017-10-11 11:18:44 -0600150 }
151 }
152 }
153
154 if status.failures > 0 {
155 error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
156 process::exit(1);
157 } else {
158 error!("{} Tests ran successfully", status.passes);
159 process::exit(0);
160 }
161}
162
David Browndb9a3952017-11-06 13:16:15 -0700163/// A test run, intended to be run from "cargo test", so panics on failure.
164pub struct Run {
165 flash: SimFlash,
166 areadesc: AreaDesc,
167 slots: [SlotInfo; 2],
David Browndb9a3952017-11-06 13:16:15 -0700168}
169
170impl Run {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300171 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Run {
172 let (flash, areadesc) = make_device(device, align, erased_val);
David Browndb9a3952017-11-06 13:16:15 -0700173
174 let (slot0_base, slot0_len) = areadesc.find(FlashId::Image0);
175 let (slot1_base, slot1_len) = areadesc.find(FlashId::Image1);
176 let (scratch_base, _) = areadesc.find(FlashId::ImageScratch);
177
178 // The code assumes that the slots are consecutive.
179 assert_eq!(slot1_base, slot0_base + slot0_len);
180 assert_eq!(scratch_base, slot1_base + slot1_len);
181
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200182 // NOTE: not accounting "swap_size" because it is not used by sim...
David Browndb9a3952017-11-06 13:16:15 -0700183 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
184
185 // Construct a primary image.
186 let slot0 = SlotInfo {
187 base_off: slot0_base as usize,
188 trailer_off: slot1_base - offset_from_end,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300189 len: slot0_len as usize,
David Browndb9a3952017-11-06 13:16:15 -0700190 };
191
192 // And an upgrade image.
193 let slot1 = SlotInfo {
194 base_off: slot1_base as usize,
195 trailer_off: scratch_base - offset_from_end,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300196 len: slot1_len as usize,
David Browndb9a3952017-11-06 13:16:15 -0700197 };
198
199 Run {
200 flash: flash,
201 areadesc: areadesc,
202 slots: [slot0, slot1],
David Browndb9a3952017-11-06 13:16:15 -0700203 }
204 }
205
206 pub fn each_device<F>(f: F)
207 where F: Fn(&mut Run)
208 {
209 for &dev in ALL_DEVICES {
210 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300211 for &erased_val in &[0, 0xff] {
212 let mut run = Run::new(dev, align, erased_val);
213 f(&mut run);
214 }
David Browndb9a3952017-11-06 13:16:15 -0700215 }
216 }
217 }
David Brownf48b9502017-11-06 14:00:26 -0700218
219 /// Construct an `Images` that doesn't expect an upgrade to happen.
220 pub fn make_no_upgrade_image(&self) -> Images {
221 let mut flash = self.flash.clone();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300222 let primaries = install_image(&mut flash, &self.slots, 0, 32784, false);
223 let upgrades = install_image(&mut flash, &self.slots, 1, 41928, false);
David Brownf48b9502017-11-06 14:00:26 -0700224 Images {
225 flash: flash,
226 areadesc: self.areadesc.clone(),
Fabio Utzig1e48b912018-09-18 09:04:18 -0300227 slots: [self.slots[0].clone(), self.slots[1].clone()],
228 primaries: primaries,
229 upgrades: upgrades,
David Brownc49811e2017-11-06 14:20:45 -0700230 total_count: None,
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();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300237 mark_upgrade(&mut images.flash, &images.slots[1]);
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();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300253 let primaries = install_image(&mut bad_flash, &self.slots, 0, 32784, false);
254 let upgrades = install_image(&mut bad_flash, &self.slots, 1, 41928, true);
David Brownf48b9502017-11-06 14:00:26 -0700255 Images {
256 flash: bad_flash,
257 areadesc: self.areadesc.clone(),
Fabio Utzig1e48b912018-09-18 09:04:18 -0300258 slots: [self.slots[0].clone(), self.slots[1].clone()],
259 primaries: primaries,
260 upgrades: upgrades,
David Brownc49811e2017-11-06 14:20:45 -0700261 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700262 }
263 }
David Brownc49811e2017-11-06 14:20:45 -0700264
David Browndb9a3952017-11-06 13:16:15 -0700265}
266
David Browndd2b1182017-11-02 15:39:21 -0600267pub struct RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600268 failures: usize,
269 passes: usize,
270}
271
272impl RunStatus {
David Browndd2b1182017-11-02 15:39:21 -0600273 pub fn new() -> RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600274 RunStatus {
275 failures: 0,
276 passes: 0,
277 }
278 }
279
Fabio Utzigea0290b2018-08-09 14:23:01 -0300280 pub fn run_single(&mut self, device: DeviceName, align: u8, erased_val: u8) {
David Brown2639e072017-10-11 11:18:44 -0600281 warn!("Running on device {} with alignment {}", device, align);
282
Fabio Utzigea0290b2018-08-09 14:23:01 -0300283 let run = Run::new(device, align, erased_val);
David Brown2639e072017-10-11 11:18:44 -0600284
David Brown2639e072017-10-11 11:18:44 -0600285 let mut failed = false;
286
287 // Creates a badly signed image in slot1 to check that it is not
288 // upgraded to
David Brownf48b9502017-11-06 14:00:26 -0700289 let bad_slot1_image = run.make_bad_slot1_image();
David Brown2639e072017-10-11 11:18:44 -0600290
David Brown5f7ec2b2017-11-06 13:54:02 -0700291 failed |= bad_slot1_image.run_signfail_upgrade();
David Brown2639e072017-10-11 11:18:44 -0600292
David Brownf48b9502017-11-06 14:00:26 -0700293 let images = run.make_no_upgrade_image();
David Brown5f7ec2b2017-11-06 13:54:02 -0700294 failed |= images.run_norevert_newimage();
David Brown2639e072017-10-11 11:18:44 -0600295
David Brownf48b9502017-11-06 14:00:26 -0700296 let images = run.make_image();
David Brown2639e072017-10-11 11:18:44 -0600297
David Brown5f7ec2b2017-11-06 13:54:02 -0700298 failed |= images.run_basic_revert();
David Brownc49811e2017-11-06 14:20:45 -0700299 failed |= images.run_revert_with_fails();
300 failed |= images.run_perm_with_fails();
301 failed |= images.run_perm_with_random_fails(5);
David Brown5f7ec2b2017-11-06 13:54:02 -0700302 failed |= images.run_norevert();
David Brown2639e072017-10-11 11:18:44 -0600303
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200304 failed |= images.run_with_status_fails_complete();
Fabio Utzigeedcc452017-11-24 10:48:52 -0200305 failed |= images.run_with_status_fails_with_reset();
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200306
David Brown2639e072017-10-11 11:18:44 -0600307 //show_flash(&flash);
308
309 if failed {
310 self.failures += 1;
311 } else {
312 self.passes += 1;
313 }
314 }
David Browndd2b1182017-11-02 15:39:21 -0600315
316 pub fn failures(&self) -> usize {
317 self.failures
318 }
David Brown2639e072017-10-11 11:18:44 -0600319}
320
David Browndecbd042017-10-19 10:43:17 -0600321/// Build the Flash and area descriptor for a given device.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300322pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimFlash, AreaDesc) {
David Browndecbd042017-10-19 10:43:17 -0600323 match device {
324 DeviceName::Stm32f4 => {
325 // STM style flash. Large sectors, with a large scratch area.
326 let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
327 64 * 1024,
328 128 * 1024, 128 * 1024, 128 * 1024],
Fabio Utzigea0290b2018-08-09 14:23:01 -0300329 align as usize, erased_val);
Fabio Utzig1caef132018-10-26 15:40:53 -0300330 let flash_id = 0;
331 let mut areadesc = AreaDesc::new();
332 areadesc.add_flash_sectors(flash_id, &flash);
333 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, flash_id);
334 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, flash_id);
335 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, flash_id);
David Browndecbd042017-10-19 10:43:17 -0600336 (flash, areadesc)
337 }
338 DeviceName::K64f => {
339 // NXP style flash. Small sectors, one small sector for scratch.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300340 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600341
Fabio Utzig1caef132018-10-26 15:40:53 -0300342 let flash_id = 0;
343 let mut areadesc = AreaDesc::new();
344 areadesc.add_flash_sectors(flash_id, &flash);
345 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, flash_id);
346 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, flash_id);
347 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, flash_id);
David Browndecbd042017-10-19 10:43:17 -0600348 (flash, areadesc)
349 }
350 DeviceName::K64fBig => {
351 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
352 // uses small sectors, but we tell the bootloader they are large.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300353 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600354
Fabio Utzig1caef132018-10-26 15:40:53 -0300355 let dev_id = 0;
356 let mut areadesc = AreaDesc::new();
357 areadesc.add_flash_sectors(dev_id, &flash);
358 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
359 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
360 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
David Browndecbd042017-10-19 10:43:17 -0600361 (flash, areadesc)
362 }
363 DeviceName::Nrf52840 => {
364 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
365 // does not divide into the image size.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300366 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600367
Fabio Utzig1caef132018-10-26 15:40:53 -0300368 let dev_id = 0;
369 let mut areadesc = AreaDesc::new();
370 areadesc.add_flash_sectors(dev_id, &flash);
371 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
372 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
373 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
David Browndecbd042017-10-19 10:43:17 -0600374 (flash, areadesc)
375 }
376 }
377}
378
David Brown5f7ec2b2017-11-06 13:54:02 -0700379impl Images {
380 /// A simple upgrade without forced failures.
381 ///
382 /// Returns the number of flash operations which can later be used to
383 /// inject failures at chosen steps.
David Brownc49811e2017-11-06 14:20:45 -0700384 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Brown5f7ec2b2017-11-06 13:54:02 -0700385 let (fl, total_count) = try_upgrade(&self.flash, &self, None);
386 info!("Total flash operation count={}", total_count);
David Brown2639e072017-10-11 11:18:44 -0600387
Fabio Utzig1e48b912018-09-18 09:04:18 -0300388 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700389 warn!("Image mismatch after first boot");
390 Err(())
391 } else {
392 Ok(total_count)
David Brown2639e072017-10-11 11:18:44 -0600393 }
394 }
395
David Brown5f7ec2b2017-11-06 13:54:02 -0700396 #[cfg(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 false
399 }
David Brown2639e072017-10-11 11:18:44 -0600400
David Brown5f7ec2b2017-11-06 13:54:02 -0700401 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700402 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700403 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600404
David Brown5f7ec2b2017-11-06 13:54:02 -0700405 // FIXME: this test would also pass if no swap is ever performed???
406 if Caps::SwapUpgrade.present() {
407 for count in 2 .. 5 {
408 info!("Try revert: {}", count);
Fabio Utzig269d2862018-10-24 17:45:38 -0300409 let fl = try_revert(&self.flash, &self.areadesc, count);
Fabio Utzig1e48b912018-09-18 09:04:18 -0300410 if !verify_image(&fl, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700411 error!("Revert failure on count {}", count);
412 fails += 1;
413 }
414 }
415 }
416
417 fails > 0
418 }
419
David Browna4167ef2017-11-06 14:30:05 -0700420 pub fn run_perm_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700421 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700422 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700423
424 // Let's try an image halfway through.
425 for i in 1 .. total_flash_ops {
426 info!("Try interruption at {}", i);
427 let (fl, count) = try_upgrade(&self.flash, &self, Some(i));
428 info!("Second boot, count={}", count);
Fabio Utzig1e48b912018-09-18 09:04:18 -0300429 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700430 warn!("FAIL at step {} of {}", i, total_flash_ops);
431 fails += 1;
432 }
433
Fabio Utzig1e48b912018-09-18 09:04:18 -0300434 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300435 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700436 warn!("Mismatched trailer for Slot 0");
437 fails += 1;
438 }
439
Fabio Utzig1e48b912018-09-18 09:04:18 -0300440 if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300441 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700442 warn!("Mismatched trailer for Slot 1");
443 fails += 1;
444 }
445
446 if Caps::SwapUpgrade.present() {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300447 if !verify_image(&fl, &self.slots, 1, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700448 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
449 fails += 1;
450 }
451 }
452 }
453
454 if fails > 0 {
455 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
456 fails as f32 * 100.0 / total_flash_ops as f32);
457 }
458
459 fails > 0
460 }
461
David Browna4167ef2017-11-06 14:30:05 -0700462 pub fn run_perm_with_random_fails_5(&self) -> bool {
463 self.run_perm_with_random_fails(5)
464 }
465
David Brownc49811e2017-11-06 14:20:45 -0700466 fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700467 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700468 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700469 let (fl, total_counts) = try_random_fails(&self.flash, &self,
470 total_flash_ops, total_fails);
471 info!("Random interruptions at reset points={:?}", total_counts);
472
Fabio Utzig1e48b912018-09-18 09:04:18 -0300473 let slot0_ok = verify_image(&fl, &self.slots, 0, &self.upgrades);
David Brown5f7ec2b2017-11-06 13:54:02 -0700474 let slot1_ok = if Caps::SwapUpgrade.present() {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300475 verify_image(&fl, &self.slots, 1, &self.primaries)
David Brown5f7ec2b2017-11-06 13:54:02 -0700476 } else {
477 true
478 };
479 if !slot0_ok || !slot1_ok {
480 error!("Image mismatch after random interrupts: slot0={} slot1={}",
481 if slot0_ok { "ok" } else { "fail" },
482 if slot1_ok { "ok" } else { "fail" });
483 fails += 1;
484 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300485 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300486 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700487 error!("Mismatched trailer for Slot 0");
488 fails += 1;
489 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300490 if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300491 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700492 error!("Mismatched trailer for Slot 1");
David Brown2639e072017-10-11 11:18:44 -0600493 fails += 1;
494 }
495
David Brown5f7ec2b2017-11-06 13:54:02 -0700496 if fails > 0 {
497 error!("Error testing perm upgrade with {} fails", total_fails);
498 }
499
500 fails > 0
501 }
502
503 #[cfg(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 false
506 }
507
508 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700509 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700510 let mut fails = 0;
511
512 if Caps::SwapUpgrade.present() {
David Brownc49811e2017-11-06 14:20:45 -0700513 for i in 1 .. (self.total_count.unwrap() - 1) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700514 info!("Try interruption at {}", i);
515 if try_revert_with_fail_at(&self.flash, &self, i) {
516 error!("Revert failed at interruption {}", i);
517 fails += 1;
518 }
519 }
520 }
521
522 fails > 0
523 }
524
525 #[cfg(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 false
528 }
529
530 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700531 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700532 let mut fl = self.flash.clone();
533 let mut fails = 0;
534
535 info!("Try norevert");
536
537 // First do a normal upgrade...
Fabio Utzig269d2862018-10-24 17:45:38 -0300538 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200539 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700540 warn!("Failed first boot");
541 fails += 1;
542 }
543
544 //FIXME: copy_done is written by boot_go, is it ok if no copy
545 // was ever done?
546
Fabio Utzig1e48b912018-09-18 09:04:18 -0300547 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700548 warn!("Slot 0 image verification FAIL");
549 fails += 1;
550 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300551 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300552 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600553 warn!("Mismatched trailer for Slot 0");
554 fails += 1;
555 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300556 if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300557 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600558 warn!("Mismatched trailer for Slot 1");
559 fails += 1;
560 }
561
David Brown5f7ec2b2017-11-06 13:54:02 -0700562 // Marks image in slot0 as permanent, no revert should happen...
Fabio Utzig269d2862018-10-24 17:45:38 -0300563 mark_permanent_upgrade(&mut fl, &self.slots[0]);
David Brown5f7ec2b2017-11-06 13:54:02 -0700564
Fabio Utzig1e48b912018-09-18 09:04:18 -0300565 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300566 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700567 warn!("Mismatched trailer for Slot 0");
568 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600569 }
David Brown2639e072017-10-11 11:18:44 -0600570
Fabio Utzig269d2862018-10-24 17:45:38 -0300571 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200572 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700573 warn!("Failed second boot");
574 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600575 }
David Brown5f7ec2b2017-11-06 13:54:02 -0700576
Fabio Utzig1e48b912018-09-18 09:04:18 -0300577 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300578 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700579 warn!("Mismatched trailer for Slot 0");
580 fails += 1;
581 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300582 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700583 warn!("Failed image verification");
584 fails += 1;
585 }
586
587 if fails > 0 {
588 error!("Error running upgrade without revert");
589 }
590
591 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600592 }
593
David Brown5f7ec2b2017-11-06 13:54:02 -0700594 // Tests a new image written to slot0 that already has magic and image_ok set
595 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700596 pub fn run_norevert_newimage(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700597 let mut fl = self.flash.clone();
598 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600599
David Brown5f7ec2b2017-11-06 13:54:02 -0700600 info!("Try non-revert on imgtool generated image");
David Brown2639e072017-10-11 11:18:44 -0600601
Fabio Utzig1e48b912018-09-18 09:04:18 -0300602 mark_upgrade(&mut fl, &self.slots[0]);
David Brown2639e072017-10-11 11:18:44 -0600603
David Brown5f7ec2b2017-11-06 13:54:02 -0700604 // This simulates writing an image created by imgtool to Slot 0
Fabio Utzig1e48b912018-09-18 09:04:18 -0300605 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300606 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700607 warn!("Mismatched trailer for Slot 0");
608 fails += 1;
609 }
David Brown2639e072017-10-11 11:18:44 -0600610
David Brown5f7ec2b2017-11-06 13:54:02 -0700611 // Run the bootloader...
Fabio Utzig269d2862018-10-24 17:45:38 -0300612 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200613 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700614 warn!("Failed first boot");
615 fails += 1;
616 }
617
618 // State should not have changed
Fabio Utzig1e48b912018-09-18 09:04:18 -0300619 if !verify_image(&fl, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700620 warn!("Failed image verification");
621 fails += 1;
622 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300623 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300624 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700625 warn!("Mismatched trailer for Slot 0");
626 fails += 1;
627 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300628 if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300629 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700630 warn!("Mismatched trailer for Slot 1");
631 fails += 1;
632 }
633
634 if fails > 0 {
635 error!("Expected a non revert with new image");
636 }
637
638 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600639 }
640
David Brown5f7ec2b2017-11-06 13:54:02 -0700641 // Tests a new image written to slot0 that already has magic and image_ok set
642 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700643 pub fn run_signfail_upgrade(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700644 let mut fl = self.flash.clone();
645 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600646
David Brown5f7ec2b2017-11-06 13:54:02 -0700647 info!("Try upgrade image with bad signature");
648
Fabio Utzig1e48b912018-09-18 09:04:18 -0300649 mark_upgrade(&mut fl, &self.slots[0]);
Fabio Utzig269d2862018-10-24 17:45:38 -0300650 mark_permanent_upgrade(&mut fl, &self.slots[0]);
Fabio Utzig1e48b912018-09-18 09:04:18 -0300651 mark_upgrade(&mut fl, &self.slots[1]);
David Brown5f7ec2b2017-11-06 13:54:02 -0700652
Fabio Utzig1e48b912018-09-18 09:04:18 -0300653 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300654 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700655 warn!("Mismatched trailer for Slot 0");
656 fails += 1;
657 }
658
659 // Run the bootloader...
Fabio Utzig269d2862018-10-24 17:45:38 -0300660 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200661 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700662 warn!("Failed first boot");
663 fails += 1;
664 }
665
666 // State should not have changed
Fabio Utzig1e48b912018-09-18 09:04:18 -0300667 if !verify_image(&fl, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700668 warn!("Failed image verification");
669 fails += 1;
670 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300671 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300672 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700673 warn!("Mismatched trailer for Slot 0");
674 fails += 1;
675 }
676
677 if fails > 0 {
678 error!("Expected an upgrade failure when image has bad signature");
679 }
680
681 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600682 }
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200683
Fabio Utziga91c6262017-12-06 09:01:12 -0200684 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300685 fn trailer_sz(&self, align: usize) -> usize {
686 c::boot_trailer_sz(align as u8) as usize
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200687 }
688
689 // FIXME: could get status sz from bootloader
Fabio Utziga91c6262017-12-06 09:01:12 -0200690 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300691 #[cfg(not(feature = "enc-rsa"))]
692 #[cfg(not(feature = "enc-kw"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300693 fn status_sz(&self, align: usize) -> usize {
694 self.trailer_sz(align) - (16 + 24)
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200695 }
696
Fabio Utzig1e48b912018-09-18 09:04:18 -0300697 #[cfg(feature = "enc-rsa")]
Fabio Utzig9b7a2582018-12-03 10:40:05 -0200698 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300699 fn status_sz(&self, align: usize) -> usize {
700 self.trailer_sz(align) - (16 + 24 + 32)
Fabio Utzig1e48b912018-09-18 09:04:18 -0300701 }
702
703 #[cfg(feature = "enc-kw")]
Fabio Utzig9b7a2582018-12-03 10:40:05 -0200704 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300705 fn status_sz(&self, align: usize) -> usize {
706 self.trailer_sz(align) - (16 + 24 + 32)
Fabio Utzig1e48b912018-09-18 09:04:18 -0300707 }
708
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200709 /// This test runs a simple upgrade with no fails in the images, but
710 /// allowing for fails in the status area. This should run to the end
711 /// and warn that write fails were detected...
712 #[cfg(not(feature = "validate-slot0"))]
713 pub fn run_with_status_fails_complete(&self) -> bool { false }
714
715 #[cfg(feature = "validate-slot0")]
716 pub fn run_with_status_fails_complete(&self) -> bool {
717 let mut fl = self.flash.clone();
718 let mut fails = 0;
719
720 info!("Try swap with status fails");
721
Fabio Utzig269d2862018-10-24 17:45:38 -0300722 mark_permanent_upgrade(&mut fl, &self.slots[1]);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200723
Fabio Utzig269d2862018-10-24 17:45:38 -0300724 let align = fl.align();
725 let status_off = self.slots[1].base_off - self.trailer_sz(align);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200726
727 // Always fail writes to status area...
Fabio Utzig269d2862018-10-24 17:45:38 -0300728 let _ = fl.add_bad_region(status_off, self.status_sz(align), 1.0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200729
Fabio Utzig269d2862018-10-24 17:45:38 -0300730 let (result, asserts) = c::boot_go(&mut fl, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200731 if result != 0 {
732 warn!("Failed!");
733 fails += 1;
734 }
735
736 // Failed writes to the marked "bad" region don't assert anymore.
737 // Any detected assert() is happening in another part of the code.
738 if asserts != 0 {
739 warn!("At least one assert() was called");
740 fails += 1;
741 }
742
Fabio Utzig1e48b912018-09-18 09:04:18 -0300743 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300744 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200745 warn!("Mismatched trailer for Slot 0");
746 fails += 1;
747 }
748
Fabio Utzig1e48b912018-09-18 09:04:18 -0300749 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200750 warn!("Failed image verification");
751 fails += 1;
752 }
753
754 info!("validate slot0 enabled; re-run of boot_go should just work");
Fabio Utzig269d2862018-10-24 17:45:38 -0300755 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200756 if result != 0 {
757 warn!("Failed!");
758 fails += 1;
759 }
760
761 if fails > 0 {
762 error!("Error running upgrade with status write fails");
763 }
764
765 fails > 0
766 }
767
768 /// This test runs a simple upgrade with no fails in the images, but
769 /// allowing for fails in the status area. This should run to the end
770 /// and warn that write fails were detected...
771 #[cfg(feature = "validate-slot0")]
772 pub fn run_with_status_fails_with_reset(&self) -> bool {
773 let mut fl = self.flash.clone();
774 let mut fails = 0;
775 let mut count = self.total_count.unwrap() / 2;
776
777 //info!("count={}\n", count);
778
779 info!("Try interrupted swap with status fails");
780
Fabio Utzig269d2862018-10-24 17:45:38 -0300781 mark_permanent_upgrade(&mut fl, &self.slots[1]);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200782
Fabio Utzig269d2862018-10-24 17:45:38 -0300783 let align = fl.align();
784 let status_off = self.slots[1].base_off - self.trailer_sz(align);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200785
786 // Mark the status area as a bad area
Fabio Utzig269d2862018-10-24 17:45:38 -0300787 let _ = fl.add_bad_region(status_off, self.status_sz(align), 0.5);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200788
789 // Should not fail, writing to bad regions does not assert
Fabio Utzig269d2862018-10-24 17:45:38 -0300790 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, Some(&mut count), true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200791 if asserts != 0 {
792 warn!("At least one assert() was called");
793 fails += 1;
794 }
795
796 fl.reset_bad_regions();
797
798 // Disabling write verification the only assert triggered by
799 // boot_go should be checking for integrity of status bytes.
800 fl.set_verify_writes(false);
801
802 info!("Resuming an interrupted swap operation");
Fabio Utzig269d2862018-10-24 17:45:38 -0300803 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200804
805 // This might throw no asserts, for large sector devices, where
806 // a single failure writing is indistinguishable from no failure,
807 // or throw a single assert for small sector devices that fail
808 // multiple times...
809 if asserts > 1 {
810 warn!("Expected single assert validating slot0, more detected {}", asserts);
811 fails += 1;
812 }
813
814 if fails > 0 {
815 error!("Error running upgrade with status write fails");
816 }
817
818 fails > 0
819 }
820
821 #[cfg(not(feature = "validate-slot0"))]
822 #[cfg(not(feature = "overwrite-only"))]
823 pub fn run_with_status_fails_with_reset(&self) -> bool {
824 let mut fl = self.flash.clone();
825 let mut fails = 0;
826
827 info!("Try interrupted swap with status fails");
828
Fabio Utzig269d2862018-10-24 17:45:38 -0300829 mark_permanent_upgrade(&mut fl, &self.slots[1]);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200830
Fabio Utzig269d2862018-10-24 17:45:38 -0300831 let status_off = self.slots[1].base_off - self.trailer_sz(fl.align());
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200832
833 // Mark the status area as a bad area
Fabio Utzig269d2862018-10-24 17:45:38 -0300834 let align = fl.align();
835 let _ = fl.add_bad_region(status_off, self.status_sz(align), 1.0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200836
837 // This is expected to fail while writing to bad regions...
Fabio Utzig269d2862018-10-24 17:45:38 -0300838 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200839 if asserts == 0 {
840 warn!("No assert() detected");
841 fails += 1;
842 }
843
844 fails > 0
845 }
846
847 #[cfg(feature = "overwrite-only")]
848 pub fn run_with_status_fails_with_reset(&self) -> bool {
849 false
850 }
David Brown2639e072017-10-11 11:18:44 -0600851}
852
853/// Test a boot, optionally stopping after 'n' flash options. Returns a count
854/// of the number of flash operations done total.
David Brown3f687dc2017-11-06 13:41:18 -0700855fn try_upgrade(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600856 stop: Option<i32>) -> (SimFlash, i32) {
857 // Clone the flash to have a new copy.
858 let mut fl = flash.clone();
859
Fabio Utzig269d2862018-10-24 17:45:38 -0300860 mark_permanent_upgrade(&mut fl, &images.slots[1]);
David Brown2639e072017-10-11 11:18:44 -0600861
David Brownee61c832017-11-06 11:13:25 -0700862 let mut counter = stop.unwrap_or(0);
863
Fabio Utzig269d2862018-10-24 17:45:38 -0300864 let (first_interrupted, count) = match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200865 (-0x13579, _) => (true, stop.unwrap()),
866 (0, _) => (false, -counter),
867 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600868 };
David Brown2639e072017-10-11 11:18:44 -0600869
David Brownee61c832017-11-06 11:13:25 -0700870 counter = 0;
David Brown2639e072017-10-11 11:18:44 -0600871 if first_interrupted {
872 // fl.dump();
Fabio Utzig269d2862018-10-24 17:45:38 -0300873 match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200874 (-0x13579, _) => panic!("Shouldn't stop again"),
875 (0, _) => (),
876 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600877 }
878 }
879
David Brownee61c832017-11-06 11:13:25 -0700880 (fl, count - counter)
David Brown2639e072017-10-11 11:18:44 -0600881}
882
883#[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300884fn try_revert(flash: &SimFlash, areadesc: &AreaDesc, count: usize) -> SimFlash {
David Brown2639e072017-10-11 11:18:44 -0600885 let mut fl = flash.clone();
David Brown2639e072017-10-11 11:18:44 -0600886
887 // fl.write_file("image0.bin").unwrap();
888 for i in 0 .. count {
889 info!("Running boot pass {}", i + 1);
Fabio Utzig269d2862018-10-24 17:45:38 -0300890 assert_eq!(c::boot_go(&mut fl, &areadesc, None, false), (0, 0));
David Brown2639e072017-10-11 11:18:44 -0600891 }
892 fl
893}
894
895#[cfg(not(feature = "overwrite-only"))]
David Brown3f687dc2017-11-06 13:41:18 -0700896fn try_revert_with_fail_at(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600897 stop: i32) -> bool {
898 let mut fl = flash.clone();
David Brown2639e072017-10-11 11:18:44 -0600899 let mut fails = 0;
900
David Brownee61c832017-11-06 11:13:25 -0700901 let mut counter = stop;
Fabio Utzig269d2862018-10-24 17:45:38 -0300902 let (x, _) = c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), false);
David Brown2639e072017-10-11 11:18:44 -0600903 if x != -0x13579 {
904 warn!("Should have stopped at interruption point");
905 fails += 1;
906 }
907
Fabio Utzig1e48b912018-09-18 09:04:18 -0300908 if !verify_trailer(&fl, images.slots[0].trailer_off, None, None, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600909 warn!("copy_done should be unset");
910 fails += 1;
911 }
912
Fabio Utzig269d2862018-10-24 17:45:38 -0300913 let (x, _) = c::boot_go(&mut fl, &images.areadesc, None, false);
David Brown2639e072017-10-11 11:18:44 -0600914 if x != 0 {
915 warn!("Should have finished upgrade");
916 fails += 1;
917 }
918
Fabio Utzig1e48b912018-09-18 09:04:18 -0300919 if !verify_image(&fl, &images.slots, 0, &images.upgrades) {
David Brown2639e072017-10-11 11:18:44 -0600920 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
921 fails += 1;
922 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300923 if !verify_image(&fl, &images.slots, 1, &images.primaries) {
David Brown2639e072017-10-11 11:18:44 -0600924 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
925 fails += 1;
926 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300927 if !verify_trailer(&fl, images.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300928 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600929 warn!("Mismatched trailer for Slot 0 before revert");
930 fails += 1;
931 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300932 if !verify_trailer(&fl, images.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300933 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600934 warn!("Mismatched trailer for Slot 1 before revert");
935 fails += 1;
936 }
937
938 // Do Revert
Fabio Utzig269d2862018-10-24 17:45:38 -0300939 let (x, _) = c::boot_go(&mut fl, &images.areadesc, None, false);
David Brown2639e072017-10-11 11:18:44 -0600940 if x != 0 {
941 warn!("Should have finished a revert");
942 fails += 1;
943 }
944
Fabio Utzig1e48b912018-09-18 09:04:18 -0300945 if !verify_image(&fl, &images.slots, 0, &images.primaries) {
David Brown2639e072017-10-11 11:18:44 -0600946 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
947 fails += 1;
948 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300949 if !verify_image(&fl, &images.slots, 1, &images.upgrades) {
David Brown2639e072017-10-11 11:18:44 -0600950 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
951 fails += 1;
952 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300953 if !verify_trailer(&fl, images.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300954 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600955 warn!("Mismatched trailer for Slot 1 after revert");
956 fails += 1;
957 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300958 if !verify_trailer(&fl, images.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300959 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600960 warn!("Mismatched trailer for Slot 1 after revert");
961 fails += 1;
962 }
963
964 fails > 0
965}
966
David Brown3f687dc2017-11-06 13:41:18 -0700967fn try_random_fails(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600968 total_ops: i32, count: usize) -> (SimFlash, Vec<i32>) {
969 let mut fl = flash.clone();
970
Fabio Utzig269d2862018-10-24 17:45:38 -0300971 mark_permanent_upgrade(&mut fl, &images.slots[1]);
David Brown2639e072017-10-11 11:18:44 -0600972
973 let mut rng = rand::thread_rng();
974 let mut resets = vec![0i32; count];
975 let mut remaining_ops = total_ops;
976 for i in 0 .. count {
977 let ops = Range::new(1, remaining_ops / 2);
978 let reset_counter = ops.ind_sample(&mut rng);
David Brownee61c832017-11-06 11:13:25 -0700979 let mut counter = reset_counter;
Fabio Utzig269d2862018-10-24 17:45:38 -0300980 match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200981 (0, _) | (-0x13579, _) => (),
982 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600983 }
984 remaining_ops -= reset_counter;
985 resets[i] = reset_counter;
986 }
987
Fabio Utzig269d2862018-10-24 17:45:38 -0300988 match c::boot_go(&mut fl, &images.areadesc, None, false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200989 (-0x13579, _) => panic!("Should not be have been interrupted!"),
990 (0, _) => (),
991 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600992 }
993
994 (fl, resets)
995}
996
997/// Show the flash layout.
998#[allow(dead_code)]
999fn show_flash(flash: &Flash) {
1000 println!("---- Flash configuration ----");
1001 for sector in flash.sector_iter() {
1002 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1003 sector.num, sector.base, sector.size);
1004 }
1005 println!("");
1006}
1007
1008/// Install a "program" into the given image. This fakes the image header, or at least all of the
1009/// fields used by the given code. Returns a copy of the image that was written.
Fabio Utzig1e48b912018-09-18 09:04:18 -03001010fn install_image(flash: &mut Flash, slots: &[SlotInfo], slot: usize, len: usize,
1011 bad_sig: bool) -> [Option<Vec<u8>>; 2] {
1012 let offset = slots[slot].base_off;
1013 let slot_len = slots[slot].len;
David Brown2639e072017-10-11 11:18:44 -06001014
1015 let mut tlv = make_tlv();
1016
Fabio Utzige5831f62018-12-14 06:46:22 -02001017 const HDR_SIZE: usize = 32;
1018
David Brown2639e072017-10-11 11:18:44 -06001019 // Generate a boot header. Note that the size doesn't include the header.
1020 let header = ImageHeader {
1021 magic: 0x96f3b83d,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001022 load_addr: 0,
Fabio Utzige5831f62018-12-14 06:46:22 -02001023 hdr_size: HDR_SIZE as u16,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001024 _pad1: 0,
David Brown2639e072017-10-11 11:18:44 -06001025 img_size: len as u32,
1026 flags: tlv.get_flags(),
1027 ver: ImageVersion {
1028 major: (offset / (128 * 1024)) as u8,
1029 minor: 0,
1030 revision: 1,
1031 build_num: offset as u32,
1032 },
Fabio Utzig1e48b912018-09-18 09:04:18 -03001033 _pad2: 0,
David Brown2639e072017-10-11 11:18:44 -06001034 };
1035
Fabio Utzige5831f62018-12-14 06:46:22 -02001036 let mut b_header = [0; HDR_SIZE];
1037 b_header[..32].clone_from_slice(header.as_raw());
1038 assert_eq!(b_header.len(), HDR_SIZE);
1039
David Brown2639e072017-10-11 11:18:44 -06001040 tlv.add_bytes(&b_header);
David Brown2639e072017-10-11 11:18:44 -06001041
1042 // The core of the image itself is just pseudorandom data.
Fabio Utzig1e48b912018-09-18 09:04:18 -03001043 let mut b_img = vec![0; len];
1044 splat(&mut b_img, offset);
David Brown2639e072017-10-11 11:18:44 -06001045
Fabio Utzig1e48b912018-09-18 09:04:18 -03001046 // TLV signatures work over plain image
1047 tlv.add_bytes(&b_img);
1048
1049 // Generate encrypted images
1050 let flag = TlvFlags::ENCRYPTED as u32;
1051 let is_encrypted = (tlv.get_flags() & flag) == flag;
1052 let mut b_encimg = vec![];
1053 if is_encrypted {
1054 let key = GenericArray::from_slice(AES_SEC_KEY);
1055 let nonce = GenericArray::from_slice(&[0; 16]);
1056 let mut cipher = Aes128Ctr::new(&key, &nonce);
1057 b_encimg = b_img.clone();
1058 cipher.apply_keystream(&mut b_encimg);
David Brown2639e072017-10-11 11:18:44 -06001059 }
1060
Fabio Utzig1e48b912018-09-18 09:04:18 -03001061 // Build the TLV itself.
1062 let mut b_tlv = if bad_sig {
1063 let good_sig = &mut tlv.make_tlv();
1064 vec![0; good_sig.len()]
1065 } else {
1066 tlv.make_tlv()
1067 };
1068
David Brown2639e072017-10-11 11:18:44 -06001069 // Pad the block to a flash alignment (8 bytes).
Fabio Utzig1e48b912018-09-18 09:04:18 -03001070 while b_tlv.len() % 8 != 0 {
1071 //FIXME: should be erase_val?
1072 b_tlv.push(0xFF);
David Brown2639e072017-10-11 11:18:44 -06001073 }
1074
Fabio Utzig1e48b912018-09-18 09:04:18 -03001075 let mut buf = vec![];
1076 buf.append(&mut b_header.to_vec());
1077 buf.append(&mut b_img);
1078 buf.append(&mut b_tlv.clone());
David Brown2639e072017-10-11 11:18:44 -06001079
Fabio Utzig1e48b912018-09-18 09:04:18 -03001080 let mut encbuf = vec![];
1081 if is_encrypted {
1082 encbuf.append(&mut b_header.to_vec());
1083 encbuf.append(&mut b_encimg);
1084 encbuf.append(&mut b_tlv);
1085 }
David Brown2639e072017-10-11 11:18:44 -06001086
Fabio Utzig1e48b912018-09-18 09:04:18 -03001087 let result: [Option<Vec<u8>>; 2];
1088
1089 // Since images are always non-encrypted in slot0, we first write an
1090 // encrypted image, re-read to use for verification, erase + flash
1091 // un-encrypted. In slot1 the image is written un-encrypted, and if
1092 // encryption is requested, it follows an erase + flash encrypted.
1093
1094 if slot == 0 {
1095 let enc_copy: Option<Vec<u8>>;
1096
1097 if is_encrypted {
1098 flash.write(offset, &encbuf).unwrap();
1099
1100 let mut enc = vec![0u8; encbuf.len()];
1101 flash.read(offset, &mut enc).unwrap();
1102
1103 enc_copy = Some(enc);
1104
1105 flash.erase(offset, slot_len).unwrap();
1106 } else {
1107 enc_copy = None;
1108 }
1109
1110 flash.write(offset, &buf).unwrap();
1111
1112 let mut copy = vec![0u8; buf.len()];
1113 flash.read(offset, &mut copy).unwrap();
1114
1115 result = [Some(copy), enc_copy];
1116 } else {
1117 flash.write(offset, &buf).unwrap();
1118
1119 let mut copy = vec![0u8; buf.len()];
1120 flash.read(offset, &mut copy).unwrap();
1121
1122 let enc_copy: Option<Vec<u8>>;
1123
1124 if is_encrypted {
1125 flash.erase(offset, slot_len).unwrap();
1126
1127 flash.write(offset, &encbuf).unwrap();
1128
1129 let mut enc = vec![0u8; encbuf.len()];
1130 flash.read(offset, &mut enc).unwrap();
1131
1132 enc_copy = Some(enc);
1133 } else {
1134 enc_copy = None;
1135 }
1136
1137 result = [Some(copy), enc_copy];
1138 }
1139
1140 result
David Brown2639e072017-10-11 11:18:44 -06001141}
1142
1143// The TLV in use depends on what kind of signature we are verifying.
1144#[cfg(feature = "sig-rsa")]
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001145#[cfg(not(feature = "enc-rsa"))]
David Brown2639e072017-10-11 11:18:44 -06001146fn make_tlv() -> TlvGen {
1147 TlvGen::new_rsa_pss()
1148}
1149
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001150#[cfg(feature = "sig-ecdsa")]
1151fn make_tlv() -> TlvGen {
1152 TlvGen::new_ecdsa()
1153}
1154
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001155#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001156#[cfg(feature = "enc-rsa")]
1157fn make_tlv() -> TlvGen {
1158 TlvGen::new_enc_rsa()
1159}
1160
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001161#[cfg(feature = "sig-rsa")]
1162#[cfg(feature = "enc-rsa")]
1163fn make_tlv() -> TlvGen {
1164 TlvGen::new_sig_enc_rsa()
1165}
1166
Fabio Utzig1e48b912018-09-18 09:04:18 -03001167#[cfg(feature = "enc-kw")]
1168fn make_tlv() -> TlvGen {
1169 TlvGen::new_enc_kw()
1170}
1171
David Brown2639e072017-10-11 11:18:44 -06001172#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001173#[cfg(not(feature = "sig-ecdsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001174#[cfg(not(feature = "enc-rsa"))]
1175#[cfg(not(feature = "enc-kw"))]
David Brown2639e072017-10-11 11:18:44 -06001176fn make_tlv() -> TlvGen {
1177 TlvGen::new_hash_only()
1178}
1179
Fabio Utzig1e48b912018-09-18 09:04:18 -03001180#[cfg(feature = "enc-rsa")]
1181fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
1182 match &images[slot] {
1183 Some(image) => return image,
1184 None => panic!("Invalid image"),
1185 }
1186}
1187
1188#[cfg(feature = "enc-kw")]
1189fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
1190 match &images[slot] {
1191 Some(image) => return image,
1192 None => panic!("Invalid image"),
1193 }
1194}
1195
1196#[cfg(not(feature = "enc-rsa"))]
1197#[cfg(not(feature = "enc-kw"))]
1198fn find_image(images: &[Option<Vec<u8>>; 2], _slot: usize) -> &Vec<u8> {
1199 match &images[0] {
1200 Some(image) => return image,
1201 None => panic!("Invalid image"),
1202 }
1203}
1204
David Brown2639e072017-10-11 11:18:44 -06001205/// Verify that given image is present in the flash at the given offset.
Fabio Utzig1e48b912018-09-18 09:04:18 -03001206fn verify_image(flash: &Flash, slots: &[SlotInfo], slot: usize,
1207 images: &[Option<Vec<u8>>; 2]) -> bool {
1208 let image = find_image(images, slot);
1209 let buf = image.as_slice();
1210
David Brown2639e072017-10-11 11:18:44 -06001211 let mut copy = vec![0u8; buf.len()];
Fabio Utzig1e48b912018-09-18 09:04:18 -03001212 let offset = slots[slot].base_off;
David Brown2639e072017-10-11 11:18:44 -06001213 flash.read(offset, &mut copy).unwrap();
1214
1215 if buf != &copy[..] {
1216 for i in 0 .. buf.len() {
1217 if buf[i] != copy[i] {
Fabio Utzig1e48b912018-09-18 09:04:18 -03001218 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1219 slot, offset + i, buf[i], copy[i]);
David Brown2639e072017-10-11 11:18:44 -06001220 break;
1221 }
1222 }
1223 false
1224 } else {
1225 true
1226 }
1227}
1228
1229#[cfg(feature = "overwrite-only")]
1230#[allow(unused_variables)]
1231// overwrite-only doesn't employ trailer management
1232fn verify_trailer(flash: &Flash, offset: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001233 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001234 copy_done: Option<u8>) -> bool {
1235 true
1236}
1237
1238#[cfg(not(feature = "overwrite-only"))]
1239fn verify_trailer(flash: &Flash, offset: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001240 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001241 copy_done: Option<u8>) -> bool {
1242 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1243 let mut failed = false;
Fabio Utzigea0290b2018-08-09 14:23:01 -03001244 let erased_val = flash.erased_val();
David Brown2639e072017-10-11 11:18:44 -06001245
1246 flash.read(offset, &mut copy).unwrap();
1247
1248 failed |= match magic {
1249 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001250 if v == 1 && &copy[16..] != MAGIC.unwrap() {
David Brown2639e072017-10-11 11:18:44 -06001251 warn!("\"magic\" mismatch at {:#x}", offset);
1252 true
Fabio Utzigea0290b2018-08-09 14:23:01 -03001253 } else if v == 3 {
1254 let expected = [erased_val; 16];
1255 if &copy[16..] != expected {
1256 warn!("\"magic\" mismatch at {:#x}", offset);
1257 true
1258 } else {
1259 false
1260 }
David Brown2639e072017-10-11 11:18:44 -06001261 } else {
1262 false
1263 }
1264 },
1265 None => false,
1266 };
1267
1268 failed |= match image_ok {
1269 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001270 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1271 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
David Brown2639e072017-10-11 11:18:44 -06001272 true
1273 } else {
1274 false
1275 }
1276 },
1277 None => false,
1278 };
1279
1280 failed |= match copy_done {
1281 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001282 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1283 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
David Brown2639e072017-10-11 11:18:44 -06001284 true
1285 } else {
1286 false
1287 }
1288 },
1289 None => false,
1290 };
1291
1292 !failed
1293}
1294
1295/// The image header
1296#[repr(C)]
1297pub struct ImageHeader {
1298 magic: u32,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001299 load_addr: u32,
David Brown2639e072017-10-11 11:18:44 -06001300 hdr_size: u16,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001301 _pad1: u16,
David Brown2639e072017-10-11 11:18:44 -06001302 img_size: u32,
1303 flags: u32,
1304 ver: ImageVersion,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001305 _pad2: u32,
David Brown2639e072017-10-11 11:18:44 -06001306}
1307
1308impl AsRaw for ImageHeader {}
1309
1310#[repr(C)]
1311pub struct ImageVersion {
1312 major: u8,
1313 minor: u8,
1314 revision: u16,
1315 build_num: u32,
1316}
1317
David Brownd5e632c2017-10-19 10:49:46 -06001318#[derive(Clone)]
David Brown2639e072017-10-11 11:18:44 -06001319struct SlotInfo {
1320 base_off: usize,
1321 trailer_off: usize,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001322 len: usize,
David Brown2639e072017-10-11 11:18:44 -06001323}
1324
David Brownf48b9502017-11-06 14:00:26 -07001325pub struct Images {
David Browndc9cba12017-11-06 13:31:42 -07001326 flash: SimFlash,
David Brown3f687dc2017-11-06 13:41:18 -07001327 areadesc: AreaDesc,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001328 slots: [SlotInfo; 2],
1329 primaries: [Option<Vec<u8>>; 2],
1330 upgrades: [Option<Vec<u8>>; 2],
David Brownc49811e2017-11-06 14:20:45 -07001331 total_count: Option<i32>,
David Brown2639e072017-10-11 11:18:44 -06001332}
1333
Fabio Utzigea0290b2018-08-09 14:23:01 -03001334const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1335 0x60, 0xd2, 0xef, 0x7f,
1336 0x35, 0x52, 0x50, 0x0f,
1337 0x2c, 0xb6, 0x79, 0x80]);
David Brown2639e072017-10-11 11:18:44 -06001338
Fabio Utzigea0290b2018-08-09 14:23:01 -03001339// Replicates defines found in bootutil.h
1340const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1341const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1342
1343const BOOT_FLAG_SET: Option<u8> = Some(1);
1344const BOOT_FLAG_UNSET: Option<u8> = Some(3);
David Brown2639e072017-10-11 11:18:44 -06001345
1346/// Write out the magic so that the loader tries doing an upgrade.
1347fn mark_upgrade(flash: &mut Flash, slot: &SlotInfo) {
1348 let offset = slot.trailer_off + c::boot_max_align() * 2;
Fabio Utzigea0290b2018-08-09 14:23:01 -03001349 flash.write(offset, MAGIC.unwrap()).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001350}
1351
1352/// Writes the image_ok flag which, guess what, tells the bootloader
1353/// the this image is ok (not a test, and no revert is to be performed).
Fabio Utzig269d2862018-10-24 17:45:38 -03001354fn mark_permanent_upgrade(flash: &mut Flash, slot: &SlotInfo) {
1355 let mut ok = [flash.erased_val(); 8];
Fabio Utzigea0290b2018-08-09 14:23:01 -03001356 ok[0] = 1u8;
David Brown2639e072017-10-11 11:18:44 -06001357 let off = slot.trailer_off + c::boot_max_align();
Fabio Utzig269d2862018-10-24 17:45:38 -03001358 let align = flash.align();
1359 flash.write(off, &ok[..align]).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001360}
1361
1362// Drop some pseudo-random gibberish onto the data.
1363fn splat(data: &mut [u8], seed: usize) {
1364 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1365 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1366 rng.fill_bytes(data);
1367}
1368
1369/// Return a read-only view into the raw bytes of this object
1370trait AsRaw : Sized {
1371 fn as_raw<'a>(&'a self) -> &'a [u8] {
1372 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1373 mem::size_of::<Self>()) }
1374 }
1375}
1376
1377fn show_sizes() {
1378 // This isn't panic safe.
David Brown2639e072017-10-11 11:18:44 -06001379 for min in &[1, 2, 4, 8] {
David Brown541860c2017-11-06 11:25:42 -07001380 let msize = c::boot_trailer_sz(*min);
David Brown2639e072017-10-11 11:18:44 -06001381 println!("{:2}: {} (0x{:x})", min, msize, msize);
1382 }
David Brown2639e072017-10-11 11:18:44 -06001383}