blob: 6b351f85bebb081cb8cfb86a2d0a51151ca8117d [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::{
7 mem,
8 slice,
9};
10use aes_ctr::{
11 Aes128Ctr,
12 stream_cipher::{
13 generic_array::GenericArray,
14 NewFixStreamCipher,
15 StreamCipherCore,
16 },
17};
18
David Brown76101572019-02-28 11:29:03 -070019use simflash::{Flash, SimFlash, SimMultiFlash};
David Browne5133242019-02-28 11:05:19 -070020use mcuboot_sys::{c, AreaDesc, FlashId};
21use crate::{
22 ALL_DEVICES,
23 DeviceName,
24};
David Brown5c9e0f12019-01-09 16:34:33 -070025use crate::caps::Caps;
David Brownc3898d62019-08-05 14:20:02 -060026use crate::depends::{
27 BoringDep,
28 Depender,
29 DepTest,
30 PairDep,
31 UpgradeInfo,
32};
David Brown43643dd2019-01-11 15:43:28 -070033use crate::tlv::{ManifestGen, TlvGen, TlvFlags, AES_SEC_KEY};
David Brown5c9e0f12019-01-09 16:34:33 -070034
David Browne5133242019-02-28 11:05:19 -070035/// A builder for Images. This describes a single run of the simulator,
36/// capturing the configuration of a particular set of devices, including
37/// the flash simulator(s) and the information about the slots.
38#[derive(Clone)]
39pub struct ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070040 flash: SimMultiFlash,
David Browne5133242019-02-28 11:05:19 -070041 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070042 slots: Vec<[SlotInfo; 2]>,
David Browne5133242019-02-28 11:05:19 -070043}
44
David Brown998aa8d2019-02-28 10:54:50 -070045/// Images represents the state of a simulation for a given set of images.
David Brown76101572019-02-28 11:29:03 -070046/// The flash holds the state of the simulated flash, whereas primaries
David Brown998aa8d2019-02-28 10:54:50 -070047/// and upgrades hold the expected contents of these images.
48pub struct Images {
David Brown76101572019-02-28 11:29:03 -070049 flash: SimMultiFlash,
David Brownca234692019-02-28 11:22:19 -070050 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070051 images: Vec<OneImage>,
52 total_count: Option<i32>,
53}
54
55/// When doing multi-image, there is an instance of this information for
56/// each of the images. Single image there will be one of these.
57struct OneImage {
David Brownca234692019-02-28 11:22:19 -070058 slots: [SlotInfo; 2],
59 primaries: ImageData,
60 upgrades: ImageData,
David Brownca234692019-02-28 11:22:19 -070061}
62
63/// The Rust-side representation of an image. For unencrypted images, this
64/// is just the unencrypted payload. For encrypted images, we store both
65/// the encrypted and the plaintext.
66struct ImageData {
67 plain: Vec<u8>,
68 cipher: Option<Vec<u8>>,
David Brown998aa8d2019-02-28 10:54:50 -070069}
70
David Browne5133242019-02-28 11:05:19 -070071impl ImagesBuilder {
David Brown5bc62c62019-03-05 12:11:48 -070072 /// Construct a new image builder for the given device. Returns
73 /// Some(builder) if is possible to test this configuration, or None if
74 /// not possible (for example, if there aren't enough image slots).
75 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Option<Self> {
David Brown76101572019-02-28 11:29:03 -070076 let (flash, areadesc) = Self::make_device(device, align, erased_val);
David Browne5133242019-02-28 11:05:19 -070077
David Brown06ef06e2019-03-05 12:28:10 -070078 let num_images = Caps::get_num_images();
David Browne5133242019-02-28 11:05:19 -070079
David Brown06ef06e2019-03-05 12:28:10 -070080 let mut slots = Vec::with_capacity(num_images);
81 for image in 0..num_images {
82 // This mapping must match that defined in
83 // `boot/zephyr/include/sysflash/sysflash.h`.
84 let id0 = match image {
85 0 => FlashId::Image0,
86 1 => FlashId::Image2,
87 _ => panic!("More than 2 images not supported"),
88 };
89 let (primary_base, primary_len, primary_dev_id) = match areadesc.find(id0) {
90 Some(info) => info,
91 None => return None,
92 };
93 let id1 = match image {
94 0 => FlashId::Image1,
95 1 => FlashId::Image3,
96 _ => panic!("More than 2 images not supported"),
97 };
98 let (secondary_base, secondary_len, secondary_dev_id) = match areadesc.find(id1) {
99 Some(info) => info,
100 None => return None,
101 };
David Browne5133242019-02-28 11:05:19 -0700102
Christopher Collinsa1c12042019-05-23 14:00:28 -0700103 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 4;
David Browne5133242019-02-28 11:05:19 -0700104
David Brown06ef06e2019-03-05 12:28:10 -0700105 // Construct a primary image.
106 let primary = SlotInfo {
107 base_off: primary_base as usize,
108 trailer_off: primary_base + primary_len - offset_from_end,
109 len: primary_len as usize,
110 dev_id: primary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600111 index: 0,
David Brown06ef06e2019-03-05 12:28:10 -0700112 };
113
114 // And an upgrade image.
115 let secondary = SlotInfo {
116 base_off: secondary_base as usize,
117 trailer_off: secondary_base + secondary_len - offset_from_end,
118 len: secondary_len as usize,
119 dev_id: secondary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600120 index: 1,
David Brown06ef06e2019-03-05 12:28:10 -0700121 };
122
123 slots.push([primary, secondary]);
124 }
David Browne5133242019-02-28 11:05:19 -0700125
David Brown5bc62c62019-03-05 12:11:48 -0700126 Some(ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -0700127 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700128 areadesc: areadesc,
David Brown06ef06e2019-03-05 12:28:10 -0700129 slots: slots,
David Brown5bc62c62019-03-05 12:11:48 -0700130 })
David Browne5133242019-02-28 11:05:19 -0700131 }
132
133 pub fn each_device<F>(f: F)
134 where F: Fn(Self)
135 {
136 for &dev in ALL_DEVICES {
137 for &align in &[1, 2, 4, 8] {
138 for &erased_val in &[0, 0xff] {
David Brown5bc62c62019-03-05 12:11:48 -0700139 match Self::new(dev, align, erased_val) {
140 Some(run) => f(run),
141 None => warn!("Skipping {:?}, insufficient partitions", dev),
142 }
David Browne5133242019-02-28 11:05:19 -0700143 }
144 }
145 }
146 }
147
148 /// Construct an `Images` that doesn't expect an upgrade to happen.
David Brownc3898d62019-08-05 14:20:02 -0600149 pub fn make_no_upgrade_image(self, deps: &DepTest) -> Images {
150 let num_images = self.num_images();
David Brown76101572019-02-28 11:29:03 -0700151 let mut flash = self.flash;
David Brownc3898d62019-08-05 14:20:02 -0600152 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
153 let dep: Box<dyn Depender> = if num_images > 1 {
154 Box::new(PairDep::new(num_images, image_num, deps))
155 } else {
156 Box::new(BoringDep(image_num))
157 };
158 let primaries = install_image(&mut flash, &slots[0], 42784, &*dep, false);
159 let upgrades = install_image(&mut flash, &slots[1], 46928, &*dep, false);
David Brown84b49f72019-03-01 10:58:22 -0700160 OneImage {
161 slots: slots,
162 primaries: primaries,
163 upgrades: upgrades,
164 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700165 Images {
David Brown76101572019-02-28 11:29:03 -0700166 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700167 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700168 images: images,
David Browne5133242019-02-28 11:05:19 -0700169 total_count: None,
170 }
171 }
172
David Brownc3898d62019-08-05 14:20:02 -0600173 pub fn make_image(self, deps: &DepTest, permanent: bool) -> Images {
174 let mut images = self.make_no_upgrade_image(deps);
David Brown84b49f72019-03-01 10:58:22 -0700175 for image in &images.images {
176 mark_upgrade(&mut images.flash, &image.slots[1]);
177 }
David Browne5133242019-02-28 11:05:19 -0700178
179 // upgrades without fails, counts number of flash operations
Fabio Utziged4a5362019-07-30 12:43:23 -0300180 let total_count = match images.run_basic_upgrade(permanent) {
David Browne5133242019-02-28 11:05:19 -0700181 Ok(v) => v,
182 Err(_) => {
183 panic!("Unable to perform basic upgrade");
184 },
185 };
186
187 images.total_count = Some(total_count);
188 images
189 }
190
191 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700192 let mut bad_flash = self.flash;
David Brownc3898d62019-08-05 14:20:02 -0600193 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
194 let dep = BoringDep(image_num);
195 let primaries = install_image(&mut bad_flash, &slots[0], 32784, &dep, false);
196 let upgrades = install_image(&mut bad_flash, &slots[1], 41928, &dep, true);
David Brown84b49f72019-03-01 10:58:22 -0700197 OneImage {
198 slots: slots,
199 primaries: primaries,
200 upgrades: upgrades,
201 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700202 Images {
David Brown76101572019-02-28 11:29:03 -0700203 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700204 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700205 images: images,
David Browne5133242019-02-28 11:05:19 -0700206 total_count: None,
207 }
208 }
209
210 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700211 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700212 match device {
213 DeviceName::Stm32f4 => {
214 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700215 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
216 64 * 1024,
217 128 * 1024, 128 * 1024, 128 * 1024],
218 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700219 let dev_id = 0;
220 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700221 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700222 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
223 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
224 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
225
David Brown76101572019-02-28 11:29:03 -0700226 let mut flash = SimMultiFlash::new();
227 flash.insert(dev_id, dev);
228 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700229 }
230 DeviceName::K64f => {
231 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700232 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700233
234 let dev_id = 0;
235 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700236 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700237 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
238 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
239 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
240
David Brown76101572019-02-28 11:29:03 -0700241 let mut flash = SimMultiFlash::new();
242 flash.insert(dev_id, dev);
243 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700244 }
245 DeviceName::K64fBig => {
246 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
247 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700248 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700249
250 let dev_id = 0;
251 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700252 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700253 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
254 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
255 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
256
David Brown76101572019-02-28 11:29:03 -0700257 let mut flash = SimMultiFlash::new();
258 flash.insert(dev_id, dev);
259 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700260 }
261 DeviceName::Nrf52840 => {
262 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
263 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700264 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700265
266 let dev_id = 0;
267 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700268 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700269 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
270 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
271 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
272
David Brown76101572019-02-28 11:29:03 -0700273 let mut flash = SimMultiFlash::new();
274 flash.insert(dev_id, dev);
275 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700276 }
277 DeviceName::Nrf52840SpiFlash => {
278 // Simulate nrf52840 with external SPI flash. The external SPI flash
279 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700280 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
281 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700282
283 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700284 areadesc.add_flash_sectors(0, &dev0);
285 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700286
287 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
288 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
289 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
290
David Brown76101572019-02-28 11:29:03 -0700291 let mut flash = SimMultiFlash::new();
292 flash.insert(0, dev0);
293 flash.insert(1, dev1);
294 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700295 }
David Brown2bff6472019-03-05 13:58:35 -0700296 DeviceName::K64fMulti => {
297 // NXP style flash, but larger, to support multiple images.
298 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
299
300 let dev_id = 0;
301 let mut areadesc = AreaDesc::new();
302 areadesc.add_flash_sectors(dev_id, &dev);
303 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
304 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
305 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
306 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
307 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
308
309 let mut flash = SimMultiFlash::new();
310 flash.insert(dev_id, dev);
311 (flash, areadesc)
312 }
David Browne5133242019-02-28 11:05:19 -0700313 }
314 }
David Brownc3898d62019-08-05 14:20:02 -0600315
316 pub fn num_images(&self) -> usize {
317 self.slots.len()
318 }
David Browne5133242019-02-28 11:05:19 -0700319}
320
David Brown5c9e0f12019-01-09 16:34:33 -0700321impl Images {
322 /// A simple upgrade without forced failures.
323 ///
324 /// Returns the number of flash operations which can later be used to
325 /// inject failures at chosen steps.
Fabio Utziged4a5362019-07-30 12:43:23 -0300326 pub fn run_basic_upgrade(&self, permanent: bool) -> Result<i32, ()> {
327 let (flash, total_count) = self.try_upgrade(None, permanent);
David Brown5c9e0f12019-01-09 16:34:33 -0700328 info!("Total flash operation count={}", total_count);
329
David Brown84b49f72019-03-01 10:58:22 -0700330 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700331 warn!("Image mismatch after first boot");
332 Err(())
333 } else {
334 Ok(total_count)
335 }
336 }
337
David Brownc3898d62019-08-05 14:20:02 -0600338 /// Test a simple upgrade, with dependencies given, and verify that the
339 /// image does as is described in the test.
340 pub fn run_check_deps(&self, deps: &DepTest) -> bool {
341 let (flash, _) = self.try_upgrade(None, true);
342
343 self.verify_dep_images(&flash, deps)
344 }
345
David Brown5c9e0f12019-01-09 16:34:33 -0700346 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700347 if Caps::OverwriteUpgrade.present() {
348 return false;
349 }
David Brown5c9e0f12019-01-09 16:34:33 -0700350
David Brown5c9e0f12019-01-09 16:34:33 -0700351 let mut fails = 0;
352
353 // FIXME: this test would also pass if no swap is ever performed???
354 if Caps::SwapUpgrade.present() {
355 for count in 2 .. 5 {
356 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700357 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700358 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700359 error!("Revert failure on count {}", count);
360 fails += 1;
361 }
362 }
363 }
364
365 fails > 0
366 }
367
368 pub fn run_perm_with_fails(&self) -> bool {
369 let mut fails = 0;
370 let total_flash_ops = self.total_count.unwrap();
371
372 // Let's try an image halfway through.
373 for i in 1 .. total_flash_ops {
374 info!("Try interruption at {}", i);
Fabio Utziged4a5362019-07-30 12:43:23 -0300375 let (flash, count) = self.try_upgrade(Some(i), true);
David Brown5c9e0f12019-01-09 16:34:33 -0700376 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700377 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700378 warn!("FAIL at step {} of {}", i, total_flash_ops);
379 fails += 1;
380 }
381
David Brown84b49f72019-03-01 10:58:22 -0700382 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
383 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100384 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700385 fails += 1;
386 }
387
David Brown84b49f72019-03-01 10:58:22 -0700388 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
389 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100390 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700391 fails += 1;
392 }
393
394 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700395 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100396 warn!("Secondary slot FAIL at step {} of {}",
397 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700398 fails += 1;
399 }
400 }
401 }
402
403 if fails > 0 {
404 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
405 fails as f32 * 100.0 / total_flash_ops as f32);
406 }
407
408 fails > 0
409 }
410
David Brown5c9e0f12019-01-09 16:34:33 -0700411 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
412 let mut fails = 0;
413 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700414 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700415 info!("Random interruptions at reset points={:?}", total_counts);
416
David Brown84b49f72019-03-01 10:58:22 -0700417 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100418 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700419 // TODO: This result is ignored.
420 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700421 } else {
422 true
423 };
David Vincze2d736ad2019-02-18 11:50:22 +0100424 if !primary_slot_ok || !secondary_slot_ok {
425 error!("Image mismatch after random interrupts: primary slot={} \
426 secondary slot={}",
427 if primary_slot_ok { "ok" } else { "fail" },
428 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700429 fails += 1;
430 }
David Brown84b49f72019-03-01 10:58:22 -0700431 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
432 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100433 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700434 fails += 1;
435 }
David Brown84b49f72019-03-01 10:58:22 -0700436 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
437 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100438 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700439 fails += 1;
440 }
441
442 if fails > 0 {
443 error!("Error testing perm upgrade with {} fails", total_fails);
444 }
445
446 fails > 0
447 }
448
David Brown5c9e0f12019-01-09 16:34:33 -0700449 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700450 if Caps::OverwriteUpgrade.present() {
451 return false;
452 }
David Brown5c9e0f12019-01-09 16:34:33 -0700453
David Brown5c9e0f12019-01-09 16:34:33 -0700454 let mut fails = 0;
455
456 if Caps::SwapUpgrade.present() {
Fabio Utziged4a5362019-07-30 12:43:23 -0300457 for i in 1 .. self.total_count.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -0700458 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700459 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700460 error!("Revert failed at interruption {}", i);
461 fails += 1;
462 }
463 }
464 }
465
466 fails > 0
467 }
468
David Brown5c9e0f12019-01-09 16:34:33 -0700469 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700470 if Caps::OverwriteUpgrade.present() {
471 return false;
472 }
David Brown5c9e0f12019-01-09 16:34:33 -0700473
David Brown76101572019-02-28 11:29:03 -0700474 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700475 let mut fails = 0;
476
477 info!("Try norevert");
478
479 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700480 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700481 if result != 0 {
482 warn!("Failed first boot");
483 fails += 1;
484 }
485
486 //FIXME: copy_done is written by boot_go, is it ok if no copy
487 // was ever done?
488
David Brown84b49f72019-03-01 10:58:22 -0700489 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100490 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700491 fails += 1;
492 }
David Brown84b49f72019-03-01 10:58:22 -0700493 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
494 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100495 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700496 fails += 1;
497 }
David Brown84b49f72019-03-01 10:58:22 -0700498 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
499 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100500 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700501 fails += 1;
502 }
503
David Vincze2d736ad2019-02-18 11:50:22 +0100504 // Marks image in the primary slot as permanent,
505 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700506 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700507
David Brown84b49f72019-03-01 10:58:22 -0700508 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
509 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100510 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700511 fails += 1;
512 }
513
David Brown76101572019-02-28 11:29:03 -0700514 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700515 if result != 0 {
516 warn!("Failed second boot");
517 fails += 1;
518 }
519
David Brown84b49f72019-03-01 10:58:22 -0700520 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
521 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100522 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700523 fails += 1;
524 }
David Brown84b49f72019-03-01 10:58:22 -0700525 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700526 warn!("Failed image verification");
527 fails += 1;
528 }
529
530 if fails > 0 {
531 error!("Error running upgrade without revert");
532 }
533
534 fails > 0
535 }
536
David Vincze2d736ad2019-02-18 11:50:22 +0100537 // Tests a new image written to the primary slot that already has magic and
538 // image_ok set while there is no image on the secondary slot, so no revert
539 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700540 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700541 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700542 let mut fails = 0;
543
544 info!("Try non-revert on imgtool generated image");
545
David Brown84b49f72019-03-01 10:58:22 -0700546 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700547
David Vincze2d736ad2019-02-18 11:50:22 +0100548 // This simulates writing an image created by imgtool to
549 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700550 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
551 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100552 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700553 fails += 1;
554 }
555
556 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700557 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700558 if result != 0 {
559 warn!("Failed first boot");
560 fails += 1;
561 }
562
563 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700564 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700565 warn!("Failed image verification");
566 fails += 1;
567 }
David Brown84b49f72019-03-01 10:58:22 -0700568 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
569 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100570 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700571 fails += 1;
572 }
David Brown84b49f72019-03-01 10:58:22 -0700573 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
574 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100575 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700576 fails += 1;
577 }
578
579 if fails > 0 {
580 error!("Expected a non revert with new image");
581 }
582
583 fails > 0
584 }
585
David Vincze2d736ad2019-02-18 11:50:22 +0100586 // Tests a new image written to the primary slot that already has magic and
587 // image_ok set while there is no image on the secondary slot, so no revert
588 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700589 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700590 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700591 let mut fails = 0;
592
593 info!("Try upgrade image with bad signature");
594
David Brown84b49f72019-03-01 10:58:22 -0700595 self.mark_upgrades(&mut flash, 0);
596 self.mark_permanent_upgrades(&mut flash, 0);
597 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700598
David Brown84b49f72019-03-01 10:58:22 -0700599 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
600 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100601 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700602 fails += 1;
603 }
604
605 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700606 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700607 if result != 0 {
608 warn!("Failed first boot");
609 fails += 1;
610 }
611
612 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700613 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700614 warn!("Failed image verification");
615 fails += 1;
616 }
David Brown84b49f72019-03-01 10:58:22 -0700617 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
618 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100619 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700620 fails += 1;
621 }
622
623 if fails > 0 {
624 error!("Expected an upgrade failure when image has bad signature");
625 }
626
627 fails > 0
628 }
629
David Brown5c9e0f12019-01-09 16:34:33 -0700630 fn trailer_sz(&self, align: usize) -> usize {
631 c::boot_trailer_sz(align as u8) as usize
632 }
633
634 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700635 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700636 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
637 32
638 } else {
639 0
640 };
David Brown5c9e0f12019-01-09 16:34:33 -0700641
Christopher Collinsa1c12042019-05-23 14:00:28 -0700642 self.trailer_sz(align) - (16 + 32 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700643 }
644
645 /// This test runs a simple upgrade with no fails in the images, but
646 /// allowing for fails in the status area. This should run to the end
647 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700648 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100649 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700650 return false;
651 }
652
David Brown76101572019-02-28 11:29:03 -0700653 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700654 let mut fails = 0;
655
656 info!("Try swap with status fails");
657
David Brown84b49f72019-03-01 10:58:22 -0700658 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700659 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700660
David Brown76101572019-02-28 11:29:03 -0700661 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700662 if result != 0 {
663 warn!("Failed!");
664 fails += 1;
665 }
666
667 // Failed writes to the marked "bad" region don't assert anymore.
668 // Any detected assert() is happening in another part of the code.
669 if asserts != 0 {
670 warn!("At least one assert() was called");
671 fails += 1;
672 }
673
David Brown84b49f72019-03-01 10:58:22 -0700674 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
675 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100676 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700677 fails += 1;
678 }
679
David Brown84b49f72019-03-01 10:58:22 -0700680 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700681 warn!("Failed image verification");
682 fails += 1;
683 }
684
David Vincze2d736ad2019-02-18 11:50:22 +0100685 info!("validate primary slot enabled; \
686 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700687 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700688 if result != 0 {
689 warn!("Failed!");
690 fails += 1;
691 }
692
693 if fails > 0 {
694 error!("Error running upgrade with status write fails");
695 }
696
697 fails > 0
698 }
699
700 /// This test runs a simple upgrade with no fails in the images, but
701 /// allowing for fails in the status area. This should run to the end
702 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700703 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700704 if Caps::OverwriteUpgrade.present() {
705 false
David Vincze2d736ad2019-02-18 11:50:22 +0100706 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700707
David Brown76101572019-02-28 11:29:03 -0700708 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700709 let mut fails = 0;
710 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700711
David Brown85904a82019-01-11 13:45:12 -0700712 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700713
David Brown85904a82019-01-11 13:45:12 -0700714 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700715
David Brown84b49f72019-03-01 10:58:22 -0700716 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700717 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700718
719 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700720 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700721 if asserts != 0 {
722 warn!("At least one assert() was called");
723 fails += 1;
724 }
725
David Brown76101572019-02-28 11:29:03 -0700726 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700727
728 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700729 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700730
731 // This might throw no asserts, for large sector devices, where
732 // a single failure writing is indistinguishable from no failure,
733 // or throw a single assert for small sector devices that fail
734 // multiple times...
735 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100736 warn!("Expected single assert validating the primary slot, \
737 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700738 fails += 1;
739 }
740
741 if fails > 0 {
742 error!("Error running upgrade with status write fails");
743 }
744
745 fails > 0
746 } else {
David Brown76101572019-02-28 11:29:03 -0700747 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700748 let mut fails = 0;
749
750 info!("Try interrupted swap with status fails");
751
David Brown84b49f72019-03-01 10:58:22 -0700752 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700753 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700754
755 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700756 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700757 if asserts == 0 {
758 warn!("No assert() detected");
759 fails += 1;
760 }
761
762 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700763 }
David Brown5c9e0f12019-01-09 16:34:33 -0700764 }
765
766 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700767 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700768 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700769 if Caps::OverwriteUpgrade.present() {
770 return;
771 }
772
David Brown84b49f72019-03-01 10:58:22 -0700773 // Set this for each image.
774 for image in &self.images {
775 let dev_id = &image.slots[slot].dev_id;
776 let dev = flash.get_mut(&dev_id).unwrap();
777 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -0700778 let off = &image.slots[slot].base_off;
779 let len = &image.slots[slot].len;
David Brown84b49f72019-03-01 10:58:22 -0700780 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700781
David Brown84b49f72019-03-01 10:58:22 -0700782 // Mark the status area as a bad area
783 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
784 }
David Brown5c9e0f12019-01-09 16:34:33 -0700785 }
786
David Brown76101572019-02-28 11:29:03 -0700787 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100788 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700789 return;
790 }
791
David Brown84b49f72019-03-01 10:58:22 -0700792 for image in &self.images {
793 let dev_id = &image.slots[slot].dev_id;
794 let dev = flash.get_mut(&dev_id).unwrap();
795 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700796
David Brown84b49f72019-03-01 10:58:22 -0700797 // Disabling write verification the only assert triggered by
798 // boot_go should be checking for integrity of status bytes.
799 dev.set_verify_writes(false);
800 }
David Brown5c9e0f12019-01-09 16:34:33 -0700801 }
802
David Browndb505822019-03-01 10:04:20 -0700803 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
804 /// of the number of flash operations done total.
Fabio Utziged4a5362019-07-30 12:43:23 -0300805 fn try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32) {
David Browndb505822019-03-01 10:04:20 -0700806 // Clone the flash to have a new copy.
807 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700808
Fabio Utziged4a5362019-07-30 12:43:23 -0300809 if permanent {
810 self.mark_permanent_upgrades(&mut flash, 1);
811 }
David Brown5c9e0f12019-01-09 16:34:33 -0700812
David Browndb505822019-03-01 10:04:20 -0700813 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700814
David Browndb505822019-03-01 10:04:20 -0700815 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
816 (-0x13579, _) => (true, stop.unwrap()),
817 (0, _) => (false, -counter),
818 (x, _) => panic!("Unknown return: {}", x),
819 };
David Brown5c9e0f12019-01-09 16:34:33 -0700820
David Browndb505822019-03-01 10:04:20 -0700821 counter = 0;
822 if first_interrupted {
823 // fl.dump();
824 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
825 (-0x13579, _) => panic!("Shouldn't stop again"),
826 (0, _) => (),
827 (x, _) => panic!("Unknown return: {}", x),
828 }
829 }
David Brown5c9e0f12019-01-09 16:34:33 -0700830
David Browndb505822019-03-01 10:04:20 -0700831 (flash, count - counter)
832 }
833
834 fn try_revert(&self, count: usize) -> SimMultiFlash {
835 let mut flash = self.flash.clone();
836
837 // fl.write_file("image0.bin").unwrap();
838 for i in 0 .. count {
839 info!("Running boot pass {}", i + 1);
840 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
841 }
842 flash
843 }
844
845 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
846 let mut flash = self.flash.clone();
847 let mut fails = 0;
848
849 let mut counter = stop;
850 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
851 if x != -0x13579 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700852 warn!("Should have stopped test at interruption point");
David Browndb505822019-03-01 10:04:20 -0700853 fails += 1;
854 }
855
Fabio Utzig8af7f792019-07-30 12:40:01 -0300856 // In a multi-image setup, copy done might be set if any number of
857 // images was already successfully swapped.
858 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
859 warn!("copy_done should be unset");
860 fails += 1;
861 }
862
David Browndb505822019-03-01 10:04:20 -0700863 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
864 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700865 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -0700866 fails += 1;
867 }
868
David Brown84b49f72019-03-01 10:58:22 -0700869 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700870 warn!("Image in the primary slot before revert is invalid at stop={}",
871 stop);
872 fails += 1;
873 }
David Brown84b49f72019-03-01 10:58:22 -0700874 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700875 warn!("Image in the secondary slot before revert is invalid at stop={}",
876 stop);
877 fails += 1;
878 }
David Brown84b49f72019-03-01 10:58:22 -0700879 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
880 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700881 warn!("Mismatched trailer for the primary slot before revert");
882 fails += 1;
883 }
David Brown84b49f72019-03-01 10:58:22 -0700884 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
885 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700886 warn!("Mismatched trailer for the secondary slot before revert");
887 fails += 1;
888 }
889
890 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700891 let mut counter = stop;
892 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
893 if x != -0x13579 {
894 warn!("Should have stopped revert at interruption point");
895 fails += 1;
896 }
897
David Browndb505822019-03-01 10:04:20 -0700898 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
899 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700900 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -0700901 fails += 1;
902 }
903
David Brown84b49f72019-03-01 10:58:22 -0700904 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700905 warn!("Image in the primary slot after revert is invalid at stop={}",
906 stop);
907 fails += 1;
908 }
David Brown84b49f72019-03-01 10:58:22 -0700909 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700910 warn!("Image in the secondary slot after revert is invalid at stop={}",
911 stop);
912 fails += 1;
913 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700914
David Brown84b49f72019-03-01 10:58:22 -0700915 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
916 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700917 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -0700918 fails += 1;
919 }
David Brown84b49f72019-03-01 10:58:22 -0700920 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
921 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700922 warn!("Mismatched trailer for the secondary slot after revert");
923 fails += 1;
924 }
925
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700926 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
927 if x != 0 {
928 warn!("Should have finished 3rd boot");
929 fails += 1;
930 }
931
932 if !self.verify_images(&flash, 0, 0) {
933 warn!("Image in the primary slot is invalid on 1st boot after revert");
934 fails += 1;
935 }
936 if !self.verify_images(&flash, 1, 1) {
937 warn!("Image in the secondary slot is invalid on 1st boot after revert");
938 fails += 1;
939 }
940
David Browndb505822019-03-01 10:04:20 -0700941 fails > 0
942 }
943
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700944
David Browndb505822019-03-01 10:04:20 -0700945 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
946 let mut flash = self.flash.clone();
947
David Brown84b49f72019-03-01 10:58:22 -0700948 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700949
950 let mut rng = rand::thread_rng();
951 let mut resets = vec![0i32; count];
952 let mut remaining_ops = total_ops;
953 for i in 0 .. count {
954 let ops = Range::new(1, remaining_ops / 2);
955 let reset_counter = ops.ind_sample(&mut rng);
956 let mut counter = reset_counter;
957 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
958 (0, _) | (-0x13579, _) => (),
959 (x, _) => panic!("Unknown return: {}", x),
960 }
961 remaining_ops -= reset_counter;
962 resets[i] = reset_counter;
963 }
964
965 match c::boot_go(&mut flash, &self.areadesc, None, false) {
966 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700967 (0, _) => (),
968 (x, _) => panic!("Unknown return: {}", x),
969 }
David Brown5c9e0f12019-01-09 16:34:33 -0700970
David Browndb505822019-03-01 10:04:20 -0700971 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700972 }
David Brown84b49f72019-03-01 10:58:22 -0700973
974 /// Verify the image in the given flash device, the specified slot
975 /// against the expected image.
976 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
977 for image in &self.images {
David Brown3b090212019-07-30 15:59:28 -0600978 if !verify_image(flash, &image.slots[slot],
David Brown84b49f72019-03-01 10:58:22 -0700979 match against {
980 0 => &image.primaries,
981 1 => &image.upgrades,
982 _ => panic!("Invalid 'against'"),
983 }) {
984 return false;
985 }
986 }
987 true
988 }
989
David Brownc3898d62019-08-05 14:20:02 -0600990 /// Verify the images, according to the dependency test.
991 fn verify_dep_images(&self, flash: &SimMultiFlash, deps: &DepTest) -> bool {
992 for (image_num, (image, upgrade)) in self.images.iter().zip(deps.upgrades.iter()).enumerate() {
993 info!("Upgrade: slot:{}, {:?}", image_num, upgrade);
994 if !verify_image(flash, &image.slots[0],
995 match upgrade {
996 UpgradeInfo::Upgraded => &image.upgrades,
997 UpgradeInfo::Held => &image.primaries,
998 }) {
999 error!("Failed to upgrade properly: image: {}, upgrade: {:?}", image_num, upgrade);
1000 return true;
1001 }
1002 }
1003
1004 false
1005 }
1006
Fabio Utzig8af7f792019-07-30 12:40:01 -03001007 /// Verify that at least one of the trailers of the images have the
1008 /// specified values.
1009 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
1010 magic: Option<u8>, image_ok: Option<u8>,
1011 copy_done: Option<u8>) -> bool {
1012 for image in &self.images {
David Brown3b090212019-07-30 15:59:28 -06001013 if verify_trailer(flash, &image.slots[slot],
Fabio Utzig8af7f792019-07-30 12:40:01 -03001014 magic, image_ok, copy_done) {
1015 return true;
1016 }
1017 }
1018 false
1019 }
1020
David Brown84b49f72019-03-01 10:58:22 -07001021 /// Verify that the trailers of the images have the specified
1022 /// values.
1023 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
1024 magic: Option<u8>, image_ok: Option<u8>,
1025 copy_done: Option<u8>) -> bool {
1026 for image in &self.images {
David Brown3b090212019-07-30 15:59:28 -06001027 if !verify_trailer(flash, &image.slots[slot],
David Brown84b49f72019-03-01 10:58:22 -07001028 magic, image_ok, copy_done) {
1029 return false;
1030 }
1031 }
1032 true
1033 }
1034
1035 /// Mark each of the images for permanent upgrade.
1036 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1037 for image in &self.images {
1038 mark_permanent_upgrade(flash, &image.slots[slot]);
1039 }
1040 }
1041
1042 /// Mark each of the images for permanent upgrade.
1043 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1044 for image in &self.images {
1045 mark_upgrade(flash, &image.slots[slot]);
1046 }
1047 }
David Brown5c9e0f12019-01-09 16:34:33 -07001048}
1049
1050/// Show the flash layout.
1051#[allow(dead_code)]
1052fn show_flash(flash: &dyn Flash) {
1053 println!("---- Flash configuration ----");
1054 for sector in flash.sector_iter() {
1055 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1056 sector.num, sector.base, sector.size);
1057 }
1058 println!("");
1059}
1060
1061/// Install a "program" into the given image. This fakes the image header, or at least all of the
1062/// fields used by the given code. Returns a copy of the image that was written.
David Brown3b090212019-07-30 15:59:28 -06001063fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: usize,
David Brownc3898d62019-08-05 14:20:02 -06001064 deps: &dyn Depender, bad_sig: bool) -> ImageData {
David Brown3b090212019-07-30 15:59:28 -06001065 let offset = slot.base_off;
1066 let slot_len = slot.len;
1067 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001068
David Brown43643dd2019-01-11 15:43:28 -07001069 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001070
David Brownc3898d62019-08-05 14:20:02 -06001071 // Add the dependencies early to the tlv.
1072 for dep in deps.my_deps(offset, slot.index) {
1073 tlv.add_dependency(deps.other_id(), &dep);
1074 }
1075
David Brown5c9e0f12019-01-09 16:34:33 -07001076 const HDR_SIZE: usize = 32;
1077
1078 // Generate a boot header. Note that the size doesn't include the header.
1079 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001080 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001081 load_addr: 0,
1082 hdr_size: HDR_SIZE as u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001083 protect_tlv_size: tlv.protect_size(),
David Brown5c9e0f12019-01-09 16:34:33 -07001084 img_size: len as u32,
1085 flags: tlv.get_flags(),
David Brownc3898d62019-08-05 14:20:02 -06001086 ver: deps.my_version(offset, slot.index),
David Brown5c9e0f12019-01-09 16:34:33 -07001087 _pad2: 0,
1088 };
1089
1090 let mut b_header = [0; HDR_SIZE];
1091 b_header[..32].clone_from_slice(header.as_raw());
1092 assert_eq!(b_header.len(), HDR_SIZE);
1093
1094 tlv.add_bytes(&b_header);
1095
1096 // The core of the image itself is just pseudorandom data.
1097 let mut b_img = vec![0; len];
1098 splat(&mut b_img, offset);
1099
1100 // TLV signatures work over plain image
1101 tlv.add_bytes(&b_img);
1102
1103 // Generate encrypted images
1104 let flag = TlvFlags::ENCRYPTED as u32;
1105 let is_encrypted = (tlv.get_flags() & flag) == flag;
1106 let mut b_encimg = vec![];
1107 if is_encrypted {
1108 let key = GenericArray::from_slice(AES_SEC_KEY);
1109 let nonce = GenericArray::from_slice(&[0; 16]);
1110 let mut cipher = Aes128Ctr::new(&key, &nonce);
1111 b_encimg = b_img.clone();
1112 cipher.apply_keystream(&mut b_encimg);
1113 }
1114
1115 // Build the TLV itself.
1116 let mut b_tlv = if bad_sig {
1117 let good_sig = &mut tlv.make_tlv();
1118 vec![0; good_sig.len()]
1119 } else {
1120 tlv.make_tlv()
1121 };
1122
1123 // Pad the block to a flash alignment (8 bytes).
1124 while b_tlv.len() % 8 != 0 {
1125 //FIXME: should be erase_val?
1126 b_tlv.push(0xFF);
1127 }
1128
1129 let mut buf = vec![];
1130 buf.append(&mut b_header.to_vec());
1131 buf.append(&mut b_img);
1132 buf.append(&mut b_tlv.clone());
1133
1134 let mut encbuf = vec![];
1135 if is_encrypted {
1136 encbuf.append(&mut b_header.to_vec());
1137 encbuf.append(&mut b_encimg);
1138 encbuf.append(&mut b_tlv);
1139 }
1140
David Vincze2d736ad2019-02-18 11:50:22 +01001141 // Since images are always non-encrypted in the primary slot, we first write
1142 // an encrypted image, re-read to use for verification, erase + flash
1143 // un-encrypted. In the secondary slot the image is written un-encrypted,
1144 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001145
David Brown76101572019-02-28 11:29:03 -07001146 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001147
David Brown3b090212019-07-30 15:59:28 -06001148 if slot.index == 0 {
David Brown5c9e0f12019-01-09 16:34:33 -07001149 let enc_copy: Option<Vec<u8>>;
1150
1151 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001152 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001153
1154 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001155 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001156
1157 enc_copy = Some(enc);
1158
David Brown76101572019-02-28 11:29:03 -07001159 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001160 } else {
1161 enc_copy = None;
1162 }
1163
David Brown76101572019-02-28 11:29:03 -07001164 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001165
1166 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001167 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001168
David Brownca234692019-02-28 11:22:19 -07001169 ImageData {
1170 plain: copy,
1171 cipher: enc_copy,
1172 }
David Brown5c9e0f12019-01-09 16:34:33 -07001173 } else {
1174
David Brown76101572019-02-28 11:29:03 -07001175 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001176
1177 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001178 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001179
1180 let enc_copy: Option<Vec<u8>>;
1181
1182 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001183 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001184
David Brown76101572019-02-28 11:29:03 -07001185 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001186
1187 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001188 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001189
1190 enc_copy = Some(enc);
1191 } else {
1192 enc_copy = None;
1193 }
1194
David Brownca234692019-02-28 11:22:19 -07001195 ImageData {
1196 plain: copy,
1197 cipher: enc_copy,
1198 }
David Brown5c9e0f12019-01-09 16:34:33 -07001199 }
David Brown5c9e0f12019-01-09 16:34:33 -07001200}
1201
David Brown5c9e0f12019-01-09 16:34:33 -07001202fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001203 if Caps::EcdsaP224.present() {
1204 panic!("Ecdsa P224 not supported in Simulator");
1205 }
David Brown5c9e0f12019-01-09 16:34:33 -07001206
David Brownb8882112019-01-11 14:04:11 -07001207 if Caps::EncKw.present() {
1208 if Caps::RSA2048.present() {
1209 TlvGen::new_rsa_kw()
1210 } else if Caps::EcdsaP256.present() {
1211 TlvGen::new_ecdsa_kw()
1212 } else {
1213 TlvGen::new_enc_kw()
1214 }
1215 } else if Caps::EncRsa.present() {
1216 if Caps::RSA2048.present() {
1217 TlvGen::new_sig_enc_rsa()
1218 } else {
1219 TlvGen::new_enc_rsa()
1220 }
1221 } else {
1222 // The non-encrypted configuration.
1223 if Caps::RSA2048.present() {
1224 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001225 } else if Caps::RSA3072.present() {
1226 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001227 } else if Caps::EcdsaP256.present() {
1228 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001229 } else if Caps::Ed25519.present() {
1230 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001231 } else {
1232 TlvGen::new_hash_only()
1233 }
1234 }
David Brown5c9e0f12019-01-09 16:34:33 -07001235}
1236
David Brownca234692019-02-28 11:22:19 -07001237impl ImageData {
1238 /// Find the image contents for the given slot. This assumes that slot 0
1239 /// is unencrypted, and slot 1 is encrypted.
1240 fn find(&self, slot: usize) -> &Vec<u8> {
1241 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1242 match (encrypted, slot) {
1243 (false, _) => &self.plain,
1244 (true, 0) => &self.plain,
1245 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1246 _ => panic!("Invalid slot requested"),
1247 }
David Brown5c9e0f12019-01-09 16:34:33 -07001248 }
1249}
1250
David Brown5c9e0f12019-01-09 16:34:33 -07001251/// Verify that given image is present in the flash at the given offset.
David Brown3b090212019-07-30 15:59:28 -06001252fn verify_image(flash: &SimMultiFlash, slot: &SlotInfo, images: &ImageData) -> bool {
1253 let image = images.find(slot.index);
David Brown5c9e0f12019-01-09 16:34:33 -07001254 let buf = image.as_slice();
David Brown3b090212019-07-30 15:59:28 -06001255 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001256
1257 let mut copy = vec![0u8; buf.len()];
David Brown3b090212019-07-30 15:59:28 -06001258 let offset = slot.base_off;
David Brown76101572019-02-28 11:29:03 -07001259 let dev = flash.get(&dev_id).unwrap();
1260 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001261
1262 if buf != &copy[..] {
1263 for i in 0 .. buf.len() {
1264 if buf[i] != copy[i] {
David Brownc3898d62019-08-05 14:20:02 -06001265 info!("First failure for slot{} at {:#x} ({:#x} within) {:#x}!={:#x}",
1266 slot.index, offset + i, i, buf[i], copy[i]);
David Brown5c9e0f12019-01-09 16:34:33 -07001267 break;
1268 }
1269 }
1270 false
1271 } else {
1272 true
1273 }
1274}
1275
David Brown3b090212019-07-30 15:59:28 -06001276fn verify_trailer(flash: &SimMultiFlash, slot: &SlotInfo,
David Brown5c9e0f12019-01-09 16:34:33 -07001277 magic: Option<u8>, image_ok: Option<u8>,
1278 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001279 if Caps::OverwriteUpgrade.present() {
1280 return true;
1281 }
David Brown5c9e0f12019-01-09 16:34:33 -07001282
David Brown3b090212019-07-30 15:59:28 -06001283 let offset = slot.trailer_off + c::boot_max_align();
1284 let dev_id = slot.dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001285 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001286 let mut failed = false;
1287
David Brown76101572019-02-28 11:29:03 -07001288 let dev = flash.get(&dev_id).unwrap();
1289 let erased_val = dev.erased_val();
1290 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001291
1292 failed |= match magic {
1293 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001294 if v == 1 && &copy[24..] != MAGIC.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -07001295 warn!("\"magic\" mismatch at {:#x}", offset);
1296 true
1297 } else if v == 3 {
1298 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001299 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001300 warn!("\"magic\" mismatch at {:#x}", offset);
1301 true
1302 } else {
1303 false
1304 }
1305 } else {
1306 false
1307 }
1308 },
1309 None => false,
1310 };
1311
1312 failed |= match image_ok {
1313 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001314 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001315 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1316 true
1317 } else {
1318 false
1319 }
1320 },
1321 None => false,
1322 };
1323
1324 failed |= match copy_done {
1325 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001326 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001327 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1328 true
1329 } else {
1330 false
1331 }
1332 },
1333 None => false,
1334 };
1335
1336 !failed
1337}
1338
1339/// The image header
1340#[repr(C)]
1341pub struct ImageHeader {
1342 magic: u32,
1343 load_addr: u32,
1344 hdr_size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001345 protect_tlv_size: u16,
David Brown5c9e0f12019-01-09 16:34:33 -07001346 img_size: u32,
1347 flags: u32,
1348 ver: ImageVersion,
1349 _pad2: u32,
1350}
1351
1352impl AsRaw for ImageHeader {}
1353
1354#[repr(C)]
David Brownc3898d62019-08-05 14:20:02 -06001355#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001356pub struct ImageVersion {
David Brown7a81c4b2019-07-29 15:20:21 -06001357 pub major: u8,
1358 pub minor: u8,
1359 pub revision: u16,
1360 pub build_num: u32,
David Brown5c9e0f12019-01-09 16:34:33 -07001361}
1362
David Brownc3898d62019-08-05 14:20:02 -06001363#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001364pub struct SlotInfo {
1365 pub base_off: usize,
1366 pub trailer_off: usize,
1367 pub len: usize,
David Brown3b090212019-07-30 15:59:28 -06001368 // Which slot within this device.
1369 pub index: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001370 pub dev_id: u8,
1371}
1372
David Brown5c9e0f12019-01-09 16:34:33 -07001373const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1374 0x60, 0xd2, 0xef, 0x7f,
1375 0x35, 0x52, 0x50, 0x0f,
1376 0x2c, 0xb6, 0x79, 0x80]);
1377
1378// Replicates defines found in bootutil.h
1379const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1380const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1381
1382const BOOT_FLAG_SET: Option<u8> = Some(1);
1383const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1384
1385/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001386pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1387 let dev = flash.get_mut(&slot.dev_id).unwrap();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001388 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown76101572019-02-28 11:29:03 -07001389 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001390}
1391
1392/// Writes the image_ok flag which, guess what, tells the bootloader
1393/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001394fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1395 let dev = flash.get_mut(&slot.dev_id).unwrap();
1396 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001397 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001398 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001399 let align = dev.align();
1400 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001401}
1402
1403// Drop some pseudo-random gibberish onto the data.
1404fn splat(data: &mut [u8], seed: usize) {
1405 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1406 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1407 rng.fill_bytes(data);
1408}
1409
1410/// Return a read-only view into the raw bytes of this object
1411trait AsRaw : Sized {
1412 fn as_raw<'a>(&'a self) -> &'a [u8] {
1413 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1414 mem::size_of::<Self>()) }
1415 }
1416}
1417
1418pub fn show_sizes() {
1419 // This isn't panic safe.
1420 for min in &[1, 2, 4, 8] {
1421 let msize = c::boot_trailer_sz(*min);
1422 println!("{:2}: {} (0x{:x})", min, msize, msize);
1423 }
1424}