blob: 0fc9363d08c5cc3a844f1bcedd3309c3fe7c5026 [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
Fabio Utzigafb2bc92018-11-19 16:11:52 -020031use simflash::{Flash, SimFlash, SimFlashMap};
David Brown2639e072017-10-11 11:18:44 -060032use 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)]
Fabio Utzigafb2bc92018-11-19 16:11:52 -020065pub enum DeviceName { Stm32f4, K64f, K64fBig, Nrf52840, Nrf52840SpiFlash, }
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,
Fabio Utzigafb2bc92018-11-19 16:11:52 -020072 DeviceName::Nrf52840SpiFlash,
David Brown2639e072017-10-11 11:18:44 -060073];
74
75impl fmt::Display for DeviceName {
76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77 let name = match *self {
78 DeviceName::Stm32f4 => "stm32f4",
79 DeviceName::K64f => "k64f",
80 DeviceName::K64fBig => "k64fbig",
81 DeviceName::Nrf52840 => "nrf52840",
Fabio Utzigafb2bc92018-11-19 16:11:52 -020082 DeviceName::Nrf52840SpiFlash => "Nrf52840SpiFlash",
David Brown2639e072017-10-11 11:18:44 -060083 };
84 f.write_str(name)
85 }
86}
87
88#[derive(Debug)]
89struct AlignArg(u8);
90
91struct AlignArgVisitor;
92
93impl<'de> serde::de::Visitor<'de> for AlignArgVisitor {
94 type Value = AlignArg;
95
96 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
97 formatter.write_str("1, 2, 4 or 8")
98 }
99
100 fn visit_u8<E>(self, n: u8) -> Result<Self::Value, E>
101 where E: serde::de::Error
102 {
103 Ok(match n {
104 1 | 2 | 4 | 8 => AlignArg(n),
105 n => {
106 let err = format!("Could not deserialize '{}' as alignment", n);
107 return Err(E::custom(err));
108 }
109 })
110 }
111}
112
113impl<'de> serde::de::Deserialize<'de> for AlignArg {
114 fn deserialize<D>(d: D) -> Result<AlignArg, D::Error>
115 where D: serde::de::Deserializer<'de>
116 {
117 d.deserialize_u8(AlignArgVisitor)
118 }
119}
120
121pub fn main() {
122 let args: Args = Docopt::new(USAGE)
123 .and_then(|d| d.deserialize())
124 .unwrap_or_else(|e| e.exit());
125 // println!("args: {:#?}", args);
126
127 if args.cmd_sizes {
128 show_sizes();
129 return;
130 }
131
132 let mut status = RunStatus::new();
133 if args.cmd_run {
134
135 let align = args.flag_align.map(|x| x.0).unwrap_or(1);
136
137
138 let device = match args.flag_device {
139 None => panic!("Missing mandatory device argument"),
140 Some(dev) => dev,
141 };
142
Fabio Utzigea0290b2018-08-09 14:23:01 -0300143 status.run_single(device, align, 0xff);
David Brown2639e072017-10-11 11:18:44 -0600144 }
145
146 if args.cmd_runall {
147 for &dev in ALL_DEVICES {
148 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300149 for &erased_val in &[0, 0xff] {
150 status.run_single(dev, align, erased_val);
151 }
David Brown2639e072017-10-11 11:18:44 -0600152 }
153 }
154 }
155
156 if status.failures > 0 {
157 error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
158 process::exit(1);
159 } else {
160 error!("{} Tests ran successfully", status.passes);
161 process::exit(0);
162 }
163}
164
David Browndb9a3952017-11-06 13:16:15 -0700165/// A test run, intended to be run from "cargo test", so panics on failure.
166pub struct Run {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200167 flashmap: SimFlashMap,
David Browndb9a3952017-11-06 13:16:15 -0700168 areadesc: AreaDesc,
169 slots: [SlotInfo; 2],
David Browndb9a3952017-11-06 13:16:15 -0700170}
171
172impl Run {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300173 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Run {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200174 let (flashmap, areadesc) = make_device(device, align, erased_val);
David Browndb9a3952017-11-06 13:16:15 -0700175
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200176 let (slot0_base, slot0_len, slot0_dev_id) = areadesc.find(FlashId::Image0);
177 let (slot1_base, slot1_len, slot1_dev_id) = areadesc.find(FlashId::Image1);
David Browndb9a3952017-11-06 13:16:15 -0700178
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200179 // NOTE: not accounting "swap_size" because it is not used by sim...
David Browndb9a3952017-11-06 13:16:15 -0700180 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
181
182 // Construct a primary image.
183 let slot0 = SlotInfo {
184 base_off: slot0_base as usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200185 trailer_off: slot0_base + slot0_len - offset_from_end,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300186 len: slot0_len as usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200187 dev_id: slot0_dev_id,
David Browndb9a3952017-11-06 13:16:15 -0700188 };
189
190 // And an upgrade image.
191 let slot1 = SlotInfo {
192 base_off: slot1_base as usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200193 trailer_off: slot1_base + slot1_len - offset_from_end,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300194 len: slot1_len as usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200195 dev_id: slot1_dev_id,
David Browndb9a3952017-11-06 13:16:15 -0700196 };
197
198 Run {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200199 flashmap: flashmap,
David Browndb9a3952017-11-06 13:16:15 -0700200 areadesc: areadesc,
201 slots: [slot0, slot1],
David Browndb9a3952017-11-06 13:16:15 -0700202 }
203 }
204
205 pub fn each_device<F>(f: F)
206 where F: Fn(&mut Run)
207 {
208 for &dev in ALL_DEVICES {
209 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300210 for &erased_val in &[0, 0xff] {
211 let mut run = Run::new(dev, align, erased_val);
212 f(&mut run);
213 }
David Browndb9a3952017-11-06 13:16:15 -0700214 }
215 }
216 }
David Brownf48b9502017-11-06 14:00:26 -0700217
218 /// Construct an `Images` that doesn't expect an upgrade to happen.
219 pub fn make_no_upgrade_image(&self) -> Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200220 let mut flashmap = self.flashmap.clone();
221 let primaries = install_image(&mut flashmap, &self.slots, 0, 32784, false);
222 let upgrades = install_image(&mut flashmap, &self.slots, 1, 41928, false);
David Brownf48b9502017-11-06 14:00:26 -0700223 Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200224 flashmap: flashmap,
David Brownf48b9502017-11-06 14:00:26 -0700225 areadesc: self.areadesc.clone(),
Fabio Utzig1e48b912018-09-18 09:04:18 -0300226 slots: [self.slots[0].clone(), self.slots[1].clone()],
227 primaries: primaries,
228 upgrades: upgrades,
David Brownc49811e2017-11-06 14:20:45 -0700229 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700230 }
231 }
232
233 /// Construct an `Images` for normal testing.
234 pub fn make_image(&self) -> Images {
235 let mut images = self.make_no_upgrade_image();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200236 mark_upgrade(&mut images.flashmap, &images.slots[1]);
David Brownc49811e2017-11-06 14:20:45 -0700237
238 // upgrades without fails, counts number of flash operations
239 let total_count = match images.run_basic_upgrade() {
240 Ok(v) => v,
241 Err(_) => {
242 panic!("Unable to perform basic upgrade");
243 },
244 };
245
246 images.total_count = Some(total_count);
David Brownf48b9502017-11-06 14:00:26 -0700247 images
248 }
249
250 pub fn make_bad_slot1_image(&self) -> Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200251 let mut bad_flashmap = self.flashmap.clone();
252 let primaries = install_image(&mut bad_flashmap, &self.slots, 0, 32784, false);
253 let upgrades = install_image(&mut bad_flashmap, &self.slots, 1, 41928, true);
David Brownf48b9502017-11-06 14:00:26 -0700254 Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200255 flashmap: bad_flashmap,
David Brownf48b9502017-11-06 14:00:26 -0700256 areadesc: self.areadesc.clone(),
Fabio Utzig1e48b912018-09-18 09:04:18 -0300257 slots: [self.slots[0].clone(), self.slots[1].clone()],
258 primaries: primaries,
259 upgrades: upgrades,
David Brownc49811e2017-11-06 14:20:45 -0700260 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700261 }
262 }
David Brownc49811e2017-11-06 14:20:45 -0700263
David Browndb9a3952017-11-06 13:16:15 -0700264}
265
David Browndd2b1182017-11-02 15:39:21 -0600266pub struct RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600267 failures: usize,
268 passes: usize,
269}
270
271impl RunStatus {
David Browndd2b1182017-11-02 15:39:21 -0600272 pub fn new() -> RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600273 RunStatus {
274 failures: 0,
275 passes: 0,
276 }
277 }
278
Fabio Utzigea0290b2018-08-09 14:23:01 -0300279 pub fn run_single(&mut self, device: DeviceName, align: u8, erased_val: u8) {
David Brown2639e072017-10-11 11:18:44 -0600280 warn!("Running on device {} with alignment {}", device, align);
281
Fabio Utzigea0290b2018-08-09 14:23:01 -0300282 let run = Run::new(device, align, erased_val);
David Brown2639e072017-10-11 11:18:44 -0600283
David Brown2639e072017-10-11 11:18:44 -0600284 let mut failed = false;
285
286 // Creates a badly signed image in slot1 to check that it is not
287 // upgraded to
David Brownf48b9502017-11-06 14:00:26 -0700288 let bad_slot1_image = run.make_bad_slot1_image();
David Brown2639e072017-10-11 11:18:44 -0600289
David Brown5f7ec2b2017-11-06 13:54:02 -0700290 failed |= bad_slot1_image.run_signfail_upgrade();
David Brown2639e072017-10-11 11:18:44 -0600291
David Brownf48b9502017-11-06 14:00:26 -0700292 let images = run.make_no_upgrade_image();
David Brown5f7ec2b2017-11-06 13:54:02 -0700293 failed |= images.run_norevert_newimage();
David Brown2639e072017-10-11 11:18:44 -0600294
David Brownf48b9502017-11-06 14:00:26 -0700295 let images = run.make_image();
David Brown2639e072017-10-11 11:18:44 -0600296
David Brown5f7ec2b2017-11-06 13:54:02 -0700297 failed |= images.run_basic_revert();
David Brownc49811e2017-11-06 14:20:45 -0700298 failed |= images.run_revert_with_fails();
299 failed |= images.run_perm_with_fails();
300 failed |= images.run_perm_with_random_fails(5);
David Brown5f7ec2b2017-11-06 13:54:02 -0700301 failed |= images.run_norevert();
David Brown2639e072017-10-11 11:18:44 -0600302
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200303 failed |= images.run_with_status_fails_complete();
Fabio Utzigeedcc452017-11-24 10:48:52 -0200304 failed |= images.run_with_status_fails_with_reset();
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200305
David Brown2639e072017-10-11 11:18:44 -0600306 //show_flash(&flash);
307
308 if failed {
309 self.failures += 1;
310 } else {
311 self.passes += 1;
312 }
313 }
David Browndd2b1182017-11-02 15:39:21 -0600314
315 pub fn failures(&self) -> usize {
316 self.failures
317 }
David Brown2639e072017-10-11 11:18:44 -0600318}
319
David Browndecbd042017-10-19 10:43:17 -0600320/// Build the Flash and area descriptor for a given device.
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200321pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimFlashMap, AreaDesc) {
David Browndecbd042017-10-19 10:43:17 -0600322 match device {
323 DeviceName::Stm32f4 => {
324 // STM style flash. Large sectors, with a large scratch area.
325 let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
326 64 * 1024,
327 128 * 1024, 128 * 1024, 128 * 1024],
Fabio Utzigea0290b2018-08-09 14:23:01 -0300328 align as usize, erased_val);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200329 let dev_id = 0;
Fabio Utzig1caef132018-10-26 15:40:53 -0300330 let mut areadesc = AreaDesc::new();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200331 areadesc.add_flash_sectors(dev_id, &flash);
332 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
333 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
334 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
335
336 let mut flashmap = SimFlashMap::new();
337 flashmap.insert(dev_id, flash);
338 (flashmap, areadesc)
David Browndecbd042017-10-19 10:43:17 -0600339 }
340 DeviceName::K64f => {
341 // NXP style flash. Small sectors, one small sector for scratch.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300342 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600343
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200344 let dev_id = 0;
Fabio Utzig1caef132018-10-26 15:40:53 -0300345 let mut areadesc = AreaDesc::new();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200346 areadesc.add_flash_sectors(dev_id, &flash);
347 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
348 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
349 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
350
351 let mut flashmap = SimFlashMap::new();
352 flashmap.insert(dev_id, flash);
353 (flashmap, areadesc)
David Browndecbd042017-10-19 10:43:17 -0600354 }
355 DeviceName::K64fBig => {
356 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
357 // uses small sectors, but we tell the bootloader they are large.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300358 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600359
Fabio Utzig1caef132018-10-26 15:40:53 -0300360 let dev_id = 0;
361 let mut areadesc = AreaDesc::new();
362 areadesc.add_flash_sectors(dev_id, &flash);
363 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
364 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
365 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200366
367 let mut flashmap = SimFlashMap::new();
368 flashmap.insert(dev_id, flash);
369 (flashmap, areadesc)
David Browndecbd042017-10-19 10:43:17 -0600370 }
371 DeviceName::Nrf52840 => {
372 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
373 // does not divide into the image size.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300374 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600375
Fabio Utzig1caef132018-10-26 15:40:53 -0300376 let dev_id = 0;
377 let mut areadesc = AreaDesc::new();
378 areadesc.add_flash_sectors(dev_id, &flash);
379 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
380 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
381 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200382
383 let mut flashmap = SimFlashMap::new();
384 flashmap.insert(dev_id, flash);
385 (flashmap, areadesc)
386 }
387 DeviceName::Nrf52840SpiFlash => {
388 // Simulate nrf52840 with external SPI flash. The external SPI flash
389 // has a larger sector size so for now store scratch on that flash.
390 let flash0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
Fabio Utzig64650772018-11-19 16:51:13 -0200391 let flash1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200392
393 let mut areadesc = AreaDesc::new();
394 areadesc.add_flash_sectors(0, &flash0);
395 areadesc.add_flash_sectors(1, &flash1);
396
397 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
398 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
399 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
400
401 let mut flashmap = SimFlashMap::new();
402 flashmap.insert(0, flash0);
403 flashmap.insert(1, flash1);
404 (flashmap, areadesc)
David Browndecbd042017-10-19 10:43:17 -0600405 }
406 }
407}
408
David Brown5f7ec2b2017-11-06 13:54:02 -0700409impl Images {
410 /// A simple upgrade without forced failures.
411 ///
412 /// Returns the number of flash operations which can later be used to
413 /// inject failures at chosen steps.
David Brownc49811e2017-11-06 14:20:45 -0700414 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200415 let (flashmap, total_count) = try_upgrade(&self.flashmap, &self, None);
David Brown5f7ec2b2017-11-06 13:54:02 -0700416 info!("Total flash operation count={}", total_count);
David Brown2639e072017-10-11 11:18:44 -0600417
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200418 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700419 warn!("Image mismatch after first boot");
420 Err(())
421 } else {
422 Ok(total_count)
David Brown2639e072017-10-11 11:18:44 -0600423 }
424 }
425
David Brown5f7ec2b2017-11-06 13:54:02 -0700426 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700427 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700428 false
429 }
David Brown2639e072017-10-11 11:18:44 -0600430
David Brown5f7ec2b2017-11-06 13:54:02 -0700431 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700432 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700433 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600434
David Brown5f7ec2b2017-11-06 13:54:02 -0700435 // FIXME: this test would also pass if no swap is ever performed???
436 if Caps::SwapUpgrade.present() {
437 for count in 2 .. 5 {
438 info!("Try revert: {}", count);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200439 let flashmap = try_revert(&self.flashmap, &self.areadesc, count);
440 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700441 error!("Revert failure on count {}", count);
442 fails += 1;
443 }
444 }
445 }
446
447 fails > 0
448 }
449
David Browna4167ef2017-11-06 14:30:05 -0700450 pub fn run_perm_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700451 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700452 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700453
454 // Let's try an image halfway through.
455 for i in 1 .. total_flash_ops {
456 info!("Try interruption at {}", i);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200457 let (flashmap, count) = try_upgrade(&self.flashmap, &self, Some(i));
David Brown5f7ec2b2017-11-06 13:54:02 -0700458 info!("Second boot, count={}", count);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200459 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700460 warn!("FAIL at step {} of {}", i, total_flash_ops);
461 fails += 1;
462 }
463
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200464 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300465 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700466 warn!("Mismatched trailer for Slot 0");
467 fails += 1;
468 }
469
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200470 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300471 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700472 warn!("Mismatched trailer for Slot 1");
473 fails += 1;
474 }
475
476 if Caps::SwapUpgrade.present() {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200477 if !verify_image(&flashmap, &self.slots, 1, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700478 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
479 fails += 1;
480 }
481 }
482 }
483
484 if fails > 0 {
485 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
486 fails as f32 * 100.0 / total_flash_ops as f32);
487 }
488
489 fails > 0
490 }
491
David Browna4167ef2017-11-06 14:30:05 -0700492 pub fn run_perm_with_random_fails_5(&self) -> bool {
493 self.run_perm_with_random_fails(5)
494 }
495
David Brownc49811e2017-11-06 14:20:45 -0700496 fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700497 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700498 let total_flash_ops = self.total_count.unwrap();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200499 let (flashmap, total_counts) = try_random_fails(&self.flashmap, &self,
500 total_flash_ops, total_fails);
David Brown5f7ec2b2017-11-06 13:54:02 -0700501 info!("Random interruptions at reset points={:?}", total_counts);
502
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200503 let slot0_ok = verify_image(&flashmap, &self.slots, 0, &self.upgrades);
David Brown5f7ec2b2017-11-06 13:54:02 -0700504 let slot1_ok = if Caps::SwapUpgrade.present() {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200505 verify_image(&flashmap, &self.slots, 1, &self.primaries)
David Brown5f7ec2b2017-11-06 13:54:02 -0700506 } else {
507 true
508 };
509 if !slot0_ok || !slot1_ok {
510 error!("Image mismatch after random interrupts: slot0={} slot1={}",
511 if slot0_ok { "ok" } else { "fail" },
512 if slot1_ok { "ok" } else { "fail" });
513 fails += 1;
514 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200515 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300516 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700517 error!("Mismatched trailer for Slot 0");
518 fails += 1;
519 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200520 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300521 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700522 error!("Mismatched trailer for Slot 1");
David Brown2639e072017-10-11 11:18:44 -0600523 fails += 1;
524 }
525
David Brown5f7ec2b2017-11-06 13:54:02 -0700526 if fails > 0 {
527 error!("Error testing perm upgrade with {} fails", total_fails);
528 }
529
530 fails > 0
531 }
532
533 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700534 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700535 false
536 }
537
538 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700539 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700540 let mut fails = 0;
541
542 if Caps::SwapUpgrade.present() {
David Brownc49811e2017-11-06 14:20:45 -0700543 for i in 1 .. (self.total_count.unwrap() - 1) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700544 info!("Try interruption at {}", i);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200545 if try_revert_with_fail_at(&self.flashmap, &self, i) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700546 error!("Revert failed at interruption {}", i);
547 fails += 1;
548 }
549 }
550 }
551
552 fails > 0
553 }
554
555 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700556 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700557 false
558 }
559
560 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700561 pub fn run_norevert(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200562 let mut flashmap = self.flashmap.clone();
David Brown5f7ec2b2017-11-06 13:54:02 -0700563 let mut fails = 0;
564
565 info!("Try norevert");
566
567 // First do a normal upgrade...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200568 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200569 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700570 warn!("Failed first boot");
571 fails += 1;
572 }
573
574 //FIXME: copy_done is written by boot_go, is it ok if no copy
575 // was ever done?
576
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200577 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700578 warn!("Slot 0 image verification FAIL");
579 fails += 1;
580 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200581 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300582 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600583 warn!("Mismatched trailer for Slot 0");
584 fails += 1;
585 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200586 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300587 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600588 warn!("Mismatched trailer for Slot 1");
589 fails += 1;
590 }
591
David Brown5f7ec2b2017-11-06 13:54:02 -0700592 // Marks image in slot0 as permanent, no revert should happen...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200593 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
David Brown5f7ec2b2017-11-06 13:54:02 -0700594
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200595 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300596 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700597 warn!("Mismatched trailer for Slot 0");
598 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600599 }
David Brown2639e072017-10-11 11:18:44 -0600600
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200601 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200602 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700603 warn!("Failed second boot");
604 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600605 }
David Brown5f7ec2b2017-11-06 13:54:02 -0700606
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200607 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300608 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700609 warn!("Mismatched trailer for Slot 0");
610 fails += 1;
611 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200612 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700613 warn!("Failed image verification");
614 fails += 1;
615 }
616
617 if fails > 0 {
618 error!("Error running upgrade without revert");
619 }
620
621 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600622 }
623
David Brown5f7ec2b2017-11-06 13:54:02 -0700624 // Tests a new image written to slot0 that already has magic and image_ok set
625 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700626 pub fn run_norevert_newimage(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200627 let mut flashmap = self.flashmap.clone();
David Brown5f7ec2b2017-11-06 13:54:02 -0700628 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600629
David Brown5f7ec2b2017-11-06 13:54:02 -0700630 info!("Try non-revert on imgtool generated image");
David Brown2639e072017-10-11 11:18:44 -0600631
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200632 mark_upgrade(&mut flashmap, &self.slots[0]);
David Brown2639e072017-10-11 11:18:44 -0600633
David Brown5f7ec2b2017-11-06 13:54:02 -0700634 // This simulates writing an image created by imgtool to Slot 0
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200635 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300636 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700637 warn!("Mismatched trailer for Slot 0");
638 fails += 1;
639 }
David Brown2639e072017-10-11 11:18:44 -0600640
David Brown5f7ec2b2017-11-06 13:54:02 -0700641 // Run the bootloader...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200642 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200643 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700644 warn!("Failed first boot");
645 fails += 1;
646 }
647
648 // State should not have changed
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200649 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700650 warn!("Failed image verification");
651 fails += 1;
652 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200653 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300654 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700655 warn!("Mismatched trailer for Slot 0");
656 fails += 1;
657 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200658 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300659 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700660 warn!("Mismatched trailer for Slot 1");
661 fails += 1;
662 }
663
664 if fails > 0 {
665 error!("Expected a non revert with new image");
666 }
667
668 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600669 }
670
David Brown5f7ec2b2017-11-06 13:54:02 -0700671 // Tests a new image written to slot0 that already has magic and image_ok set
672 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700673 pub fn run_signfail_upgrade(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200674 let mut flashmap = self.flashmap.clone();
David Brown5f7ec2b2017-11-06 13:54:02 -0700675 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600676
David Brown5f7ec2b2017-11-06 13:54:02 -0700677 info!("Try upgrade image with bad signature");
678
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200679 mark_upgrade(&mut flashmap, &self.slots[0]);
680 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
681 mark_upgrade(&mut flashmap, &self.slots[1]);
David Brown5f7ec2b2017-11-06 13:54:02 -0700682
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200683 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300684 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700685 warn!("Mismatched trailer for Slot 0");
686 fails += 1;
687 }
688
689 // Run the bootloader...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200690 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200691 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700692 warn!("Failed first boot");
693 fails += 1;
694 }
695
696 // State should not have changed
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200697 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700698 warn!("Failed image verification");
699 fails += 1;
700 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200701 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300702 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700703 warn!("Mismatched trailer for Slot 0");
704 fails += 1;
705 }
706
707 if fails > 0 {
708 error!("Expected an upgrade failure when image has bad signature");
709 }
710
711 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600712 }
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200713
Fabio Utziga91c6262017-12-06 09:01:12 -0200714 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300715 fn trailer_sz(&self, align: usize) -> usize {
716 c::boot_trailer_sz(align as u8) as usize
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200717 }
718
719 // FIXME: could get status sz from bootloader
Fabio Utziga91c6262017-12-06 09:01:12 -0200720 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300721 #[cfg(not(feature = "enc-rsa"))]
722 #[cfg(not(feature = "enc-kw"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300723 fn status_sz(&self, align: usize) -> usize {
724 self.trailer_sz(align) - (16 + 24)
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200725 }
726
Fabio Utzig1e48b912018-09-18 09:04:18 -0300727 #[cfg(feature = "enc-rsa")]
Fabio Utzig9b7a2582018-12-03 10:40:05 -0200728 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300729 fn status_sz(&self, align: usize) -> usize {
730 self.trailer_sz(align) - (16 + 24 + 32)
Fabio Utzig1e48b912018-09-18 09:04:18 -0300731 }
732
733 #[cfg(feature = "enc-kw")]
Fabio Utzig9b7a2582018-12-03 10:40:05 -0200734 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300735 fn status_sz(&self, align: usize) -> usize {
736 self.trailer_sz(align) - (16 + 24 + 32)
Fabio Utzig1e48b912018-09-18 09:04:18 -0300737 }
738
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200739 /// This test runs a simple upgrade with no fails in the images, but
740 /// allowing for fails in the status area. This should run to the end
741 /// and warn that write fails were detected...
742 #[cfg(not(feature = "validate-slot0"))]
743 pub fn run_with_status_fails_complete(&self) -> bool { false }
744
745 #[cfg(feature = "validate-slot0")]
746 pub fn run_with_status_fails_complete(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200747 let mut flashmap = self.flashmap.clone();
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200748 let mut fails = 0;
749
750 info!("Try swap with status fails");
751
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200752 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
753 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200754
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200755 let (result, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200756 if result != 0 {
757 warn!("Failed!");
758 fails += 1;
759 }
760
761 // Failed writes to the marked "bad" region don't assert anymore.
762 // Any detected assert() is happening in another part of the code.
763 if asserts != 0 {
764 warn!("At least one assert() was called");
765 fails += 1;
766 }
767
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200768 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300769 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200770 warn!("Mismatched trailer for Slot 0");
771 fails += 1;
772 }
773
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200774 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200775 warn!("Failed image verification");
776 fails += 1;
777 }
778
779 info!("validate slot0 enabled; re-run of boot_go should just work");
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200780 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200781 if result != 0 {
782 warn!("Failed!");
783 fails += 1;
784 }
785
786 if fails > 0 {
787 error!("Error running upgrade with status write fails");
788 }
789
790 fails > 0
791 }
792
793 /// This test runs a simple upgrade with no fails in the images, but
794 /// allowing for fails in the status area. This should run to the end
795 /// and warn that write fails were detected...
796 #[cfg(feature = "validate-slot0")]
797 pub fn run_with_status_fails_with_reset(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200798 let mut flashmap = self.flashmap.clone();
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200799 let mut fails = 0;
800 let mut count = self.total_count.unwrap() / 2;
801
802 //info!("count={}\n", count);
803
804 info!("Try interrupted swap with status fails");
805
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200806 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
807 self.mark_bad_status_with_rate(&mut flashmap, 0, 0.5);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200808
809 // Should not fail, writing to bad regions does not assert
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200810 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, Some(&mut count), true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200811 if asserts != 0 {
812 warn!("At least one assert() was called");
813 fails += 1;
814 }
815
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200816 self.reset_bad_status(&mut flashmap, 0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200817
818 info!("Resuming an interrupted swap operation");
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200819 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200820
821 // This might throw no asserts, for large sector devices, where
822 // a single failure writing is indistinguishable from no failure,
823 // or throw a single assert for small sector devices that fail
824 // multiple times...
825 if asserts > 1 {
826 warn!("Expected single assert validating slot0, more detected {}", asserts);
827 fails += 1;
828 }
829
830 if fails > 0 {
831 error!("Error running upgrade with status write fails");
832 }
833
834 fails > 0
835 }
836
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200837 /// Adds a new flash area that fails statistically
838 #[cfg(not(feature = "overwrite-only"))]
839 fn mark_bad_status_with_rate(&self, flashmap: &mut SimFlashMap, slot: usize,
840 rate: f32) {
841 let dev_id = &self.slots[slot].dev_id;
842 let flash = flashmap.get_mut(&dev_id).unwrap();
843 let align = flash.align();
844 let off = &self.slots[0].base_off;
845 let len = &self.slots[0].len;
846 let status_off = off + len - self.trailer_sz(align);
847
848 // Mark the status area as a bad area
849 let _ = flash.add_bad_region(status_off, self.status_sz(align), rate);
850 }
851
852 #[cfg(feature = "validate-slot0")]
853 fn reset_bad_status(&self, flashmap: &mut SimFlashMap, slot: usize) {
854 let dev_id = &self.slots[slot].dev_id;
855 let flash = flashmap.get_mut(&dev_id).unwrap();
856 flash.reset_bad_regions();
857
858 // Disabling write verification the only assert triggered by
859 // boot_go should be checking for integrity of status bytes.
860 flash.set_verify_writes(false);
861 }
862
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200863 #[cfg(not(feature = "validate-slot0"))]
864 #[cfg(not(feature = "overwrite-only"))]
865 pub fn run_with_status_fails_with_reset(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200866 let mut flashmap = self.flashmap.clone();
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200867 let mut fails = 0;
868
869 info!("Try interrupted swap with status fails");
870
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200871 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
872 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200873
874 // This is expected to fail while writing to bad regions...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200875 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200876 if asserts == 0 {
877 warn!("No assert() detected");
878 fails += 1;
879 }
880
881 fails > 0
882 }
883
884 #[cfg(feature = "overwrite-only")]
885 pub fn run_with_status_fails_with_reset(&self) -> bool {
886 false
887 }
David Brown2639e072017-10-11 11:18:44 -0600888}
889
890/// Test a boot, optionally stopping after 'n' flash options. Returns a count
891/// of the number of flash operations done total.
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200892fn try_upgrade(flashmap: &SimFlashMap, images: &Images,
893 stop: Option<i32>) -> (SimFlashMap, i32) {
David Brown2639e072017-10-11 11:18:44 -0600894 // Clone the flash to have a new copy.
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200895 let mut flashmap = flashmap.clone();
David Brown2639e072017-10-11 11:18:44 -0600896
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200897 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
David Brown2639e072017-10-11 11:18:44 -0600898
David Brownee61c832017-11-06 11:13:25 -0700899 let mut counter = stop.unwrap_or(0);
900
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200901 let (first_interrupted, count) = match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200902 (-0x13579, _) => (true, stop.unwrap()),
903 (0, _) => (false, -counter),
904 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600905 };
David Brown2639e072017-10-11 11:18:44 -0600906
David Brownee61c832017-11-06 11:13:25 -0700907 counter = 0;
David Brown2639e072017-10-11 11:18:44 -0600908 if first_interrupted {
909 // fl.dump();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200910 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200911 (-0x13579, _) => panic!("Shouldn't stop again"),
912 (0, _) => (),
913 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600914 }
915 }
916
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200917 (flashmap, count - counter)
David Brown2639e072017-10-11 11:18:44 -0600918}
919
920#[cfg(not(feature = "overwrite-only"))]
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200921fn try_revert(flashmap: &SimFlashMap, areadesc: &AreaDesc, count: usize) -> SimFlashMap {
922 let mut flashmap = flashmap.clone();
David Brown2639e072017-10-11 11:18:44 -0600923
924 // fl.write_file("image0.bin").unwrap();
925 for i in 0 .. count {
926 info!("Running boot pass {}", i + 1);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200927 assert_eq!(c::boot_go(&mut flashmap, &areadesc, None, false), (0, 0));
David Brown2639e072017-10-11 11:18:44 -0600928 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200929 flashmap
David Brown2639e072017-10-11 11:18:44 -0600930}
931
932#[cfg(not(feature = "overwrite-only"))]
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200933fn try_revert_with_fail_at(flashmap: &SimFlashMap, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600934 stop: i32) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200935 let mut flashmap = flashmap.clone();
David Brown2639e072017-10-11 11:18:44 -0600936 let mut fails = 0;
937
David Brownee61c832017-11-06 11:13:25 -0700938 let mut counter = stop;
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200939 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false);
David Brown2639e072017-10-11 11:18:44 -0600940 if x != -0x13579 {
941 warn!("Should have stopped at interruption point");
942 fails += 1;
943 }
944
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200945 if !verify_trailer(&flashmap, &images.slots, 0, None, None, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600946 warn!("copy_done should be unset");
947 fails += 1;
948 }
949
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200950 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
David Brown2639e072017-10-11 11:18:44 -0600951 if x != 0 {
952 warn!("Should have finished upgrade");
953 fails += 1;
954 }
955
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200956 if !verify_image(&flashmap, &images.slots, 0, &images.upgrades) {
David Brown2639e072017-10-11 11:18:44 -0600957 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
958 fails += 1;
959 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200960 if !verify_image(&flashmap, &images.slots, 1, &images.primaries) {
David Brown2639e072017-10-11 11:18:44 -0600961 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
962 fails += 1;
963 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200964 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300965 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600966 warn!("Mismatched trailer for Slot 0 before revert");
967 fails += 1;
968 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200969 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300970 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600971 warn!("Mismatched trailer for Slot 1 before revert");
972 fails += 1;
973 }
974
975 // Do Revert
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200976 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
David Brown2639e072017-10-11 11:18:44 -0600977 if x != 0 {
978 warn!("Should have finished a revert");
979 fails += 1;
980 }
981
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200982 if !verify_image(&flashmap, &images.slots, 0, &images.primaries) {
David Brown2639e072017-10-11 11:18:44 -0600983 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
984 fails += 1;
985 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200986 if !verify_image(&flashmap, &images.slots, 1, &images.upgrades) {
David Brown2639e072017-10-11 11:18:44 -0600987 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
988 fails += 1;
989 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200990 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300991 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600992 warn!("Mismatched trailer for Slot 1 after revert");
993 fails += 1;
994 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200995 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300996 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600997 warn!("Mismatched trailer for Slot 1 after revert");
998 fails += 1;
999 }
1000
1001 fails > 0
1002}
1003
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001004fn try_random_fails(flashmap: &SimFlashMap, images: &Images,
1005 total_ops: i32, count: usize) -> (SimFlashMap, Vec<i32>) {
1006 let mut flashmap = flashmap.clone();
David Brown2639e072017-10-11 11:18:44 -06001007
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001008 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
David Brown2639e072017-10-11 11:18:44 -06001009
1010 let mut rng = rand::thread_rng();
1011 let mut resets = vec![0i32; count];
1012 let mut remaining_ops = total_ops;
1013 for i in 0 .. count {
1014 let ops = Range::new(1, remaining_ops / 2);
1015 let reset_counter = ops.ind_sample(&mut rng);
David Brownee61c832017-11-06 11:13:25 -07001016 let mut counter = reset_counter;
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001017 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -02001018 (0, _) | (-0x13579, _) => (),
1019 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -06001020 }
1021 remaining_ops -= reset_counter;
1022 resets[i] = reset_counter;
1023 }
1024
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001025 match c::boot_go(&mut flashmap, &images.areadesc, None, false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -02001026 (-0x13579, _) => panic!("Should not be have been interrupted!"),
1027 (0, _) => (),
1028 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -06001029 }
1030
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001031 (flashmap, resets)
David Brown2639e072017-10-11 11:18:44 -06001032}
1033
1034/// Show the flash layout.
1035#[allow(dead_code)]
1036fn show_flash(flash: &Flash) {
1037 println!("---- Flash configuration ----");
1038 for sector in flash.sector_iter() {
1039 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1040 sector.num, sector.base, sector.size);
1041 }
1042 println!("");
1043}
1044
1045/// Install a "program" into the given image. This fakes the image header, or at least all of the
1046/// fields used by the given code. Returns a copy of the image that was written.
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001047fn install_image(flashmap: &mut SimFlashMap, slots: &[SlotInfo], slot: usize, len: usize,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001048 bad_sig: bool) -> [Option<Vec<u8>>; 2] {
1049 let offset = slots[slot].base_off;
1050 let slot_len = slots[slot].len;
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001051 let dev_id = slots[slot].dev_id;
David Brown2639e072017-10-11 11:18:44 -06001052
1053 let mut tlv = make_tlv();
1054
Fabio Utzige5831f62018-12-14 06:46:22 -02001055 const HDR_SIZE: usize = 32;
1056
David Brown2639e072017-10-11 11:18:44 -06001057 // Generate a boot header. Note that the size doesn't include the header.
1058 let header = ImageHeader {
1059 magic: 0x96f3b83d,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001060 load_addr: 0,
Fabio Utzige5831f62018-12-14 06:46:22 -02001061 hdr_size: HDR_SIZE as u16,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001062 _pad1: 0,
David Brown2639e072017-10-11 11:18:44 -06001063 img_size: len as u32,
1064 flags: tlv.get_flags(),
1065 ver: ImageVersion {
1066 major: (offset / (128 * 1024)) as u8,
1067 minor: 0,
1068 revision: 1,
1069 build_num: offset as u32,
1070 },
Fabio Utzig1e48b912018-09-18 09:04:18 -03001071 _pad2: 0,
David Brown2639e072017-10-11 11:18:44 -06001072 };
1073
Fabio Utzige5831f62018-12-14 06:46:22 -02001074 let mut b_header = [0; HDR_SIZE];
1075 b_header[..32].clone_from_slice(header.as_raw());
1076 assert_eq!(b_header.len(), HDR_SIZE);
1077
David Brown2639e072017-10-11 11:18:44 -06001078 tlv.add_bytes(&b_header);
David Brown2639e072017-10-11 11:18:44 -06001079
1080 // The core of the image itself is just pseudorandom data.
Fabio Utzig1e48b912018-09-18 09:04:18 -03001081 let mut b_img = vec![0; len];
1082 splat(&mut b_img, offset);
David Brown2639e072017-10-11 11:18:44 -06001083
Fabio Utzig1e48b912018-09-18 09:04:18 -03001084 // TLV signatures work over plain image
1085 tlv.add_bytes(&b_img);
1086
1087 // Generate encrypted images
1088 let flag = TlvFlags::ENCRYPTED as u32;
1089 let is_encrypted = (tlv.get_flags() & flag) == flag;
1090 let mut b_encimg = vec![];
1091 if is_encrypted {
1092 let key = GenericArray::from_slice(AES_SEC_KEY);
1093 let nonce = GenericArray::from_slice(&[0; 16]);
1094 let mut cipher = Aes128Ctr::new(&key, &nonce);
1095 b_encimg = b_img.clone();
1096 cipher.apply_keystream(&mut b_encimg);
David Brown2639e072017-10-11 11:18:44 -06001097 }
1098
Fabio Utzig1e48b912018-09-18 09:04:18 -03001099 // Build the TLV itself.
1100 let mut b_tlv = if bad_sig {
1101 let good_sig = &mut tlv.make_tlv();
1102 vec![0; good_sig.len()]
1103 } else {
1104 tlv.make_tlv()
1105 };
1106
David Brown2639e072017-10-11 11:18:44 -06001107 // Pad the block to a flash alignment (8 bytes).
Fabio Utzig1e48b912018-09-18 09:04:18 -03001108 while b_tlv.len() % 8 != 0 {
1109 //FIXME: should be erase_val?
1110 b_tlv.push(0xFF);
David Brown2639e072017-10-11 11:18:44 -06001111 }
1112
Fabio Utzig1e48b912018-09-18 09:04:18 -03001113 let mut buf = vec![];
1114 buf.append(&mut b_header.to_vec());
1115 buf.append(&mut b_img);
1116 buf.append(&mut b_tlv.clone());
David Brown2639e072017-10-11 11:18:44 -06001117
Fabio Utzig1e48b912018-09-18 09:04:18 -03001118 let mut encbuf = vec![];
1119 if is_encrypted {
1120 encbuf.append(&mut b_header.to_vec());
1121 encbuf.append(&mut b_encimg);
1122 encbuf.append(&mut b_tlv);
1123 }
David Brown2639e072017-10-11 11:18:44 -06001124
Fabio Utzig1e48b912018-09-18 09:04:18 -03001125 let result: [Option<Vec<u8>>; 2];
1126
1127 // Since images are always non-encrypted in slot0, we first write an
1128 // encrypted image, re-read to use for verification, erase + flash
1129 // un-encrypted. In slot1 the image is written un-encrypted, and if
1130 // encryption is requested, it follows an erase + flash encrypted.
1131
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001132 let flash = flashmap.get_mut(&dev_id).unwrap();
1133
Fabio Utzig1e48b912018-09-18 09:04:18 -03001134 if slot == 0 {
1135 let enc_copy: Option<Vec<u8>>;
1136
1137 if is_encrypted {
1138 flash.write(offset, &encbuf).unwrap();
1139
1140 let mut enc = vec![0u8; encbuf.len()];
1141 flash.read(offset, &mut enc).unwrap();
1142
1143 enc_copy = Some(enc);
1144
1145 flash.erase(offset, slot_len).unwrap();
1146 } else {
1147 enc_copy = None;
1148 }
1149
1150 flash.write(offset, &buf).unwrap();
1151
1152 let mut copy = vec![0u8; buf.len()];
1153 flash.read(offset, &mut copy).unwrap();
1154
1155 result = [Some(copy), enc_copy];
1156 } else {
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001157
Fabio Utzig1e48b912018-09-18 09:04:18 -03001158 flash.write(offset, &buf).unwrap();
1159
1160 let mut copy = vec![0u8; buf.len()];
1161 flash.read(offset, &mut copy).unwrap();
1162
1163 let enc_copy: Option<Vec<u8>>;
1164
1165 if is_encrypted {
1166 flash.erase(offset, slot_len).unwrap();
1167
1168 flash.write(offset, &encbuf).unwrap();
1169
1170 let mut enc = vec![0u8; encbuf.len()];
1171 flash.read(offset, &mut enc).unwrap();
1172
1173 enc_copy = Some(enc);
1174 } else {
1175 enc_copy = None;
1176 }
1177
1178 result = [Some(copy), enc_copy];
1179 }
1180
1181 result
David Brown2639e072017-10-11 11:18:44 -06001182}
1183
1184// The TLV in use depends on what kind of signature we are verifying.
1185#[cfg(feature = "sig-rsa")]
Fabio Utzig251ef1d2018-12-18 17:20:19 -02001186#[cfg(feature = "enc-kw")]
1187fn make_tlv() -> TlvGen {
1188 TlvGen::new_rsa_kw()
1189}
1190
1191#[cfg(feature = "sig-rsa")]
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001192#[cfg(not(feature = "enc-rsa"))]
Fabio Utzig251ef1d2018-12-18 17:20:19 -02001193#[cfg(not(feature = "enc-kw"))]
David Brown2639e072017-10-11 11:18:44 -06001194fn make_tlv() -> TlvGen {
1195 TlvGen::new_rsa_pss()
1196}
1197
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001198#[cfg(feature = "sig-ecdsa")]
Fabio Utzigb4d20c82018-12-27 16:08:39 -02001199#[cfg(feature = "enc-kw")]
1200fn make_tlv() -> TlvGen {
1201 TlvGen::new_ecdsa_kw()
1202}
1203
1204#[cfg(feature = "sig-ecdsa")]
1205#[cfg(not(feature = "enc-kw"))]
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001206fn make_tlv() -> TlvGen {
1207 TlvGen::new_ecdsa()
1208}
1209
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001210#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001211#[cfg(feature = "enc-rsa")]
1212fn make_tlv() -> TlvGen {
1213 TlvGen::new_enc_rsa()
1214}
1215
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001216#[cfg(feature = "sig-rsa")]
1217#[cfg(feature = "enc-rsa")]
1218fn make_tlv() -> TlvGen {
1219 TlvGen::new_sig_enc_rsa()
1220}
1221
Fabio Utzig251ef1d2018-12-18 17:20:19 -02001222#[cfg(not(feature = "sig-rsa"))]
Fabio Utzigb4d20c82018-12-27 16:08:39 -02001223#[cfg(not(feature = "sig-ecdsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001224#[cfg(feature = "enc-kw")]
1225fn make_tlv() -> TlvGen {
1226 TlvGen::new_enc_kw()
1227}
1228
David Brown2639e072017-10-11 11:18:44 -06001229#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001230#[cfg(not(feature = "sig-ecdsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001231#[cfg(not(feature = "enc-rsa"))]
1232#[cfg(not(feature = "enc-kw"))]
David Brown2639e072017-10-11 11:18:44 -06001233fn make_tlv() -> TlvGen {
1234 TlvGen::new_hash_only()
1235}
1236
Fabio Utzig1e48b912018-09-18 09:04:18 -03001237#[cfg(feature = "enc-rsa")]
1238fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
1239 match &images[slot] {
1240 Some(image) => return image,
1241 None => panic!("Invalid image"),
1242 }
1243}
1244
1245#[cfg(feature = "enc-kw")]
1246fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
1247 match &images[slot] {
1248 Some(image) => return image,
1249 None => panic!("Invalid image"),
1250 }
1251}
1252
1253#[cfg(not(feature = "enc-rsa"))]
1254#[cfg(not(feature = "enc-kw"))]
1255fn find_image(images: &[Option<Vec<u8>>; 2], _slot: usize) -> &Vec<u8> {
1256 match &images[0] {
1257 Some(image) => return image,
1258 None => panic!("Invalid image"),
1259 }
1260}
1261
David Brown2639e072017-10-11 11:18:44 -06001262/// Verify that given image is present in the flash at the given offset.
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001263fn verify_image(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001264 images: &[Option<Vec<u8>>; 2]) -> bool {
1265 let image = find_image(images, slot);
1266 let buf = image.as_slice();
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001267 let dev_id = slots[slot].dev_id;
Fabio Utzig1e48b912018-09-18 09:04:18 -03001268
David Brown2639e072017-10-11 11:18:44 -06001269 let mut copy = vec![0u8; buf.len()];
Fabio Utzig1e48b912018-09-18 09:04:18 -03001270 let offset = slots[slot].base_off;
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001271 let flash = flashmap.get(&dev_id).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001272 flash.read(offset, &mut copy).unwrap();
1273
1274 if buf != &copy[..] {
1275 for i in 0 .. buf.len() {
1276 if buf[i] != copy[i] {
Fabio Utzig1e48b912018-09-18 09:04:18 -03001277 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1278 slot, offset + i, buf[i], copy[i]);
David Brown2639e072017-10-11 11:18:44 -06001279 break;
1280 }
1281 }
1282 false
1283 } else {
1284 true
1285 }
1286}
1287
1288#[cfg(feature = "overwrite-only")]
1289#[allow(unused_variables)]
1290// overwrite-only doesn't employ trailer management
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001291fn verify_trailer(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001292 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001293 copy_done: Option<u8>) -> bool {
1294 true
1295}
1296
1297#[cfg(not(feature = "overwrite-only"))]
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001298fn verify_trailer(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001299 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001300 copy_done: Option<u8>) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001301 let offset = slots[slot].trailer_off;
1302 let dev_id = slots[slot].dev_id;
David Brown2639e072017-10-11 11:18:44 -06001303 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1304 let mut failed = false;
1305
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001306 let flash = flashmap.get(&dev_id).unwrap();
1307 let erased_val = flash.erased_val();
David Brown2639e072017-10-11 11:18:44 -06001308 flash.read(offset, &mut copy).unwrap();
1309
1310 failed |= match magic {
1311 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001312 if v == 1 && &copy[16..] != MAGIC.unwrap() {
David Brown2639e072017-10-11 11:18:44 -06001313 warn!("\"magic\" mismatch at {:#x}", offset);
1314 true
Fabio Utzigea0290b2018-08-09 14:23:01 -03001315 } else if v == 3 {
1316 let expected = [erased_val; 16];
1317 if &copy[16..] != expected {
1318 warn!("\"magic\" mismatch at {:#x}", offset);
1319 true
1320 } else {
1321 false
1322 }
David Brown2639e072017-10-11 11:18:44 -06001323 } else {
1324 false
1325 }
1326 },
1327 None => false,
1328 };
1329
1330 failed |= match image_ok {
1331 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001332 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1333 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
David Brown2639e072017-10-11 11:18:44 -06001334 true
1335 } else {
1336 false
1337 }
1338 },
1339 None => false,
1340 };
1341
1342 failed |= match copy_done {
1343 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001344 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1345 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
David Brown2639e072017-10-11 11:18:44 -06001346 true
1347 } else {
1348 false
1349 }
1350 },
1351 None => false,
1352 };
1353
1354 !failed
1355}
1356
1357/// The image header
1358#[repr(C)]
1359pub struct ImageHeader {
1360 magic: u32,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001361 load_addr: u32,
David Brown2639e072017-10-11 11:18:44 -06001362 hdr_size: u16,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001363 _pad1: u16,
David Brown2639e072017-10-11 11:18:44 -06001364 img_size: u32,
1365 flags: u32,
1366 ver: ImageVersion,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001367 _pad2: u32,
David Brown2639e072017-10-11 11:18:44 -06001368}
1369
1370impl AsRaw for ImageHeader {}
1371
1372#[repr(C)]
1373pub struct ImageVersion {
1374 major: u8,
1375 minor: u8,
1376 revision: u16,
1377 build_num: u32,
1378}
1379
David Brownd5e632c2017-10-19 10:49:46 -06001380#[derive(Clone)]
David Brown2639e072017-10-11 11:18:44 -06001381struct SlotInfo {
1382 base_off: usize,
1383 trailer_off: usize,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001384 len: usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001385 dev_id: u8,
David Brown2639e072017-10-11 11:18:44 -06001386}
1387
David Brownf48b9502017-11-06 14:00:26 -07001388pub struct Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001389 flashmap: SimFlashMap,
David Brown3f687dc2017-11-06 13:41:18 -07001390 areadesc: AreaDesc,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001391 slots: [SlotInfo; 2],
1392 primaries: [Option<Vec<u8>>; 2],
1393 upgrades: [Option<Vec<u8>>; 2],
David Brownc49811e2017-11-06 14:20:45 -07001394 total_count: Option<i32>,
David Brown2639e072017-10-11 11:18:44 -06001395}
1396
Fabio Utzigea0290b2018-08-09 14:23:01 -03001397const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1398 0x60, 0xd2, 0xef, 0x7f,
1399 0x35, 0x52, 0x50, 0x0f,
1400 0x2c, 0xb6, 0x79, 0x80]);
David Brown2639e072017-10-11 11:18:44 -06001401
Fabio Utzigea0290b2018-08-09 14:23:01 -03001402// Replicates defines found in bootutil.h
1403const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1404const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1405
1406const BOOT_FLAG_SET: Option<u8> = Some(1);
1407const BOOT_FLAG_UNSET: Option<u8> = Some(3);
David Brown2639e072017-10-11 11:18:44 -06001408
1409/// Write out the magic so that the loader tries doing an upgrade.
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001410fn mark_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
1411 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001412 let offset = slot.trailer_off + c::boot_max_align() * 2;
Fabio Utzigea0290b2018-08-09 14:23:01 -03001413 flash.write(offset, MAGIC.unwrap()).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001414}
1415
1416/// Writes the image_ok flag which, guess what, tells the bootloader
1417/// the this image is ok (not a test, and no revert is to be performed).
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001418fn mark_permanent_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
1419 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
Fabio Utzig269d2862018-10-24 17:45:38 -03001420 let mut ok = [flash.erased_val(); 8];
Fabio Utzigea0290b2018-08-09 14:23:01 -03001421 ok[0] = 1u8;
David Brown2639e072017-10-11 11:18:44 -06001422 let off = slot.trailer_off + c::boot_max_align();
Fabio Utzig269d2862018-10-24 17:45:38 -03001423 let align = flash.align();
1424 flash.write(off, &ok[..align]).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001425}
1426
1427// Drop some pseudo-random gibberish onto the data.
1428fn splat(data: &mut [u8], seed: usize) {
1429 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1430 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1431 rng.fill_bytes(data);
1432}
1433
1434/// Return a read-only view into the raw bytes of this object
1435trait AsRaw : Sized {
1436 fn as_raw<'a>(&'a self) -> &'a [u8] {
1437 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1438 mem::size_of::<Self>()) }
1439 }
1440}
1441
1442fn show_sizes() {
1443 // This isn't panic safe.
David Brown2639e072017-10-11 11:18:44 -06001444 for min in &[1, 2, 4, 8] {
David Brown541860c2017-11-06 11:25:42 -07001445 let msize = c::boot_trailer_sz(*min);
David Brown2639e072017-10-11 11:18:44 -06001446 println!("{:2}: {} (0x{:x})", min, msize, msize);
1447 }
David Brown2639e072017-10-11 11:18:44 -06001448}