blob: e04f06f586fa8e44630422181c77df8667fa0444 [file] [log] [blame]
David Brown2639e072017-10-11 11:18:44 -06001use docopt::Docopt;
David Brown10b5de12019-01-02 16:10:01 -07002use log::{info, warn, error};
3use rand::{
4 distributions::{IndependentSample, Range},
5 Rng, SeedableRng, XorShiftRng,
6};
7use std::{
8 fmt,
9 mem,
10 process,
11 slice,
12};
13use aes_ctr::{
14 Aes128Ctr,
15 stream_cipher::{
16 generic_array::GenericArray,
17 NewFixStreamCipher,
18 StreamCipherCore,
19 },
20};
21use serde_derive::Deserialize;
David Brown2639e072017-10-11 11:18:44 -060022
23mod caps;
24mod tlv;
David Brownca7b5d32017-11-03 08:37:38 -060025pub mod testlog;
David Brown2639e072017-10-11 11:18:44 -060026
Fabio Utzigafb2bc92018-11-19 16:11:52 -020027use simflash::{Flash, SimFlash, SimFlashMap};
David Brown2639e072017-10-11 11:18:44 -060028use mcuboot_sys::{c, AreaDesc, FlashId};
David Brown29b0b5e2019-01-02 16:04:16 -070029use crate::caps::Caps;
30use crate::tlv::{TlvGen, TlvFlags, AES_SEC_KEY};
David Brown2639e072017-10-11 11:18:44 -060031
32const USAGE: &'static str = "
33Mcuboot simulator
34
35Usage:
36 bootsim sizes
37 bootsim run --device TYPE [--align SIZE]
38 bootsim runall
39 bootsim (--help | --version)
40
41Options:
42 -h, --help Show this message
43 --version Version
44 --device TYPE MCU to simulate
45 Valid values: stm32f4, k64f
46 --align SIZE Flash write alignment
47";
48
49#[derive(Debug, Deserialize)]
50struct Args {
51 flag_help: bool,
52 flag_version: bool,
53 flag_device: Option<DeviceName>,
54 flag_align: Option<AlignArg>,
55 cmd_sizes: bool,
56 cmd_run: bool,
57 cmd_runall: bool,
58}
59
60#[derive(Copy, Clone, Debug, Deserialize)]
Fabio Utzigafb2bc92018-11-19 16:11:52 -020061pub enum DeviceName { Stm32f4, K64f, K64fBig, Nrf52840, Nrf52840SpiFlash, }
David Brown2639e072017-10-11 11:18:44 -060062
David Browndd2b1182017-11-02 15:39:21 -060063pub static ALL_DEVICES: &'static [DeviceName] = &[
David Brown2639e072017-10-11 11:18:44 -060064 DeviceName::Stm32f4,
65 DeviceName::K64f,
66 DeviceName::K64fBig,
67 DeviceName::Nrf52840,
Fabio Utzigafb2bc92018-11-19 16:11:52 -020068 DeviceName::Nrf52840SpiFlash,
David Brown2639e072017-10-11 11:18:44 -060069];
70
71impl fmt::Display for DeviceName {
David Brown10b5de12019-01-02 16:10:01 -070072 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
David Brown2639e072017-10-11 11:18:44 -060073 let name = match *self {
74 DeviceName::Stm32f4 => "stm32f4",
75 DeviceName::K64f => "k64f",
76 DeviceName::K64fBig => "k64fbig",
77 DeviceName::Nrf52840 => "nrf52840",
Fabio Utzigafb2bc92018-11-19 16:11:52 -020078 DeviceName::Nrf52840SpiFlash => "Nrf52840SpiFlash",
David Brown2639e072017-10-11 11:18:44 -060079 };
80 f.write_str(name)
81 }
82}
83
84#[derive(Debug)]
85struct AlignArg(u8);
86
87struct AlignArgVisitor;
88
89impl<'de> serde::de::Visitor<'de> for AlignArgVisitor {
90 type Value = AlignArg;
91
David Brown10b5de12019-01-02 16:10:01 -070092 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
David Brown2639e072017-10-11 11:18:44 -060093 formatter.write_str("1, 2, 4 or 8")
94 }
95
96 fn visit_u8<E>(self, n: u8) -> Result<Self::Value, E>
97 where E: serde::de::Error
98 {
99 Ok(match n {
100 1 | 2 | 4 | 8 => AlignArg(n),
101 n => {
102 let err = format!("Could not deserialize '{}' as alignment", n);
103 return Err(E::custom(err));
104 }
105 })
106 }
107}
108
109impl<'de> serde::de::Deserialize<'de> for AlignArg {
110 fn deserialize<D>(d: D) -> Result<AlignArg, D::Error>
111 where D: serde::de::Deserializer<'de>
112 {
113 d.deserialize_u8(AlignArgVisitor)
114 }
115}
116
117pub fn main() {
118 let args: Args = Docopt::new(USAGE)
119 .and_then(|d| d.deserialize())
120 .unwrap_or_else(|e| e.exit());
121 // println!("args: {:#?}", args);
122
123 if args.cmd_sizes {
124 show_sizes();
125 return;
126 }
127
128 let mut status = RunStatus::new();
129 if args.cmd_run {
130
131 let align = args.flag_align.map(|x| x.0).unwrap_or(1);
132
133
134 let device = match args.flag_device {
135 None => panic!("Missing mandatory device argument"),
136 Some(dev) => dev,
137 };
138
Fabio Utzigea0290b2018-08-09 14:23:01 -0300139 status.run_single(device, align, 0xff);
David Brown2639e072017-10-11 11:18:44 -0600140 }
141
142 if args.cmd_runall {
143 for &dev in ALL_DEVICES {
144 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300145 for &erased_val in &[0, 0xff] {
146 status.run_single(dev, align, erased_val);
147 }
David Brown2639e072017-10-11 11:18:44 -0600148 }
149 }
150 }
151
152 if status.failures > 0 {
153 error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
154 process::exit(1);
155 } else {
156 error!("{} Tests ran successfully", status.passes);
157 process::exit(0);
158 }
159}
160
David Browndb9a3952017-11-06 13:16:15 -0700161/// A test run, intended to be run from "cargo test", so panics on failure.
162pub struct Run {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200163 flashmap: SimFlashMap,
David Browndb9a3952017-11-06 13:16:15 -0700164 areadesc: AreaDesc,
165 slots: [SlotInfo; 2],
David Browndb9a3952017-11-06 13:16:15 -0700166}
167
168impl Run {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300169 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Run {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200170 let (flashmap, areadesc) = make_device(device, align, erased_val);
David Browndb9a3952017-11-06 13:16:15 -0700171
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200172 let (slot0_base, slot0_len, slot0_dev_id) = areadesc.find(FlashId::Image0);
173 let (slot1_base, slot1_len, slot1_dev_id) = areadesc.find(FlashId::Image1);
David Browndb9a3952017-11-06 13:16:15 -0700174
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200175 // NOTE: not accounting "swap_size" because it is not used by sim...
David Browndb9a3952017-11-06 13:16:15 -0700176 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
177
178 // Construct a primary image.
179 let slot0 = SlotInfo {
180 base_off: slot0_base as usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200181 trailer_off: slot0_base + slot0_len - offset_from_end,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300182 len: slot0_len as usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200183 dev_id: slot0_dev_id,
David Browndb9a3952017-11-06 13:16:15 -0700184 };
185
186 // And an upgrade image.
187 let slot1 = SlotInfo {
188 base_off: slot1_base as usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200189 trailer_off: slot1_base + slot1_len - offset_from_end,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300190 len: slot1_len as usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200191 dev_id: slot1_dev_id,
David Browndb9a3952017-11-06 13:16:15 -0700192 };
193
194 Run {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200195 flashmap: flashmap,
David Browndb9a3952017-11-06 13:16:15 -0700196 areadesc: areadesc,
197 slots: [slot0, slot1],
David Browndb9a3952017-11-06 13:16:15 -0700198 }
199 }
200
201 pub fn each_device<F>(f: F)
202 where F: Fn(&mut Run)
203 {
204 for &dev in ALL_DEVICES {
205 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300206 for &erased_val in &[0, 0xff] {
207 let mut run = Run::new(dev, align, erased_val);
208 f(&mut run);
209 }
David Browndb9a3952017-11-06 13:16:15 -0700210 }
211 }
212 }
David Brownf48b9502017-11-06 14:00:26 -0700213
214 /// Construct an `Images` that doesn't expect an upgrade to happen.
215 pub fn make_no_upgrade_image(&self) -> Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200216 let mut flashmap = self.flashmap.clone();
217 let primaries = install_image(&mut flashmap, &self.slots, 0, 32784, false);
218 let upgrades = install_image(&mut flashmap, &self.slots, 1, 41928, false);
David Brownf48b9502017-11-06 14:00:26 -0700219 Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200220 flashmap: flashmap,
David Brownf48b9502017-11-06 14:00:26 -0700221 areadesc: self.areadesc.clone(),
Fabio Utzig1e48b912018-09-18 09:04:18 -0300222 slots: [self.slots[0].clone(), self.slots[1].clone()],
223 primaries: primaries,
224 upgrades: upgrades,
David Brownc49811e2017-11-06 14:20:45 -0700225 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700226 }
227 }
228
229 /// Construct an `Images` for normal testing.
230 pub fn make_image(&self) -> Images {
231 let mut images = self.make_no_upgrade_image();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200232 mark_upgrade(&mut images.flashmap, &images.slots[1]);
David Brownc49811e2017-11-06 14:20:45 -0700233
234 // upgrades without fails, counts number of flash operations
235 let total_count = match images.run_basic_upgrade() {
236 Ok(v) => v,
237 Err(_) => {
238 panic!("Unable to perform basic upgrade");
239 },
240 };
241
242 images.total_count = Some(total_count);
David Brownf48b9502017-11-06 14:00:26 -0700243 images
244 }
245
246 pub fn make_bad_slot1_image(&self) -> Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200247 let mut bad_flashmap = self.flashmap.clone();
248 let primaries = install_image(&mut bad_flashmap, &self.slots, 0, 32784, false);
249 let upgrades = install_image(&mut bad_flashmap, &self.slots, 1, 41928, true);
David Brownf48b9502017-11-06 14:00:26 -0700250 Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200251 flashmap: bad_flashmap,
David Brownf48b9502017-11-06 14:00:26 -0700252 areadesc: self.areadesc.clone(),
Fabio Utzig1e48b912018-09-18 09:04:18 -0300253 slots: [self.slots[0].clone(), self.slots[1].clone()],
254 primaries: primaries,
255 upgrades: upgrades,
David Brownc49811e2017-11-06 14:20:45 -0700256 total_count: None,
David Brownf48b9502017-11-06 14:00:26 -0700257 }
258 }
David Brownc49811e2017-11-06 14:20:45 -0700259
David Browndb9a3952017-11-06 13:16:15 -0700260}
261
David Browndd2b1182017-11-02 15:39:21 -0600262pub struct RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600263 failures: usize,
264 passes: usize,
265}
266
267impl RunStatus {
David Browndd2b1182017-11-02 15:39:21 -0600268 pub fn new() -> RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600269 RunStatus {
270 failures: 0,
271 passes: 0,
272 }
273 }
274
Fabio Utzigea0290b2018-08-09 14:23:01 -0300275 pub fn run_single(&mut self, device: DeviceName, align: u8, erased_val: u8) {
David Brown2639e072017-10-11 11:18:44 -0600276 warn!("Running on device {} with alignment {}", device, align);
277
Fabio Utzigea0290b2018-08-09 14:23:01 -0300278 let run = Run::new(device, align, erased_val);
David Brown2639e072017-10-11 11:18:44 -0600279
David Brown2639e072017-10-11 11:18:44 -0600280 let mut failed = false;
281
282 // Creates a badly signed image in slot1 to check that it is not
283 // upgraded to
David Brownf48b9502017-11-06 14:00:26 -0700284 let bad_slot1_image = run.make_bad_slot1_image();
David Brown2639e072017-10-11 11:18:44 -0600285
David Brown5f7ec2b2017-11-06 13:54:02 -0700286 failed |= bad_slot1_image.run_signfail_upgrade();
David Brown2639e072017-10-11 11:18:44 -0600287
David Brownf48b9502017-11-06 14:00:26 -0700288 let images = run.make_no_upgrade_image();
David Brown5f7ec2b2017-11-06 13:54:02 -0700289 failed |= images.run_norevert_newimage();
David Brown2639e072017-10-11 11:18:44 -0600290
David Brownf48b9502017-11-06 14:00:26 -0700291 let images = run.make_image();
David Brown2639e072017-10-11 11:18:44 -0600292
David Brown5f7ec2b2017-11-06 13:54:02 -0700293 failed |= images.run_basic_revert();
David Brownc49811e2017-11-06 14:20:45 -0700294 failed |= images.run_revert_with_fails();
295 failed |= images.run_perm_with_fails();
296 failed |= images.run_perm_with_random_fails(5);
David Brown5f7ec2b2017-11-06 13:54:02 -0700297 failed |= images.run_norevert();
David Brown2639e072017-10-11 11:18:44 -0600298
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200299 failed |= images.run_with_status_fails_complete();
Fabio Utzigeedcc452017-11-24 10:48:52 -0200300 failed |= images.run_with_status_fails_with_reset();
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200301
David Brown2639e072017-10-11 11:18:44 -0600302 //show_flash(&flash);
303
304 if failed {
305 self.failures += 1;
306 } else {
307 self.passes += 1;
308 }
309 }
David Browndd2b1182017-11-02 15:39:21 -0600310
311 pub fn failures(&self) -> usize {
312 self.failures
313 }
David Brown2639e072017-10-11 11:18:44 -0600314}
315
David Browndecbd042017-10-19 10:43:17 -0600316/// Build the Flash and area descriptor for a given device.
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200317pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimFlashMap, AreaDesc) {
David Browndecbd042017-10-19 10:43:17 -0600318 match device {
319 DeviceName::Stm32f4 => {
320 // STM style flash. Large sectors, with a large scratch area.
321 let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
322 64 * 1024,
323 128 * 1024, 128 * 1024, 128 * 1024],
Fabio Utzigea0290b2018-08-09 14:23:01 -0300324 align as usize, erased_val);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200325 let dev_id = 0;
Fabio Utzig1caef132018-10-26 15:40:53 -0300326 let mut areadesc = AreaDesc::new();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200327 areadesc.add_flash_sectors(dev_id, &flash);
328 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
329 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
330 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
331
332 let mut flashmap = SimFlashMap::new();
333 flashmap.insert(dev_id, flash);
334 (flashmap, areadesc)
David Browndecbd042017-10-19 10:43:17 -0600335 }
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
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200340 let dev_id = 0;
Fabio Utzig1caef132018-10-26 15:40:53 -0300341 let mut areadesc = AreaDesc::new();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200342 areadesc.add_flash_sectors(dev_id, &flash);
343 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
344 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
345 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
346
347 let mut flashmap = SimFlashMap::new();
348 flashmap.insert(dev_id, flash);
349 (flashmap, areadesc)
David Browndecbd042017-10-19 10:43:17 -0600350 }
351 DeviceName::K64fBig => {
352 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
353 // uses small sectors, but we tell the bootloader they are large.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300354 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600355
Fabio Utzig1caef132018-10-26 15:40:53 -0300356 let dev_id = 0;
357 let mut areadesc = AreaDesc::new();
358 areadesc.add_flash_sectors(dev_id, &flash);
359 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
360 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
361 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200362
363 let mut flashmap = SimFlashMap::new();
364 flashmap.insert(dev_id, flash);
365 (flashmap, areadesc)
David Browndecbd042017-10-19 10:43:17 -0600366 }
367 DeviceName::Nrf52840 => {
368 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
369 // does not divide into the image size.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300370 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browndecbd042017-10-19 10:43:17 -0600371
Fabio Utzig1caef132018-10-26 15:40:53 -0300372 let dev_id = 0;
373 let mut areadesc = AreaDesc::new();
374 areadesc.add_flash_sectors(dev_id, &flash);
375 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
376 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
377 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200378
379 let mut flashmap = SimFlashMap::new();
380 flashmap.insert(dev_id, flash);
381 (flashmap, areadesc)
382 }
383 DeviceName::Nrf52840SpiFlash => {
384 // Simulate nrf52840 with external SPI flash. The external SPI flash
385 // has a larger sector size so for now store scratch on that flash.
386 let flash0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
Fabio Utzig64650772018-11-19 16:51:13 -0200387 let flash1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200388
389 let mut areadesc = AreaDesc::new();
390 areadesc.add_flash_sectors(0, &flash0);
391 areadesc.add_flash_sectors(1, &flash1);
392
393 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
394 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
395 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
396
397 let mut flashmap = SimFlashMap::new();
398 flashmap.insert(0, flash0);
399 flashmap.insert(1, flash1);
400 (flashmap, areadesc)
David Browndecbd042017-10-19 10:43:17 -0600401 }
402 }
403}
404
David Brown5f7ec2b2017-11-06 13:54:02 -0700405impl Images {
406 /// A simple upgrade without forced failures.
407 ///
408 /// Returns the number of flash operations which can later be used to
409 /// inject failures at chosen steps.
David Brownc49811e2017-11-06 14:20:45 -0700410 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200411 let (flashmap, total_count) = try_upgrade(&self.flashmap, &self, None);
David Brown5f7ec2b2017-11-06 13:54:02 -0700412 info!("Total flash operation count={}", total_count);
David Brown2639e072017-10-11 11:18:44 -0600413
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200414 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700415 warn!("Image mismatch after first boot");
416 Err(())
417 } else {
418 Ok(total_count)
David Brown2639e072017-10-11 11:18:44 -0600419 }
420 }
421
David Brown5f7ec2b2017-11-06 13:54:02 -0700422 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700423 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700424 false
425 }
David Brown2639e072017-10-11 11:18:44 -0600426
David Brown5f7ec2b2017-11-06 13:54:02 -0700427 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700428 pub fn run_basic_revert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700429 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600430
David Brown5f7ec2b2017-11-06 13:54:02 -0700431 // FIXME: this test would also pass if no swap is ever performed???
432 if Caps::SwapUpgrade.present() {
433 for count in 2 .. 5 {
434 info!("Try revert: {}", count);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200435 let flashmap = try_revert(&self.flashmap, &self.areadesc, count);
436 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700437 error!("Revert failure on count {}", count);
438 fails += 1;
439 }
440 }
441 }
442
443 fails > 0
444 }
445
David Browna4167ef2017-11-06 14:30:05 -0700446 pub fn run_perm_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700447 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700448 let total_flash_ops = self.total_count.unwrap();
David Brown5f7ec2b2017-11-06 13:54:02 -0700449
450 // Let's try an image halfway through.
451 for i in 1 .. total_flash_ops {
452 info!("Try interruption at {}", i);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200453 let (flashmap, count) = try_upgrade(&self.flashmap, &self, Some(i));
David Brown5f7ec2b2017-11-06 13:54:02 -0700454 info!("Second boot, count={}", count);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200455 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700456 warn!("FAIL at step {} of {}", i, total_flash_ops);
457 fails += 1;
458 }
459
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200460 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300461 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700462 warn!("Mismatched trailer for Slot 0");
463 fails += 1;
464 }
465
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200466 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300467 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700468 warn!("Mismatched trailer for Slot 1");
469 fails += 1;
470 }
471
472 if Caps::SwapUpgrade.present() {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200473 if !verify_image(&flashmap, &self.slots, 1, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700474 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
475 fails += 1;
476 }
477 }
478 }
479
480 if fails > 0 {
481 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
482 fails as f32 * 100.0 / total_flash_ops as f32);
483 }
484
485 fails > 0
486 }
487
David Browna4167ef2017-11-06 14:30:05 -0700488 pub fn run_perm_with_random_fails_5(&self) -> bool {
489 self.run_perm_with_random_fails(5)
490 }
491
David Brownc49811e2017-11-06 14:20:45 -0700492 fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700493 let mut fails = 0;
David Brownc49811e2017-11-06 14:20:45 -0700494 let total_flash_ops = self.total_count.unwrap();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200495 let (flashmap, total_counts) = try_random_fails(&self.flashmap, &self,
496 total_flash_ops, total_fails);
David Brown5f7ec2b2017-11-06 13:54:02 -0700497 info!("Random interruptions at reset points={:?}", total_counts);
498
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200499 let slot0_ok = verify_image(&flashmap, &self.slots, 0, &self.upgrades);
David Brown5f7ec2b2017-11-06 13:54:02 -0700500 let slot1_ok = if Caps::SwapUpgrade.present() {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200501 verify_image(&flashmap, &self.slots, 1, &self.primaries)
David Brown5f7ec2b2017-11-06 13:54:02 -0700502 } else {
503 true
504 };
505 if !slot0_ok || !slot1_ok {
506 error!("Image mismatch after random interrupts: slot0={} slot1={}",
507 if slot0_ok { "ok" } else { "fail" },
508 if slot1_ok { "ok" } else { "fail" });
509 fails += 1;
510 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200511 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300512 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700513 error!("Mismatched trailer for Slot 0");
514 fails += 1;
515 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200516 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300517 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700518 error!("Mismatched trailer for Slot 1");
David Brown2639e072017-10-11 11:18:44 -0600519 fails += 1;
520 }
521
David Brown5f7ec2b2017-11-06 13:54:02 -0700522 if fails > 0 {
523 error!("Error testing perm upgrade with {} fails", total_fails);
524 }
525
526 fails > 0
527 }
528
529 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700530 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700531 false
532 }
533
534 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700535 pub fn run_revert_with_fails(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700536 let mut fails = 0;
537
538 if Caps::SwapUpgrade.present() {
David Brownc49811e2017-11-06 14:20:45 -0700539 for i in 1 .. (self.total_count.unwrap() - 1) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700540 info!("Try interruption at {}", i);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200541 if try_revert_with_fail_at(&self.flashmap, &self, i) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700542 error!("Revert failed at interruption {}", i);
543 fails += 1;
544 }
545 }
546 }
547
548 fails > 0
549 }
550
551 #[cfg(feature = "overwrite-only")]
David Browna4167ef2017-11-06 14:30:05 -0700552 pub fn run_norevert(&self) -> bool {
David Brown5f7ec2b2017-11-06 13:54:02 -0700553 false
554 }
555
556 #[cfg(not(feature = "overwrite-only"))]
David Browna4167ef2017-11-06 14:30:05 -0700557 pub fn run_norevert(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200558 let mut flashmap = self.flashmap.clone();
David Brown5f7ec2b2017-11-06 13:54:02 -0700559 let mut fails = 0;
560
561 info!("Try norevert");
562
563 // First do a normal upgrade...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200564 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200565 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700566 warn!("Failed first boot");
567 fails += 1;
568 }
569
570 //FIXME: copy_done is written by boot_go, is it ok if no copy
571 // was ever done?
572
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200573 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700574 warn!("Slot 0 image verification FAIL");
575 fails += 1;
576 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200577 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300578 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600579 warn!("Mismatched trailer for Slot 0");
580 fails += 1;
581 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200582 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300583 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600584 warn!("Mismatched trailer for Slot 1");
585 fails += 1;
586 }
587
David Brown5f7ec2b2017-11-06 13:54:02 -0700588 // Marks image in slot0 as permanent, no revert should happen...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200589 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
David Brown5f7ec2b2017-11-06 13:54:02 -0700590
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200591 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300592 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700593 warn!("Mismatched trailer for Slot 0");
594 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600595 }
David Brown2639e072017-10-11 11:18:44 -0600596
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200597 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200598 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700599 warn!("Failed second boot");
600 fails += 1;
David Brown2639e072017-10-11 11:18:44 -0600601 }
David Brown5f7ec2b2017-11-06 13:54:02 -0700602
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200603 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300604 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700605 warn!("Mismatched trailer for Slot 0");
606 fails += 1;
607 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200608 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700609 warn!("Failed image verification");
610 fails += 1;
611 }
612
613 if fails > 0 {
614 error!("Error running upgrade without revert");
615 }
616
617 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600618 }
619
David Brown5f7ec2b2017-11-06 13:54:02 -0700620 // Tests a new image written to slot0 that already has magic and image_ok set
621 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700622 pub fn run_norevert_newimage(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200623 let mut flashmap = self.flashmap.clone();
David Brown5f7ec2b2017-11-06 13:54:02 -0700624 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600625
David Brown5f7ec2b2017-11-06 13:54:02 -0700626 info!("Try non-revert on imgtool generated image");
David Brown2639e072017-10-11 11:18:44 -0600627
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200628 mark_upgrade(&mut flashmap, &self.slots[0]);
David Brown2639e072017-10-11 11:18:44 -0600629
David Brown5f7ec2b2017-11-06 13:54:02 -0700630 // This simulates writing an image created by imgtool to Slot 0
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200631 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300632 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700633 warn!("Mismatched trailer for Slot 0");
634 fails += 1;
635 }
David Brown2639e072017-10-11 11:18:44 -0600636
David Brown5f7ec2b2017-11-06 13:54:02 -0700637 // Run the bootloader...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200638 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200639 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700640 warn!("Failed first boot");
641 fails += 1;
642 }
643
644 // State should not have changed
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200645 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700646 warn!("Failed image verification");
647 fails += 1;
648 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200649 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300650 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700651 warn!("Mismatched trailer for Slot 0");
652 fails += 1;
653 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200654 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300655 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700656 warn!("Mismatched trailer for Slot 1");
657 fails += 1;
658 }
659
660 if fails > 0 {
661 error!("Expected a non revert with new image");
662 }
663
664 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600665 }
666
David Brown5f7ec2b2017-11-06 13:54:02 -0700667 // Tests a new image written to slot0 that already has magic and image_ok set
668 // while there is no image on slot1, so no revert should ever happen...
David Brownc49811e2017-11-06 14:20:45 -0700669 pub fn run_signfail_upgrade(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200670 let mut flashmap = self.flashmap.clone();
David Brown5f7ec2b2017-11-06 13:54:02 -0700671 let mut fails = 0;
David Brown2639e072017-10-11 11:18:44 -0600672
David Brown5f7ec2b2017-11-06 13:54:02 -0700673 info!("Try upgrade image with bad signature");
674
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200675 mark_upgrade(&mut flashmap, &self.slots[0]);
676 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
677 mark_upgrade(&mut flashmap, &self.slots[1]);
David Brown5f7ec2b2017-11-06 13:54:02 -0700678
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200679 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300680 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700681 warn!("Mismatched trailer for Slot 0");
682 fails += 1;
683 }
684
685 // Run the bootloader...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200686 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200687 if result != 0 {
David Brown5f7ec2b2017-11-06 13:54:02 -0700688 warn!("Failed first boot");
689 fails += 1;
690 }
691
692 // State should not have changed
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200693 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700694 warn!("Failed image verification");
695 fails += 1;
696 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200697 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300698 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Brown5f7ec2b2017-11-06 13:54:02 -0700699 warn!("Mismatched trailer for Slot 0");
700 fails += 1;
701 }
702
703 if fails > 0 {
704 error!("Expected an upgrade failure when image has bad signature");
705 }
706
707 fails > 0
David Brown2639e072017-10-11 11:18:44 -0600708 }
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200709
Fabio Utziga91c6262017-12-06 09:01:12 -0200710 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300711 fn trailer_sz(&self, align: usize) -> usize {
712 c::boot_trailer_sz(align as u8) as usize
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200713 }
714
715 // FIXME: could get status sz from bootloader
Fabio Utziga91c6262017-12-06 09:01:12 -0200716 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300717 #[cfg(not(feature = "enc-rsa"))]
718 #[cfg(not(feature = "enc-kw"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300719 fn status_sz(&self, align: usize) -> usize {
720 self.trailer_sz(align) - (16 + 24)
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200721 }
722
Fabio Utzig1e48b912018-09-18 09:04:18 -0300723 #[cfg(feature = "enc-rsa")]
Fabio Utzig9b7a2582018-12-03 10:40:05 -0200724 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300725 fn status_sz(&self, align: usize) -> usize {
726 self.trailer_sz(align) - (16 + 24 + 32)
Fabio Utzig1e48b912018-09-18 09:04:18 -0300727 }
728
729 #[cfg(feature = "enc-kw")]
Fabio Utzig9b7a2582018-12-03 10:40:05 -0200730 #[cfg(not(feature = "overwrite-only"))]
Fabio Utzig269d2862018-10-24 17:45:38 -0300731 fn status_sz(&self, align: usize) -> usize {
732 self.trailer_sz(align) - (16 + 24 + 32)
Fabio Utzig1e48b912018-09-18 09:04:18 -0300733 }
734
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200735 /// This test runs a simple upgrade with no fails in the images, but
736 /// allowing for fails in the status area. This should run to the end
737 /// and warn that write fails were detected...
738 #[cfg(not(feature = "validate-slot0"))]
739 pub fn run_with_status_fails_complete(&self) -> bool { false }
740
741 #[cfg(feature = "validate-slot0")]
742 pub fn run_with_status_fails_complete(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200743 let mut flashmap = self.flashmap.clone();
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200744 let mut fails = 0;
745
746 info!("Try swap with status fails");
747
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200748 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
749 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200750
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200751 let (result, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200752 if result != 0 {
753 warn!("Failed!");
754 fails += 1;
755 }
756
757 // Failed writes to the marked "bad" region don't assert anymore.
758 // Any detected assert() is happening in another part of the code.
759 if asserts != 0 {
760 warn!("At least one assert() was called");
761 fails += 1;
762 }
763
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200764 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300765 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200766 warn!("Mismatched trailer for Slot 0");
767 fails += 1;
768 }
769
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200770 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200771 warn!("Failed image verification");
772 fails += 1;
773 }
774
775 info!("validate slot0 enabled; re-run of boot_go should just work");
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200776 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200777 if result != 0 {
778 warn!("Failed!");
779 fails += 1;
780 }
781
782 if fails > 0 {
783 error!("Error running upgrade with status write fails");
784 }
785
786 fails > 0
787 }
788
789 /// This test runs a simple upgrade with no fails in the images, but
790 /// allowing for fails in the status area. This should run to the end
791 /// and warn that write fails were detected...
792 #[cfg(feature = "validate-slot0")]
793 pub fn run_with_status_fails_with_reset(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200794 let mut flashmap = self.flashmap.clone();
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200795 let mut fails = 0;
796 let mut count = self.total_count.unwrap() / 2;
797
798 //info!("count={}\n", count);
799
800 info!("Try interrupted swap with status fails");
801
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200802 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
803 self.mark_bad_status_with_rate(&mut flashmap, 0, 0.5);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200804
805 // Should not fail, writing to bad regions does not assert
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200806 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, Some(&mut count), true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200807 if asserts != 0 {
808 warn!("At least one assert() was called");
809 fails += 1;
810 }
811
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200812 self.reset_bad_status(&mut flashmap, 0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200813
814 info!("Resuming an interrupted swap operation");
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200815 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200816
817 // This might throw no asserts, for large sector devices, where
818 // a single failure writing is indistinguishable from no failure,
819 // or throw a single assert for small sector devices that fail
820 // multiple times...
821 if asserts > 1 {
822 warn!("Expected single assert validating slot0, more detected {}", asserts);
823 fails += 1;
824 }
825
826 if fails > 0 {
827 error!("Error running upgrade with status write fails");
828 }
829
830 fails > 0
831 }
832
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200833 /// Adds a new flash area that fails statistically
834 #[cfg(not(feature = "overwrite-only"))]
835 fn mark_bad_status_with_rate(&self, flashmap: &mut SimFlashMap, slot: usize,
836 rate: f32) {
837 let dev_id = &self.slots[slot].dev_id;
838 let flash = flashmap.get_mut(&dev_id).unwrap();
839 let align = flash.align();
840 let off = &self.slots[0].base_off;
841 let len = &self.slots[0].len;
842 let status_off = off + len - self.trailer_sz(align);
843
844 // Mark the status area as a bad area
845 let _ = flash.add_bad_region(status_off, self.status_sz(align), rate);
846 }
847
848 #[cfg(feature = "validate-slot0")]
849 fn reset_bad_status(&self, flashmap: &mut SimFlashMap, slot: usize) {
850 let dev_id = &self.slots[slot].dev_id;
851 let flash = flashmap.get_mut(&dev_id).unwrap();
852 flash.reset_bad_regions();
853
854 // Disabling write verification the only assert triggered by
855 // boot_go should be checking for integrity of status bytes.
856 flash.set_verify_writes(false);
857 }
858
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200859 #[cfg(not(feature = "validate-slot0"))]
860 #[cfg(not(feature = "overwrite-only"))]
861 pub fn run_with_status_fails_with_reset(&self) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200862 let mut flashmap = self.flashmap.clone();
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200863 let mut fails = 0;
864
865 info!("Try interrupted swap with status fails");
866
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200867 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
868 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200869
870 // This is expected to fail while writing to bad regions...
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200871 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200872 if asserts == 0 {
873 warn!("No assert() detected");
874 fails += 1;
875 }
876
877 fails > 0
878 }
879
880 #[cfg(feature = "overwrite-only")]
881 pub fn run_with_status_fails_with_reset(&self) -> bool {
882 false
883 }
David Brown2639e072017-10-11 11:18:44 -0600884}
885
886/// Test a boot, optionally stopping after 'n' flash options. Returns a count
887/// of the number of flash operations done total.
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200888fn try_upgrade(flashmap: &SimFlashMap, images: &Images,
889 stop: Option<i32>) -> (SimFlashMap, i32) {
David Brown2639e072017-10-11 11:18:44 -0600890 // Clone the flash to have a new copy.
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200891 let mut flashmap = flashmap.clone();
David Brown2639e072017-10-11 11:18:44 -0600892
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200893 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
David Brown2639e072017-10-11 11:18:44 -0600894
David Brownee61c832017-11-06 11:13:25 -0700895 let mut counter = stop.unwrap_or(0);
896
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200897 let (first_interrupted, count) = match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200898 (-0x13579, _) => (true, stop.unwrap()),
899 (0, _) => (false, -counter),
900 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600901 };
David Brown2639e072017-10-11 11:18:44 -0600902
David Brownee61c832017-11-06 11:13:25 -0700903 counter = 0;
David Brown2639e072017-10-11 11:18:44 -0600904 if first_interrupted {
905 // fl.dump();
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200906 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200907 (-0x13579, _) => panic!("Shouldn't stop again"),
908 (0, _) => (),
909 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -0600910 }
911 }
912
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200913 (flashmap, count - counter)
David Brown2639e072017-10-11 11:18:44 -0600914}
915
916#[cfg(not(feature = "overwrite-only"))]
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200917fn try_revert(flashmap: &SimFlashMap, areadesc: &AreaDesc, count: usize) -> SimFlashMap {
918 let mut flashmap = flashmap.clone();
David Brown2639e072017-10-11 11:18:44 -0600919
920 // fl.write_file("image0.bin").unwrap();
921 for i in 0 .. count {
922 info!("Running boot pass {}", i + 1);
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200923 assert_eq!(c::boot_go(&mut flashmap, &areadesc, None, false), (0, 0));
David Brown2639e072017-10-11 11:18:44 -0600924 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200925 flashmap
David Brown2639e072017-10-11 11:18:44 -0600926}
927
928#[cfg(not(feature = "overwrite-only"))]
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200929fn try_revert_with_fail_at(flashmap: &SimFlashMap, images: &Images,
David Brown2639e072017-10-11 11:18:44 -0600930 stop: i32) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200931 let mut flashmap = flashmap.clone();
David Brown2639e072017-10-11 11:18:44 -0600932 let mut fails = 0;
933
David Brownee61c832017-11-06 11:13:25 -0700934 let mut counter = stop;
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200935 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false);
David Brown2639e072017-10-11 11:18:44 -0600936 if x != -0x13579 {
937 warn!("Should have stopped at interruption point");
938 fails += 1;
939 }
940
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200941 if !verify_trailer(&flashmap, &images.slots, 0, None, None, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600942 warn!("copy_done should be unset");
943 fails += 1;
944 }
945
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200946 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
David Brown2639e072017-10-11 11:18:44 -0600947 if x != 0 {
948 warn!("Should have finished upgrade");
949 fails += 1;
950 }
951
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200952 if !verify_image(&flashmap, &images.slots, 0, &images.upgrades) {
David Brown2639e072017-10-11 11:18:44 -0600953 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
954 fails += 1;
955 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200956 if !verify_image(&flashmap, &images.slots, 1, &images.primaries) {
David Brown2639e072017-10-11 11:18:44 -0600957 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
958 fails += 1;
959 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200960 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300961 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600962 warn!("Mismatched trailer for Slot 0 before revert");
963 fails += 1;
964 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200965 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300966 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600967 warn!("Mismatched trailer for Slot 1 before revert");
968 fails += 1;
969 }
970
971 // Do Revert
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200972 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
David Brown2639e072017-10-11 11:18:44 -0600973 if x != 0 {
974 warn!("Should have finished a revert");
975 fails += 1;
976 }
977
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200978 if !verify_image(&flashmap, &images.slots, 0, &images.primaries) {
David Brown2639e072017-10-11 11:18:44 -0600979 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
980 fails += 1;
981 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200982 if !verify_image(&flashmap, &images.slots, 1, &images.upgrades) {
David Brown2639e072017-10-11 11:18:44 -0600983 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
984 fails += 1;
985 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200986 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300987 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Brown2639e072017-10-11 11:18:44 -0600988 warn!("Mismatched trailer for Slot 1 after revert");
989 fails += 1;
990 }
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200991 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300992 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Brown2639e072017-10-11 11:18:44 -0600993 warn!("Mismatched trailer for Slot 1 after revert");
994 fails += 1;
995 }
996
997 fails > 0
998}
999
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001000fn try_random_fails(flashmap: &SimFlashMap, images: &Images,
1001 total_ops: i32, count: usize) -> (SimFlashMap, Vec<i32>) {
1002 let mut flashmap = flashmap.clone();
David Brown2639e072017-10-11 11:18:44 -06001003
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001004 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
David Brown2639e072017-10-11 11:18:44 -06001005
1006 let mut rng = rand::thread_rng();
1007 let mut resets = vec![0i32; count];
1008 let mut remaining_ops = total_ops;
1009 for i in 0 .. count {
1010 let ops = Range::new(1, remaining_ops / 2);
1011 let reset_counter = ops.ind_sample(&mut rng);
David Brownee61c832017-11-06 11:13:25 -07001012 let mut counter = reset_counter;
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001013 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -02001014 (0, _) | (-0x13579, _) => (),
1015 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -06001016 }
1017 remaining_ops -= reset_counter;
1018 resets[i] = reset_counter;
1019 }
1020
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001021 match c::boot_go(&mut flashmap, &images.areadesc, None, false) {
Fabio Utzig9b0ee902017-11-23 19:49:00 -02001022 (-0x13579, _) => panic!("Should not be have been interrupted!"),
1023 (0, _) => (),
1024 (x, _) => panic!("Unknown return: {}", x),
David Brown2639e072017-10-11 11:18:44 -06001025 }
1026
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001027 (flashmap, resets)
David Brown2639e072017-10-11 11:18:44 -06001028}
1029
1030/// Show the flash layout.
1031#[allow(dead_code)]
David Brown10b5de12019-01-02 16:10:01 -07001032fn show_flash(flash: &dyn Flash) {
David Brown2639e072017-10-11 11:18:44 -06001033 println!("---- Flash configuration ----");
1034 for sector in flash.sector_iter() {
1035 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1036 sector.num, sector.base, sector.size);
1037 }
1038 println!("");
1039}
1040
1041/// Install a "program" into the given image. This fakes the image header, or at least all of the
1042/// fields used by the given code. Returns a copy of the image that was written.
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001043fn install_image(flashmap: &mut SimFlashMap, slots: &[SlotInfo], slot: usize, len: usize,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001044 bad_sig: bool) -> [Option<Vec<u8>>; 2] {
1045 let offset = slots[slot].base_off;
1046 let slot_len = slots[slot].len;
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001047 let dev_id = slots[slot].dev_id;
David Brown2639e072017-10-11 11:18:44 -06001048
1049 let mut tlv = make_tlv();
1050
Fabio Utzige5831f62018-12-14 06:46:22 -02001051 const HDR_SIZE: usize = 32;
1052
David Brown2639e072017-10-11 11:18:44 -06001053 // Generate a boot header. Note that the size doesn't include the header.
1054 let header = ImageHeader {
1055 magic: 0x96f3b83d,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001056 load_addr: 0,
Fabio Utzige5831f62018-12-14 06:46:22 -02001057 hdr_size: HDR_SIZE as u16,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001058 _pad1: 0,
David Brown2639e072017-10-11 11:18:44 -06001059 img_size: len as u32,
1060 flags: tlv.get_flags(),
1061 ver: ImageVersion {
1062 major: (offset / (128 * 1024)) as u8,
1063 minor: 0,
1064 revision: 1,
1065 build_num: offset as u32,
1066 },
Fabio Utzig1e48b912018-09-18 09:04:18 -03001067 _pad2: 0,
David Brown2639e072017-10-11 11:18:44 -06001068 };
1069
Fabio Utzige5831f62018-12-14 06:46:22 -02001070 let mut b_header = [0; HDR_SIZE];
1071 b_header[..32].clone_from_slice(header.as_raw());
1072 assert_eq!(b_header.len(), HDR_SIZE);
1073
David Brown2639e072017-10-11 11:18:44 -06001074 tlv.add_bytes(&b_header);
David Brown2639e072017-10-11 11:18:44 -06001075
1076 // The core of the image itself is just pseudorandom data.
Fabio Utzig1e48b912018-09-18 09:04:18 -03001077 let mut b_img = vec![0; len];
1078 splat(&mut b_img, offset);
David Brown2639e072017-10-11 11:18:44 -06001079
Fabio Utzig1e48b912018-09-18 09:04:18 -03001080 // TLV signatures work over plain image
1081 tlv.add_bytes(&b_img);
1082
1083 // Generate encrypted images
1084 let flag = TlvFlags::ENCRYPTED as u32;
1085 let is_encrypted = (tlv.get_flags() & flag) == flag;
1086 let mut b_encimg = vec![];
1087 if is_encrypted {
1088 let key = GenericArray::from_slice(AES_SEC_KEY);
1089 let nonce = GenericArray::from_slice(&[0; 16]);
1090 let mut cipher = Aes128Ctr::new(&key, &nonce);
1091 b_encimg = b_img.clone();
1092 cipher.apply_keystream(&mut b_encimg);
David Brown2639e072017-10-11 11:18:44 -06001093 }
1094
Fabio Utzig1e48b912018-09-18 09:04:18 -03001095 // Build the TLV itself.
1096 let mut b_tlv = if bad_sig {
1097 let good_sig = &mut tlv.make_tlv();
1098 vec![0; good_sig.len()]
1099 } else {
1100 tlv.make_tlv()
1101 };
1102
David Brown2639e072017-10-11 11:18:44 -06001103 // Pad the block to a flash alignment (8 bytes).
Fabio Utzig1e48b912018-09-18 09:04:18 -03001104 while b_tlv.len() % 8 != 0 {
1105 //FIXME: should be erase_val?
1106 b_tlv.push(0xFF);
David Brown2639e072017-10-11 11:18:44 -06001107 }
1108
Fabio Utzig1e48b912018-09-18 09:04:18 -03001109 let mut buf = vec![];
1110 buf.append(&mut b_header.to_vec());
1111 buf.append(&mut b_img);
1112 buf.append(&mut b_tlv.clone());
David Brown2639e072017-10-11 11:18:44 -06001113
Fabio Utzig1e48b912018-09-18 09:04:18 -03001114 let mut encbuf = vec![];
1115 if is_encrypted {
1116 encbuf.append(&mut b_header.to_vec());
1117 encbuf.append(&mut b_encimg);
1118 encbuf.append(&mut b_tlv);
1119 }
David Brown2639e072017-10-11 11:18:44 -06001120
Fabio Utzig1e48b912018-09-18 09:04:18 -03001121 let result: [Option<Vec<u8>>; 2];
1122
1123 // Since images are always non-encrypted in slot0, we first write an
1124 // encrypted image, re-read to use for verification, erase + flash
1125 // un-encrypted. In slot1 the image is written un-encrypted, and if
1126 // encryption is requested, it follows an erase + flash encrypted.
1127
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001128 let flash = flashmap.get_mut(&dev_id).unwrap();
1129
Fabio Utzig1e48b912018-09-18 09:04:18 -03001130 if slot == 0 {
1131 let enc_copy: Option<Vec<u8>>;
1132
1133 if is_encrypted {
1134 flash.write(offset, &encbuf).unwrap();
1135
1136 let mut enc = vec![0u8; encbuf.len()];
1137 flash.read(offset, &mut enc).unwrap();
1138
1139 enc_copy = Some(enc);
1140
1141 flash.erase(offset, slot_len).unwrap();
1142 } else {
1143 enc_copy = None;
1144 }
1145
1146 flash.write(offset, &buf).unwrap();
1147
1148 let mut copy = vec![0u8; buf.len()];
1149 flash.read(offset, &mut copy).unwrap();
1150
1151 result = [Some(copy), enc_copy];
1152 } else {
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001153
Fabio Utzig1e48b912018-09-18 09:04:18 -03001154 flash.write(offset, &buf).unwrap();
1155
1156 let mut copy = vec![0u8; buf.len()];
1157 flash.read(offset, &mut copy).unwrap();
1158
1159 let enc_copy: Option<Vec<u8>>;
1160
1161 if is_encrypted {
1162 flash.erase(offset, slot_len).unwrap();
1163
1164 flash.write(offset, &encbuf).unwrap();
1165
1166 let mut enc = vec![0u8; encbuf.len()];
1167 flash.read(offset, &mut enc).unwrap();
1168
1169 enc_copy = Some(enc);
1170 } else {
1171 enc_copy = None;
1172 }
1173
1174 result = [Some(copy), enc_copy];
1175 }
1176
1177 result
David Brown2639e072017-10-11 11:18:44 -06001178}
1179
1180// The TLV in use depends on what kind of signature we are verifying.
1181#[cfg(feature = "sig-rsa")]
Fabio Utzig251ef1d2018-12-18 17:20:19 -02001182#[cfg(feature = "enc-kw")]
1183fn make_tlv() -> TlvGen {
1184 TlvGen::new_rsa_kw()
1185}
1186
1187#[cfg(feature = "sig-rsa")]
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001188#[cfg(not(feature = "enc-rsa"))]
Fabio Utzig251ef1d2018-12-18 17:20:19 -02001189#[cfg(not(feature = "enc-kw"))]
David Brown2639e072017-10-11 11:18:44 -06001190fn make_tlv() -> TlvGen {
1191 TlvGen::new_rsa_pss()
1192}
1193
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001194#[cfg(feature = "sig-ecdsa")]
Fabio Utzigb4d20c82018-12-27 16:08:39 -02001195#[cfg(feature = "enc-kw")]
1196fn make_tlv() -> TlvGen {
1197 TlvGen::new_ecdsa_kw()
1198}
1199
1200#[cfg(feature = "sig-ecdsa")]
1201#[cfg(not(feature = "enc-kw"))]
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001202fn make_tlv() -> TlvGen {
1203 TlvGen::new_ecdsa()
1204}
1205
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001206#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001207#[cfg(feature = "enc-rsa")]
1208fn make_tlv() -> TlvGen {
1209 TlvGen::new_enc_rsa()
1210}
1211
Fabio Utzigc8d67f12018-12-14 06:45:23 -02001212#[cfg(feature = "sig-rsa")]
1213#[cfg(feature = "enc-rsa")]
1214fn make_tlv() -> TlvGen {
1215 TlvGen::new_sig_enc_rsa()
1216}
1217
Fabio Utzig251ef1d2018-12-18 17:20:19 -02001218#[cfg(not(feature = "sig-rsa"))]
Fabio Utzigb4d20c82018-12-27 16:08:39 -02001219#[cfg(not(feature = "sig-ecdsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001220#[cfg(feature = "enc-kw")]
1221fn make_tlv() -> TlvGen {
1222 TlvGen::new_enc_kw()
1223}
1224
David Brown2639e072017-10-11 11:18:44 -06001225#[cfg(not(feature = "sig-rsa"))]
Fabio Utzig80fde2f2017-12-05 09:25:31 -02001226#[cfg(not(feature = "sig-ecdsa"))]
Fabio Utzig1e48b912018-09-18 09:04:18 -03001227#[cfg(not(feature = "enc-rsa"))]
1228#[cfg(not(feature = "enc-kw"))]
David Brown2639e072017-10-11 11:18:44 -06001229fn make_tlv() -> TlvGen {
1230 TlvGen::new_hash_only()
1231}
1232
Fabio Utzig1e48b912018-09-18 09:04:18 -03001233#[cfg(feature = "enc-rsa")]
1234fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
1235 match &images[slot] {
1236 Some(image) => return image,
1237 None => panic!("Invalid image"),
1238 }
1239}
1240
1241#[cfg(feature = "enc-kw")]
1242fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
1243 match &images[slot] {
1244 Some(image) => return image,
1245 None => panic!("Invalid image"),
1246 }
1247}
1248
1249#[cfg(not(feature = "enc-rsa"))]
1250#[cfg(not(feature = "enc-kw"))]
1251fn find_image(images: &[Option<Vec<u8>>; 2], _slot: usize) -> &Vec<u8> {
1252 match &images[0] {
1253 Some(image) => return image,
1254 None => panic!("Invalid image"),
1255 }
1256}
1257
David Brown2639e072017-10-11 11:18:44 -06001258/// Verify that given image is present in the flash at the given offset.
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001259fn verify_image(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001260 images: &[Option<Vec<u8>>; 2]) -> bool {
1261 let image = find_image(images, slot);
1262 let buf = image.as_slice();
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001263 let dev_id = slots[slot].dev_id;
Fabio Utzig1e48b912018-09-18 09:04:18 -03001264
David Brown2639e072017-10-11 11:18:44 -06001265 let mut copy = vec![0u8; buf.len()];
Fabio Utzig1e48b912018-09-18 09:04:18 -03001266 let offset = slots[slot].base_off;
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001267 let flash = flashmap.get(&dev_id).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001268 flash.read(offset, &mut copy).unwrap();
1269
1270 if buf != &copy[..] {
1271 for i in 0 .. buf.len() {
1272 if buf[i] != copy[i] {
Fabio Utzig1e48b912018-09-18 09:04:18 -03001273 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1274 slot, offset + i, buf[i], copy[i]);
David Brown2639e072017-10-11 11:18:44 -06001275 break;
1276 }
1277 }
1278 false
1279 } else {
1280 true
1281 }
1282}
1283
1284#[cfg(feature = "overwrite-only")]
1285#[allow(unused_variables)]
1286// overwrite-only doesn't employ trailer management
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001287fn verify_trailer(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001288 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001289 copy_done: Option<u8>) -> bool {
1290 true
1291}
1292
1293#[cfg(not(feature = "overwrite-only"))]
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001294fn verify_trailer(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
Fabio Utzigea0290b2018-08-09 14:23:01 -03001295 magic: Option<u8>, image_ok: Option<u8>,
David Brown2639e072017-10-11 11:18:44 -06001296 copy_done: Option<u8>) -> bool {
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001297 let offset = slots[slot].trailer_off;
1298 let dev_id = slots[slot].dev_id;
David Brown2639e072017-10-11 11:18:44 -06001299 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1300 let mut failed = false;
1301
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001302 let flash = flashmap.get(&dev_id).unwrap();
1303 let erased_val = flash.erased_val();
David Brown2639e072017-10-11 11:18:44 -06001304 flash.read(offset, &mut copy).unwrap();
1305
1306 failed |= match magic {
1307 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001308 if v == 1 && &copy[16..] != MAGIC.unwrap() {
David Brown2639e072017-10-11 11:18:44 -06001309 warn!("\"magic\" mismatch at {:#x}", offset);
1310 true
Fabio Utzigea0290b2018-08-09 14:23:01 -03001311 } else if v == 3 {
1312 let expected = [erased_val; 16];
1313 if &copy[16..] != expected {
1314 warn!("\"magic\" mismatch at {:#x}", offset);
1315 true
1316 } else {
1317 false
1318 }
David Brown2639e072017-10-11 11:18:44 -06001319 } else {
1320 false
1321 }
1322 },
1323 None => false,
1324 };
1325
1326 failed |= match image_ok {
1327 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001328 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1329 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
David Brown2639e072017-10-11 11:18:44 -06001330 true
1331 } else {
1332 false
1333 }
1334 },
1335 None => false,
1336 };
1337
1338 failed |= match copy_done {
1339 Some(v) => {
Fabio Utzigea0290b2018-08-09 14:23:01 -03001340 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1341 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
David Brown2639e072017-10-11 11:18:44 -06001342 true
1343 } else {
1344 false
1345 }
1346 },
1347 None => false,
1348 };
1349
1350 !failed
1351}
1352
1353/// The image header
1354#[repr(C)]
1355pub struct ImageHeader {
1356 magic: u32,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001357 load_addr: u32,
David Brown2639e072017-10-11 11:18:44 -06001358 hdr_size: u16,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001359 _pad1: u16,
David Brown2639e072017-10-11 11:18:44 -06001360 img_size: u32,
1361 flags: u32,
1362 ver: ImageVersion,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001363 _pad2: u32,
David Brown2639e072017-10-11 11:18:44 -06001364}
1365
1366impl AsRaw for ImageHeader {}
1367
1368#[repr(C)]
1369pub struct ImageVersion {
1370 major: u8,
1371 minor: u8,
1372 revision: u16,
1373 build_num: u32,
1374}
1375
David Brownd5e632c2017-10-19 10:49:46 -06001376#[derive(Clone)]
David Brown2639e072017-10-11 11:18:44 -06001377struct SlotInfo {
1378 base_off: usize,
1379 trailer_off: usize,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001380 len: usize,
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001381 dev_id: u8,
David Brown2639e072017-10-11 11:18:44 -06001382}
1383
David Brownf48b9502017-11-06 14:00:26 -07001384pub struct Images {
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001385 flashmap: SimFlashMap,
David Brown3f687dc2017-11-06 13:41:18 -07001386 areadesc: AreaDesc,
Fabio Utzig1e48b912018-09-18 09:04:18 -03001387 slots: [SlotInfo; 2],
1388 primaries: [Option<Vec<u8>>; 2],
1389 upgrades: [Option<Vec<u8>>; 2],
David Brownc49811e2017-11-06 14:20:45 -07001390 total_count: Option<i32>,
David Brown2639e072017-10-11 11:18:44 -06001391}
1392
Fabio Utzigea0290b2018-08-09 14:23:01 -03001393const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1394 0x60, 0xd2, 0xef, 0x7f,
1395 0x35, 0x52, 0x50, 0x0f,
1396 0x2c, 0xb6, 0x79, 0x80]);
David Brown2639e072017-10-11 11:18:44 -06001397
Fabio Utzigea0290b2018-08-09 14:23:01 -03001398// Replicates defines found in bootutil.h
1399const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1400const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1401
1402const BOOT_FLAG_SET: Option<u8> = Some(1);
1403const BOOT_FLAG_UNSET: Option<u8> = Some(3);
David Brown2639e072017-10-11 11:18:44 -06001404
1405/// Write out the magic so that the loader tries doing an upgrade.
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001406fn mark_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
1407 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001408 let offset = slot.trailer_off + c::boot_max_align() * 2;
Fabio Utzigea0290b2018-08-09 14:23:01 -03001409 flash.write(offset, MAGIC.unwrap()).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001410}
1411
1412/// Writes the image_ok flag which, guess what, tells the bootloader
1413/// the this image is ok (not a test, and no revert is to be performed).
Fabio Utzigafb2bc92018-11-19 16:11:52 -02001414fn mark_permanent_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
1415 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
Fabio Utzig269d2862018-10-24 17:45:38 -03001416 let mut ok = [flash.erased_val(); 8];
Fabio Utzigea0290b2018-08-09 14:23:01 -03001417 ok[0] = 1u8;
David Brown2639e072017-10-11 11:18:44 -06001418 let off = slot.trailer_off + c::boot_max_align();
Fabio Utzig269d2862018-10-24 17:45:38 -03001419 let align = flash.align();
1420 flash.write(off, &ok[..align]).unwrap();
David Brown2639e072017-10-11 11:18:44 -06001421}
1422
1423// Drop some pseudo-random gibberish onto the data.
1424fn splat(data: &mut [u8], seed: usize) {
1425 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1426 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1427 rng.fill_bytes(data);
1428}
1429
1430/// Return a read-only view into the raw bytes of this object
1431trait AsRaw : Sized {
1432 fn as_raw<'a>(&'a self) -> &'a [u8] {
1433 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1434 mem::size_of::<Self>()) }
1435 }
1436}
1437
1438fn show_sizes() {
1439 // This isn't panic safe.
David Brown2639e072017-10-11 11:18:44 -06001440 for min in &[1, 2, 4, 8] {
David Brown541860c2017-11-06 11:25:42 -07001441 let msize = c::boot_trailer_sz(*min);
David Brown2639e072017-10-11 11:18:44 -06001442 println!("{:2}: {} (0x{:x})", min, msize, msize);
1443 }
David Brown2639e072017-10-11 11:18:44 -06001444}