blob: 39e7fbb020d2153843e4c7407dbaa9e9a4581da4 [file] [log] [blame]
David Brown5c9e0f12019-01-09 16:34:33 -07001use log::{info, warn, error};
2use rand::{
3 distributions::{IndependentSample, Range},
4 Rng, SeedableRng, XorShiftRng,
5};
6use std::{
David Browncb47dd72019-08-05 14:21:49 -06007 io::{Cursor, Write},
David Brown5c9e0f12019-01-09 16:34:33 -07008 mem,
9 slice,
10};
11use aes_ctr::{
12 Aes128Ctr,
13 stream_cipher::{
14 generic_array::GenericArray,
15 NewFixStreamCipher,
16 StreamCipherCore,
17 },
18};
19
David Brown76101572019-02-28 11:29:03 -070020use simflash::{Flash, SimFlash, SimMultiFlash};
David Browne5133242019-02-28 11:05:19 -070021use mcuboot_sys::{c, AreaDesc, FlashId};
22use crate::{
23 ALL_DEVICES,
24 DeviceName,
25};
David Brown5c9e0f12019-01-09 16:34:33 -070026use crate::caps::Caps;
David Brownc3898d62019-08-05 14:20:02 -060027use crate::depends::{
28 BoringDep,
29 Depender,
30 DepTest,
31 PairDep,
32 UpgradeInfo,
33};
David Brown43643dd2019-01-11 15:43:28 -070034use crate::tlv::{ManifestGen, TlvGen, TlvFlags, AES_SEC_KEY};
David Brown5c9e0f12019-01-09 16:34:33 -070035
David Browne5133242019-02-28 11:05:19 -070036/// A builder for Images. This describes a single run of the simulator,
37/// capturing the configuration of a particular set of devices, including
38/// the flash simulator(s) and the information about the slots.
39#[derive(Clone)]
40pub struct ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070041 flash: SimMultiFlash,
David Browne5133242019-02-28 11:05:19 -070042 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070043 slots: Vec<[SlotInfo; 2]>,
David Browne5133242019-02-28 11:05:19 -070044}
45
David Brown998aa8d2019-02-28 10:54:50 -070046/// Images represents the state of a simulation for a given set of images.
David Brown76101572019-02-28 11:29:03 -070047/// The flash holds the state of the simulated flash, whereas primaries
David Brown998aa8d2019-02-28 10:54:50 -070048/// and upgrades hold the expected contents of these images.
49pub struct Images {
David Brown76101572019-02-28 11:29:03 -070050 flash: SimMultiFlash,
David Brownca234692019-02-28 11:22:19 -070051 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070052 images: Vec<OneImage>,
53 total_count: Option<i32>,
54}
55
56/// When doing multi-image, there is an instance of this information for
57/// each of the images. Single image there will be one of these.
58struct OneImage {
David Brownca234692019-02-28 11:22:19 -070059 slots: [SlotInfo; 2],
60 primaries: ImageData,
61 upgrades: ImageData,
David Brownca234692019-02-28 11:22:19 -070062}
63
64/// The Rust-side representation of an image. For unencrypted images, this
65/// is just the unencrypted payload. For encrypted images, we store both
66/// the encrypted and the plaintext.
67struct ImageData {
68 plain: Vec<u8>,
69 cipher: Option<Vec<u8>>,
David Brown998aa8d2019-02-28 10:54:50 -070070}
71
David Browne5133242019-02-28 11:05:19 -070072impl ImagesBuilder {
David Brown5bc62c62019-03-05 12:11:48 -070073 /// Construct a new image builder for the given device. Returns
74 /// Some(builder) if is possible to test this configuration, or None if
75 /// not possible (for example, if there aren't enough image slots).
76 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Option<Self> {
David Brown76101572019-02-28 11:29:03 -070077 let (flash, areadesc) = Self::make_device(device, align, erased_val);
David Browne5133242019-02-28 11:05:19 -070078
David Brown06ef06e2019-03-05 12:28:10 -070079 let num_images = Caps::get_num_images();
David Browne5133242019-02-28 11:05:19 -070080
David Brown06ef06e2019-03-05 12:28:10 -070081 let mut slots = Vec::with_capacity(num_images);
82 for image in 0..num_images {
83 // This mapping must match that defined in
84 // `boot/zephyr/include/sysflash/sysflash.h`.
85 let id0 = match image {
86 0 => FlashId::Image0,
87 1 => FlashId::Image2,
88 _ => panic!("More than 2 images not supported"),
89 };
90 let (primary_base, primary_len, primary_dev_id) = match areadesc.find(id0) {
91 Some(info) => info,
92 None => return None,
93 };
94 let id1 = match image {
95 0 => FlashId::Image1,
96 1 => FlashId::Image3,
97 _ => panic!("More than 2 images not supported"),
98 };
99 let (secondary_base, secondary_len, secondary_dev_id) = match areadesc.find(id1) {
100 Some(info) => info,
101 None => return None,
102 };
David Browne5133242019-02-28 11:05:19 -0700103
Christopher Collinsa1c12042019-05-23 14:00:28 -0700104 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 4;
David Browne5133242019-02-28 11:05:19 -0700105
David Brown06ef06e2019-03-05 12:28:10 -0700106 // Construct a primary image.
107 let primary = SlotInfo {
108 base_off: primary_base as usize,
109 trailer_off: primary_base + primary_len - offset_from_end,
110 len: primary_len as usize,
111 dev_id: primary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600112 index: 0,
David Brown06ef06e2019-03-05 12:28:10 -0700113 };
114
115 // And an upgrade image.
116 let secondary = SlotInfo {
117 base_off: secondary_base as usize,
118 trailer_off: secondary_base + secondary_len - offset_from_end,
119 len: secondary_len as usize,
120 dev_id: secondary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600121 index: 1,
David Brown06ef06e2019-03-05 12:28:10 -0700122 };
123
124 slots.push([primary, secondary]);
125 }
David Browne5133242019-02-28 11:05:19 -0700126
David Brown5bc62c62019-03-05 12:11:48 -0700127 Some(ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -0700128 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700129 areadesc: areadesc,
David Brown06ef06e2019-03-05 12:28:10 -0700130 slots: slots,
David Brown5bc62c62019-03-05 12:11:48 -0700131 })
David Browne5133242019-02-28 11:05:19 -0700132 }
133
134 pub fn each_device<F>(f: F)
135 where F: Fn(Self)
136 {
137 for &dev in ALL_DEVICES {
138 for &align in &[1, 2, 4, 8] {
139 for &erased_val in &[0, 0xff] {
David Brown5bc62c62019-03-05 12:11:48 -0700140 match Self::new(dev, align, erased_val) {
141 Some(run) => f(run),
142 None => warn!("Skipping {:?}, insufficient partitions", dev),
143 }
David Browne5133242019-02-28 11:05:19 -0700144 }
145 }
146 }
147 }
148
149 /// Construct an `Images` that doesn't expect an upgrade to happen.
David Brownc3898d62019-08-05 14:20:02 -0600150 pub fn make_no_upgrade_image(self, deps: &DepTest) -> Images {
151 let num_images = self.num_images();
David Brown76101572019-02-28 11:29:03 -0700152 let mut flash = self.flash;
David Brownc3898d62019-08-05 14:20:02 -0600153 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
154 let dep: Box<dyn Depender> = if num_images > 1 {
155 Box::new(PairDep::new(num_images, image_num, deps))
156 } else {
157 Box::new(BoringDep(image_num))
158 };
159 let primaries = install_image(&mut flash, &slots[0], 42784, &*dep, false);
160 let upgrades = install_image(&mut flash, &slots[1], 46928, &*dep, false);
David Brown84b49f72019-03-01 10:58:22 -0700161 OneImage {
162 slots: slots,
163 primaries: primaries,
164 upgrades: upgrades,
165 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700166 Images {
David Brown76101572019-02-28 11:29:03 -0700167 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700168 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700169 images: images,
David Browne5133242019-02-28 11:05:19 -0700170 total_count: None,
171 }
172 }
173
David Brownc3898d62019-08-05 14:20:02 -0600174 pub fn make_image(self, deps: &DepTest, permanent: bool) -> Images {
175 let mut images = self.make_no_upgrade_image(deps);
David Brown84b49f72019-03-01 10:58:22 -0700176 for image in &images.images {
177 mark_upgrade(&mut images.flash, &image.slots[1]);
178 }
David Browne5133242019-02-28 11:05:19 -0700179
180 // upgrades without fails, counts number of flash operations
Fabio Utziged4a5362019-07-30 12:43:23 -0300181 let total_count = match images.run_basic_upgrade(permanent) {
David Browne5133242019-02-28 11:05:19 -0700182 Ok(v) => v,
183 Err(_) => {
184 panic!("Unable to perform basic upgrade");
185 },
186 };
187
188 images.total_count = Some(total_count);
189 images
190 }
191
192 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700193 let mut bad_flash = self.flash;
David Brownc3898d62019-08-05 14:20:02 -0600194 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
195 let dep = BoringDep(image_num);
196 let primaries = install_image(&mut bad_flash, &slots[0], 32784, &dep, false);
197 let upgrades = install_image(&mut bad_flash, &slots[1], 41928, &dep, true);
David Brown84b49f72019-03-01 10:58:22 -0700198 OneImage {
199 slots: slots,
200 primaries: primaries,
201 upgrades: upgrades,
202 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700203 Images {
David Brown76101572019-02-28 11:29:03 -0700204 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700205 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700206 images: images,
David Browne5133242019-02-28 11:05:19 -0700207 total_count: None,
208 }
209 }
210
211 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700212 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700213 match device {
214 DeviceName::Stm32f4 => {
215 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700216 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
217 64 * 1024,
218 128 * 1024, 128 * 1024, 128 * 1024],
219 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700220 let dev_id = 0;
221 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700222 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700223 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
224 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
225 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
226
David Brown76101572019-02-28 11:29:03 -0700227 let mut flash = SimMultiFlash::new();
228 flash.insert(dev_id, dev);
229 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700230 }
231 DeviceName::K64f => {
232 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700233 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700234
235 let dev_id = 0;
236 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700237 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700238 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
239 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
240 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
241
David Brown76101572019-02-28 11:29:03 -0700242 let mut flash = SimMultiFlash::new();
243 flash.insert(dev_id, dev);
244 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700245 }
246 DeviceName::K64fBig => {
247 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
248 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700249 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700250
251 let dev_id = 0;
252 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700253 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700254 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
255 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
256 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
257
David Brown76101572019-02-28 11:29:03 -0700258 let mut flash = SimMultiFlash::new();
259 flash.insert(dev_id, dev);
260 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700261 }
262 DeviceName::Nrf52840 => {
263 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
264 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700265 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700266
267 let dev_id = 0;
268 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700269 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700270 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
271 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
272 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
273
David Brown76101572019-02-28 11:29:03 -0700274 let mut flash = SimMultiFlash::new();
275 flash.insert(dev_id, dev);
276 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700277 }
278 DeviceName::Nrf52840SpiFlash => {
279 // Simulate nrf52840 with external SPI flash. The external SPI flash
280 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700281 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
282 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700283
284 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700285 areadesc.add_flash_sectors(0, &dev0);
286 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700287
288 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
289 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
290 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
291
David Brown76101572019-02-28 11:29:03 -0700292 let mut flash = SimMultiFlash::new();
293 flash.insert(0, dev0);
294 flash.insert(1, dev1);
295 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700296 }
David Brown2bff6472019-03-05 13:58:35 -0700297 DeviceName::K64fMulti => {
298 // NXP style flash, but larger, to support multiple images.
299 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
300
301 let dev_id = 0;
302 let mut areadesc = AreaDesc::new();
303 areadesc.add_flash_sectors(dev_id, &dev);
304 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
305 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
306 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
307 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
308 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
309
310 let mut flash = SimMultiFlash::new();
311 flash.insert(dev_id, dev);
312 (flash, areadesc)
313 }
David Browne5133242019-02-28 11:05:19 -0700314 }
315 }
David Brownc3898d62019-08-05 14:20:02 -0600316
317 pub fn num_images(&self) -> usize {
318 self.slots.len()
319 }
David Browne5133242019-02-28 11:05:19 -0700320}
321
David Brown5c9e0f12019-01-09 16:34:33 -0700322impl Images {
323 /// A simple upgrade without forced failures.
324 ///
325 /// Returns the number of flash operations which can later be used to
326 /// inject failures at chosen steps.
Fabio Utziged4a5362019-07-30 12:43:23 -0300327 pub fn run_basic_upgrade(&self, permanent: bool) -> Result<i32, ()> {
328 let (flash, total_count) = self.try_upgrade(None, permanent);
David Brown5c9e0f12019-01-09 16:34:33 -0700329 info!("Total flash operation count={}", total_count);
330
David Brown84b49f72019-03-01 10:58:22 -0700331 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700332 warn!("Image mismatch after first boot");
333 Err(())
334 } else {
335 Ok(total_count)
336 }
337 }
338
David Brownc3898d62019-08-05 14:20:02 -0600339 /// Test a simple upgrade, with dependencies given, and verify that the
340 /// image does as is described in the test.
341 pub fn run_check_deps(&self, deps: &DepTest) -> bool {
342 let (flash, _) = self.try_upgrade(None, true);
343
344 self.verify_dep_images(&flash, deps)
345 }
346
David Brown5c9e0f12019-01-09 16:34:33 -0700347 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700348 if Caps::OverwriteUpgrade.present() {
349 return false;
350 }
David Brown5c9e0f12019-01-09 16:34:33 -0700351
David Brown5c9e0f12019-01-09 16:34:33 -0700352 let mut fails = 0;
353
354 // FIXME: this test would also pass if no swap is ever performed???
355 if Caps::SwapUpgrade.present() {
356 for count in 2 .. 5 {
357 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700358 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700359 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700360 error!("Revert failure on count {}", count);
361 fails += 1;
362 }
363 }
364 }
365
366 fails > 0
367 }
368
369 pub fn run_perm_with_fails(&self) -> bool {
370 let mut fails = 0;
371 let total_flash_ops = self.total_count.unwrap();
372
373 // Let's try an image halfway through.
374 for i in 1 .. total_flash_ops {
375 info!("Try interruption at {}", i);
Fabio Utziged4a5362019-07-30 12:43:23 -0300376 let (flash, count) = self.try_upgrade(Some(i), true);
David Brown5c9e0f12019-01-09 16:34:33 -0700377 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700378 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700379 warn!("FAIL at step {} of {}", i, total_flash_ops);
380 fails += 1;
381 }
382
David Brown84b49f72019-03-01 10:58:22 -0700383 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
384 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100385 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700386 fails += 1;
387 }
388
David Brown84b49f72019-03-01 10:58:22 -0700389 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
390 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100391 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700392 fails += 1;
393 }
394
395 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700396 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100397 warn!("Secondary slot FAIL at step {} of {}",
398 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700399 fails += 1;
400 }
401 }
402 }
403
404 if fails > 0 {
405 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
406 fails as f32 * 100.0 / total_flash_ops as f32);
407 }
408
409 fails > 0
410 }
411
David Brown5c9e0f12019-01-09 16:34:33 -0700412 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
413 let mut fails = 0;
414 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700415 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700416 info!("Random interruptions at reset points={:?}", total_counts);
417
David Brown84b49f72019-03-01 10:58:22 -0700418 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100419 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700420 // TODO: This result is ignored.
421 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700422 } else {
423 true
424 };
David Vincze2d736ad2019-02-18 11:50:22 +0100425 if !primary_slot_ok || !secondary_slot_ok {
426 error!("Image mismatch after random interrupts: primary slot={} \
427 secondary slot={}",
428 if primary_slot_ok { "ok" } else { "fail" },
429 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700430 fails += 1;
431 }
David Brown84b49f72019-03-01 10:58:22 -0700432 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
433 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100434 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700435 fails += 1;
436 }
David Brown84b49f72019-03-01 10:58:22 -0700437 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
438 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100439 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700440 fails += 1;
441 }
442
443 if fails > 0 {
444 error!("Error testing perm upgrade with {} fails", total_fails);
445 }
446
447 fails > 0
448 }
449
David Brown5c9e0f12019-01-09 16:34:33 -0700450 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700451 if Caps::OverwriteUpgrade.present() {
452 return false;
453 }
David Brown5c9e0f12019-01-09 16:34:33 -0700454
David Brown5c9e0f12019-01-09 16:34:33 -0700455 let mut fails = 0;
456
457 if Caps::SwapUpgrade.present() {
Fabio Utziged4a5362019-07-30 12:43:23 -0300458 for i in 1 .. self.total_count.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -0700459 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700460 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700461 error!("Revert failed at interruption {}", i);
462 fails += 1;
463 }
464 }
465 }
466
467 fails > 0
468 }
469
David Brown5c9e0f12019-01-09 16:34:33 -0700470 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700471 if Caps::OverwriteUpgrade.present() {
472 return false;
473 }
David Brown5c9e0f12019-01-09 16:34:33 -0700474
David Brown76101572019-02-28 11:29:03 -0700475 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700476 let mut fails = 0;
477
478 info!("Try norevert");
479
480 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700481 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700482 if result != 0 {
483 warn!("Failed first boot");
484 fails += 1;
485 }
486
487 //FIXME: copy_done is written by boot_go, is it ok if no copy
488 // was ever done?
489
David Brown84b49f72019-03-01 10:58:22 -0700490 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100491 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700492 fails += 1;
493 }
David Brown84b49f72019-03-01 10:58:22 -0700494 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
495 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100496 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700497 fails += 1;
498 }
David Brown84b49f72019-03-01 10:58:22 -0700499 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
500 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100501 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700502 fails += 1;
503 }
504
David Vincze2d736ad2019-02-18 11:50:22 +0100505 // Marks image in the primary slot as permanent,
506 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700507 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700508
David Brown84b49f72019-03-01 10:58:22 -0700509 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
510 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100511 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700512 fails += 1;
513 }
514
David Brown76101572019-02-28 11:29:03 -0700515 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700516 if result != 0 {
517 warn!("Failed second boot");
518 fails += 1;
519 }
520
David Brown84b49f72019-03-01 10:58:22 -0700521 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
522 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100523 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700524 fails += 1;
525 }
David Brown84b49f72019-03-01 10:58:22 -0700526 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700527 warn!("Failed image verification");
528 fails += 1;
529 }
530
531 if fails > 0 {
532 error!("Error running upgrade without revert");
533 }
534
535 fails > 0
536 }
537
David Vincze2d736ad2019-02-18 11:50:22 +0100538 // Tests a new image written to the primary slot that already has magic and
539 // image_ok set while there is no image on the secondary slot, so no revert
540 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700541 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700542 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700543 let mut fails = 0;
544
545 info!("Try non-revert on imgtool generated image");
546
David Brown84b49f72019-03-01 10:58:22 -0700547 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700548
David Vincze2d736ad2019-02-18 11:50:22 +0100549 // This simulates writing an image created by imgtool to
550 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700551 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
552 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100553 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700554 fails += 1;
555 }
556
557 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700558 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700559 if result != 0 {
560 warn!("Failed first boot");
561 fails += 1;
562 }
563
564 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700565 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700566 warn!("Failed image verification");
567 fails += 1;
568 }
David Brown84b49f72019-03-01 10:58:22 -0700569 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
570 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100571 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700572 fails += 1;
573 }
David Brown84b49f72019-03-01 10:58:22 -0700574 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
575 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100576 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700577 fails += 1;
578 }
579
580 if fails > 0 {
581 error!("Expected a non revert with new image");
582 }
583
584 fails > 0
585 }
586
David Vincze2d736ad2019-02-18 11:50:22 +0100587 // Tests a new image written to the primary slot that already has magic and
588 // image_ok set while there is no image on the secondary slot, so no revert
589 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700590 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700591 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700592 let mut fails = 0;
593
594 info!("Try upgrade image with bad signature");
595
David Brown84b49f72019-03-01 10:58:22 -0700596 self.mark_upgrades(&mut flash, 0);
597 self.mark_permanent_upgrades(&mut flash, 0);
598 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700599
David Brown84b49f72019-03-01 10:58:22 -0700600 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
601 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100602 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700603 fails += 1;
604 }
605
606 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700607 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700608 if result != 0 {
609 warn!("Failed first boot");
610 fails += 1;
611 }
612
613 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700614 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700615 warn!("Failed image verification");
616 fails += 1;
617 }
David Brown84b49f72019-03-01 10:58:22 -0700618 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
619 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100620 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700621 fails += 1;
622 }
623
624 if fails > 0 {
625 error!("Expected an upgrade failure when image has bad signature");
626 }
627
628 fails > 0
629 }
630
David Brown5c9e0f12019-01-09 16:34:33 -0700631 fn trailer_sz(&self, align: usize) -> usize {
632 c::boot_trailer_sz(align as u8) as usize
633 }
634
635 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700636 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700637 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
638 32
639 } else {
640 0
641 };
David Brown5c9e0f12019-01-09 16:34:33 -0700642
Christopher Collinsa1c12042019-05-23 14:00:28 -0700643 self.trailer_sz(align) - (16 + 32 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700644 }
645
646 /// This test runs a simple upgrade with no fails in the images, but
647 /// allowing for fails in the status area. This should run to the end
648 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700649 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100650 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700651 return false;
652 }
653
David Brown76101572019-02-28 11:29:03 -0700654 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700655 let mut fails = 0;
656
657 info!("Try swap with status fails");
658
David Brown84b49f72019-03-01 10:58:22 -0700659 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700660 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700661
David Brown76101572019-02-28 11:29:03 -0700662 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700663 if result != 0 {
664 warn!("Failed!");
665 fails += 1;
666 }
667
668 // Failed writes to the marked "bad" region don't assert anymore.
669 // Any detected assert() is happening in another part of the code.
670 if asserts != 0 {
671 warn!("At least one assert() was called");
672 fails += 1;
673 }
674
David Brown84b49f72019-03-01 10:58:22 -0700675 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
676 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100677 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700678 fails += 1;
679 }
680
David Brown84b49f72019-03-01 10:58:22 -0700681 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700682 warn!("Failed image verification");
683 fails += 1;
684 }
685
David Vincze2d736ad2019-02-18 11:50:22 +0100686 info!("validate primary slot enabled; \
687 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700688 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700689 if result != 0 {
690 warn!("Failed!");
691 fails += 1;
692 }
693
694 if fails > 0 {
695 error!("Error running upgrade with status write fails");
696 }
697
698 fails > 0
699 }
700
701 /// This test runs a simple upgrade with no fails in the images, but
702 /// allowing for fails in the status area. This should run to the end
703 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700704 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700705 if Caps::OverwriteUpgrade.present() {
706 false
David Vincze2d736ad2019-02-18 11:50:22 +0100707 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700708
David Brown76101572019-02-28 11:29:03 -0700709 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700710 let mut fails = 0;
711 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700712
David Brown85904a82019-01-11 13:45:12 -0700713 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700714
David Brown85904a82019-01-11 13:45:12 -0700715 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700716
David Brown84b49f72019-03-01 10:58:22 -0700717 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700718 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700719
720 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700721 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700722 if asserts != 0 {
723 warn!("At least one assert() was called");
724 fails += 1;
725 }
726
David Brown76101572019-02-28 11:29:03 -0700727 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700728
729 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700730 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700731
732 // This might throw no asserts, for large sector devices, where
733 // a single failure writing is indistinguishable from no failure,
734 // or throw a single assert for small sector devices that fail
735 // multiple times...
736 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100737 warn!("Expected single assert validating the primary slot, \
738 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700739 fails += 1;
740 }
741
742 if fails > 0 {
743 error!("Error running upgrade with status write fails");
744 }
745
746 fails > 0
747 } else {
David Brown76101572019-02-28 11:29:03 -0700748 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700749 let mut fails = 0;
750
751 info!("Try interrupted swap with status fails");
752
David Brown84b49f72019-03-01 10:58:22 -0700753 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700754 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700755
756 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700757 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700758 if asserts == 0 {
759 warn!("No assert() detected");
760 fails += 1;
761 }
762
763 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700764 }
David Brown5c9e0f12019-01-09 16:34:33 -0700765 }
766
767 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700768 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700769 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700770 if Caps::OverwriteUpgrade.present() {
771 return;
772 }
773
David Brown84b49f72019-03-01 10:58:22 -0700774 // Set this for each image.
775 for image in &self.images {
776 let dev_id = &image.slots[slot].dev_id;
777 let dev = flash.get_mut(&dev_id).unwrap();
778 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -0700779 let off = &image.slots[slot].base_off;
780 let len = &image.slots[slot].len;
David Brown84b49f72019-03-01 10:58:22 -0700781 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700782
David Brown84b49f72019-03-01 10:58:22 -0700783 // Mark the status area as a bad area
784 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
785 }
David Brown5c9e0f12019-01-09 16:34:33 -0700786 }
787
David Brown76101572019-02-28 11:29:03 -0700788 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100789 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700790 return;
791 }
792
David Brown84b49f72019-03-01 10:58:22 -0700793 for image in &self.images {
794 let dev_id = &image.slots[slot].dev_id;
795 let dev = flash.get_mut(&dev_id).unwrap();
796 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700797
David Brown84b49f72019-03-01 10:58:22 -0700798 // Disabling write verification the only assert triggered by
799 // boot_go should be checking for integrity of status bytes.
800 dev.set_verify_writes(false);
801 }
David Brown5c9e0f12019-01-09 16:34:33 -0700802 }
803
David Browndb505822019-03-01 10:04:20 -0700804 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
805 /// of the number of flash operations done total.
Fabio Utziged4a5362019-07-30 12:43:23 -0300806 fn try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32) {
David Browndb505822019-03-01 10:04:20 -0700807 // Clone the flash to have a new copy.
808 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700809
Fabio Utziged4a5362019-07-30 12:43:23 -0300810 if permanent {
811 self.mark_permanent_upgrades(&mut flash, 1);
812 }
David Brown5c9e0f12019-01-09 16:34:33 -0700813
David Browndb505822019-03-01 10:04:20 -0700814 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700815
David Browndb505822019-03-01 10:04:20 -0700816 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
817 (-0x13579, _) => (true, stop.unwrap()),
818 (0, _) => (false, -counter),
819 (x, _) => panic!("Unknown return: {}", x),
820 };
David Brown5c9e0f12019-01-09 16:34:33 -0700821
David Browndb505822019-03-01 10:04:20 -0700822 counter = 0;
823 if first_interrupted {
824 // fl.dump();
825 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
826 (-0x13579, _) => panic!("Shouldn't stop again"),
827 (0, _) => (),
828 (x, _) => panic!("Unknown return: {}", x),
829 }
830 }
David Brown5c9e0f12019-01-09 16:34:33 -0700831
David Browndb505822019-03-01 10:04:20 -0700832 (flash, count - counter)
833 }
834
835 fn try_revert(&self, count: usize) -> SimMultiFlash {
836 let mut flash = self.flash.clone();
837
838 // fl.write_file("image0.bin").unwrap();
839 for i in 0 .. count {
840 info!("Running boot pass {}", i + 1);
841 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
842 }
843 flash
844 }
845
846 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
847 let mut flash = self.flash.clone();
848 let mut fails = 0;
849
850 let mut counter = stop;
851 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
852 if x != -0x13579 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700853 warn!("Should have stopped test at interruption point");
David Browndb505822019-03-01 10:04:20 -0700854 fails += 1;
855 }
856
Fabio Utzig8af7f792019-07-30 12:40:01 -0300857 // In a multi-image setup, copy done might be set if any number of
858 // images was already successfully swapped.
859 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
860 warn!("copy_done should be unset");
861 fails += 1;
862 }
863
David Browndb505822019-03-01 10:04:20 -0700864 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
865 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700866 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -0700867 fails += 1;
868 }
869
David Brown84b49f72019-03-01 10:58:22 -0700870 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700871 warn!("Image in the primary slot before revert is invalid at stop={}",
872 stop);
873 fails += 1;
874 }
David Brown84b49f72019-03-01 10:58:22 -0700875 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700876 warn!("Image in the secondary slot before revert is invalid at stop={}",
877 stop);
878 fails += 1;
879 }
David Brown84b49f72019-03-01 10:58:22 -0700880 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
881 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700882 warn!("Mismatched trailer for the primary slot before revert");
883 fails += 1;
884 }
David Brown84b49f72019-03-01 10:58:22 -0700885 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
886 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700887 warn!("Mismatched trailer for the secondary slot before revert");
888 fails += 1;
889 }
890
891 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700892 let mut counter = stop;
893 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
894 if x != -0x13579 {
895 warn!("Should have stopped revert at interruption point");
896 fails += 1;
897 }
898
David Browndb505822019-03-01 10:04:20 -0700899 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
900 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700901 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -0700902 fails += 1;
903 }
904
David Brown84b49f72019-03-01 10:58:22 -0700905 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700906 warn!("Image in the primary slot after revert is invalid at stop={}",
907 stop);
908 fails += 1;
909 }
David Brown84b49f72019-03-01 10:58:22 -0700910 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700911 warn!("Image in the secondary slot after revert is invalid at stop={}",
912 stop);
913 fails += 1;
914 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700915
David Brown84b49f72019-03-01 10:58:22 -0700916 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
917 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700918 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -0700919 fails += 1;
920 }
David Brown84b49f72019-03-01 10:58:22 -0700921 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
922 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700923 warn!("Mismatched trailer for the secondary slot after revert");
924 fails += 1;
925 }
926
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700927 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
928 if x != 0 {
929 warn!("Should have finished 3rd boot");
930 fails += 1;
931 }
932
933 if !self.verify_images(&flash, 0, 0) {
934 warn!("Image in the primary slot is invalid on 1st boot after revert");
935 fails += 1;
936 }
937 if !self.verify_images(&flash, 1, 1) {
938 warn!("Image in the secondary slot is invalid on 1st boot after revert");
939 fails += 1;
940 }
941
David Browndb505822019-03-01 10:04:20 -0700942 fails > 0
943 }
944
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700945
David Browndb505822019-03-01 10:04:20 -0700946 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
947 let mut flash = self.flash.clone();
948
David Brown84b49f72019-03-01 10:58:22 -0700949 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700950
951 let mut rng = rand::thread_rng();
952 let mut resets = vec![0i32; count];
953 let mut remaining_ops = total_ops;
954 for i in 0 .. count {
955 let ops = Range::new(1, remaining_ops / 2);
956 let reset_counter = ops.ind_sample(&mut rng);
957 let mut counter = reset_counter;
958 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
959 (0, _) | (-0x13579, _) => (),
960 (x, _) => panic!("Unknown return: {}", x),
961 }
962 remaining_ops -= reset_counter;
963 resets[i] = reset_counter;
964 }
965
966 match c::boot_go(&mut flash, &self.areadesc, None, false) {
967 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700968 (0, _) => (),
969 (x, _) => panic!("Unknown return: {}", x),
970 }
David Brown5c9e0f12019-01-09 16:34:33 -0700971
David Browndb505822019-03-01 10:04:20 -0700972 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700973 }
David Brown84b49f72019-03-01 10:58:22 -0700974
975 /// Verify the image in the given flash device, the specified slot
976 /// against the expected image.
977 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
978 for image in &self.images {
David Brown3b090212019-07-30 15:59:28 -0600979 if !verify_image(flash, &image.slots[slot],
David Brown84b49f72019-03-01 10:58:22 -0700980 match against {
981 0 => &image.primaries,
982 1 => &image.upgrades,
983 _ => panic!("Invalid 'against'"),
984 }) {
985 return false;
986 }
987 }
988 true
989 }
990
David Brownc3898d62019-08-05 14:20:02 -0600991 /// Verify the images, according to the dependency test.
992 fn verify_dep_images(&self, flash: &SimMultiFlash, deps: &DepTest) -> bool {
993 for (image_num, (image, upgrade)) in self.images.iter().zip(deps.upgrades.iter()).enumerate() {
994 info!("Upgrade: slot:{}, {:?}", image_num, upgrade);
995 if !verify_image(flash, &image.slots[0],
996 match upgrade {
997 UpgradeInfo::Upgraded => &image.upgrades,
998 UpgradeInfo::Held => &image.primaries,
999 }) {
1000 error!("Failed to upgrade properly: image: {}, upgrade: {:?}", image_num, upgrade);
1001 return true;
1002 }
1003 }
1004
1005 false
1006 }
1007
Fabio Utzig8af7f792019-07-30 12:40:01 -03001008 /// Verify that at least one of the trailers of the images have the
1009 /// specified values.
1010 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
1011 magic: Option<u8>, image_ok: Option<u8>,
1012 copy_done: Option<u8>) -> bool {
1013 for image in &self.images {
David Brown3b090212019-07-30 15:59:28 -06001014 if verify_trailer(flash, &image.slots[slot],
Fabio Utzig8af7f792019-07-30 12:40:01 -03001015 magic, image_ok, copy_done) {
1016 return true;
1017 }
1018 }
1019 false
1020 }
1021
David Brown84b49f72019-03-01 10:58:22 -07001022 /// Verify that the trailers of the images have the specified
1023 /// values.
1024 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
1025 magic: Option<u8>, image_ok: Option<u8>,
1026 copy_done: Option<u8>) -> bool {
1027 for image in &self.images {
David Brown3b090212019-07-30 15:59:28 -06001028 if !verify_trailer(flash, &image.slots[slot],
David Brown84b49f72019-03-01 10:58:22 -07001029 magic, image_ok, copy_done) {
1030 return false;
1031 }
1032 }
1033 true
1034 }
1035
1036 /// Mark each of the images for permanent upgrade.
1037 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1038 for image in &self.images {
1039 mark_permanent_upgrade(flash, &image.slots[slot]);
1040 }
1041 }
1042
1043 /// Mark each of the images for permanent upgrade.
1044 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1045 for image in &self.images {
1046 mark_upgrade(flash, &image.slots[slot]);
1047 }
1048 }
David Brown5c9e0f12019-01-09 16:34:33 -07001049}
1050
1051/// Show the flash layout.
1052#[allow(dead_code)]
1053fn show_flash(flash: &dyn Flash) {
1054 println!("---- Flash configuration ----");
1055 for sector in flash.sector_iter() {
1056 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1057 sector.num, sector.base, sector.size);
1058 }
1059 println!("");
1060}
1061
1062/// Install a "program" into the given image. This fakes the image header, or at least all of the
1063/// fields used by the given code. Returns a copy of the image that was written.
David Brown3b090212019-07-30 15:59:28 -06001064fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: usize,
David Brownc3898d62019-08-05 14:20:02 -06001065 deps: &dyn Depender, bad_sig: bool) -> ImageData {
David Brown3b090212019-07-30 15:59:28 -06001066 let offset = slot.base_off;
1067 let slot_len = slot.len;
1068 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001069
David Brown43643dd2019-01-11 15:43:28 -07001070 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001071
David Brownc3898d62019-08-05 14:20:02 -06001072 // Add the dependencies early to the tlv.
1073 for dep in deps.my_deps(offset, slot.index) {
1074 tlv.add_dependency(deps.other_id(), &dep);
1075 }
1076
David Brown5c9e0f12019-01-09 16:34:33 -07001077 const HDR_SIZE: usize = 32;
1078
1079 // Generate a boot header. Note that the size doesn't include the header.
1080 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001081 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001082 load_addr: 0,
1083 hdr_size: HDR_SIZE as u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001084 protect_tlv_size: tlv.protect_size(),
David Brown5c9e0f12019-01-09 16:34:33 -07001085 img_size: len as u32,
1086 flags: tlv.get_flags(),
David Brownc3898d62019-08-05 14:20:02 -06001087 ver: deps.my_version(offset, slot.index),
David Brown5c9e0f12019-01-09 16:34:33 -07001088 _pad2: 0,
1089 };
1090
1091 let mut b_header = [0; HDR_SIZE];
1092 b_header[..32].clone_from_slice(header.as_raw());
1093 assert_eq!(b_header.len(), HDR_SIZE);
1094
1095 tlv.add_bytes(&b_header);
1096
1097 // The core of the image itself is just pseudorandom data.
1098 let mut b_img = vec![0; len];
1099 splat(&mut b_img, offset);
1100
David Browncb47dd72019-08-05 14:21:49 -06001101 // Add some information at the start of the payload to make it easier
1102 // to see what it is. This will fail if the image itself is too small.
1103 {
1104 let mut wr = Cursor::new(&mut b_img);
1105 writeln!(&mut wr, "offset: {:#x}, dev_id: {:#x}, slot_info: {:?}",
1106 offset, dev_id, slot).unwrap();
1107 writeln!(&mut wr, "version: {:?}", deps.my_version(offset, slot.index)).unwrap();
1108 }
1109
David Brown5c9e0f12019-01-09 16:34:33 -07001110 // TLV signatures work over plain image
1111 tlv.add_bytes(&b_img);
1112
1113 // Generate encrypted images
1114 let flag = TlvFlags::ENCRYPTED as u32;
1115 let is_encrypted = (tlv.get_flags() & flag) == flag;
1116 let mut b_encimg = vec![];
1117 if is_encrypted {
1118 let key = GenericArray::from_slice(AES_SEC_KEY);
1119 let nonce = GenericArray::from_slice(&[0; 16]);
1120 let mut cipher = Aes128Ctr::new(&key, &nonce);
1121 b_encimg = b_img.clone();
1122 cipher.apply_keystream(&mut b_encimg);
1123 }
1124
1125 // Build the TLV itself.
1126 let mut b_tlv = if bad_sig {
1127 let good_sig = &mut tlv.make_tlv();
1128 vec![0; good_sig.len()]
1129 } else {
1130 tlv.make_tlv()
1131 };
1132
1133 // Pad the block to a flash alignment (8 bytes).
1134 while b_tlv.len() % 8 != 0 {
1135 //FIXME: should be erase_val?
1136 b_tlv.push(0xFF);
1137 }
1138
1139 let mut buf = vec![];
1140 buf.append(&mut b_header.to_vec());
1141 buf.append(&mut b_img);
1142 buf.append(&mut b_tlv.clone());
1143
1144 let mut encbuf = vec![];
1145 if is_encrypted {
1146 encbuf.append(&mut b_header.to_vec());
1147 encbuf.append(&mut b_encimg);
1148 encbuf.append(&mut b_tlv);
1149 }
1150
David Vincze2d736ad2019-02-18 11:50:22 +01001151 // Since images are always non-encrypted in the primary slot, we first write
1152 // an encrypted image, re-read to use for verification, erase + flash
1153 // un-encrypted. In the secondary slot the image is written un-encrypted,
1154 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001155
David Brown76101572019-02-28 11:29:03 -07001156 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001157
David Brown3b090212019-07-30 15:59:28 -06001158 if slot.index == 0 {
David Brown5c9e0f12019-01-09 16:34:33 -07001159 let enc_copy: Option<Vec<u8>>;
1160
1161 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001162 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001163
1164 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001165 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001166
1167 enc_copy = Some(enc);
1168
David Brown76101572019-02-28 11:29:03 -07001169 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001170 } else {
1171 enc_copy = None;
1172 }
1173
David Brown76101572019-02-28 11:29:03 -07001174 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001175
1176 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001177 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001178
David Brownca234692019-02-28 11:22:19 -07001179 ImageData {
1180 plain: copy,
1181 cipher: enc_copy,
1182 }
David Brown5c9e0f12019-01-09 16:34:33 -07001183 } else {
1184
David Brown76101572019-02-28 11:29:03 -07001185 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001186
1187 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001188 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001189
1190 let enc_copy: Option<Vec<u8>>;
1191
1192 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001193 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001194
David Brown76101572019-02-28 11:29:03 -07001195 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001196
1197 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001198 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001199
1200 enc_copy = Some(enc);
1201 } else {
1202 enc_copy = None;
1203 }
1204
David Brownca234692019-02-28 11:22:19 -07001205 ImageData {
1206 plain: copy,
1207 cipher: enc_copy,
1208 }
David Brown5c9e0f12019-01-09 16:34:33 -07001209 }
David Brown5c9e0f12019-01-09 16:34:33 -07001210}
1211
David Brown5c9e0f12019-01-09 16:34:33 -07001212fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001213 if Caps::EcdsaP224.present() {
1214 panic!("Ecdsa P224 not supported in Simulator");
1215 }
David Brown5c9e0f12019-01-09 16:34:33 -07001216
David Brownb8882112019-01-11 14:04:11 -07001217 if Caps::EncKw.present() {
1218 if Caps::RSA2048.present() {
1219 TlvGen::new_rsa_kw()
1220 } else if Caps::EcdsaP256.present() {
1221 TlvGen::new_ecdsa_kw()
1222 } else {
1223 TlvGen::new_enc_kw()
1224 }
1225 } else if Caps::EncRsa.present() {
1226 if Caps::RSA2048.present() {
1227 TlvGen::new_sig_enc_rsa()
1228 } else {
1229 TlvGen::new_enc_rsa()
1230 }
1231 } else {
1232 // The non-encrypted configuration.
1233 if Caps::RSA2048.present() {
1234 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001235 } else if Caps::RSA3072.present() {
1236 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001237 } else if Caps::EcdsaP256.present() {
1238 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001239 } else if Caps::Ed25519.present() {
1240 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001241 } else {
1242 TlvGen::new_hash_only()
1243 }
1244 }
David Brown5c9e0f12019-01-09 16:34:33 -07001245}
1246
David Brownca234692019-02-28 11:22:19 -07001247impl ImageData {
1248 /// Find the image contents for the given slot. This assumes that slot 0
1249 /// is unencrypted, and slot 1 is encrypted.
1250 fn find(&self, slot: usize) -> &Vec<u8> {
1251 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1252 match (encrypted, slot) {
1253 (false, _) => &self.plain,
1254 (true, 0) => &self.plain,
1255 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1256 _ => panic!("Invalid slot requested"),
1257 }
David Brown5c9e0f12019-01-09 16:34:33 -07001258 }
1259}
1260
David Brown5c9e0f12019-01-09 16:34:33 -07001261/// Verify that given image is present in the flash at the given offset.
David Brown3b090212019-07-30 15:59:28 -06001262fn verify_image(flash: &SimMultiFlash, slot: &SlotInfo, images: &ImageData) -> bool {
1263 let image = images.find(slot.index);
David Brown5c9e0f12019-01-09 16:34:33 -07001264 let buf = image.as_slice();
David Brown3b090212019-07-30 15:59:28 -06001265 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001266
1267 let mut copy = vec![0u8; buf.len()];
David Brown3b090212019-07-30 15:59:28 -06001268 let offset = slot.base_off;
David Brown76101572019-02-28 11:29:03 -07001269 let dev = flash.get(&dev_id).unwrap();
1270 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001271
1272 if buf != &copy[..] {
1273 for i in 0 .. buf.len() {
1274 if buf[i] != copy[i] {
David Brownc3898d62019-08-05 14:20:02 -06001275 info!("First failure for slot{} at {:#x} ({:#x} within) {:#x}!={:#x}",
1276 slot.index, offset + i, i, buf[i], copy[i]);
David Brown5c9e0f12019-01-09 16:34:33 -07001277 break;
1278 }
1279 }
1280 false
1281 } else {
1282 true
1283 }
1284}
1285
David Brown3b090212019-07-30 15:59:28 -06001286fn verify_trailer(flash: &SimMultiFlash, slot: &SlotInfo,
David Brown5c9e0f12019-01-09 16:34:33 -07001287 magic: Option<u8>, image_ok: Option<u8>,
1288 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001289 if Caps::OverwriteUpgrade.present() {
1290 return true;
1291 }
David Brown5c9e0f12019-01-09 16:34:33 -07001292
David Brown3b090212019-07-30 15:59:28 -06001293 let offset = slot.trailer_off + c::boot_max_align();
1294 let dev_id = slot.dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001295 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001296 let mut failed = false;
1297
David Brown76101572019-02-28 11:29:03 -07001298 let dev = flash.get(&dev_id).unwrap();
1299 let erased_val = dev.erased_val();
1300 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001301
1302 failed |= match magic {
1303 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001304 if v == 1 && &copy[24..] != MAGIC.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -07001305 warn!("\"magic\" mismatch at {:#x}", offset);
1306 true
1307 } else if v == 3 {
1308 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001309 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001310 warn!("\"magic\" mismatch at {:#x}", offset);
1311 true
1312 } else {
1313 false
1314 }
1315 } else {
1316 false
1317 }
1318 },
1319 None => false,
1320 };
1321
1322 failed |= match image_ok {
1323 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001324 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001325 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1326 true
1327 } else {
1328 false
1329 }
1330 },
1331 None => false,
1332 };
1333
1334 failed |= match copy_done {
1335 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001336 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001337 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1338 true
1339 } else {
1340 false
1341 }
1342 },
1343 None => false,
1344 };
1345
1346 !failed
1347}
1348
1349/// The image header
1350#[repr(C)]
1351pub struct ImageHeader {
1352 magic: u32,
1353 load_addr: u32,
1354 hdr_size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001355 protect_tlv_size: u16,
David Brown5c9e0f12019-01-09 16:34:33 -07001356 img_size: u32,
1357 flags: u32,
1358 ver: ImageVersion,
1359 _pad2: u32,
1360}
1361
1362impl AsRaw for ImageHeader {}
1363
1364#[repr(C)]
David Brownc3898d62019-08-05 14:20:02 -06001365#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001366pub struct ImageVersion {
David Brown7a81c4b2019-07-29 15:20:21 -06001367 pub major: u8,
1368 pub minor: u8,
1369 pub revision: u16,
1370 pub build_num: u32,
David Brown5c9e0f12019-01-09 16:34:33 -07001371}
1372
David Brownc3898d62019-08-05 14:20:02 -06001373#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001374pub struct SlotInfo {
1375 pub base_off: usize,
1376 pub trailer_off: usize,
1377 pub len: usize,
David Brown3b090212019-07-30 15:59:28 -06001378 // Which slot within this device.
1379 pub index: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001380 pub dev_id: u8,
1381}
1382
David Brown5c9e0f12019-01-09 16:34:33 -07001383const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1384 0x60, 0xd2, 0xef, 0x7f,
1385 0x35, 0x52, 0x50, 0x0f,
1386 0x2c, 0xb6, 0x79, 0x80]);
1387
1388// Replicates defines found in bootutil.h
1389const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1390const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1391
1392const BOOT_FLAG_SET: Option<u8> = Some(1);
1393const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1394
1395/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001396pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1397 let dev = flash.get_mut(&slot.dev_id).unwrap();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001398 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown76101572019-02-28 11:29:03 -07001399 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001400}
1401
1402/// Writes the image_ok flag which, guess what, tells the bootloader
1403/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001404fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1405 let dev = flash.get_mut(&slot.dev_id).unwrap();
1406 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001407 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001408 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001409 let align = dev.align();
1410 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001411}
1412
1413// Drop some pseudo-random gibberish onto the data.
1414fn splat(data: &mut [u8], seed: usize) {
1415 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1416 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1417 rng.fill_bytes(data);
1418}
1419
1420/// Return a read-only view into the raw bytes of this object
1421trait AsRaw : Sized {
1422 fn as_raw<'a>(&'a self) -> &'a [u8] {
1423 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1424 mem::size_of::<Self>()) }
1425 }
1426}
1427
1428pub fn show_sizes() {
1429 // This isn't panic safe.
1430 for min in &[1, 2, 4, 8] {
1431 let msize = c::boot_trailer_sz(*min);
1432 println!("{:2}: {} (0x{:x})", min, msize, msize);
1433 }
1434}