blob: fd9fdfe29dfcf6681b823cb16874a6d370706193 [file] [log] [blame]
David Brown297029a2019-08-13 14:29:51 -06001use byteorder::{
2 LittleEndian, WriteBytesExt,
3};
4use log::{
5 Level::Info,
6 error,
7 info,
8 log_enabled,
9 warn,
10};
David Brown5c9e0f12019-01-09 16:34:33 -070011use rand::{
12 distributions::{IndependentSample, Range},
13 Rng, SeedableRng, XorShiftRng,
14};
15use std::{
David Brown297029a2019-08-13 14:29:51 -060016 collections::HashSet,
David Browncb47dd72019-08-05 14:21:49 -060017 io::{Cursor, Write},
David Brown5c9e0f12019-01-09 16:34:33 -070018 mem,
19 slice,
20};
21use aes_ctr::{
22 Aes128Ctr,
23 stream_cipher::{
24 generic_array::GenericArray,
25 NewFixStreamCipher,
26 StreamCipherCore,
27 },
28};
29
David Brown76101572019-02-28 11:29:03 -070030use simflash::{Flash, SimFlash, SimMultiFlash};
David Browne5133242019-02-28 11:05:19 -070031use mcuboot_sys::{c, AreaDesc, FlashId};
32use crate::{
33 ALL_DEVICES,
34 DeviceName,
35};
David Brown5c9e0f12019-01-09 16:34:33 -070036use crate::caps::Caps;
David Brownc3898d62019-08-05 14:20:02 -060037use crate::depends::{
38 BoringDep,
39 Depender,
40 DepTest,
41 PairDep,
42 UpgradeInfo,
43};
David Brown43643dd2019-01-11 15:43:28 -070044use crate::tlv::{ManifestGen, TlvGen, TlvFlags, AES_SEC_KEY};
David Brown5c9e0f12019-01-09 16:34:33 -070045
David Browne5133242019-02-28 11:05:19 -070046/// A builder for Images. This describes a single run of the simulator,
47/// capturing the configuration of a particular set of devices, including
48/// the flash simulator(s) and the information about the slots.
49#[derive(Clone)]
50pub struct ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070051 flash: SimMultiFlash,
David Browne5133242019-02-28 11:05:19 -070052 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070053 slots: Vec<[SlotInfo; 2]>,
David Browne5133242019-02-28 11:05:19 -070054}
55
David Brown998aa8d2019-02-28 10:54:50 -070056/// Images represents the state of a simulation for a given set of images.
David Brown76101572019-02-28 11:29:03 -070057/// The flash holds the state of the simulated flash, whereas primaries
David Brown998aa8d2019-02-28 10:54:50 -070058/// and upgrades hold the expected contents of these images.
59pub struct Images {
David Brown76101572019-02-28 11:29:03 -070060 flash: SimMultiFlash,
David Brownca234692019-02-28 11:22:19 -070061 areadesc: AreaDesc,
David Brown84b49f72019-03-01 10:58:22 -070062 images: Vec<OneImage>,
63 total_count: Option<i32>,
64}
65
66/// When doing multi-image, there is an instance of this information for
67/// each of the images. Single image there will be one of these.
68struct OneImage {
David Brownca234692019-02-28 11:22:19 -070069 slots: [SlotInfo; 2],
70 primaries: ImageData,
71 upgrades: ImageData,
David Brownca234692019-02-28 11:22:19 -070072}
73
74/// The Rust-side representation of an image. For unencrypted images, this
75/// is just the unencrypted payload. For encrypted images, we store both
76/// the encrypted and the plaintext.
77struct ImageData {
78 plain: Vec<u8>,
79 cipher: Option<Vec<u8>>,
David Brown998aa8d2019-02-28 10:54:50 -070080}
81
David Browne5133242019-02-28 11:05:19 -070082impl ImagesBuilder {
David Brown5bc62c62019-03-05 12:11:48 -070083 /// Construct a new image builder for the given device. Returns
84 /// Some(builder) if is possible to test this configuration, or None if
85 /// not possible (for example, if there aren't enough image slots).
86 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Option<Self> {
David Brown76101572019-02-28 11:29:03 -070087 let (flash, areadesc) = Self::make_device(device, align, erased_val);
David Browne5133242019-02-28 11:05:19 -070088
David Brown06ef06e2019-03-05 12:28:10 -070089 let num_images = Caps::get_num_images();
David Browne5133242019-02-28 11:05:19 -070090
David Brown06ef06e2019-03-05 12:28:10 -070091 let mut slots = Vec::with_capacity(num_images);
92 for image in 0..num_images {
93 // This mapping must match that defined in
94 // `boot/zephyr/include/sysflash/sysflash.h`.
95 let id0 = match image {
96 0 => FlashId::Image0,
97 1 => FlashId::Image2,
98 _ => panic!("More than 2 images not supported"),
99 };
100 let (primary_base, primary_len, primary_dev_id) = match areadesc.find(id0) {
101 Some(info) => info,
102 None => return None,
103 };
104 let id1 = match image {
105 0 => FlashId::Image1,
106 1 => FlashId::Image3,
107 _ => panic!("More than 2 images not supported"),
108 };
109 let (secondary_base, secondary_len, secondary_dev_id) = match areadesc.find(id1) {
110 Some(info) => info,
111 None => return None,
112 };
David Browne5133242019-02-28 11:05:19 -0700113
Christopher Collinsa1c12042019-05-23 14:00:28 -0700114 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 4;
David Browne5133242019-02-28 11:05:19 -0700115
David Brown06ef06e2019-03-05 12:28:10 -0700116 // Construct a primary image.
117 let primary = SlotInfo {
118 base_off: primary_base as usize,
119 trailer_off: primary_base + primary_len - offset_from_end,
120 len: primary_len as usize,
121 dev_id: primary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600122 index: 0,
David Brown06ef06e2019-03-05 12:28:10 -0700123 };
124
125 // And an upgrade image.
126 let secondary = SlotInfo {
127 base_off: secondary_base as usize,
128 trailer_off: secondary_base + secondary_len - offset_from_end,
129 len: secondary_len as usize,
130 dev_id: secondary_dev_id,
David Brown3b090212019-07-30 15:59:28 -0600131 index: 1,
David Brown06ef06e2019-03-05 12:28:10 -0700132 };
133
134 slots.push([primary, secondary]);
135 }
David Browne5133242019-02-28 11:05:19 -0700136
David Brown5bc62c62019-03-05 12:11:48 -0700137 Some(ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -0700138 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700139 areadesc: areadesc,
David Brown06ef06e2019-03-05 12:28:10 -0700140 slots: slots,
David Brown5bc62c62019-03-05 12:11:48 -0700141 })
David Browne5133242019-02-28 11:05:19 -0700142 }
143
144 pub fn each_device<F>(f: F)
145 where F: Fn(Self)
146 {
147 for &dev in ALL_DEVICES {
148 for &align in &[1, 2, 4, 8] {
149 for &erased_val in &[0, 0xff] {
David Brown5bc62c62019-03-05 12:11:48 -0700150 match Self::new(dev, align, erased_val) {
151 Some(run) => f(run),
152 None => warn!("Skipping {:?}, insufficient partitions", dev),
153 }
David Browne5133242019-02-28 11:05:19 -0700154 }
155 }
156 }
157 }
158
159 /// Construct an `Images` that doesn't expect an upgrade to happen.
David Brownc3898d62019-08-05 14:20:02 -0600160 pub fn make_no_upgrade_image(self, deps: &DepTest) -> Images {
161 let num_images = self.num_images();
David Brown76101572019-02-28 11:29:03 -0700162 let mut flash = self.flash;
David Brownc3898d62019-08-05 14:20:02 -0600163 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
164 let dep: Box<dyn Depender> = if num_images > 1 {
165 Box::new(PairDep::new(num_images, image_num, deps))
166 } else {
167 Box::new(BoringDep(image_num))
168 };
169 let primaries = install_image(&mut flash, &slots[0], 42784, &*dep, false);
170 let upgrades = install_image(&mut flash, &slots[1], 46928, &*dep, false);
David Brown84b49f72019-03-01 10:58:22 -0700171 OneImage {
172 slots: slots,
173 primaries: primaries,
174 upgrades: upgrades,
175 }}).collect();
David Brown297029a2019-08-13 14:29:51 -0600176 install_ptable(&mut flash, &self.areadesc);
David Browne5133242019-02-28 11:05:19 -0700177 Images {
David Brown76101572019-02-28 11:29:03 -0700178 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700179 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700180 images: images,
David Browne5133242019-02-28 11:05:19 -0700181 total_count: None,
182 }
183 }
184
David Brownc3898d62019-08-05 14:20:02 -0600185 pub fn make_image(self, deps: &DepTest, permanent: bool) -> Images {
186 let mut images = self.make_no_upgrade_image(deps);
David Brown84b49f72019-03-01 10:58:22 -0700187 for image in &images.images {
188 mark_upgrade(&mut images.flash, &image.slots[1]);
189 }
David Browne5133242019-02-28 11:05:19 -0700190
191 // upgrades without fails, counts number of flash operations
Fabio Utziged4a5362019-07-30 12:43:23 -0300192 let total_count = match images.run_basic_upgrade(permanent) {
David Browne5133242019-02-28 11:05:19 -0700193 Ok(v) => v,
Fabio Utzig7c1d1552019-08-28 10:59:22 -0300194 Err(_) =>
195 match deps.upgrades[0] {
196 UpgradeInfo::Held => 0,
197 UpgradeInfo::Upgraded => panic!("Unable to perform basic upgrade"),
198 },
David Browne5133242019-02-28 11:05:19 -0700199 };
200
201 images.total_count = Some(total_count);
202 images
203 }
204
205 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700206 let mut bad_flash = self.flash;
David Brownc3898d62019-08-05 14:20:02 -0600207 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
208 let dep = BoringDep(image_num);
209 let primaries = install_image(&mut bad_flash, &slots[0], 32784, &dep, false);
210 let upgrades = install_image(&mut bad_flash, &slots[1], 41928, &dep, true);
David Brown84b49f72019-03-01 10:58:22 -0700211 OneImage {
212 slots: slots,
213 primaries: primaries,
214 upgrades: upgrades,
215 }}).collect();
David Browne5133242019-02-28 11:05:19 -0700216 Images {
David Brown76101572019-02-28 11:29:03 -0700217 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700218 areadesc: self.areadesc,
David Brown84b49f72019-03-01 10:58:22 -0700219 images: images,
David Browne5133242019-02-28 11:05:19 -0700220 total_count: None,
221 }
222 }
223
224 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700225 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700226 match device {
227 DeviceName::Stm32f4 => {
228 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700229 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
230 64 * 1024,
231 128 * 1024, 128 * 1024, 128 * 1024],
232 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700233 let dev_id = 0;
234 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700235 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700236 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
237 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
238 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
239
David Brown76101572019-02-28 11:29:03 -0700240 let mut flash = SimMultiFlash::new();
241 flash.insert(dev_id, dev);
242 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700243 }
244 DeviceName::K64f => {
245 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700246 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700247
248 let dev_id = 0;
249 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700250 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700251 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
252 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
253 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
254
David Brown76101572019-02-28 11:29:03 -0700255 let mut flash = SimMultiFlash::new();
256 flash.insert(dev_id, dev);
257 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700258 }
259 DeviceName::K64fBig => {
260 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
261 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700262 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700263
264 let dev_id = 0;
265 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700266 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700267 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
268 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
269 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
270
David Brown76101572019-02-28 11:29:03 -0700271 let mut flash = SimMultiFlash::new();
272 flash.insert(dev_id, dev);
273 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700274 }
275 DeviceName::Nrf52840 => {
276 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
277 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700278 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700279
280 let dev_id = 0;
281 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700282 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700283 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
284 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
285 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
286
David Brown76101572019-02-28 11:29:03 -0700287 let mut flash = SimMultiFlash::new();
288 flash.insert(dev_id, dev);
289 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700290 }
291 DeviceName::Nrf52840SpiFlash => {
292 // Simulate nrf52840 with external SPI flash. The external SPI flash
293 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700294 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
295 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700296
297 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700298 areadesc.add_flash_sectors(0, &dev0);
299 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700300
301 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
302 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
303 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
304
David Brown76101572019-02-28 11:29:03 -0700305 let mut flash = SimMultiFlash::new();
306 flash.insert(0, dev0);
307 flash.insert(1, dev1);
308 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700309 }
David Brown2bff6472019-03-05 13:58:35 -0700310 DeviceName::K64fMulti => {
311 // NXP style flash, but larger, to support multiple images.
312 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
313
314 let dev_id = 0;
315 let mut areadesc = AreaDesc::new();
316 areadesc.add_flash_sectors(dev_id, &dev);
317 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
318 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
319 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
320 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
321 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
322
323 let mut flash = SimMultiFlash::new();
324 flash.insert(dev_id, dev);
325 (flash, areadesc)
326 }
David Browne5133242019-02-28 11:05:19 -0700327 }
328 }
David Brownc3898d62019-08-05 14:20:02 -0600329
330 pub fn num_images(&self) -> usize {
331 self.slots.len()
332 }
David Browne5133242019-02-28 11:05:19 -0700333}
334
David Brown5c9e0f12019-01-09 16:34:33 -0700335impl Images {
336 /// A simple upgrade without forced failures.
337 ///
338 /// Returns the number of flash operations which can later be used to
339 /// inject failures at chosen steps.
Fabio Utziged4a5362019-07-30 12:43:23 -0300340 pub fn run_basic_upgrade(&self, permanent: bool) -> Result<i32, ()> {
341 let (flash, total_count) = self.try_upgrade(None, permanent);
David Brown5c9e0f12019-01-09 16:34:33 -0700342 info!("Total flash operation count={}", total_count);
343
David Brown84b49f72019-03-01 10:58:22 -0700344 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700345 warn!("Image mismatch after first boot");
346 Err(())
347 } else {
348 Ok(total_count)
349 }
350 }
351
David Brownc3898d62019-08-05 14:20:02 -0600352 /// Test a simple upgrade, with dependencies given, and verify that the
353 /// image does as is described in the test.
354 pub fn run_check_deps(&self, deps: &DepTest) -> bool {
355 let (flash, _) = self.try_upgrade(None, true);
356
357 self.verify_dep_images(&flash, deps)
358 }
359
David Brown5c9e0f12019-01-09 16:34:33 -0700360 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700361 if Caps::OverwriteUpgrade.present() {
362 return false;
363 }
David Brown5c9e0f12019-01-09 16:34:33 -0700364
David Brown5c9e0f12019-01-09 16:34:33 -0700365 let mut fails = 0;
366
367 // FIXME: this test would also pass if no swap is ever performed???
368 if Caps::SwapUpgrade.present() {
369 for count in 2 .. 5 {
370 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700371 let flash = self.try_revert(count);
David Brown84b49f72019-03-01 10:58:22 -0700372 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700373 error!("Revert failure on count {}", count);
374 fails += 1;
375 }
376 }
377 }
378
379 fails > 0
380 }
381
382 pub fn run_perm_with_fails(&self) -> bool {
383 let mut fails = 0;
384 let total_flash_ops = self.total_count.unwrap();
385
386 // Let's try an image halfway through.
387 for i in 1 .. total_flash_ops {
388 info!("Try interruption at {}", i);
Fabio Utziged4a5362019-07-30 12:43:23 -0300389 let (flash, count) = self.try_upgrade(Some(i), true);
David Brown5c9e0f12019-01-09 16:34:33 -0700390 info!("Second boot, count={}", count);
David Brown84b49f72019-03-01 10:58:22 -0700391 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700392 warn!("FAIL at step {} of {}", i, total_flash_ops);
393 fails += 1;
394 }
395
David Brown84b49f72019-03-01 10:58:22 -0700396 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
397 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100398 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700399 fails += 1;
400 }
401
David Brown84b49f72019-03-01 10:58:22 -0700402 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
403 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100404 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700405 fails += 1;
406 }
407
408 if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700409 if !self.verify_images(&flash, 1, 0) {
David Vincze2d736ad2019-02-18 11:50:22 +0100410 warn!("Secondary slot FAIL at step {} of {}",
411 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700412 fails += 1;
413 }
414 }
415 }
416
417 if fails > 0 {
418 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
419 fails as f32 * 100.0 / total_flash_ops as f32);
420 }
421
422 fails > 0
423 }
424
David Brown5c9e0f12019-01-09 16:34:33 -0700425 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
426 let mut fails = 0;
427 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700428 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700429 info!("Random interruptions at reset points={:?}", total_counts);
430
David Brown84b49f72019-03-01 10:58:22 -0700431 let primary_slot_ok = self.verify_images(&flash, 0, 1);
David Vincze2d736ad2019-02-18 11:50:22 +0100432 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown84b49f72019-03-01 10:58:22 -0700433 // TODO: This result is ignored.
434 self.verify_images(&flash, 1, 0)
David Brown5c9e0f12019-01-09 16:34:33 -0700435 } else {
436 true
437 };
David Vincze2d736ad2019-02-18 11:50:22 +0100438 if !primary_slot_ok || !secondary_slot_ok {
439 error!("Image mismatch after random interrupts: primary slot={} \
440 secondary slot={}",
441 if primary_slot_ok { "ok" } else { "fail" },
442 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700443 fails += 1;
444 }
David Brown84b49f72019-03-01 10:58:22 -0700445 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
446 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100447 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700448 fails += 1;
449 }
David Brown84b49f72019-03-01 10:58:22 -0700450 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
451 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100452 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700453 fails += 1;
454 }
455
456 if fails > 0 {
457 error!("Error testing perm upgrade with {} fails", total_fails);
458 }
459
460 fails > 0
461 }
462
David Brown5c9e0f12019-01-09 16:34:33 -0700463 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700464 if Caps::OverwriteUpgrade.present() {
465 return false;
466 }
David Brown5c9e0f12019-01-09 16:34:33 -0700467
David Brown5c9e0f12019-01-09 16:34:33 -0700468 let mut fails = 0;
469
470 if Caps::SwapUpgrade.present() {
Fabio Utziged4a5362019-07-30 12:43:23 -0300471 for i in 1 .. self.total_count.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -0700472 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700473 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700474 error!("Revert failed at interruption {}", i);
475 fails += 1;
476 }
477 }
478 }
479
480 fails > 0
481 }
482
David Brown5c9e0f12019-01-09 16:34:33 -0700483 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700484 if Caps::OverwriteUpgrade.present() {
485 return false;
486 }
David Brown5c9e0f12019-01-09 16:34:33 -0700487
David Brown76101572019-02-28 11:29:03 -0700488 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700489 let mut fails = 0;
490
491 info!("Try norevert");
492
493 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700494 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700495 if result != 0 {
496 warn!("Failed first boot");
497 fails += 1;
498 }
499
500 //FIXME: copy_done is written by boot_go, is it ok if no copy
501 // was ever done?
502
David Brown84b49f72019-03-01 10:58:22 -0700503 if !self.verify_images(&flash, 0, 1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100504 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700505 fails += 1;
506 }
David Brown84b49f72019-03-01 10:58:22 -0700507 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
508 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100509 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700510 fails += 1;
511 }
David Brown84b49f72019-03-01 10:58:22 -0700512 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
513 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100514 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700515 fails += 1;
516 }
517
David Vincze2d736ad2019-02-18 11:50:22 +0100518 // Marks image in the primary slot as permanent,
519 // no revert should happen...
David Brown84b49f72019-03-01 10:58:22 -0700520 self.mark_permanent_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700521
David Brown84b49f72019-03-01 10:58:22 -0700522 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
523 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100524 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700525 fails += 1;
526 }
527
David Brown76101572019-02-28 11:29:03 -0700528 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700529 if result != 0 {
530 warn!("Failed second boot");
531 fails += 1;
532 }
533
David Brown84b49f72019-03-01 10:58:22 -0700534 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
535 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100536 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700537 fails += 1;
538 }
David Brown84b49f72019-03-01 10:58:22 -0700539 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700540 warn!("Failed image verification");
541 fails += 1;
542 }
543
544 if fails > 0 {
545 error!("Error running upgrade without revert");
546 }
547
548 fails > 0
549 }
550
David Vincze2d736ad2019-02-18 11:50:22 +0100551 // Tests a new image written to the primary slot that already has magic and
552 // image_ok set while there is no image on the secondary slot, so no revert
553 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700554 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700555 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700556 let mut fails = 0;
557
558 info!("Try non-revert on imgtool generated image");
559
David Brown84b49f72019-03-01 10:58:22 -0700560 self.mark_upgrades(&mut flash, 0);
David Brown5c9e0f12019-01-09 16:34:33 -0700561
David Vincze2d736ad2019-02-18 11:50:22 +0100562 // This simulates writing an image created by imgtool to
563 // the primary slot
David Brown84b49f72019-03-01 10:58:22 -0700564 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
565 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100566 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700567 fails += 1;
568 }
569
570 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700571 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700572 if result != 0 {
573 warn!("Failed first boot");
574 fails += 1;
575 }
576
577 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700578 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700579 warn!("Failed image verification");
580 fails += 1;
581 }
David Brown84b49f72019-03-01 10:58:22 -0700582 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
583 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100584 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700585 fails += 1;
586 }
David Brown84b49f72019-03-01 10:58:22 -0700587 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
588 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100589 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700590 fails += 1;
591 }
592
593 if fails > 0 {
594 error!("Expected a non revert with new image");
595 }
596
597 fails > 0
598 }
599
David Vincze2d736ad2019-02-18 11:50:22 +0100600 // Tests a new image written to the primary slot that already has magic and
601 // image_ok set while there is no image on the secondary slot, so no revert
602 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700603 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700604 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700605 let mut fails = 0;
606
607 info!("Try upgrade image with bad signature");
608
David Brown84b49f72019-03-01 10:58:22 -0700609 self.mark_upgrades(&mut flash, 0);
610 self.mark_permanent_upgrades(&mut flash, 0);
611 self.mark_upgrades(&mut flash, 1);
David Brown5c9e0f12019-01-09 16:34:33 -0700612
David Brown84b49f72019-03-01 10:58:22 -0700613 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
614 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100615 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700616 fails += 1;
617 }
618
619 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700620 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700621 if result != 0 {
622 warn!("Failed first boot");
623 fails += 1;
624 }
625
626 // State should not have changed
David Brown84b49f72019-03-01 10:58:22 -0700627 if !self.verify_images(&flash, 0, 0) {
David Brown5c9e0f12019-01-09 16:34:33 -0700628 warn!("Failed image verification");
629 fails += 1;
630 }
David Brown84b49f72019-03-01 10:58:22 -0700631 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
632 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100633 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700634 fails += 1;
635 }
636
637 if fails > 0 {
638 error!("Expected an upgrade failure when image has bad signature");
639 }
640
641 fails > 0
642 }
643
David Brown5c9e0f12019-01-09 16:34:33 -0700644 fn trailer_sz(&self, align: usize) -> usize {
645 c::boot_trailer_sz(align as u8) as usize
646 }
647
648 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700649 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700650 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
651 32
652 } else {
653 0
654 };
David Brown5c9e0f12019-01-09 16:34:33 -0700655
Christopher Collinsa1c12042019-05-23 14:00:28 -0700656 self.trailer_sz(align) - (16 + 32 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700657 }
658
659 /// This test runs a simple upgrade with no fails in the images, but
660 /// allowing for fails in the status area. This should run to the end
661 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700662 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100663 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700664 return false;
665 }
666
David Brown76101572019-02-28 11:29:03 -0700667 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700668 let mut fails = 0;
669
670 info!("Try swap with status fails");
671
David Brown84b49f72019-03-01 10:58:22 -0700672 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700673 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700674
David Brown76101572019-02-28 11:29:03 -0700675 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700676 if result != 0 {
677 warn!("Failed!");
678 fails += 1;
679 }
680
681 // Failed writes to the marked "bad" region don't assert anymore.
682 // Any detected assert() is happening in another part of the code.
683 if asserts != 0 {
684 warn!("At least one assert() was called");
685 fails += 1;
686 }
687
David Brown84b49f72019-03-01 10:58:22 -0700688 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
689 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100690 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700691 fails += 1;
692 }
693
David Brown84b49f72019-03-01 10:58:22 -0700694 if !self.verify_images(&flash, 0, 1) {
David Brown5c9e0f12019-01-09 16:34:33 -0700695 warn!("Failed image verification");
696 fails += 1;
697 }
698
David Vincze2d736ad2019-02-18 11:50:22 +0100699 info!("validate primary slot enabled; \
700 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700701 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700702 if result != 0 {
703 warn!("Failed!");
704 fails += 1;
705 }
706
707 if fails > 0 {
708 error!("Error running upgrade with status write fails");
709 }
710
711 fails > 0
712 }
713
714 /// This test runs a simple upgrade with no fails in the images, but
715 /// allowing for fails in the status area. This should run to the end
716 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700717 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700718 if Caps::OverwriteUpgrade.present() {
719 false
David Vincze2d736ad2019-02-18 11:50:22 +0100720 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700721
David Brown76101572019-02-28 11:29:03 -0700722 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700723 let mut fails = 0;
724 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700725
David Brown85904a82019-01-11 13:45:12 -0700726 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700727
David Brown85904a82019-01-11 13:45:12 -0700728 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700729
David Brown84b49f72019-03-01 10:58:22 -0700730 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700731 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700732
733 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700734 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700735 if asserts != 0 {
736 warn!("At least one assert() was called");
737 fails += 1;
738 }
739
David Brown76101572019-02-28 11:29:03 -0700740 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700741
742 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700743 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700744
745 // This might throw no asserts, for large sector devices, where
746 // a single failure writing is indistinguishable from no failure,
747 // or throw a single assert for small sector devices that fail
748 // multiple times...
749 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100750 warn!("Expected single assert validating the primary slot, \
751 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700752 fails += 1;
753 }
754
755 if fails > 0 {
756 error!("Error running upgrade with status write fails");
757 }
758
759 fails > 0
760 } else {
David Brown76101572019-02-28 11:29:03 -0700761 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700762 let mut fails = 0;
763
764 info!("Try interrupted swap with status fails");
765
David Brown84b49f72019-03-01 10:58:22 -0700766 self.mark_permanent_upgrades(&mut flash, 1);
David Brown76101572019-02-28 11:29:03 -0700767 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700768
769 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700770 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700771 if asserts == 0 {
772 warn!("No assert() detected");
773 fails += 1;
774 }
775
776 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700777 }
David Brown5c9e0f12019-01-09 16:34:33 -0700778 }
779
780 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700781 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700782 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700783 if Caps::OverwriteUpgrade.present() {
784 return;
785 }
786
David Brown84b49f72019-03-01 10:58:22 -0700787 // Set this for each image.
788 for image in &self.images {
789 let dev_id = &image.slots[slot].dev_id;
790 let dev = flash.get_mut(&dev_id).unwrap();
791 let align = dev.align();
Christopher Collinsa1c12042019-05-23 14:00:28 -0700792 let off = &image.slots[slot].base_off;
793 let len = &image.slots[slot].len;
David Brown84b49f72019-03-01 10:58:22 -0700794 let status_off = off + len - self.trailer_sz(align);
David Brown5c9e0f12019-01-09 16:34:33 -0700795
David Brown84b49f72019-03-01 10:58:22 -0700796 // Mark the status area as a bad area
797 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
798 }
David Brown5c9e0f12019-01-09 16:34:33 -0700799 }
800
David Brown76101572019-02-28 11:29:03 -0700801 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100802 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700803 return;
804 }
805
David Brown84b49f72019-03-01 10:58:22 -0700806 for image in &self.images {
807 let dev_id = &image.slots[slot].dev_id;
808 let dev = flash.get_mut(&dev_id).unwrap();
809 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700810
David Brown84b49f72019-03-01 10:58:22 -0700811 // Disabling write verification the only assert triggered by
812 // boot_go should be checking for integrity of status bytes.
813 dev.set_verify_writes(false);
814 }
David Brown5c9e0f12019-01-09 16:34:33 -0700815 }
816
David Browndb505822019-03-01 10:04:20 -0700817 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
818 /// of the number of flash operations done total.
Fabio Utziged4a5362019-07-30 12:43:23 -0300819 fn try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32) {
David Browndb505822019-03-01 10:04:20 -0700820 // Clone the flash to have a new copy.
821 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700822
Fabio Utziged4a5362019-07-30 12:43:23 -0300823 if permanent {
824 self.mark_permanent_upgrades(&mut flash, 1);
825 }
David Brown5c9e0f12019-01-09 16:34:33 -0700826
David Browndb505822019-03-01 10:04:20 -0700827 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700828
David Browndb505822019-03-01 10:04:20 -0700829 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
830 (-0x13579, _) => (true, stop.unwrap()),
831 (0, _) => (false, -counter),
832 (x, _) => panic!("Unknown return: {}", x),
833 };
David Brown5c9e0f12019-01-09 16:34:33 -0700834
David Browndb505822019-03-01 10:04:20 -0700835 counter = 0;
836 if first_interrupted {
837 // fl.dump();
838 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
839 (-0x13579, _) => panic!("Shouldn't stop again"),
840 (0, _) => (),
841 (x, _) => panic!("Unknown return: {}", x),
842 }
843 }
David Brown5c9e0f12019-01-09 16:34:33 -0700844
David Browndb505822019-03-01 10:04:20 -0700845 (flash, count - counter)
846 }
847
848 fn try_revert(&self, count: usize) -> SimMultiFlash {
849 let mut flash = self.flash.clone();
850
851 // fl.write_file("image0.bin").unwrap();
852 for i in 0 .. count {
853 info!("Running boot pass {}", i + 1);
854 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
855 }
856 flash
857 }
858
859 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
860 let mut flash = self.flash.clone();
861 let mut fails = 0;
862
863 let mut counter = stop;
864 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
865 if x != -0x13579 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700866 warn!("Should have stopped test at interruption point");
David Browndb505822019-03-01 10:04:20 -0700867 fails += 1;
868 }
869
Fabio Utzig8af7f792019-07-30 12:40:01 -0300870 // In a multi-image setup, copy done might be set if any number of
871 // images was already successfully swapped.
872 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
873 warn!("copy_done should be unset");
874 fails += 1;
875 }
876
David Browndb505822019-03-01 10:04:20 -0700877 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
878 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700879 warn!("Should have finished test upgrade");
David Browndb505822019-03-01 10:04:20 -0700880 fails += 1;
881 }
882
David Brown84b49f72019-03-01 10:58:22 -0700883 if !self.verify_images(&flash, 0, 1) {
David Browndb505822019-03-01 10:04:20 -0700884 warn!("Image in the primary slot before revert is invalid at stop={}",
885 stop);
886 fails += 1;
887 }
David Brown84b49f72019-03-01 10:58:22 -0700888 if !self.verify_images(&flash, 1, 0) {
David Browndb505822019-03-01 10:04:20 -0700889 warn!("Image in the secondary slot before revert is invalid at stop={}",
890 stop);
891 fails += 1;
892 }
David Brown84b49f72019-03-01 10:58:22 -0700893 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
894 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Browndb505822019-03-01 10:04:20 -0700895 warn!("Mismatched trailer for the primary slot before revert");
896 fails += 1;
897 }
David Brown84b49f72019-03-01 10:58:22 -0700898 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
899 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700900 warn!("Mismatched trailer for the secondary slot before revert");
901 fails += 1;
902 }
903
904 // Do Revert
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700905 let mut counter = stop;
906 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
907 if x != -0x13579 {
908 warn!("Should have stopped revert at interruption point");
909 fails += 1;
910 }
911
David Browndb505822019-03-01 10:04:20 -0700912 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
913 if x != 0 {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700914 warn!("Should have finished revert upgrade");
David Browndb505822019-03-01 10:04:20 -0700915 fails += 1;
916 }
917
David Brown84b49f72019-03-01 10:58:22 -0700918 if !self.verify_images(&flash, 0, 0) {
David Browndb505822019-03-01 10:04:20 -0700919 warn!("Image in the primary slot after revert is invalid at stop={}",
920 stop);
921 fails += 1;
922 }
David Brown84b49f72019-03-01 10:58:22 -0700923 if !self.verify_images(&flash, 1, 1) {
David Browndb505822019-03-01 10:04:20 -0700924 warn!("Image in the secondary slot after revert is invalid at stop={}",
925 stop);
926 fails += 1;
927 }
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700928
David Brown84b49f72019-03-01 10:58:22 -0700929 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
930 BOOT_FLAG_SET, BOOT_FLAG_SET) {
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700931 warn!("Mismatched trailer for the primary slot after revert");
David Browndb505822019-03-01 10:04:20 -0700932 fails += 1;
933 }
David Brown84b49f72019-03-01 10:58:22 -0700934 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
935 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Browndb505822019-03-01 10:04:20 -0700936 warn!("Mismatched trailer for the secondary slot after revert");
937 fails += 1;
938 }
939
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700940 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
941 if x != 0 {
942 warn!("Should have finished 3rd boot");
943 fails += 1;
944 }
945
946 if !self.verify_images(&flash, 0, 0) {
947 warn!("Image in the primary slot is invalid on 1st boot after revert");
948 fails += 1;
949 }
950 if !self.verify_images(&flash, 1, 1) {
951 warn!("Image in the secondary slot is invalid on 1st boot after revert");
952 fails += 1;
953 }
954
David Browndb505822019-03-01 10:04:20 -0700955 fails > 0
956 }
957
Fabio Utzigfc07eab2019-05-17 10:23:38 -0700958
David Browndb505822019-03-01 10:04:20 -0700959 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
960 let mut flash = self.flash.clone();
961
David Brown84b49f72019-03-01 10:58:22 -0700962 self.mark_permanent_upgrades(&mut flash, 1);
David Browndb505822019-03-01 10:04:20 -0700963
964 let mut rng = rand::thread_rng();
965 let mut resets = vec![0i32; count];
966 let mut remaining_ops = total_ops;
967 for i in 0 .. count {
968 let ops = Range::new(1, remaining_ops / 2);
969 let reset_counter = ops.ind_sample(&mut rng);
970 let mut counter = reset_counter;
971 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
972 (0, _) | (-0x13579, _) => (),
973 (x, _) => panic!("Unknown return: {}", x),
974 }
975 remaining_ops -= reset_counter;
976 resets[i] = reset_counter;
977 }
978
979 match c::boot_go(&mut flash, &self.areadesc, None, false) {
980 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700981 (0, _) => (),
982 (x, _) => panic!("Unknown return: {}", x),
983 }
David Brown5c9e0f12019-01-09 16:34:33 -0700984
David Browndb505822019-03-01 10:04:20 -0700985 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700986 }
David Brown84b49f72019-03-01 10:58:22 -0700987
988 /// Verify the image in the given flash device, the specified slot
989 /// against the expected image.
990 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
David Brownf9aec952019-08-06 10:23:58 -0600991 self.images.iter().all(|image| {
992 verify_image(flash, &image.slots[slot],
993 match against {
994 0 => &image.primaries,
995 1 => &image.upgrades,
996 _ => panic!("Invalid 'against'")
997 })
998 })
David Brown84b49f72019-03-01 10:58:22 -0700999 }
1000
David Brownc3898d62019-08-05 14:20:02 -06001001 /// Verify the images, according to the dependency test.
1002 fn verify_dep_images(&self, flash: &SimMultiFlash, deps: &DepTest) -> bool {
1003 for (image_num, (image, upgrade)) in self.images.iter().zip(deps.upgrades.iter()).enumerate() {
1004 info!("Upgrade: slot:{}, {:?}", image_num, upgrade);
1005 if !verify_image(flash, &image.slots[0],
1006 match upgrade {
1007 UpgradeInfo::Upgraded => &image.upgrades,
1008 UpgradeInfo::Held => &image.primaries,
1009 }) {
1010 error!("Failed to upgrade properly: image: {}, upgrade: {:?}", image_num, upgrade);
1011 return true;
1012 }
1013 }
1014
1015 false
1016 }
1017
Fabio Utzig8af7f792019-07-30 12:40:01 -03001018 /// Verify that at least one of the trailers of the images have the
1019 /// specified values.
1020 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
1021 magic: Option<u8>, image_ok: Option<u8>,
1022 copy_done: Option<u8>) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001023 self.images.iter().any(|image| {
1024 verify_trailer(flash, &image.slots[slot],
1025 magic, image_ok, copy_done)
1026 })
Fabio Utzig8af7f792019-07-30 12:40:01 -03001027 }
1028
David Brown84b49f72019-03-01 10:58:22 -07001029 /// Verify that the trailers of the images have the specified
1030 /// values.
1031 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
1032 magic: Option<u8>, image_ok: Option<u8>,
1033 copy_done: Option<u8>) -> bool {
David Brownf9aec952019-08-06 10:23:58 -06001034 self.images.iter().all(|image| {
1035 verify_trailer(flash, &image.slots[slot],
1036 magic, image_ok, copy_done)
1037 })
David Brown84b49f72019-03-01 10:58:22 -07001038 }
1039
1040 /// Mark each of the images for permanent upgrade.
1041 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1042 for image in &self.images {
1043 mark_permanent_upgrade(flash, &image.slots[slot]);
1044 }
1045 }
1046
1047 /// Mark each of the images for permanent upgrade.
1048 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1049 for image in &self.images {
1050 mark_upgrade(flash, &image.slots[slot]);
1051 }
1052 }
David Brown297029a2019-08-13 14:29:51 -06001053
1054 /// Dump out the flash image(s) to one or more files for debugging
1055 /// purposes. The names will be written as either "{prefix}.mcubin" or
1056 /// "{prefix}-001.mcubin" depending on how many images there are.
1057 pub fn debug_dump(&self, prefix: &str) {
1058 for (id, fdev) in &self.flash {
1059 let name = if self.flash.len() == 1 {
1060 format!("{}.mcubin", prefix)
1061 } else {
1062 format!("{}-{:>0}.mcubin", prefix, id)
1063 };
1064 fdev.write_file(&name).unwrap();
1065 }
1066 }
David Brown5c9e0f12019-01-09 16:34:33 -07001067}
1068
1069/// Show the flash layout.
1070#[allow(dead_code)]
1071fn show_flash(flash: &dyn Flash) {
1072 println!("---- Flash configuration ----");
1073 for sector in flash.sector_iter() {
1074 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1075 sector.num, sector.base, sector.size);
1076 }
1077 println!("");
1078}
1079
1080/// Install a "program" into the given image. This fakes the image header, or at least all of the
1081/// fields used by the given code. Returns a copy of the image that was written.
David Brown3b090212019-07-30 15:59:28 -06001082fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: usize,
David Brownc3898d62019-08-05 14:20:02 -06001083 deps: &dyn Depender, bad_sig: bool) -> ImageData {
David Brown3b090212019-07-30 15:59:28 -06001084 let offset = slot.base_off;
1085 let slot_len = slot.len;
1086 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001087
David Brown43643dd2019-01-11 15:43:28 -07001088 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -07001089
David Brownc3898d62019-08-05 14:20:02 -06001090 // Add the dependencies early to the tlv.
1091 for dep in deps.my_deps(offset, slot.index) {
1092 tlv.add_dependency(deps.other_id(), &dep);
1093 }
1094
David Brown5c9e0f12019-01-09 16:34:33 -07001095 const HDR_SIZE: usize = 32;
1096
1097 // Generate a boot header. Note that the size doesn't include the header.
1098 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -07001099 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -07001100 load_addr: 0,
1101 hdr_size: HDR_SIZE as u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001102 protect_tlv_size: tlv.protect_size(),
David Brown5c9e0f12019-01-09 16:34:33 -07001103 img_size: len as u32,
1104 flags: tlv.get_flags(),
David Brownc3898d62019-08-05 14:20:02 -06001105 ver: deps.my_version(offset, slot.index),
David Brown5c9e0f12019-01-09 16:34:33 -07001106 _pad2: 0,
1107 };
1108
1109 let mut b_header = [0; HDR_SIZE];
1110 b_header[..32].clone_from_slice(header.as_raw());
1111 assert_eq!(b_header.len(), HDR_SIZE);
1112
1113 tlv.add_bytes(&b_header);
1114
1115 // The core of the image itself is just pseudorandom data.
1116 let mut b_img = vec![0; len];
1117 splat(&mut b_img, offset);
1118
David Browncb47dd72019-08-05 14:21:49 -06001119 // Add some information at the start of the payload to make it easier
1120 // to see what it is. This will fail if the image itself is too small.
1121 {
1122 let mut wr = Cursor::new(&mut b_img);
1123 writeln!(&mut wr, "offset: {:#x}, dev_id: {:#x}, slot_info: {:?}",
1124 offset, dev_id, slot).unwrap();
1125 writeln!(&mut wr, "version: {:?}", deps.my_version(offset, slot.index)).unwrap();
1126 }
1127
David Brown5c9e0f12019-01-09 16:34:33 -07001128 // TLV signatures work over plain image
1129 tlv.add_bytes(&b_img);
1130
1131 // Generate encrypted images
1132 let flag = TlvFlags::ENCRYPTED as u32;
1133 let is_encrypted = (tlv.get_flags() & flag) == flag;
1134 let mut b_encimg = vec![];
1135 if is_encrypted {
1136 let key = GenericArray::from_slice(AES_SEC_KEY);
1137 let nonce = GenericArray::from_slice(&[0; 16]);
1138 let mut cipher = Aes128Ctr::new(&key, &nonce);
1139 b_encimg = b_img.clone();
1140 cipher.apply_keystream(&mut b_encimg);
1141 }
1142
1143 // Build the TLV itself.
1144 let mut b_tlv = if bad_sig {
1145 let good_sig = &mut tlv.make_tlv();
1146 vec![0; good_sig.len()]
1147 } else {
1148 tlv.make_tlv()
1149 };
1150
1151 // Pad the block to a flash alignment (8 bytes).
1152 while b_tlv.len() % 8 != 0 {
1153 //FIXME: should be erase_val?
1154 b_tlv.push(0xFF);
1155 }
1156
1157 let mut buf = vec![];
1158 buf.append(&mut b_header.to_vec());
1159 buf.append(&mut b_img);
1160 buf.append(&mut b_tlv.clone());
1161
1162 let mut encbuf = vec![];
1163 if is_encrypted {
1164 encbuf.append(&mut b_header.to_vec());
1165 encbuf.append(&mut b_encimg);
1166 encbuf.append(&mut b_tlv);
1167 }
1168
David Vincze2d736ad2019-02-18 11:50:22 +01001169 // Since images are always non-encrypted in the primary slot, we first write
1170 // an encrypted image, re-read to use for verification, erase + flash
1171 // un-encrypted. In the secondary slot the image is written un-encrypted,
1172 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -07001173
David Brown76101572019-02-28 11:29:03 -07001174 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001175
David Brown3b090212019-07-30 15:59:28 -06001176 if slot.index == 0 {
David Brown5c9e0f12019-01-09 16:34:33 -07001177 let enc_copy: Option<Vec<u8>>;
1178
1179 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001180 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001181
1182 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001183 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001184
1185 enc_copy = Some(enc);
1186
David Brown76101572019-02-28 11:29:03 -07001187 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001188 } else {
1189 enc_copy = None;
1190 }
1191
David Brown76101572019-02-28 11:29:03 -07001192 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001193
1194 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001195 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001196
David Brownca234692019-02-28 11:22:19 -07001197 ImageData {
1198 plain: copy,
1199 cipher: enc_copy,
1200 }
David Brown5c9e0f12019-01-09 16:34:33 -07001201 } else {
1202
David Brown76101572019-02-28 11:29:03 -07001203 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001204
1205 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -07001206 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001207
1208 let enc_copy: Option<Vec<u8>>;
1209
1210 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -07001211 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001212
David Brown76101572019-02-28 11:29:03 -07001213 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001214
1215 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -07001216 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001217
1218 enc_copy = Some(enc);
1219 } else {
1220 enc_copy = None;
1221 }
1222
David Brownca234692019-02-28 11:22:19 -07001223 ImageData {
1224 plain: copy,
1225 cipher: enc_copy,
1226 }
David Brown5c9e0f12019-01-09 16:34:33 -07001227 }
David Brown5c9e0f12019-01-09 16:34:33 -07001228}
1229
David Brown5c9e0f12019-01-09 16:34:33 -07001230fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001231 if Caps::EcdsaP224.present() {
1232 panic!("Ecdsa P224 not supported in Simulator");
1233 }
David Brown5c9e0f12019-01-09 16:34:33 -07001234
David Brownb8882112019-01-11 14:04:11 -07001235 if Caps::EncKw.present() {
1236 if Caps::RSA2048.present() {
1237 TlvGen::new_rsa_kw()
1238 } else if Caps::EcdsaP256.present() {
1239 TlvGen::new_ecdsa_kw()
1240 } else {
1241 TlvGen::new_enc_kw()
1242 }
1243 } else if Caps::EncRsa.present() {
1244 if Caps::RSA2048.present() {
1245 TlvGen::new_sig_enc_rsa()
1246 } else {
1247 TlvGen::new_enc_rsa()
1248 }
1249 } else {
1250 // The non-encrypted configuration.
1251 if Caps::RSA2048.present() {
1252 TlvGen::new_rsa_pss()
Fabio Utzig39297432019-05-08 18:51:10 -03001253 } else if Caps::RSA3072.present() {
1254 TlvGen::new_rsa3072_pss()
David Brownb8882112019-01-11 14:04:11 -07001255 } else if Caps::EcdsaP256.present() {
1256 TlvGen::new_ecdsa()
Fabio Utzig97710282019-05-24 17:44:49 -03001257 } else if Caps::Ed25519.present() {
1258 TlvGen::new_ed25519()
David Brownb8882112019-01-11 14:04:11 -07001259 } else {
1260 TlvGen::new_hash_only()
1261 }
1262 }
David Brown5c9e0f12019-01-09 16:34:33 -07001263}
1264
David Brownca234692019-02-28 11:22:19 -07001265impl ImageData {
1266 /// Find the image contents for the given slot. This assumes that slot 0
1267 /// is unencrypted, and slot 1 is encrypted.
1268 fn find(&self, slot: usize) -> &Vec<u8> {
1269 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1270 match (encrypted, slot) {
1271 (false, _) => &self.plain,
1272 (true, 0) => &self.plain,
1273 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1274 _ => panic!("Invalid slot requested"),
1275 }
David Brown5c9e0f12019-01-09 16:34:33 -07001276 }
1277}
1278
David Brown5c9e0f12019-01-09 16:34:33 -07001279/// Verify that given image is present in the flash at the given offset.
David Brown3b090212019-07-30 15:59:28 -06001280fn verify_image(flash: &SimMultiFlash, slot: &SlotInfo, images: &ImageData) -> bool {
1281 let image = images.find(slot.index);
David Brown5c9e0f12019-01-09 16:34:33 -07001282 let buf = image.as_slice();
David Brown3b090212019-07-30 15:59:28 -06001283 let dev_id = slot.dev_id;
David Brown5c9e0f12019-01-09 16:34:33 -07001284
1285 let mut copy = vec![0u8; buf.len()];
David Brown3b090212019-07-30 15:59:28 -06001286 let offset = slot.base_off;
David Brown76101572019-02-28 11:29:03 -07001287 let dev = flash.get(&dev_id).unwrap();
1288 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001289
1290 if buf != &copy[..] {
1291 for i in 0 .. buf.len() {
1292 if buf[i] != copy[i] {
David Brownc3898d62019-08-05 14:20:02 -06001293 info!("First failure for slot{} at {:#x} ({:#x} within) {:#x}!={:#x}",
1294 slot.index, offset + i, i, buf[i], copy[i]);
David Brown5c9e0f12019-01-09 16:34:33 -07001295 break;
1296 }
1297 }
1298 false
1299 } else {
1300 true
1301 }
1302}
1303
David Brown3b090212019-07-30 15:59:28 -06001304fn verify_trailer(flash: &SimMultiFlash, slot: &SlotInfo,
David Brown5c9e0f12019-01-09 16:34:33 -07001305 magic: Option<u8>, image_ok: Option<u8>,
1306 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001307 if Caps::OverwriteUpgrade.present() {
1308 return true;
1309 }
David Brown5c9e0f12019-01-09 16:34:33 -07001310
David Brown3b090212019-07-30 15:59:28 -06001311 let offset = slot.trailer_off + c::boot_max_align();
1312 let dev_id = slot.dev_id;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001313 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
David Brown5c9e0f12019-01-09 16:34:33 -07001314 let mut failed = false;
1315
David Brown76101572019-02-28 11:29:03 -07001316 let dev = flash.get(&dev_id).unwrap();
1317 let erased_val = dev.erased_val();
1318 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001319
1320 failed |= match magic {
1321 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001322 if v == 1 && &copy[24..] != MAGIC.unwrap() {
David Brown5c9e0f12019-01-09 16:34:33 -07001323 warn!("\"magic\" mismatch at {:#x}", offset);
1324 true
1325 } else if v == 3 {
1326 let expected = [erased_val; 16];
Christopher Collinsa1c12042019-05-23 14:00:28 -07001327 if &copy[24..] != expected {
David Brown5c9e0f12019-01-09 16:34:33 -07001328 warn!("\"magic\" mismatch at {:#x}", offset);
1329 true
1330 } else {
1331 false
1332 }
1333 } else {
1334 false
1335 }
1336 },
1337 None => false,
1338 };
1339
1340 failed |= match image_ok {
1341 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001342 if (v == 1 && copy[16] != v) || (v == 3 && copy[16] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001343 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1344 true
1345 } else {
1346 false
1347 }
1348 },
1349 None => false,
1350 };
1351
1352 failed |= match copy_done {
1353 Some(v) => {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001354 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
David Brown5c9e0f12019-01-09 16:34:33 -07001355 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1356 true
1357 } else {
1358 false
1359 }
1360 },
1361 None => false,
1362 };
1363
1364 !failed
1365}
1366
David Brown297029a2019-08-13 14:29:51 -06001367/// Install a partition table. This is a simplified partition table that
1368/// we write at the beginning of flash so make it easier for external tools
1369/// to analyze these images.
1370fn install_ptable(flash: &mut SimMultiFlash, areadesc: &AreaDesc) {
1371 let ids: HashSet<u8> = areadesc.iter_areas().map(|area| area.device_id).collect();
1372 for &id in &ids {
1373 // If there are any partitions in this device that start at 0, and
1374 // aren't marked as the BootLoader partition, avoid adding the
1375 // partition table. This makes it harder to view the image, but
1376 // avoids messing up images already written.
1377 if areadesc.iter_areas().any(|area| {
1378 area.device_id == id &&
1379 area.off == 0 &&
1380 area.flash_id != FlashId::BootLoader
1381 }) {
1382 if log_enabled!(Info) {
1383 let special: Vec<FlashId> = areadesc.iter_areas()
1384 .filter(|area| area.device_id == id && area.off == 0)
1385 .map(|area| area.flash_id)
1386 .collect();
1387 info!("Skipping partition table: {:?}", special);
1388 }
1389 break;
1390 }
1391
1392 let mut buf: Vec<u8> = vec![];
1393 write!(&mut buf, "mcuboot\0").unwrap();
1394
1395 // Iterate through all of the partitions in that device, and encode
1396 // into the table.
1397 let count = areadesc.iter_areas().filter(|area| area.device_id == id).count();
1398 buf.write_u32::<LittleEndian>(count as u32).unwrap();
1399
1400 for area in areadesc.iter_areas().filter(|area| area.device_id == id) {
1401 buf.write_u32::<LittleEndian>(area.flash_id as u32).unwrap();
1402 buf.write_u32::<LittleEndian>(area.off).unwrap();
1403 buf.write_u32::<LittleEndian>(area.size).unwrap();
1404 buf.write_u32::<LittleEndian>(0).unwrap();
1405 }
1406
1407 let dev = flash.get_mut(&id).unwrap();
1408
1409 // Pad to alignment.
1410 while buf.len() % dev.align() != 0 {
1411 buf.push(0);
1412 }
1413
1414 dev.write(0, &buf).unwrap();
1415 }
1416}
1417
David Brown5c9e0f12019-01-09 16:34:33 -07001418/// The image header
1419#[repr(C)]
1420pub struct ImageHeader {
1421 magic: u32,
1422 load_addr: u32,
1423 hdr_size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -06001424 protect_tlv_size: u16,
David Brown5c9e0f12019-01-09 16:34:33 -07001425 img_size: u32,
1426 flags: u32,
1427 ver: ImageVersion,
1428 _pad2: u32,
1429}
1430
1431impl AsRaw for ImageHeader {}
1432
1433#[repr(C)]
David Brownc3898d62019-08-05 14:20:02 -06001434#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001435pub struct ImageVersion {
David Brown7a81c4b2019-07-29 15:20:21 -06001436 pub major: u8,
1437 pub minor: u8,
1438 pub revision: u16,
1439 pub build_num: u32,
David Brown5c9e0f12019-01-09 16:34:33 -07001440}
1441
David Brownc3898d62019-08-05 14:20:02 -06001442#[derive(Clone, Debug)]
David Brown5c9e0f12019-01-09 16:34:33 -07001443pub struct SlotInfo {
1444 pub base_off: usize,
1445 pub trailer_off: usize,
1446 pub len: usize,
David Brown3b090212019-07-30 15:59:28 -06001447 // Which slot within this device.
1448 pub index: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001449 pub dev_id: u8,
1450}
1451
David Brown5c9e0f12019-01-09 16:34:33 -07001452const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1453 0x60, 0xd2, 0xef, 0x7f,
1454 0x35, 0x52, 0x50, 0x0f,
1455 0x2c, 0xb6, 0x79, 0x80]);
1456
1457// Replicates defines found in bootutil.h
1458const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1459const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1460
1461const BOOT_FLAG_SET: Option<u8> = Some(1);
1462const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1463
1464/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001465pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1466 let dev = flash.get_mut(&slot.dev_id).unwrap();
Christopher Collinsa1c12042019-05-23 14:00:28 -07001467 let offset = slot.trailer_off + c::boot_max_align() * 4;
David Brown76101572019-02-28 11:29:03 -07001468 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001469}
1470
1471/// Writes the image_ok flag which, guess what, tells the bootloader
1472/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001473fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1474 let dev = flash.get_mut(&slot.dev_id).unwrap();
1475 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001476 ok[0] = 1u8;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001477 let off = slot.trailer_off + c::boot_max_align() * 3;
David Brown76101572019-02-28 11:29:03 -07001478 let align = dev.align();
1479 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001480}
1481
1482// Drop some pseudo-random gibberish onto the data.
1483fn splat(data: &mut [u8], seed: usize) {
1484 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1485 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1486 rng.fill_bytes(data);
1487}
1488
1489/// Return a read-only view into the raw bytes of this object
1490trait AsRaw : Sized {
1491 fn as_raw<'a>(&'a self) -> &'a [u8] {
1492 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1493 mem::size_of::<Self>()) }
1494 }
1495}
1496
1497pub fn show_sizes() {
1498 // This isn't panic safe.
1499 for min in &[1, 2, 4, 8] {
1500 let msize = c::boot_trailer_sz(*min);
1501 println!("{:2}: {} (0x{:x})", min, msize, msize);
1502 }
1503}