blob: 194fd7fff8325251a27d29ef3f119a5950bf4cdf [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);
David Browndecbd042017-10-19 10:43:17 -0600330 let mut areadesc = AreaDesc::new(&flash);
331 areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
332 areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
333 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch);
334 (flash, areadesc)
335 }
336 DeviceName::K64f => {
337 // NXP style flash. Small sectors, one small sector for scratch.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300338 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600339
340 let mut areadesc = AreaDesc::new(&flash);
341 areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
342 areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
343 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch);
344 (flash, areadesc)
345 }
346 DeviceName::K64fBig => {
347 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
348 // uses small sectors, but we tell the bootloader they are large.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300349 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600350
351 let mut areadesc = AreaDesc::new(&flash);
352 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0);
353 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1);
354 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch);
355 (flash, areadesc)
356 }
357 DeviceName::Nrf52840 => {
358 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
359 // does not divide into the image size.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300360 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600361
362 let mut areadesc = AreaDesc::new(&flash);
363 areadesc.add_image(0x008000, 0x034000, FlashId::Image0);
364 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1);
365 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch);
366 (flash, areadesc)
367 }
368 }
369}
370
David Brown5f7ec2b2017-11-06 13:54:02 -0700371impl Images {
372 /// A simple upgrade without forced failures.
373 ///
374 /// Returns the number of flash operations which can later be used to
375 /// inject failures at chosen steps.
David Brownc49811e2017-11-06 14:20:45 -0700376 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Brown5f7ec2b2017-11-06 13:54:02 -0700377 let (fl, total_count) = try_upgrade(&self.flash, &self, None);
378 info!("Total flash operation count={}", total_count);
David Brown2639e072017-10-11 11:18:44 -0600379
Fabio Utzig1e48b912018-09-18 09:04:18 -0300380 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700381 warn!("Image mismatch after first boot");
382 Err(())
383 } else {
384 Ok(total_count)
David Brown2639e072017-10-11 11:18:44 -0600385 }
386 }
387
David Brown5f7ec2b2017-11-06 13:54:02 -0700388 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700389 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700390 false
391 }
David Brown2639e072017-10-11 11:18:44 -0600392
David Brown5f7ec2b2017-11-06 13:54:02 -0700393 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700394 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700395 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600396
David Brown5f7ec2b2017-11-06 13:54:02 -0700397 // FIXME: this test would also pass if no swap is ever performed???
398 if Caps::SwapUpgrade.present() {
399 for count in 2 .. 5 {
400 info!("Try revert: {}", count);
Fabio Utzig269d2862018-10-24 17:45:38 -0300401 let fl = try_revert(&self.flash, &self.areadesc, count);
Fabio Utzig1e48b912018-09-18 09:04:18 -0300402 if !verify_image(&fl, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700403 error!("Revert failure on count {}", count);
404 fails += 1;
405 }
406 }
407 }
408
409 fails > 0
410 }
411
David Browna4167ef2017-11-06 14:30:05 -0700412 pub fn run_perm_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700413 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700414 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700415
416 // Let's try an image halfway through.
417 for i in 1 .. total_flash_ops {
418 info!("Try interruption at {}", i);
419 let (fl, count) = try_upgrade(&self.flash, &self, Some(i));
420 info!("Second boot, count={}", count);
Fabio Utzig1e48b912018-09-18 09:04:18 -0300421 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700422 warn!("FAIL at step {} of {}", i, total_flash_ops);
423 fails += 1;
424 }
425
Fabio Utzig1e48b912018-09-18 09:04:18 -0300426 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300427 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700428 warn!("Mismatched trailer for Slot 0");
429 fails += 1;
430 }
431
Fabio Utzig1e48b912018-09-18 09:04:18 -0300432 if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300433 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700434 warn!("Mismatched trailer for Slot 1");
435 fails += 1;
436 }
437
438 if Caps::SwapUpgrade.present() {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300439 if !verify_image(&fl, &self.slots, 1, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700440 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
441 fails += 1;
442 }
443 }
444 }
445
446 if fails > 0 {
447 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
448 fails as f32 * 100.0 / total_flash_ops as f32);
449 }
450
451 fails > 0
452 }
453
David Browna4167ef2017-11-06 14:30:05 -0700454 pub fn run_perm_with_random_fails_5(&self) -> bool {
455 self.run_perm_with_random_fails(5)
456 }
457
David Brownc49811e2017-11-06 14:20:45 -0700458 fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700459 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700460 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700461 let (fl, total_counts) = try_random_fails(&self.flash, &self,
462 total_flash_ops, total_fails);
463 info!("Random interruptions at reset points={:?}", total_counts);
464
Fabio Utzig1e48b912018-09-18 09:04:18 -0300465 let slot0_ok = verify_image(&fl, &self.slots, 0, &self.upgrades);
David Brown5f7ec2b2017-11-06 13:54:02 -0700466 let slot1_ok = if Caps::SwapUpgrade.present() {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300467 verify_image(&fl, &self.slots, 1, &self.primaries)
David Brown5f7ec2b2017-11-06 13:54:02 -0700468 } else {
469 true
470 };
471 if !slot0_ok || !slot1_ok {
472 error!("Image mismatch after random interrupts: slot0={} slot1={}",
473 if slot0_ok { "ok" } else { "fail" },
474 if slot1_ok { "ok" } else { "fail" });
475 fails += 1;
476 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300477 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300478 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700479 error!("Mismatched trailer for Slot 0");
480 fails += 1;
481 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300482 if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300483 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700484 error!("Mismatched trailer for Slot 1");
David Brown2639e072017-10-11 11:18:44 -0600485 fails += 1;
486 }
487
David Brown5f7ec2b2017-11-06 13:54:02 -0700488 if fails > 0 {
489 error!("Error testing perm upgrade with {} fails", total_fails);
490 }
491
492 fails > 0
493 }
494
495 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700496 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700497 false
498 }
499
500 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700501 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700502 let mut fails = 0;
503
504 if Caps::SwapUpgrade.present() {
David Brownc49811e2017-11-06 14:20:45 -0700505 for i in 1 .. (self.total_count.unwrap() - 1) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700506 info!("Try interruption at {}", i);
507 if try_revert_with_fail_at(&self.flash, &self, i) {
508 error!("Revert failed at interruption {}", i);
509 fails += 1;
510 }
511 }
512 }
513
514 fails > 0
515 }
516
517 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700518 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700519 false
520 }
521
522 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700523 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700524 let mut fl = self.flash.clone();
525 let mut fails = 0;
526
527 info!("Try norevert");
528
529 // First do a normal upgrade...
Fabio Utzig269d2862018-10-24 17:45:38 -0300530 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200531 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700532 warn!("Failed first boot");
533 fails += 1;
534 }
535
536 //FIXME: copy_done is written by boot_go, is it ok if no copy
537 // was ever done?
538
Fabio Utzig1e48b912018-09-18 09:04:18 -0300539 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700540 warn!("Slot 0 image verification FAIL");
541 fails += 1;
542 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300543 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300544 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600545 warn!("Mismatched trailer for Slot 0");
546 fails += 1;
547 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300548 if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300549 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600550 warn!("Mismatched trailer for Slot 1");
551 fails += 1;
552 }
553
David Brown5f7ec2b2017-11-06 13:54:02 -0700554 // Marks image in slot0 as permanent, no revert should happen...
Fabio Utzig269d2862018-10-24 17:45:38 -0300555 mark_permanent_upgrade(&mut fl, &self.slots[0]);
David Brown5f7ec2b2017-11-06 13:54:02 -0700556
Fabio Utzig1e48b912018-09-18 09:04:18 -0300557 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300558 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700559 warn!("Mismatched trailer for Slot 0");
560 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600561 }
David Brown2639e072017-10-11 11:18:44 -0600562
Fabio Utzig269d2862018-10-24 17:45:38 -0300563 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200564 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700565 warn!("Failed second boot");
566 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600567 }
David Brown5f7ec2b2017-11-06 13:54:02 -0700568
Fabio Utzig1e48b912018-09-18 09:04:18 -0300569 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300570 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700571 warn!("Mismatched trailer for Slot 0");
572 fails += 1;
573 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300574 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700575 warn!("Failed image verification");
576 fails += 1;
577 }
578
579 if fails > 0 {
580 error!("Error running upgrade without revert");
581 }
582
583 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600584 }
585
David Brown5f7ec2b2017-11-06 13:54:02 -0700586 // Tests a new image written to slot0 that already has magic and image_ok set
587 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700588 pub fn run_norevert_newimage(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700589 let mut fl = self.flash.clone();
590 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600591
David Brown5f7ec2b2017-11-06 13:54:02 -0700592 info!("Try non-revert on imgtool generated image");
David Brown2639e072017-10-11 11:18:44 -0600593
Fabio Utzig1e48b912018-09-18 09:04:18 -0300594 mark_upgrade(&mut fl, &self.slots[0]);
David Brown2639e072017-10-11 11:18:44 -0600595
David Brown5f7ec2b2017-11-06 13:54:02 -0700596 // This simulates writing an image created by imgtool to Slot 0
Fabio Utzig1e48b912018-09-18 09:04:18 -0300597 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300598 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700599 warn!("Mismatched trailer for Slot 0");
600 fails += 1;
601 }
David Brown2639e072017-10-11 11:18:44 -0600602
David Brown5f7ec2b2017-11-06 13:54:02 -0700603 // Run the bootloader...
Fabio Utzig269d2862018-10-24 17:45:38 -0300604 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200605 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700606 warn!("Failed first boot");
607 fails += 1;
608 }
609
610 // State should not have changed
Fabio Utzig1e48b912018-09-18 09:04:18 -0300611 if !verify_image(&fl, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700612 warn!("Failed image verification");
613 fails += 1;
614 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300615 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300616 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700617 warn!("Mismatched trailer for Slot 0");
618 fails += 1;
619 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300620 if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300621 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700622 warn!("Mismatched trailer for Slot 1");
623 fails += 1;
624 }
625
626 if fails > 0 {
627 error!("Expected a non revert with new image");
628 }
629
630 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600631 }
632
David Brown5f7ec2b2017-11-06 13:54:02 -0700633 // Tests a new image written to slot0 that already has magic and image_ok set
634 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700635 pub fn run_signfail_upgrade(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700636 let mut fl = self.flash.clone();
637 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600638
David Brown5f7ec2b2017-11-06 13:54:02 -0700639 info!("Try upgrade image with bad signature");
640
Fabio Utzig1e48b912018-09-18 09:04:18 -0300641 mark_upgrade(&mut fl, &self.slots[0]);
Fabio Utzig269d2862018-10-24 17:45:38 -0300642 mark_permanent_upgrade(&mut fl, &self.slots[0]);
Fabio Utzig1e48b912018-09-18 09:04:18 -0300643 mark_upgrade(&mut fl, &self.slots[1]);
David Brown5f7ec2b2017-11-06 13:54:02 -0700644
Fabio Utzig1e48b912018-09-18 09:04:18 -0300645 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300646 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700647 warn!("Mismatched trailer for Slot 0");
648 fails += 1;
649 }
650
651 // Run the bootloader...
Fabio Utzig269d2862018-10-24 17:45:38 -0300652 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200653 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700654 warn!("Failed first boot");
655 fails += 1;
656 }
657
658 // State should not have changed
Fabio Utzig1e48b912018-09-18 09:04:18 -0300659 if !verify_image(&fl, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700660 warn!("Failed image verification");
661 fails += 1;
662 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300663 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300664 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700665 warn!("Mismatched trailer for Slot 0");
666 fails += 1;
667 }
668
669 if fails > 0 {
670 error!("Expected an upgrade failure when image has bad signature");
671 }
672
673 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600674 }
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200675
Fabio Utziga91c6262017-12-06 09:01:12 -0200676 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300677 fn trailer_sz(&self, align: usize) -> usize {
678 c::boot_trailer_sz(align as u8) as usize
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200679 }
680
681 // FIXME: could get status sz from bootloader
Fabio Utziga91c6262017-12-06 09:01:12 -0200682 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300683 #[cfg(not(feature = "enc-rsa"))]
684 #[cfg(not(feature = "enc-kw"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300685 fn status_sz(&self, align: usize) -> usize {
686 self.trailer_sz(align) - (16 + 24)
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200687 }
688
Fabio Utzig1e48b912018-09-18 09:04:18 -0300689 #[cfg(feature = "enc-rsa")]
Fabio Utzig9b7a2582018-12-03 10:40:05 -0200690 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300691 fn status_sz(&self, align: usize) -> usize {
692 self.trailer_sz(align) - (16 + 24 + 32)
Fabio Utzig1e48b912018-09-18 09:04:18 -0300693 }
694
695 #[cfg(feature = "enc-kw")]
Fabio Utzig9b7a2582018-12-03 10:40:05 -0200696 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300697 fn status_sz(&self, align: usize) -> usize {
698 self.trailer_sz(align) - (16 + 24 + 32)
Fabio Utzig1e48b912018-09-18 09:04:18 -0300699 }
700
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200701 /// This test runs a simple upgrade with no fails in the images, but
702 /// allowing for fails in the status area. This should run to the end
703 /// and warn that write fails were detected...
704 #[cfg(not(feature = "validate-slot0"))]
705 pub fn run_with_status_fails_complete(&self) -> bool { false }
706
707 #[cfg(feature = "validate-slot0")]
708 pub fn run_with_status_fails_complete(&self) -> bool {
709 let mut fl = self.flash.clone();
710 let mut fails = 0;
711
712 info!("Try swap with status fails");
713
Fabio Utzig269d2862018-10-24 17:45:38 -0300714 mark_permanent_upgrade(&mut fl, &self.slots[1]);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200715
Fabio Utzig269d2862018-10-24 17:45:38 -0300716 let align = fl.align();
717 let status_off = self.slots[1].base_off - self.trailer_sz(align);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200718
719 // Always fail writes to status area...
Fabio Utzig269d2862018-10-24 17:45:38 -0300720 let _ = fl.add_bad_region(status_off, self.status_sz(align), 1.0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200721
Fabio Utzig269d2862018-10-24 17:45:38 -0300722 let (result, asserts) = c::boot_go(&mut fl, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200723 if result != 0 {
724 warn!("Failed!");
725 fails += 1;
726 }
727
728 // Failed writes to the marked "bad" region don't assert anymore.
729 // Any detected assert() is happening in another part of the code.
730 if asserts != 0 {
731 warn!("At least one assert() was called");
732 fails += 1;
733 }
734
Fabio Utzig1e48b912018-09-18 09:04:18 -0300735 if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300736 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200737 warn!("Mismatched trailer for Slot 0");
738 fails += 1;
739 }
740
Fabio Utzig1e48b912018-09-18 09:04:18 -0300741 if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200742 warn!("Failed image verification");
743 fails += 1;
744 }
745
746 info!("validate slot0 enabled; re-run of boot_go should just work");
Fabio Utzig269d2862018-10-24 17:45:38 -0300747 let (result, _) = c::boot_go(&mut fl, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200748 if result != 0 {
749 warn!("Failed!");
750 fails += 1;
751 }
752
753 if fails > 0 {
754 error!("Error running upgrade with status write fails");
755 }
756
757 fails > 0
758 }
759
760 /// This test runs a simple upgrade with no fails in the images, but
761 /// allowing for fails in the status area. This should run to the end
762 /// and warn that write fails were detected...
763 #[cfg(feature = "validate-slot0")]
764 pub fn run_with_status_fails_with_reset(&self) -> bool {
765 let mut fl = self.flash.clone();
766 let mut fails = 0;
767 let mut count = self.total_count.unwrap() / 2;
768
769 //info!("count={}\n", count);
770
771 info!("Try interrupted swap with status fails");
772
Fabio Utzig269d2862018-10-24 17:45:38 -0300773 mark_permanent_upgrade(&mut fl, &self.slots[1]);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200774
Fabio Utzig269d2862018-10-24 17:45:38 -0300775 let align = fl.align();
776 let status_off = self.slots[1].base_off - self.trailer_sz(align);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200777
778 // Mark the status area as a bad area
Fabio Utzig269d2862018-10-24 17:45:38 -0300779 let _ = fl.add_bad_region(status_off, self.status_sz(align), 0.5);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200780
781 // Should not fail, writing to bad regions does not assert
Fabio Utzig269d2862018-10-24 17:45:38 -0300782 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, Some(&mut count), true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200783 if asserts != 0 {
784 warn!("At least one assert() was called");
785 fails += 1;
786 }
787
788 fl.reset_bad_regions();
789
790 // Disabling write verification the only assert triggered by
791 // boot_go should be checking for integrity of status bytes.
792 fl.set_verify_writes(false);
793
794 info!("Resuming an interrupted swap operation");
Fabio Utzig269d2862018-10-24 17:45:38 -0300795 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200796
797 // This might throw no asserts, for large sector devices, where
798 // a single failure writing is indistinguishable from no failure,
799 // or throw a single assert for small sector devices that fail
800 // multiple times...
801 if asserts > 1 {
802 warn!("Expected single assert validating slot0, more detected {}", asserts);
803 fails += 1;
804 }
805
806 if fails > 0 {
807 error!("Error running upgrade with status write fails");
808 }
809
810 fails > 0
811 }
812
813 #[cfg(not(feature = "validate-slot0"))]
814 #[cfg(not(feature = "overwrite-only"))]
815 pub fn run_with_status_fails_with_reset(&self) -> bool {
816 let mut fl = self.flash.clone();
817 let mut fails = 0;
818
819 info!("Try interrupted swap with status fails");
820
Fabio Utzig269d2862018-10-24 17:45:38 -0300821 mark_permanent_upgrade(&mut fl, &self.slots[1]);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200822
Fabio Utzig269d2862018-10-24 17:45:38 -0300823 let status_off = self.slots[1].base_off - self.trailer_sz(fl.align());
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200824
825 // Mark the status area as a bad area
Fabio Utzig269d2862018-10-24 17:45:38 -0300826 let align = fl.align();
827 let _ = fl.add_bad_region(status_off, self.status_sz(align), 1.0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200828
829 // This is expected to fail while writing to bad regions...
Fabio Utzig269d2862018-10-24 17:45:38 -0300830 let (_, asserts) = c::boot_go(&mut fl, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200831 if asserts == 0 {
832 warn!("No assert() detected");
833 fails += 1;
834 }
835
836 fails > 0
837 }
838
839 #[cfg(feature = "overwrite-only")]
840 pub fn run_with_status_fails_with_reset(&self) -> bool {
841 false
842 }
David Brown2639e072017-10-11 11:18:44 -0600843}
844
845/// Test a boot, optionally stopping after 'n' flash options. Returns a count
846/// of the number of flash operations done total.
David Brown3f687dc2017-11-06 13:41:18 -0700847fn try_upgrade(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600848 stop: Option<i32>) -> (SimFlash, i32) {
849 // Clone the flash to have a new copy.
850 let mut fl = flash.clone();
851
Fabio Utzig269d2862018-10-24 17:45:38 -0300852 mark_permanent_upgrade(&mut fl, &images.slots[1]);
David Brown2639e072017-10-11 11:18:44 -0600853
David Brownee61c832017-11-06 11:13:25 -0700854 let mut counter = stop.unwrap_or(0);
855
Fabio Utzig269d2862018-10-24 17:45:38 -0300856 let (first_interrupted, count) = match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200857 (-0x13579, _) => (true, stop.unwrap()),
858 (0, _) => (false, -counter),
859 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600860 };
David Brown2639e072017-10-11 11:18:44 -0600861
David Brownee61c832017-11-06 11:13:25 -0700862 counter = 0;
David Brown2639e072017-10-11 11:18:44 -0600863 if first_interrupted {
864 // fl.dump();
Fabio Utzig269d2862018-10-24 17:45:38 -0300865 match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200866 (-0x13579, _) => panic!("Shouldn't stop again"),
867 (0, _) => (),
868 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600869 }
870 }
871
David Brownee61c832017-11-06 11:13:25 -0700872 (fl, count - counter)
David Brown2639e072017-10-11 11:18:44 -0600873}
874
875#[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300876fn try_revert(flash: &SimFlash, areadesc: &AreaDesc, count: usize) -> SimFlash {
David Brown2639e072017-10-11 11:18:44 -0600877 let mut fl = flash.clone();
David Brown2639e072017-10-11 11:18:44 -0600878
879 // fl.write_file("image0.bin").unwrap();
880 for i in 0 .. count {
881 info!("Running boot pass {}", i + 1);
Fabio Utzig269d2862018-10-24 17:45:38 -0300882 assert_eq!(c::boot_go(&mut fl, &areadesc, None, false), (0, 0));
David Brown2639e072017-10-11 11:18:44 -0600883 }
884 fl
885}
886
887#[cfg(not(feature = "overwrite-only"))]
David Brown3f687dc2017-11-06 13:41:18 -0700888fn try_revert_with_fail_at(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600889 stop: i32) -> bool {
890 let mut fl = flash.clone();
David Brown2639e072017-10-11 11:18:44 -0600891 let mut fails = 0;
892
David Brownee61c832017-11-06 11:13:25 -0700893 let mut counter = stop;
Fabio Utzig269d2862018-10-24 17:45:38 -0300894 let (x, _) = c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), false);
David Brown2639e072017-10-11 11:18:44 -0600895 if x != -0x13579 {
896 warn!("Should have stopped at interruption point");
897 fails += 1;
898 }
899
Fabio Utzig1e48b912018-09-18 09:04:18 -0300900 if !verify_trailer(&fl, images.slots[0].trailer_off, None, None, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600901 warn!("copy_done should be unset");
902 fails += 1;
903 }
904
Fabio Utzig269d2862018-10-24 17:45:38 -0300905 let (x, _) = c::boot_go(&mut fl, &images.areadesc, None, false);
David Brown2639e072017-10-11 11:18:44 -0600906 if x != 0 {
907 warn!("Should have finished upgrade");
908 fails += 1;
909 }
910
Fabio Utzig1e48b912018-09-18 09:04:18 -0300911 if !verify_image(&fl, &images.slots, 0, &images.upgrades) {
David Brown2639e072017-10-11 11:18:44 -0600912 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
913 fails += 1;
914 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300915 if !verify_image(&fl, &images.slots, 1, &images.primaries) {
David Brown2639e072017-10-11 11:18:44 -0600916 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
917 fails += 1;
918 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300919 if !verify_trailer(&fl, images.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300920 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600921 warn!("Mismatched trailer for Slot 0 before revert");
922 fails += 1;
923 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300924 if !verify_trailer(&fl, images.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300925 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600926 warn!("Mismatched trailer for Slot 1 before revert");
927 fails += 1;
928 }
929
930 // Do Revert
Fabio Utzig269d2862018-10-24 17:45:38 -0300931 let (x, _) = c::boot_go(&mut fl, &images.areadesc, None, false);
David Brown2639e072017-10-11 11:18:44 -0600932 if x != 0 {
933 warn!("Should have finished a revert");
934 fails += 1;
935 }
936
Fabio Utzig1e48b912018-09-18 09:04:18 -0300937 if !verify_image(&fl, &images.slots, 0, &images.primaries) {
David Brown2639e072017-10-11 11:18:44 -0600938 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
939 fails += 1;
940 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300941 if !verify_image(&fl, &images.slots, 1, &images.upgrades) {
David Brown2639e072017-10-11 11:18:44 -0600942 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
943 fails += 1;
944 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300945 if !verify_trailer(&fl, images.slots[0].trailer_off, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300946 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600947 warn!("Mismatched trailer for Slot 1 after revert");
948 fails += 1;
949 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300950 if !verify_trailer(&fl, images.slots[1].trailer_off, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300951 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600952 warn!("Mismatched trailer for Slot 1 after revert");
953 fails += 1;
954 }
955
956 fails > 0
957}
958
David Brown3f687dc2017-11-06 13:41:18 -0700959fn try_random_fails(flash: &SimFlash, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600960 total_ops: i32, count: usize) -> (SimFlash, Vec<i32>) {
961 let mut fl = flash.clone();
962
Fabio Utzig269d2862018-10-24 17:45:38 -0300963 mark_permanent_upgrade(&mut fl, &images.slots[1]);
David Brown2639e072017-10-11 11:18:44 -0600964
965 let mut rng = rand::thread_rng();
966 let mut resets = vec![0i32; count];
967 let mut remaining_ops = total_ops;
968 for i in 0 .. count {
969 let ops = Range::new(1, remaining_ops / 2);
970 let reset_counter = ops.ind_sample(&mut rng);
David Brownee61c832017-11-06 11:13:25 -0700971 let mut counter = reset_counter;
Fabio Utzig269d2862018-10-24 17:45:38 -0300972 match c::boot_go(&mut fl, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200973 (0, _) | (-0x13579, _) => (),
974 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600975 }
976 remaining_ops -= reset_counter;
977 resets[i] = reset_counter;
978 }
979
Fabio Utzig269d2862018-10-24 17:45:38 -0300980 match c::boot_go(&mut fl, &images.areadesc, None, false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200981 (-0x13579, _) => panic!("Should not be have been interrupted!"),
982 (0, _) => (),
983 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600984 }
985
986 (fl, resets)
987}
988
989/// Show the flash layout.
990#[allow(dead_code)]
991fn show_flash(flash: &Flash) {
992 println!("---- Flash configuration ----");
993 for sector in flash.sector_iter() {
994 println!(" {:3}: 0x{:08x}, 0x{:08x}",
995 sector.num, sector.base, sector.size);
996 }
997 println!("");
998}
999
1000/// Install a "program" into the given image. This fakes the image header, or at least all of the
1001/// fields used by the given code. Returns a copy of the image that was written.
Fabio Utzig1e48b912018-09-18 09:04:18 -03001002fn install_image(flash: &mut Flash, slots: &[SlotInfo], slot: usize, len: usize,
1003 bad_sig: bool) -> [Option<Vec<u8>>; 2] {
1004 let offset = slots[slot].base_off;
1005 let slot_len = slots[slot].len;
David Brown2639e072017-10-11 11:18:44 -06001006
1007 let mut tlv = make_tlv();
1008
Fabio Utzige5831f62018-12-14 06:46:22 -02001009 const HDR_SIZE: usize = 32;
1010
David Brown2639e072017-10-11 11:18:44 -06001011 // Generate a boot header. Note that the size doesn't include the header.
1012 let header = ImageHeader {
1013 magic: 0x96f3b83d,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001014 load_addr: 0,
Fabio Utzige5831f62018-12-14 06:46:22 -02001015 hdr_size: HDR_SIZE as u16,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001016 _pad1: 0,
David Brown2639e072017-10-11 11:18:44 -06001017 img_size: len as u32,
1018 flags: tlv.get_flags(),
1019 ver: ImageVersion {
1020 major: (offset / (128 * 1024)) as u8,
1021 minor: 0,
1022 revision: 1,
1023 build_num: offset as u32,
1024 },
Fabio Utzig1e48b912018-09-18 09:04:18 -03001025 _pad2: 0,
David Brown2639e072017-10-11 11:18:44 -06001026 };
1027
Fabio Utzige5831f62018-12-14 06:46:22 -02001028 let mut b_header = [0; HDR_SIZE];
1029 b_header[..32].clone_from_slice(header.as_raw());
1030 assert_eq!(b_header.len(), HDR_SIZE);
1031
David Brown2639e072017-10-11 11:18:44 -06001032 tlv.add_bytes(&b_header);
David Brown2639e072017-10-11 11:18:44 -06001033
1034 // The core of the image itself is just pseudorandom data.
Fabio Utzig1e48b912018-09-18 09:04:18 -03001035 let mut b_img = vec![0; len];
1036 splat(&mut b_img, offset);
David Brown2639e072017-10-11 11:18:44 -06001037
Fabio Utzig1e48b912018-09-18 09:04:18 -03001038 // TLV signatures work over plain image
1039 tlv.add_bytes(&b_img);
1040
1041 // Generate encrypted images
1042 let flag = TlvFlags::ENCRYPTED as u32;
1043 let is_encrypted = (tlv.get_flags() & flag) == flag;
1044 let mut b_encimg = vec![];
1045 if is_encrypted {
1046 let key = GenericArray::from_slice(AES_SEC_KEY);
1047 let nonce = GenericArray::from_slice(&[0; 16]);
1048 let mut cipher = Aes128Ctr::new(&key, &nonce);
1049 b_encimg = b_img.clone();
1050 cipher.apply_keystream(&mut b_encimg);
David Brown2639e072017-10-11 11:18:44 -06001051 }
1052
Fabio Utzig1e48b912018-09-18 09:04:18 -03001053 // Build the TLV itself.
1054 let mut b_tlv = if bad_sig {
1055 let good_sig = &mut tlv.make_tlv();
1056 vec![0; good_sig.len()]
1057 } else {
1058 tlv.make_tlv()
1059 };
1060
David Brown2639e072017-10-11 11:18:44 -06001061 // Pad the block to a flash alignment (8 bytes).
Fabio Utzig1e48b912018-09-18 09:04:18 -03001062 while b_tlv.len() % 8 != 0 {
1063 //FIXME: should be erase_val?
1064 b_tlv.push(0xFF);
David Brown2639e072017-10-11 11:18:44 -06001065 }
1066
Fabio Utzig1e48b912018-09-18 09:04:18 -03001067 let mut buf = vec![];
1068 buf.append(&mut b_header.to_vec());
1069 buf.append(&mut b_img);
1070 buf.append(&mut b_tlv.clone());
David Brown2639e072017-10-11 11:18:44 -06001071
Fabio Utzig1e48b912018-09-18 09:04:18 -03001072 let mut encbuf = vec![];
1073 if is_encrypted {
1074 encbuf.append(&mut b_header.to_vec());
1075 encbuf.append(&mut b_encimg);
1076 encbuf.append(&mut b_tlv);
1077 }
David Brown2639e072017-10-11 11:18:44 -06001078
Fabio Utzig1e48b912018-09-18 09:04:18 -03001079 let result: [Option<Vec<u8>>; 2];
1080
1081 // Since images are always non-encrypted in slot0, we first write an
1082 // encrypted image, re-read to use for verification, erase + flash
1083 // un-encrypted. In slot1 the image is written un-encrypted, and if
1084 // encryption is requested, it follows an erase + flash encrypted.
1085
1086 if slot == 0 {
1087 let enc_copy: Option<Vec<u8>>;
1088
1089 if is_encrypted {
1090 flash.write(offset, &encbuf).unwrap();
1091
1092 let mut enc = vec![0u8; encbuf.len()];
1093 flash.read(offset, &mut enc).unwrap();
1094
1095 enc_copy = Some(enc);
1096
1097 flash.erase(offset, slot_len).unwrap();
1098 } else {
1099 enc_copy = None;
1100 }
1101
1102 flash.write(offset, &buf).unwrap();
1103
1104 let mut copy = vec![0u8; buf.len()];
1105 flash.read(offset, &mut copy).unwrap();
1106
1107 result = [Some(copy), enc_copy];
1108 } else {
1109 flash.write(offset, &buf).unwrap();
1110
1111 let mut copy = vec![0u8; buf.len()];
1112 flash.read(offset, &mut copy).unwrap();
1113
1114 let enc_copy: Option<Vec<u8>>;
1115
1116 if is_encrypted {
1117 flash.erase(offset, slot_len).unwrap();
1118
1119 flash.write(offset, &encbuf).unwrap();
1120
1121 let mut enc = vec![0u8; encbuf.len()];
1122 flash.read(offset, &mut enc).unwrap();
1123
1124 enc_copy = Some(enc);
1125 } else {
1126 enc_copy = None;
1127 }
1128
1129 result = [Some(copy), enc_copy];
1130 }
1131
1132 result
David Brown2639e072017-10-11 11:18:44 -06001133}
1134
1135// The TLV in use depends on what kind of signature we are verifying.
1136#[cfg(feature = "sig-rsa")]
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001137#[cfg(not(feature = "enc-rsa"))]
David Brown2639e072017-10-11 11:18:44 -06001138fn make_tlv() -> TlvGen {
1139 TlvGen::new_rsa_pss()
1140}
1141
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001142#[cfg(feature = "sig-ecdsa")]
1143fn make_tlv() -> TlvGen {
1144 TlvGen::new_ecdsa()
1145}
1146
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001147#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001148#[cfg(feature = "enc-rsa")]
1149fn make_tlv() -> TlvGen {
1150 TlvGen::new_enc_rsa()
1151}
1152
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001153#[cfg(feature = "sig-rsa")]
1154#[cfg(feature = "enc-rsa")]
1155fn make_tlv() -> TlvGen {
1156 TlvGen::new_sig_enc_rsa()
1157}
1158
Fabio Utzig1e48b912018-09-18 09:04:18 -03001159#[cfg(feature = "enc-kw")]
1160fn make_tlv() -> TlvGen {
1161 TlvGen::new_enc_kw()
1162}
1163
David Brown2639e072017-10-11 11:18:44 -06001164#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001165#[cfg(not(feature = "sig-ecdsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001166#[cfg(not(feature = "enc-rsa"))]
1167#[cfg(not(feature = "enc-kw"))]
David Brown2639e072017-10-11 11:18:44 -06001168fn make_tlv() -> TlvGen {
1169 TlvGen::new_hash_only()
1170}
1171
Fabio Utzig1e48b912018-09-18 09:04:18 -03001172#[cfg(feature = "enc-rsa")]
1173fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
1174 match &images[slot] {
1175 Some(image) => return image,
1176 None => panic!("Invalid image"),
1177 }
1178}
1179
1180#[cfg(feature = "enc-kw")]
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(not(feature = "enc-rsa"))]
1189#[cfg(not(feature = "enc-kw"))]
1190fn find_image(images: &[Option<Vec<u8>>; 2], _slot: usize) -> &Vec<u8> {
1191 match &images[0] {
1192 Some(image) => return image,
1193 None => panic!("Invalid image"),
1194 }
1195}
1196
David Brown2639e072017-10-11 11:18:44 -06001197/// Verify that given image is present in the flash at the given offset.
Fabio Utzig1e48b912018-09-18 09:04:18 -03001198fn verify_image(flash: &Flash, slots: &[SlotInfo], slot: usize,
1199 images: &[Option<Vec<u8>>; 2]) -> bool {
1200 let image = find_image(images, slot);
1201 let buf = image.as_slice();
1202
David Brown2639e072017-10-11 11:18:44 -06001203 let mut copy = vec![0u8; buf.len()];
Fabio Utzig1e48b912018-09-18 09:04:18 -03001204 let offset = slots[slot].base_off;
David Brown2639e072017-10-11 11:18:44 -06001205 flash.read(offset, &mut copy).unwrap();
1206
1207 if buf != &copy[..] {
1208 for i in 0 .. buf.len() {
1209 if buf[i] != copy[i] {
Fabio Utzig1e48b912018-09-18 09:04:18 -03001210 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1211 slot, offset + i, buf[i], copy[i]);
David Brown2639e072017-10-11 11:18:44 -06001212 break;
1213 }
1214 }
1215 false
1216 } else {
1217 true
1218 }
1219}
1220
1221#[cfg(feature = "overwrite-only")]
1222#[allow(unused_variables)]
1223// overwrite-only doesn't employ trailer management
1224fn verify_trailer(flash: &Flash, offset: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001225 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001226 copy_done: Option<u8>) -> bool {
1227 true
1228}
1229
1230#[cfg(not(feature = "overwrite-only"))]
1231fn verify_trailer(flash: &Flash, offset: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001232 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001233 copy_done: Option<u8>) -> bool {
1234 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1235 let mut failed = false;
Fabio Utzigea0290b2018-08-09 14:23:01 -03001236 let erased_val = flash.erased_val();
David Brown2639e072017-10-11 11:18:44 -06001237
1238 flash.read(offset, &mut copy).unwrap();
1239
1240 failed |= match magic {
1241 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001242 if v == 1 && &copy[16..] != MAGIC.unwrap() {
David Brown2639e072017-10-11 11:18:44 -06001243 warn!("\"magic\" mismatch at {:#x}", offset);
1244 true
Fabio Utzigea0290b2018-08-09 14:23:01 -03001245 } else if v == 3 {
1246 let expected = [erased_val; 16];
1247 if &copy[16..] != expected {
1248 warn!("\"magic\" mismatch at {:#x}", offset);
1249 true
1250 } else {
1251 false
1252 }
David Brown2639e072017-10-11 11:18:44 -06001253 } else {
1254 false
1255 }
1256 },
1257 None => false,
1258 };
1259
1260 failed |= match image_ok {
1261 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001262 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1263 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
David Brown2639e072017-10-11 11:18:44 -06001264 true
1265 } else {
1266 false
1267 }
1268 },
1269 None => false,
1270 };
1271
1272 failed |= match copy_done {
1273 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001274 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1275 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
David Brown2639e072017-10-11 11:18:44 -06001276 true
1277 } else {
1278 false
1279 }
1280 },
1281 None => false,
1282 };
1283
1284 !failed
1285}
1286
1287/// The image header
1288#[repr(C)]
1289pub struct ImageHeader {
1290 magic: u32,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001291 load_addr: u32,
David Brown2639e072017-10-11 11:18:44 -06001292 hdr_size: u16,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001293 _pad1: u16,
David Brown2639e072017-10-11 11:18:44 -06001294 img_size: u32,
1295 flags: u32,
1296 ver: ImageVersion,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001297 _pad2: u32,
David Brown2639e072017-10-11 11:18:44 -06001298}
1299
1300impl AsRaw for ImageHeader {}
1301
1302#[repr(C)]
1303pub struct ImageVersion {
1304 major: u8,
1305 minor: u8,
1306 revision: u16,
1307 build_num: u32,
1308}
1309
David Brownd5e632c2017-10-19 10:49:46 -06001310#[derive(Clone)]
David Brown2639e072017-10-11 11:18:44 -06001311struct SlotInfo {
1312 base_off: usize,
1313 trailer_off: usize,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001314 len: usize,
David Brown2639e072017-10-11 11:18:44 -06001315}
1316
David Brownf48b9502017-11-06 14:00:26 -07001317pub struct Images {
David Browndc9cba12017-11-06 13:31:42 -07001318 flash: SimFlash,
David Brown3f687dc2017-11-06 13:41:18 -07001319 areadesc: AreaDesc,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001320 slots: [SlotInfo; 2],
1321 primaries: [Option<Vec<u8>>; 2],
1322 upgrades: [Option<Vec<u8>>; 2],
David Brownc49811e2017-11-06 14:20:45 -07001323 total_count: Option<i32>,
David Brown2639e072017-10-11 11:18:44 -06001324}
1325
Fabio Utzigea0290b2018-08-09 14:23:01 -03001326const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1327 0x60, 0xd2, 0xef, 0x7f,
1328 0x35, 0x52, 0x50, 0x0f,
1329 0x2c, 0xb6, 0x79, 0x80]);
David Brown2639e072017-10-11 11:18:44 -06001330
Fabio Utzigea0290b2018-08-09 14:23:01 -03001331// Replicates defines found in bootutil.h
1332const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1333const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1334
1335const BOOT_FLAG_SET: Option<u8> = Some(1);
1336const BOOT_FLAG_UNSET: Option<u8> = Some(3);
David Brown2639e072017-10-11 11:18:44 -06001337
1338/// Write out the magic so that the loader tries doing an upgrade.
1339fn mark_upgrade(flash: &mut Flash, slot: &SlotInfo) {
1340 let offset = slot.trailer_off + c::boot_max_align() * 2;
Fabio Utzigea0290b2018-08-09 14:23:01 -03001341 flash.write(offset, MAGIC.unwrap()).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001342}
1343
1344/// Writes the image_ok flag which, guess what, tells the bootloader
1345/// the this image is ok (not a test, and no revert is to be performed).
Fabio Utzig269d2862018-10-24 17:45:38 -03001346fn mark_permanent_upgrade(flash: &mut Flash, slot: &SlotInfo) {
1347 let mut ok = [flash.erased_val(); 8];
Fabio Utzigea0290b2018-08-09 14:23:01 -03001348 ok[0] = 1u8;
David Brown2639e072017-10-11 11:18:44 -06001349 let off = slot.trailer_off + c::boot_max_align();
Fabio Utzig269d2862018-10-24 17:45:38 -03001350 let align = flash.align();
1351 flash.write(off, &ok[..align]).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001352}
1353
1354// Drop some pseudo-random gibberish onto the data.
1355fn splat(data: &mut [u8], seed: usize) {
1356 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1357 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1358 rng.fill_bytes(data);
1359}
1360
1361/// Return a read-only view into the raw bytes of this object
1362trait AsRaw : Sized {
1363 fn as_raw<'a>(&'a self) -> &'a [u8] {
1364 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1365 mem::size_of::<Self>()) }
1366 }
1367}
1368
1369fn show_sizes() {
1370 // This isn't panic safe.
David Brown2639e072017-10-11 11:18:44 -06001371 for min in &[1, 2, 4, 8] {
David Brown541860c2017-11-06 11:25:42 -07001372 let msize = c::boot_trailer_sz(*min);
David Brown2639e072017-10-11 11:18:44 -06001373 println!("{:2}: {} (0x{:x})", min, msize, msize);
1374 }
David Brown2639e072017-10-11 11:18:44 -06001375}