blob: b2fe0de1dd847987215a3cec3dd482ac6e9bd839 [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 {
David Brownf9aec952019-08-06 10:23:58 -0600978 self.images.iter().all(|image| {
979 verify_image(flash, &image.slots[slot],
980 match against {
981 0 => &image.primaries,
982 1 => &image.upgrades,
983 _ => panic!("Invalid 'against'")
984 })
985 })
David Brown84b49f72019-03-01 10:58:22 -0700986 }
987
David Brownc3898d62019-08-05 14:20:02 -0600988 /// Verify the images, according to the dependency test.
989 fn verify_dep_images(&self, flash: &SimMultiFlash, deps: &DepTest) -> bool {
990 for (image_num, (image, upgrade)) in self.images.iter().zip(deps.upgrades.iter()).enumerate() {
991 info!("Upgrade: slot:{}, {:?}", image_num, upgrade);
992 if !verify_image(flash, &image.slots[0],
993 match upgrade {
994 UpgradeInfo::Upgraded => &image.upgrades,
995 UpgradeInfo::Held => &image.primaries,
996 }) {
997 error!("Failed to upgrade properly: image: {}, upgrade: {:?}", image_num, upgrade);
998 return true;
999 }
1000 }
1001
1002 false
1003 }
1004
Fabio Utzig8af7f792019-07-30 12:40:01 -03001005 /// Verify that at least one of the trailers of the images have the
1006 /// specified values.
1007 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
1008 magic: Option<u8>, image_ok: Option<u8>,
1009 copy_done: Option<u8>) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001010 self.images.iter().any(|image| {
1011 verify_trailer(flash, &image.slots[slot],
1012 magic, image_ok, copy_done)
1013 })
Fabio Utzig8af7f792019-07-30 12:40:01 -03001014 }
1015
David Brown84b49f72019-03-01 10:58:22 -07001016 /// Verify that the trailers of the images have the specified
1017 /// values.
1018 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
1019 magic: Option<u8>, image_ok: Option<u8>,
1020 copy_done: Option<u8>) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001021 self.images.iter().all(|image| {
1022 verify_trailer(flash, &image.slots[slot],
1023 magic, image_ok, copy_done)
1024 })
David Brown84b49f72019-03-01 10:58:22 -07001025 }
1026
1027 /// Mark each of the images for permanent upgrade.
1028 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1029 for image in &self.images {
1030 mark_permanent_upgrade(flash, &image.slots[slot]);
1031 }
1032 }
1033
1034 /// Mark each of the images for permanent upgrade.
1035 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1036 for image in &self.images {
1037 mark_upgrade(flash, &image.slots[slot]);
1038 }
1039 }
David Brown5c9e0f12019-01-09 16:34:33 -07001040}
1041
1042/// Show the flash layout.
1043#[allow(dead_code)]
1044fn show_flash(flash: &dyn Flash) {
1045 println!("---- Flash configuration ----");
1046 for sector in flash.sector_iter() {
1047 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1048 sector.num, sector.base, sector.size);
1049 }
1050 println!("");
1051}
1052
1053/// Install a "program" into the given image. This fakes the image header, or at least all of the
1054/// fields used by the given code. Returns a copy of the image that was written.
David Brown3b090212019-07-30 15:59:28 -06001055fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: usize,
David Brownc3898d62019-08-05 14:20:02 -06001056 deps: &dyn Depender, bad_sig: bool) -> ImageData {
David Brown3b090212019-07-30 15:59:28 -06001057 let offset = slot.base_off;
1058 let slot_len = slot.len;
1059 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001060
David Brown43643dd2019-01-11 15:43:28 -07001061 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001062
David Brownc3898d62019-08-05 14:20:02 -06001063 // Add the dependencies early to the tlv.
1064 for dep in deps.my_deps(offset, slot.index) {
1065 tlv.add_dependency(deps.other_id(), &dep);
1066 }
1067
David Brown5c9e0f12019-01-09 16:34:33 -07001068 const HDR_SIZE: usize = 32;
1069
1070 // Generate a boot header. Note that the size doesn't include the header.
1071 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001072 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001073 load_addr: 0,
1074 hdr_size: HDR_SIZE as u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001075 protect_tlv_size: tlv.protect_size(),
David Brown5c9e0f12019-01-09 16:34:33 -07001076 img_size: len as u32,
1077 flags: tlv.get_flags(),
David Brownc3898d62019-08-05 14:20:02 -06001078 ver: deps.my_version(offset, slot.index),
David Brown5c9e0f12019-01-09 16:34:33 -07001079 _pad2: 0,
1080 };
1081
1082 let mut b_header = [0; HDR_SIZE];
1083 b_header[..32].clone_from_slice(header.as_raw());
1084 assert_eq!(b_header.len(), HDR_SIZE);
1085
1086 tlv.add_bytes(&b_header);
1087
1088 // The core of the image itself is just pseudorandom data.
1089 let mut b_img = vec![0; len];
1090 splat(&mut b_img, offset);
1091
David Browncb47dd72019-08-05 14:21:49 -06001092 // Add some information at the start of the payload to make it easier
1093 // to see what it is. This will fail if the image itself is too small.
1094 {
1095 let mut wr = Cursor::new(&mut b_img);
1096 writeln!(&mut wr, "offset: {:#x}, dev_id: {:#x}, slot_info: {:?}",
1097 offset, dev_id, slot).unwrap();
1098 writeln!(&mut wr, "version: {:?}", deps.my_version(offset, slot.index)).unwrap();
1099 }
1100
David Brown5c9e0f12019-01-09 16:34:33 -07001101 // TLV signatures work over plain image
1102 tlv.add_bytes(&b_img);
1103
1104 // Generate encrypted images
1105 let flag = TlvFlags::ENCRYPTED as u32;
1106 let is_encrypted = (tlv.get_flags() & flag) == flag;
1107 let mut b_encimg = vec![];
1108 if is_encrypted {
1109 let key = GenericArray::from_slice(AES_SEC_KEY);
1110 let nonce = GenericArray::from_slice(&[0; 16]);
1111 let mut cipher = Aes128Ctr::new(&key, &nonce);
1112 b_encimg = b_img.clone();
1113 cipher.apply_keystream(&mut b_encimg);
1114 }
1115
1116 // Build the TLV itself.
1117 let mut b_tlv = if bad_sig {
1118 let good_sig = &mut tlv.make_tlv();
1119 vec![0; good_sig.len()]
1120 } else {
1121 tlv.make_tlv()
1122 };
1123
1124 // Pad the block to a flash alignment (8 bytes).
1125 while b_tlv.len() % 8 != 0 {
1126 //FIXME: should be erase_val?
1127 b_tlv.push(0xFF);
1128 }
1129
1130 let mut buf = vec![];
1131 buf.append(&mut b_header.to_vec());
1132 buf.append(&mut b_img);
1133 buf.append(&mut b_tlv.clone());
1134
1135 let mut encbuf = vec![];
1136 if is_encrypted {
1137 encbuf.append(&mut b_header.to_vec());
1138 encbuf.append(&mut b_encimg);
1139 encbuf.append(&mut b_tlv);
1140 }
1141
David Vincze2d736ad2019-02-18 11:50:22 +01001142 // Since images are always non-encrypted in the primary slot, we first write
1143 // an encrypted image, re-read to use for verification, erase + flash
1144 // un-encrypted. In the secondary slot the image is written un-encrypted,
1145 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001146
David Brown76101572019-02-28 11:29:03 -07001147 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001148
David Brown3b090212019-07-30 15:59:28 -06001149 if slot.index == 0 {
David Brown5c9e0f12019-01-09 16:34:33 -07001150 let enc_copy: Option<Vec<u8>>;
1151
1152 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001153 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001154
1155 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001156 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001157
1158 enc_copy = Some(enc);
1159
David Brown76101572019-02-28 11:29:03 -07001160 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001161 } else {
1162 enc_copy = None;
1163 }
1164
David Brown76101572019-02-28 11:29:03 -07001165 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001166
1167 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001168 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001169
David Brownca234692019-02-28 11:22:19 -07001170 ImageData {
1171 plain: copy,
1172 cipher: enc_copy,
1173 }
David Brown5c9e0f12019-01-09 16:34:33 -07001174 } else {
1175
David Brown76101572019-02-28 11:29:03 -07001176 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001177
1178 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001179 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001180
1181 let enc_copy: Option<Vec<u8>>;
1182
1183 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001184 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001185
David Brown76101572019-02-28 11:29:03 -07001186 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001187
1188 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001189 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001190
1191 enc_copy = Some(enc);
1192 } else {
1193 enc_copy = None;
1194 }
1195
David Brownca234692019-02-28 11:22:19 -07001196 ImageData {
1197 plain: copy,
1198 cipher: enc_copy,
1199 }
David Brown5c9e0f12019-01-09 16:34:33 -07001200 }
David Brown5c9e0f12019-01-09 16:34:33 -07001201}
1202
David Brown5c9e0f12019-01-09 16:34:33 -07001203fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001204 if Caps::EcdsaP224.present() {
1205 panic!("Ecdsa P224 not supported in Simulator");
1206 }
David Brown5c9e0f12019-01-09 16:34:33 -07001207
David Brownb8882112019-01-11 14:04:11 -07001208 if Caps::EncKw.present() {
1209 if Caps::RSA2048.present() {
1210 TlvGen::new_rsa_kw()
1211 } else if Caps::EcdsaP256.present() {
1212 TlvGen::new_ecdsa_kw()
1213 } else {
1214 TlvGen::new_enc_kw()
1215 }
1216 } else if Caps::EncRsa.present() {
1217 if Caps::RSA2048.present() {
1218 TlvGen::new_sig_enc_rsa()
1219 } else {
1220 TlvGen::new_enc_rsa()
1221 }
1222 } else {
1223 // The non-encrypted configuration.
1224 if Caps::RSA2048.present() {
1225 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001226 } else if Caps::RSA3072.present() {
1227 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001228 } else if Caps::EcdsaP256.present() {
1229 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001230 } else if Caps::Ed25519.present() {
1231 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001232 } else {
1233 TlvGen::new_hash_only()
1234 }
1235 }
David Brown5c9e0f12019-01-09 16:34:33 -07001236}
1237
David Brownca234692019-02-28 11:22:19 -07001238impl ImageData {
1239 /// Find the image contents for the given slot. This assumes that slot 0
1240 /// is unencrypted, and slot 1 is encrypted.
1241 fn find(&self, slot: usize) -> &Vec<u8> {
1242 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1243 match (encrypted, slot) {
1244 (false, _) => &self.plain,
1245 (true, 0) => &self.plain,
1246 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1247 _ => panic!("Invalid slot requested"),
1248 }
David Brown5c9e0f12019-01-09 16:34:33 -07001249 }
1250}
1251
David Brown5c9e0f12019-01-09 16:34:33 -07001252/// Verify that given image is present in the flash at the given offset.
David Brown3b090212019-07-30 15:59:28 -06001253fn verify_image(flash: &SimMultiFlash, slot: &SlotInfo, images: &ImageData) -> bool {
1254 let image = images.find(slot.index);
David Brown5c9e0f12019-01-09 16:34:33 -07001255 let buf = image.as_slice();
David Brown3b090212019-07-30 15:59:28 -06001256 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001257
1258 let mut copy = vec![0u8; buf.len()];
David Brown3b090212019-07-30 15:59:28 -06001259 let offset = slot.base_off;
David Brown76101572019-02-28 11:29:03 -07001260 let dev = flash.get(&dev_id).unwrap();
1261 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001262
1263 if buf != &copy[..] {
1264 for i in 0 .. buf.len() {
1265 if buf[i] != copy[i] {
David Brownc3898d62019-08-05 14:20:02 -06001266 info!("First failure for slot{} at {:#x} ({:#x} within) {:#x}!={:#x}",
1267 slot.index, offset + i, i, buf[i], copy[i]);
David Brown5c9e0f12019-01-09 16:34:33 -07001268 break;
1269 }
1270 }
1271 false
1272 } else {
1273 true
1274 }
1275}
1276
David Brown3b090212019-07-30 15:59:28 -06001277fn verify_trailer(flash: &SimMultiFlash, slot: &SlotInfo,
David Brown5c9e0f12019-01-09 16:34:33 -07001278 magic: Option<u8>, image_ok: Option<u8>,
1279 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001280 if Caps::OverwriteUpgrade.present() {
1281 return true;
1282 }
David Brown5c9e0f12019-01-09 16:34:33 -07001283
David Brown3b090212019-07-30 15:59:28 -06001284 let offset = slot.trailer_off + c::boot_max_align();
1285 let dev_id = slot.dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001286 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001287 let mut failed = false;
1288
David Brown76101572019-02-28 11:29:03 -07001289 let dev = flash.get(&dev_id).unwrap();
1290 let erased_val = dev.erased_val();
1291 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001292
1293 failed |= match magic {
1294 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001295 if v == 1 && &copy[24..] != MAGIC.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -07001296 warn!("\"magic\" mismatch at {:#x}", offset);
1297 true
1298 } else if v == 3 {
1299 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001300 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001301 warn!("\"magic\" mismatch at {:#x}", offset);
1302 true
1303 } else {
1304 false
1305 }
1306 } else {
1307 false
1308 }
1309 },
1310 None => false,
1311 };
1312
1313 failed |= match image_ok {
1314 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001315 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001316 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1317 true
1318 } else {
1319 false
1320 }
1321 },
1322 None => false,
1323 };
1324
1325 failed |= match copy_done {
1326 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001327 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001328 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1329 true
1330 } else {
1331 false
1332 }
1333 },
1334 None => false,
1335 };
1336
1337 !failed
1338}
1339
1340/// The image header
1341#[repr(C)]
1342pub struct ImageHeader {
1343 magic: u32,
1344 load_addr: u32,
1345 hdr_size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001346 protect_tlv_size: u16,
David Brown5c9e0f12019-01-09 16:34:33 -07001347 img_size: u32,
1348 flags: u32,
1349 ver: ImageVersion,
1350 _pad2: u32,
1351}
1352
1353impl AsRaw for ImageHeader {}
1354
1355#[repr(C)]
David Brownc3898d62019-08-05 14:20:02 -06001356#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001357pub struct ImageVersion {
David Brown7a81c4b2019-07-29 15:20:21 -06001358 pub major: u8,
1359 pub minor: u8,
1360 pub revision: u16,
1361 pub build_num: u32,
David Brown5c9e0f12019-01-09 16:34:33 -07001362}
1363
David Brownc3898d62019-08-05 14:20:02 -06001364#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001365pub struct SlotInfo {
1366 pub base_off: usize,
1367 pub trailer_off: usize,
1368 pub len: usize,
David Brown3b090212019-07-30 15:59:28 -06001369 // Which slot within this device.
1370 pub index: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001371 pub dev_id: u8,
1372}
1373
David Brown5c9e0f12019-01-09 16:34:33 -07001374const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1375 0x60, 0xd2, 0xef, 0x7f,
1376 0x35, 0x52, 0x50, 0x0f,
1377 0x2c, 0xb6, 0x79, 0x80]);
1378
1379// Replicates defines found in bootutil.h
1380const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1381const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1382
1383const BOOT_FLAG_SET: Option<u8> = Some(1);
1384const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1385
1386/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001387pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1388 let dev = flash.get_mut(&slot.dev_id).unwrap();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001389 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown76101572019-02-28 11:29:03 -07001390 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001391}
1392
1393/// Writes the image_ok flag which, guess what, tells the bootloader
1394/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001395fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1396 let dev = flash.get_mut(&slot.dev_id).unwrap();
1397 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001398 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001399 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001400 let align = dev.align();
1401 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001402}
1403
1404// Drop some pseudo-random gibberish onto the data.
1405fn splat(data: &mut [u8], seed: usize) {
1406 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1407 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1408 rng.fill_bytes(data);
1409}
1410
1411/// Return a read-only view into the raw bytes of this object
1412trait AsRaw : Sized {
1413 fn as_raw<'a>(&'a self) -> &'a [u8] {
1414 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1415 mem::size_of::<Self>()) }
1416 }
1417}
1418
1419pub fn show_sizes() {
1420 // This isn't panic safe.
1421 for min in &[1, 2, 4, 8] {
1422 let msize = c::boot_trailer_sz(*min);
1423 println!("{:2}: {} (0x{:x})", min, msize, msize);
1424 }
1425}