blob: e7dc38294ee67e85f64ca29bd54bfbd7bc61a243 [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 Brown43643dd2019-01-11 15:43:28 -070026use crate::tlv::{ManifestGen, TlvGen, TlvFlags, AES_SEC_KEY};
David Brown5c9e0f12019-01-09 16:34:33 -070027
David Browne5133242019-02-28 11:05:19 -070028/// A builder for Images. This describes a single run of the simulator,
29/// capturing the configuration of a particular set of devices, including
30/// the flash simulator(s) and the information about the slots.
31#[derive(Clone)]
32pub struct ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070033 flash: SimMultiFlash,
David Browne5133242019-02-28 11:05:19 -070034 areadesc: AreaDesc,
35 slots: [SlotInfo; 2],
36}
37
David Brown998aa8d2019-02-28 10:54:50 -070038/// Images represents the state of a simulation for a given set of images.
David Brown76101572019-02-28 11:29:03 -070039/// The flash holds the state of the simulated flash, whereas primaries
David Brown998aa8d2019-02-28 10:54:50 -070040/// and upgrades hold the expected contents of these images.
41pub struct Images {
David Brown76101572019-02-28 11:29:03 -070042 flash: SimMultiFlash,
David Brownca234692019-02-28 11:22:19 -070043 areadesc: AreaDesc,
44 slots: [SlotInfo; 2],
45 primaries: ImageData,
46 upgrades: ImageData,
47 total_count: Option<i32>,
48}
49
50/// The Rust-side representation of an image. For unencrypted images, this
51/// is just the unencrypted payload. For encrypted images, we store both
52/// the encrypted and the plaintext.
53struct ImageData {
54 plain: Vec<u8>,
55 cipher: Option<Vec<u8>>,
David Brown998aa8d2019-02-28 10:54:50 -070056}
57
David Browne5133242019-02-28 11:05:19 -070058impl ImagesBuilder {
59 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Self {
David Brown76101572019-02-28 11:29:03 -070060 let (flash, areadesc) = Self::make_device(device, align, erased_val);
David Browne5133242019-02-28 11:05:19 -070061
62 let (slot0_base, slot0_len, slot0_dev_id) = areadesc.find(FlashId::Image0);
63 let (slot1_base, slot1_len, slot1_dev_id) = areadesc.find(FlashId::Image1);
64
65 // NOTE: not accounting "swap_size" because it is not used by sim...
66 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
67
68 // Construct a primary image.
69 let slot0 = SlotInfo {
70 base_off: slot0_base as usize,
71 trailer_off: slot0_base + slot0_len - offset_from_end,
72 len: slot0_len as usize,
73 dev_id: slot0_dev_id,
74 };
75
76 // And an upgrade image.
77 let slot1 = SlotInfo {
78 base_off: slot1_base as usize,
79 trailer_off: slot1_base + slot1_len - offset_from_end,
80 len: slot1_len as usize,
81 dev_id: slot1_dev_id,
82 };
83
84 ImagesBuilder {
David Brown76101572019-02-28 11:29:03 -070085 flash: flash,
David Browne5133242019-02-28 11:05:19 -070086 areadesc: areadesc,
87 slots: [slot0, slot1],
88 }
89 }
90
91 pub fn each_device<F>(f: F)
92 where F: Fn(Self)
93 {
94 for &dev in ALL_DEVICES {
95 for &align in &[1, 2, 4, 8] {
96 for &erased_val in &[0, 0xff] {
97 let run = Self::new(dev, align, erased_val);
98 f(run);
99 }
100 }
101 }
102 }
103
104 /// Construct an `Images` that doesn't expect an upgrade to happen.
105 pub fn make_no_upgrade_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700106 let mut flash = self.flash;
107 let primaries = install_image(&mut flash, &self.slots, 0, 32784, false);
108 let upgrades = install_image(&mut flash, &self.slots, 1, 41928, false);
David Browne5133242019-02-28 11:05:19 -0700109 Images {
David Brown76101572019-02-28 11:29:03 -0700110 flash: flash,
David Browne5133242019-02-28 11:05:19 -0700111 areadesc: self.areadesc,
112 slots: self.slots,
113 primaries: primaries,
114 upgrades: upgrades,
115 total_count: None,
116 }
117 }
118
119 /// Construct an `Images` for normal testing.
120 pub fn make_image(self) -> Images {
121 let mut images = self.make_no_upgrade_image();
David Brown76101572019-02-28 11:29:03 -0700122 mark_upgrade(&mut images.flash, &images.slots[1]);
David Browne5133242019-02-28 11:05:19 -0700123
124 // upgrades without fails, counts number of flash operations
125 let total_count = match images.run_basic_upgrade() {
126 Ok(v) => v,
127 Err(_) => {
128 panic!("Unable to perform basic upgrade");
129 },
130 };
131
132 images.total_count = Some(total_count);
133 images
134 }
135
136 pub fn make_bad_secondary_slot_image(self) -> Images {
David Brown76101572019-02-28 11:29:03 -0700137 let mut bad_flash = self.flash;
138 let primaries = install_image(&mut bad_flash, &self.slots, 0, 32784, false);
139 let upgrades = install_image(&mut bad_flash, &self.slots, 1, 41928, true);
David Browne5133242019-02-28 11:05:19 -0700140 Images {
David Brown76101572019-02-28 11:29:03 -0700141 flash: bad_flash,
David Browne5133242019-02-28 11:05:19 -0700142 areadesc: self.areadesc,
143 slots: self.slots,
144 primaries: primaries,
145 upgrades: upgrades,
146 total_count: None,
147 }
148 }
149
150 /// Build the Flash and area descriptor for a given device.
David Brown76101572019-02-28 11:29:03 -0700151 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
David Browne5133242019-02-28 11:05:19 -0700152 match device {
153 DeviceName::Stm32f4 => {
154 // STM style flash. Large sectors, with a large scratch area.
David Brown76101572019-02-28 11:29:03 -0700155 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
156 64 * 1024,
157 128 * 1024, 128 * 1024, 128 * 1024],
158 align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700159 let dev_id = 0;
160 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700161 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700162 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
163 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
164 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
165
David Brown76101572019-02-28 11:29:03 -0700166 let mut flash = SimMultiFlash::new();
167 flash.insert(dev_id, dev);
168 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700169 }
170 DeviceName::K64f => {
171 // NXP style flash. Small sectors, one small sector for scratch.
David Brown76101572019-02-28 11:29:03 -0700172 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700173
174 let dev_id = 0;
175 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700176 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700177 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
178 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
179 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
180
David Brown76101572019-02-28 11:29:03 -0700181 let mut flash = SimMultiFlash::new();
182 flash.insert(dev_id, dev);
183 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700184 }
185 DeviceName::K64fBig => {
186 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
187 // uses small sectors, but we tell the bootloader they are large.
David Brown76101572019-02-28 11:29:03 -0700188 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700189
190 let dev_id = 0;
191 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700192 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700193 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
194 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
195 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
196
David Brown76101572019-02-28 11:29:03 -0700197 let mut flash = SimMultiFlash::new();
198 flash.insert(dev_id, dev);
199 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700200 }
201 DeviceName::Nrf52840 => {
202 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
203 // does not divide into the image size.
David Brown76101572019-02-28 11:29:03 -0700204 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700205
206 let dev_id = 0;
207 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700208 areadesc.add_flash_sectors(dev_id, &dev);
David Browne5133242019-02-28 11:05:19 -0700209 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
210 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
211 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
212
David Brown76101572019-02-28 11:29:03 -0700213 let mut flash = SimMultiFlash::new();
214 flash.insert(dev_id, dev);
215 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700216 }
217 DeviceName::Nrf52840SpiFlash => {
218 // Simulate nrf52840 with external SPI flash. The external SPI flash
219 // has a larger sector size so for now store scratch on that flash.
David Brown76101572019-02-28 11:29:03 -0700220 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
221 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
David Browne5133242019-02-28 11:05:19 -0700222
223 let mut areadesc = AreaDesc::new();
David Brown76101572019-02-28 11:29:03 -0700224 areadesc.add_flash_sectors(0, &dev0);
225 areadesc.add_flash_sectors(1, &dev1);
David Browne5133242019-02-28 11:05:19 -0700226
227 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
228 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
229 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
230
David Brown76101572019-02-28 11:29:03 -0700231 let mut flash = SimMultiFlash::new();
232 flash.insert(0, dev0);
233 flash.insert(1, dev1);
234 (flash, areadesc)
David Browne5133242019-02-28 11:05:19 -0700235 }
236 }
237 }
238}
239
David Brown5c9e0f12019-01-09 16:34:33 -0700240impl Images {
241 /// A simple upgrade without forced failures.
242 ///
243 /// Returns the number of flash operations which can later be used to
244 /// inject failures at chosen steps.
245 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
David Browndb505822019-03-01 10:04:20 -0700246 let (flash, total_count) = self.try_upgrade(None);
David Brown5c9e0f12019-01-09 16:34:33 -0700247 info!("Total flash operation count={}", total_count);
248
David Brown76101572019-02-28 11:29:03 -0700249 if !verify_image(&flash, &self.slots, 0, &self.upgrades) {
David Brown5c9e0f12019-01-09 16:34:33 -0700250 warn!("Image mismatch after first boot");
251 Err(())
252 } else {
253 Ok(total_count)
254 }
255 }
256
David Brown5c9e0f12019-01-09 16:34:33 -0700257 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700258 if Caps::OverwriteUpgrade.present() {
259 return false;
260 }
David Brown5c9e0f12019-01-09 16:34:33 -0700261
David Brown5c9e0f12019-01-09 16:34:33 -0700262 let mut fails = 0;
263
264 // FIXME: this test would also pass if no swap is ever performed???
265 if Caps::SwapUpgrade.present() {
266 for count in 2 .. 5 {
267 info!("Try revert: {}", count);
David Browndb505822019-03-01 10:04:20 -0700268 let flash = self.try_revert(count);
David Brown76101572019-02-28 11:29:03 -0700269 if !verify_image(&flash, &self.slots, 0, &self.primaries) {
David Brown5c9e0f12019-01-09 16:34:33 -0700270 error!("Revert failure on count {}", count);
271 fails += 1;
272 }
273 }
274 }
275
276 fails > 0
277 }
278
279 pub fn run_perm_with_fails(&self) -> bool {
280 let mut fails = 0;
281 let total_flash_ops = self.total_count.unwrap();
282
283 // Let's try an image halfway through.
284 for i in 1 .. total_flash_ops {
285 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700286 let (flash, count) = self.try_upgrade(Some(i));
David Brown5c9e0f12019-01-09 16:34:33 -0700287 info!("Second boot, count={}", count);
David Brown76101572019-02-28 11:29:03 -0700288 if !verify_image(&flash, &self.slots, 0, &self.upgrades) {
David Brown5c9e0f12019-01-09 16:34:33 -0700289 warn!("FAIL at step {} of {}", i, total_flash_ops);
290 fails += 1;
291 }
292
David Brown76101572019-02-28 11:29:03 -0700293 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700294 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100295 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700296 fails += 1;
297 }
298
David Brown76101572019-02-28 11:29:03 -0700299 if !verify_trailer(&flash, &self.slots, 1, BOOT_MAGIC_UNSET,
David Brown5c9e0f12019-01-09 16:34:33 -0700300 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100301 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700302 fails += 1;
303 }
304
305 if Caps::SwapUpgrade.present() {
David Brown76101572019-02-28 11:29:03 -0700306 if !verify_image(&flash, &self.slots, 1, &self.primaries) {
David Vincze2d736ad2019-02-18 11:50:22 +0100307 warn!("Secondary slot FAIL at step {} of {}",
308 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700309 fails += 1;
310 }
311 }
312 }
313
314 if fails > 0 {
315 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
316 fails as f32 * 100.0 / total_flash_ops as f32);
317 }
318
319 fails > 0
320 }
321
322 pub fn run_perm_with_random_fails_5(&self) -> bool {
323 self.run_perm_with_random_fails(5)
324 }
325
326 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
327 let mut fails = 0;
328 let total_flash_ops = self.total_count.unwrap();
David Browndb505822019-03-01 10:04:20 -0700329 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
David Brown5c9e0f12019-01-09 16:34:33 -0700330 info!("Random interruptions at reset points={:?}", total_counts);
331
David Brown76101572019-02-28 11:29:03 -0700332 let primary_slot_ok = verify_image(&flash, &self.slots,
David Vincze2d736ad2019-02-18 11:50:22 +0100333 0, &self.upgrades);
334 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown76101572019-02-28 11:29:03 -0700335 verify_image(&flash, &self.slots, 1, &self.primaries)
David Brown5c9e0f12019-01-09 16:34:33 -0700336 } else {
337 true
338 };
David Vincze2d736ad2019-02-18 11:50:22 +0100339 if !primary_slot_ok || !secondary_slot_ok {
340 error!("Image mismatch after random interrupts: primary slot={} \
341 secondary slot={}",
342 if primary_slot_ok { "ok" } else { "fail" },
343 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700344 fails += 1;
345 }
David Brown76101572019-02-28 11:29:03 -0700346 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700347 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100348 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700349 fails += 1;
350 }
David Brown76101572019-02-28 11:29:03 -0700351 if !verify_trailer(&flash, &self.slots, 1, BOOT_MAGIC_UNSET,
David Brown5c9e0f12019-01-09 16:34:33 -0700352 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100353 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700354 fails += 1;
355 }
356
357 if fails > 0 {
358 error!("Error testing perm upgrade with {} fails", total_fails);
359 }
360
361 fails > 0
362 }
363
David Brown5c9e0f12019-01-09 16:34:33 -0700364 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700365 if Caps::OverwriteUpgrade.present() {
366 return false;
367 }
David Brown5c9e0f12019-01-09 16:34:33 -0700368
David Brown5c9e0f12019-01-09 16:34:33 -0700369 let mut fails = 0;
370
371 if Caps::SwapUpgrade.present() {
372 for i in 1 .. (self.total_count.unwrap() - 1) {
373 info!("Try interruption at {}", i);
David Browndb505822019-03-01 10:04:20 -0700374 if self.try_revert_with_fail_at(i) {
David Brown5c9e0f12019-01-09 16:34:33 -0700375 error!("Revert failed at interruption {}", i);
376 fails += 1;
377 }
378 }
379 }
380
381 fails > 0
382 }
383
David Brown5c9e0f12019-01-09 16:34:33 -0700384 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700385 if Caps::OverwriteUpgrade.present() {
386 return false;
387 }
David Brown5c9e0f12019-01-09 16:34:33 -0700388
David Brown76101572019-02-28 11:29:03 -0700389 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700390 let mut fails = 0;
391
392 info!("Try norevert");
393
394 // First do a normal upgrade...
David Brown76101572019-02-28 11:29:03 -0700395 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700396 if result != 0 {
397 warn!("Failed first boot");
398 fails += 1;
399 }
400
401 //FIXME: copy_done is written by boot_go, is it ok if no copy
402 // was ever done?
403
David Brown76101572019-02-28 11:29:03 -0700404 if !verify_image(&flash, &self.slots, 0, &self.upgrades) {
David Vincze2d736ad2019-02-18 11:50:22 +0100405 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700406 fails += 1;
407 }
David Brown76101572019-02-28 11:29:03 -0700408 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700409 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100410 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700411 fails += 1;
412 }
David Brown76101572019-02-28 11:29:03 -0700413 if !verify_trailer(&flash, &self.slots, 1, BOOT_MAGIC_UNSET,
David Brown5c9e0f12019-01-09 16:34:33 -0700414 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100415 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700416 fails += 1;
417 }
418
David Vincze2d736ad2019-02-18 11:50:22 +0100419 // Marks image in the primary slot as permanent,
420 // no revert should happen...
David Brown76101572019-02-28 11:29:03 -0700421 mark_permanent_upgrade(&mut flash, &self.slots[0]);
David Brown5c9e0f12019-01-09 16:34:33 -0700422
David Brown76101572019-02-28 11:29:03 -0700423 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700424 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100425 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700426 fails += 1;
427 }
428
David Brown76101572019-02-28 11:29:03 -0700429 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700430 if result != 0 {
431 warn!("Failed second boot");
432 fails += 1;
433 }
434
David Brown76101572019-02-28 11:29:03 -0700435 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700436 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100437 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700438 fails += 1;
439 }
David Brown76101572019-02-28 11:29:03 -0700440 if !verify_image(&flash, &self.slots, 0, &self.upgrades) {
David Brown5c9e0f12019-01-09 16:34:33 -0700441 warn!("Failed image verification");
442 fails += 1;
443 }
444
445 if fails > 0 {
446 error!("Error running upgrade without revert");
447 }
448
449 fails > 0
450 }
451
David Vincze2d736ad2019-02-18 11:50:22 +0100452 // Tests a new image written to the primary slot that already has magic and
453 // image_ok set while there is no image on the secondary slot, so no revert
454 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700455 pub fn run_norevert_newimage(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700456 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700457 let mut fails = 0;
458
459 info!("Try non-revert on imgtool generated image");
460
David Brown76101572019-02-28 11:29:03 -0700461 mark_upgrade(&mut flash, &self.slots[0]);
David Brown5c9e0f12019-01-09 16:34:33 -0700462
David Vincze2d736ad2019-02-18 11:50:22 +0100463 // This simulates writing an image created by imgtool to
464 // the primary slot
David Brown76101572019-02-28 11:29:03 -0700465 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700466 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100467 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700468 fails += 1;
469 }
470
471 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700472 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700473 if result != 0 {
474 warn!("Failed first boot");
475 fails += 1;
476 }
477
478 // State should not have changed
David Brown76101572019-02-28 11:29:03 -0700479 if !verify_image(&flash, &self.slots, 0, &self.primaries) {
David Brown5c9e0f12019-01-09 16:34:33 -0700480 warn!("Failed image verification");
481 fails += 1;
482 }
David Brown76101572019-02-28 11:29:03 -0700483 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700484 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100485 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700486 fails += 1;
487 }
David Brown76101572019-02-28 11:29:03 -0700488 if !verify_trailer(&flash, &self.slots, 1, BOOT_MAGIC_UNSET,
David Brown5c9e0f12019-01-09 16:34:33 -0700489 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100490 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700491 fails += 1;
492 }
493
494 if fails > 0 {
495 error!("Expected a non revert with new image");
496 }
497
498 fails > 0
499 }
500
David Vincze2d736ad2019-02-18 11:50:22 +0100501 // Tests a new image written to the primary slot that already has magic and
502 // image_ok set while there is no image on the secondary slot, so no revert
503 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700504 pub fn run_signfail_upgrade(&self) -> bool {
David Brown76101572019-02-28 11:29:03 -0700505 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700506 let mut fails = 0;
507
508 info!("Try upgrade image with bad signature");
509
David Brown76101572019-02-28 11:29:03 -0700510 mark_upgrade(&mut flash, &self.slots[0]);
511 mark_permanent_upgrade(&mut flash, &self.slots[0]);
512 mark_upgrade(&mut flash, &self.slots[1]);
David Brown5c9e0f12019-01-09 16:34:33 -0700513
David Brown76101572019-02-28 11:29:03 -0700514 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700515 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100516 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700517 fails += 1;
518 }
519
520 // Run the bootloader...
David Brown76101572019-02-28 11:29:03 -0700521 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700522 if result != 0 {
523 warn!("Failed first boot");
524 fails += 1;
525 }
526
527 // State should not have changed
David Brown76101572019-02-28 11:29:03 -0700528 if !verify_image(&flash, &self.slots, 0, &self.primaries) {
David Brown5c9e0f12019-01-09 16:34:33 -0700529 warn!("Failed image verification");
530 fails += 1;
531 }
David Brown76101572019-02-28 11:29:03 -0700532 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700533 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100534 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700535 fails += 1;
536 }
537
538 if fails > 0 {
539 error!("Expected an upgrade failure when image has bad signature");
540 }
541
542 fails > 0
543 }
544
David Brown5c9e0f12019-01-09 16:34:33 -0700545 fn trailer_sz(&self, align: usize) -> usize {
546 c::boot_trailer_sz(align as u8) as usize
547 }
548
549 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700550 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700551 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
552 32
553 } else {
554 0
555 };
David Brown5c9e0f12019-01-09 16:34:33 -0700556
David Brown9930a3e2019-01-11 12:28:26 -0700557 self.trailer_sz(align) - (16 + 24 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700558 }
559
560 /// This test runs a simple upgrade with no fails in the images, but
561 /// allowing for fails in the status area. This should run to the end
562 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700563 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100564 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700565 return false;
566 }
567
David Brown76101572019-02-28 11:29:03 -0700568 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700569 let mut fails = 0;
570
571 info!("Try swap with status fails");
572
David Brown76101572019-02-28 11:29:03 -0700573 mark_permanent_upgrade(&mut flash, &self.slots[1]);
574 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown5c9e0f12019-01-09 16:34:33 -0700575
David Brown76101572019-02-28 11:29:03 -0700576 let (result, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown5c9e0f12019-01-09 16:34:33 -0700577 if result != 0 {
578 warn!("Failed!");
579 fails += 1;
580 }
581
582 // Failed writes to the marked "bad" region don't assert anymore.
583 // Any detected assert() is happening in another part of the code.
584 if asserts != 0 {
585 warn!("At least one assert() was called");
586 fails += 1;
587 }
588
David Brown76101572019-02-28 11:29:03 -0700589 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
David Brown5c9e0f12019-01-09 16:34:33 -0700590 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100591 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700592 fails += 1;
593 }
594
David Brown76101572019-02-28 11:29:03 -0700595 if !verify_image(&flash, &self.slots, 0, &self.upgrades) {
David Brown5c9e0f12019-01-09 16:34:33 -0700596 warn!("Failed image verification");
597 fails += 1;
598 }
599
David Vincze2d736ad2019-02-18 11:50:22 +0100600 info!("validate primary slot enabled; \
601 re-run of boot_go should just work");
David Brown76101572019-02-28 11:29:03 -0700602 let (result, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
David Brown5c9e0f12019-01-09 16:34:33 -0700603 if result != 0 {
604 warn!("Failed!");
605 fails += 1;
606 }
607
608 if fails > 0 {
609 error!("Error running upgrade with status write fails");
610 }
611
612 fails > 0
613 }
614
615 /// This test runs a simple upgrade with no fails in the images, but
616 /// allowing for fails in the status area. This should run to the end
617 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700618 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700619 if Caps::OverwriteUpgrade.present() {
620 false
David Vincze2d736ad2019-02-18 11:50:22 +0100621 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700622
David Brown76101572019-02-28 11:29:03 -0700623 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700624 let mut fails = 0;
625 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700626
David Brown85904a82019-01-11 13:45:12 -0700627 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700628
David Brown85904a82019-01-11 13:45:12 -0700629 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700630
David Brown76101572019-02-28 11:29:03 -0700631 mark_permanent_upgrade(&mut flash, &self.slots[1]);
632 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
David Brown85904a82019-01-11 13:45:12 -0700633
634 // Should not fail, writing to bad regions does not assert
David Brown76101572019-02-28 11:29:03 -0700635 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, Some(&mut count), true);
David Brown85904a82019-01-11 13:45:12 -0700636 if asserts != 0 {
637 warn!("At least one assert() was called");
638 fails += 1;
639 }
640
David Brown76101572019-02-28 11:29:03 -0700641 self.reset_bad_status(&mut flash, 0);
David Brown85904a82019-01-11 13:45:12 -0700642
643 info!("Resuming an interrupted swap operation");
David Brown76101572019-02-28 11:29:03 -0700644 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700645
646 // This might throw no asserts, for large sector devices, where
647 // a single failure writing is indistinguishable from no failure,
648 // or throw a single assert for small sector devices that fail
649 // multiple times...
650 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100651 warn!("Expected single assert validating the primary slot, \
652 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700653 fails += 1;
654 }
655
656 if fails > 0 {
657 error!("Error running upgrade with status write fails");
658 }
659
660 fails > 0
661 } else {
David Brown76101572019-02-28 11:29:03 -0700662 let mut flash = self.flash.clone();
David Brown85904a82019-01-11 13:45:12 -0700663 let mut fails = 0;
664
665 info!("Try interrupted swap with status fails");
666
David Brown76101572019-02-28 11:29:03 -0700667 mark_permanent_upgrade(&mut flash, &self.slots[1]);
668 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
David Brown85904a82019-01-11 13:45:12 -0700669
670 // This is expected to fail while writing to bad regions...
David Brown76101572019-02-28 11:29:03 -0700671 let (_, asserts) = c::boot_go(&mut flash, &self.areadesc, None, true);
David Brown85904a82019-01-11 13:45:12 -0700672 if asserts == 0 {
673 warn!("No assert() detected");
674 fails += 1;
675 }
676
677 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700678 }
David Brown5c9e0f12019-01-09 16:34:33 -0700679 }
680
681 /// Adds a new flash area that fails statistically
David Brown76101572019-02-28 11:29:03 -0700682 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -0700683 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700684 if Caps::OverwriteUpgrade.present() {
685 return;
686 }
687
David Brown5c9e0f12019-01-09 16:34:33 -0700688 let dev_id = &self.slots[slot].dev_id;
David Brown76101572019-02-28 11:29:03 -0700689 let dev = flash.get_mut(&dev_id).unwrap();
690 let align = dev.align();
David Brown5c9e0f12019-01-09 16:34:33 -0700691 let off = &self.slots[0].base_off;
692 let len = &self.slots[0].len;
693 let status_off = off + len - self.trailer_sz(align);
694
695 // Mark the status area as a bad area
David Brown76101572019-02-28 11:29:03 -0700696 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
David Brown5c9e0f12019-01-09 16:34:33 -0700697 }
698
David Brown76101572019-02-28 11:29:03 -0700699 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100700 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700701 return;
702 }
703
David Brown5c9e0f12019-01-09 16:34:33 -0700704 let dev_id = &self.slots[slot].dev_id;
David Brown76101572019-02-28 11:29:03 -0700705 let dev = flash.get_mut(&dev_id).unwrap();
706 dev.reset_bad_regions();
David Brown5c9e0f12019-01-09 16:34:33 -0700707
708 // Disabling write verification the only assert triggered by
709 // boot_go should be checking for integrity of status bytes.
David Brown76101572019-02-28 11:29:03 -0700710 dev.set_verify_writes(false);
David Brown5c9e0f12019-01-09 16:34:33 -0700711 }
712
David Browndb505822019-03-01 10:04:20 -0700713 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
714 /// of the number of flash operations done total.
715 fn try_upgrade(&self, stop: Option<i32>) -> (SimMultiFlash, i32) {
716 // Clone the flash to have a new copy.
717 let mut flash = self.flash.clone();
David Brown5c9e0f12019-01-09 16:34:33 -0700718
David Browndb505822019-03-01 10:04:20 -0700719 mark_permanent_upgrade(&mut flash, &self.slots[1]);
David Brown5c9e0f12019-01-09 16:34:33 -0700720
David Browndb505822019-03-01 10:04:20 -0700721 let mut counter = stop.unwrap_or(0);
David Brown5c9e0f12019-01-09 16:34:33 -0700722
David Browndb505822019-03-01 10:04:20 -0700723 let (first_interrupted, count) = match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
724 (-0x13579, _) => (true, stop.unwrap()),
725 (0, _) => (false, -counter),
726 (x, _) => panic!("Unknown return: {}", x),
727 };
David Brown5c9e0f12019-01-09 16:34:33 -0700728
David Browndb505822019-03-01 10:04:20 -0700729 counter = 0;
730 if first_interrupted {
731 // fl.dump();
732 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
733 (-0x13579, _) => panic!("Shouldn't stop again"),
734 (0, _) => (),
735 (x, _) => panic!("Unknown return: {}", x),
736 }
737 }
David Brown5c9e0f12019-01-09 16:34:33 -0700738
David Browndb505822019-03-01 10:04:20 -0700739 (flash, count - counter)
740 }
741
742 fn try_revert(&self, count: usize) -> SimMultiFlash {
743 let mut flash = self.flash.clone();
744
745 // fl.write_file("image0.bin").unwrap();
746 for i in 0 .. count {
747 info!("Running boot pass {}", i + 1);
748 assert_eq!(c::boot_go(&mut flash, &self.areadesc, None, false), (0, 0));
749 }
750 flash
751 }
752
753 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
754 let mut flash = self.flash.clone();
755 let mut fails = 0;
756
757 let mut counter = stop;
758 let (x, _) = c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false);
759 if x != -0x13579 {
760 warn!("Should have stopped at interruption point");
761 fails += 1;
762 }
763
764 if !verify_trailer(&flash, &self.slots, 0, None, None, BOOT_FLAG_UNSET) {
765 warn!("copy_done should be unset");
766 fails += 1;
767 }
768
769 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
770 if x != 0 {
771 warn!("Should have finished upgrade");
772 fails += 1;
773 }
774
775 if !verify_image(&flash, &self.slots, 0, &self.upgrades) {
776 warn!("Image in the primary slot before revert is invalid at stop={}",
777 stop);
778 fails += 1;
779 }
780 if !verify_image(&flash, &self.slots, 1, &self.primaries) {
781 warn!("Image in the secondary slot before revert is invalid at stop={}",
782 stop);
783 fails += 1;
784 }
785 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
786 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
787 warn!("Mismatched trailer for the primary slot before revert");
788 fails += 1;
789 }
790 if !verify_trailer(&flash, &self.slots, 1, BOOT_MAGIC_UNSET,
791 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
792 warn!("Mismatched trailer for the secondary slot before revert");
793 fails += 1;
794 }
795
796 // Do Revert
797 let (x, _) = c::boot_go(&mut flash, &self.areadesc, None, false);
798 if x != 0 {
799 warn!("Should have finished a revert");
800 fails += 1;
801 }
802
803 if !verify_image(&flash, &self.slots, 0, &self.primaries) {
804 warn!("Image in the primary slot after revert is invalid at stop={}",
805 stop);
806 fails += 1;
807 }
808 if !verify_image(&flash, &self.slots, 1, &self.upgrades) {
809 warn!("Image in the secondary slot after revert is invalid at stop={}",
810 stop);
811 fails += 1;
812 }
813 if !verify_trailer(&flash, &self.slots, 0, BOOT_MAGIC_GOOD,
814 BOOT_FLAG_SET, BOOT_FLAG_SET) {
815 warn!("Mismatched trailer for the secondary slot after revert");
816 fails += 1;
817 }
818 if !verify_trailer(&flash, &self.slots, 1, BOOT_MAGIC_UNSET,
819 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
820 warn!("Mismatched trailer for the secondary slot after revert");
821 fails += 1;
822 }
823
824 fails > 0
825 }
826
827 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
828 let mut flash = self.flash.clone();
829
830 mark_permanent_upgrade(&mut flash, &self.slots[1]);
831
832 let mut rng = rand::thread_rng();
833 let mut resets = vec![0i32; count];
834 let mut remaining_ops = total_ops;
835 for i in 0 .. count {
836 let ops = Range::new(1, remaining_ops / 2);
837 let reset_counter = ops.ind_sample(&mut rng);
838 let mut counter = reset_counter;
839 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), false) {
840 (0, _) | (-0x13579, _) => (),
841 (x, _) => panic!("Unknown return: {}", x),
842 }
843 remaining_ops -= reset_counter;
844 resets[i] = reset_counter;
845 }
846
847 match c::boot_go(&mut flash, &self.areadesc, None, false) {
848 (-0x13579, _) => panic!("Should not be have been interrupted!"),
David Brown5c9e0f12019-01-09 16:34:33 -0700849 (0, _) => (),
850 (x, _) => panic!("Unknown return: {}", x),
851 }
David Brown5c9e0f12019-01-09 16:34:33 -0700852
David Browndb505822019-03-01 10:04:20 -0700853 (flash, resets)
David Brown5c9e0f12019-01-09 16:34:33 -0700854 }
David Brown5c9e0f12019-01-09 16:34:33 -0700855}
856
857/// Show the flash layout.
858#[allow(dead_code)]
859fn show_flash(flash: &dyn Flash) {
860 println!("---- Flash configuration ----");
861 for sector in flash.sector_iter() {
862 println!(" {:3}: 0x{:08x}, 0x{:08x}",
863 sector.num, sector.base, sector.size);
864 }
865 println!("");
866}
867
868/// Install a "program" into the given image. This fakes the image header, or at least all of the
869/// fields used by the given code. Returns a copy of the image that was written.
David Brown76101572019-02-28 11:29:03 -0700870fn install_image(flash: &mut SimMultiFlash, slots: &[SlotInfo], slot: usize, len: usize,
David Brownca234692019-02-28 11:22:19 -0700871 bad_sig: bool) -> ImageData {
David Brown5c9e0f12019-01-09 16:34:33 -0700872 let offset = slots[slot].base_off;
873 let slot_len = slots[slot].len;
874 let dev_id = slots[slot].dev_id;
875
David Brown43643dd2019-01-11 15:43:28 -0700876 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -0700877
878 const HDR_SIZE: usize = 32;
879
880 // Generate a boot header. Note that the size doesn't include the header.
881 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -0700882 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -0700883 load_addr: 0,
884 hdr_size: HDR_SIZE as u16,
885 _pad1: 0,
886 img_size: len as u32,
887 flags: tlv.get_flags(),
888 ver: ImageVersion {
889 major: (offset / (128 * 1024)) as u8,
890 minor: 0,
891 revision: 1,
892 build_num: offset as u32,
893 },
894 _pad2: 0,
895 };
896
897 let mut b_header = [0; HDR_SIZE];
898 b_header[..32].clone_from_slice(header.as_raw());
899 assert_eq!(b_header.len(), HDR_SIZE);
900
901 tlv.add_bytes(&b_header);
902
903 // The core of the image itself is just pseudorandom data.
904 let mut b_img = vec![0; len];
905 splat(&mut b_img, offset);
906
907 // TLV signatures work over plain image
908 tlv.add_bytes(&b_img);
909
910 // Generate encrypted images
911 let flag = TlvFlags::ENCRYPTED as u32;
912 let is_encrypted = (tlv.get_flags() & flag) == flag;
913 let mut b_encimg = vec![];
914 if is_encrypted {
915 let key = GenericArray::from_slice(AES_SEC_KEY);
916 let nonce = GenericArray::from_slice(&[0; 16]);
917 let mut cipher = Aes128Ctr::new(&key, &nonce);
918 b_encimg = b_img.clone();
919 cipher.apply_keystream(&mut b_encimg);
920 }
921
922 // Build the TLV itself.
923 let mut b_tlv = if bad_sig {
924 let good_sig = &mut tlv.make_tlv();
925 vec![0; good_sig.len()]
926 } else {
927 tlv.make_tlv()
928 };
929
930 // Pad the block to a flash alignment (8 bytes).
931 while b_tlv.len() % 8 != 0 {
932 //FIXME: should be erase_val?
933 b_tlv.push(0xFF);
934 }
935
936 let mut buf = vec![];
937 buf.append(&mut b_header.to_vec());
938 buf.append(&mut b_img);
939 buf.append(&mut b_tlv.clone());
940
941 let mut encbuf = vec![];
942 if is_encrypted {
943 encbuf.append(&mut b_header.to_vec());
944 encbuf.append(&mut b_encimg);
945 encbuf.append(&mut b_tlv);
946 }
947
David Vincze2d736ad2019-02-18 11:50:22 +0100948 // Since images are always non-encrypted in the primary slot, we first write
949 // an encrypted image, re-read to use for verification, erase + flash
950 // un-encrypted. In the secondary slot the image is written un-encrypted,
951 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -0700952
David Brown76101572019-02-28 11:29:03 -0700953 let dev = flash.get_mut(&dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700954
955 if slot == 0 {
956 let enc_copy: Option<Vec<u8>>;
957
958 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -0700959 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700960
961 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -0700962 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700963
964 enc_copy = Some(enc);
965
David Brown76101572019-02-28 11:29:03 -0700966 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700967 } else {
968 enc_copy = None;
969 }
970
David Brown76101572019-02-28 11:29:03 -0700971 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700972
973 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -0700974 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700975
David Brownca234692019-02-28 11:22:19 -0700976 ImageData {
977 plain: copy,
978 cipher: enc_copy,
979 }
David Brown5c9e0f12019-01-09 16:34:33 -0700980 } else {
981
David Brown76101572019-02-28 11:29:03 -0700982 dev.write(offset, &buf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700983
984 let mut copy = vec![0u8; buf.len()];
David Brown76101572019-02-28 11:29:03 -0700985 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700986
987 let enc_copy: Option<Vec<u8>>;
988
989 if is_encrypted {
David Brown76101572019-02-28 11:29:03 -0700990 dev.erase(offset, slot_len).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700991
David Brown76101572019-02-28 11:29:03 -0700992 dev.write(offset, &encbuf).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700993
994 let mut enc = vec![0u8; encbuf.len()];
David Brown76101572019-02-28 11:29:03 -0700995 dev.read(offset, &mut enc).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -0700996
997 enc_copy = Some(enc);
998 } else {
999 enc_copy = None;
1000 }
1001
David Brownca234692019-02-28 11:22:19 -07001002 ImageData {
1003 plain: copy,
1004 cipher: enc_copy,
1005 }
David Brown5c9e0f12019-01-09 16:34:33 -07001006 }
David Brown5c9e0f12019-01-09 16:34:33 -07001007}
1008
David Brown5c9e0f12019-01-09 16:34:33 -07001009fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001010 if Caps::EcdsaP224.present() {
1011 panic!("Ecdsa P224 not supported in Simulator");
1012 }
David Brown5c9e0f12019-01-09 16:34:33 -07001013
David Brownb8882112019-01-11 14:04:11 -07001014 if Caps::EncKw.present() {
1015 if Caps::RSA2048.present() {
1016 TlvGen::new_rsa_kw()
1017 } else if Caps::EcdsaP256.present() {
1018 TlvGen::new_ecdsa_kw()
1019 } else {
1020 TlvGen::new_enc_kw()
1021 }
1022 } else if Caps::EncRsa.present() {
1023 if Caps::RSA2048.present() {
1024 TlvGen::new_sig_enc_rsa()
1025 } else {
1026 TlvGen::new_enc_rsa()
1027 }
1028 } else {
1029 // The non-encrypted configuration.
1030 if Caps::RSA2048.present() {
1031 TlvGen::new_rsa_pss()
1032 } else if Caps::EcdsaP256.present() {
1033 TlvGen::new_ecdsa()
1034 } else {
1035 TlvGen::new_hash_only()
1036 }
1037 }
David Brown5c9e0f12019-01-09 16:34:33 -07001038}
1039
David Brownca234692019-02-28 11:22:19 -07001040impl ImageData {
1041 /// Find the image contents for the given slot. This assumes that slot 0
1042 /// is unencrypted, and slot 1 is encrypted.
1043 fn find(&self, slot: usize) -> &Vec<u8> {
1044 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present();
1045 match (encrypted, slot) {
1046 (false, _) => &self.plain,
1047 (true, 0) => &self.plain,
1048 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
1049 _ => panic!("Invalid slot requested"),
1050 }
David Brown5c9e0f12019-01-09 16:34:33 -07001051 }
1052}
1053
David Brown5c9e0f12019-01-09 16:34:33 -07001054/// Verify that given image is present in the flash at the given offset.
David Brown76101572019-02-28 11:29:03 -07001055fn verify_image(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brownca234692019-02-28 11:22:19 -07001056 images: &ImageData) -> bool {
1057 let image = images.find(slot);
David Brown5c9e0f12019-01-09 16:34:33 -07001058 let buf = image.as_slice();
1059 let dev_id = slots[slot].dev_id;
1060
1061 let mut copy = vec![0u8; buf.len()];
1062 let offset = slots[slot].base_off;
David Brown76101572019-02-28 11:29:03 -07001063 let dev = flash.get(&dev_id).unwrap();
1064 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001065
1066 if buf != &copy[..] {
1067 for i in 0 .. buf.len() {
1068 if buf[i] != copy[i] {
1069 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1070 slot, offset + i, buf[i], copy[i]);
1071 break;
1072 }
1073 }
1074 false
1075 } else {
1076 true
1077 }
1078}
1079
David Brown76101572019-02-28 11:29:03 -07001080fn verify_trailer(flash: &SimMultiFlash, slots: &[SlotInfo], slot: usize,
David Brown5c9e0f12019-01-09 16:34:33 -07001081 magic: Option<u8>, image_ok: Option<u8>,
1082 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001083 if Caps::OverwriteUpgrade.present() {
1084 return true;
1085 }
David Brown5c9e0f12019-01-09 16:34:33 -07001086
David Brown5c9e0f12019-01-09 16:34:33 -07001087 let offset = slots[slot].trailer_off;
1088 let dev_id = slots[slot].dev_id;
1089 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1090 let mut failed = false;
1091
David Brown76101572019-02-28 11:29:03 -07001092 let dev = flash.get(&dev_id).unwrap();
1093 let erased_val = dev.erased_val();
1094 dev.read(offset, &mut copy).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001095
1096 failed |= match magic {
1097 Some(v) => {
1098 if v == 1 && &copy[16..] != MAGIC.unwrap() {
1099 warn!("\"magic\" mismatch at {:#x}", offset);
1100 true
1101 } else if v == 3 {
1102 let expected = [erased_val; 16];
1103 if &copy[16..] != expected {
1104 warn!("\"magic\" mismatch at {:#x}", offset);
1105 true
1106 } else {
1107 false
1108 }
1109 } else {
1110 false
1111 }
1112 },
1113 None => false,
1114 };
1115
1116 failed |= match image_ok {
1117 Some(v) => {
1118 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1119 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1120 true
1121 } else {
1122 false
1123 }
1124 },
1125 None => false,
1126 };
1127
1128 failed |= match copy_done {
1129 Some(v) => {
1130 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1131 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1132 true
1133 } else {
1134 false
1135 }
1136 },
1137 None => false,
1138 };
1139
1140 !failed
1141}
1142
1143/// The image header
1144#[repr(C)]
1145pub struct ImageHeader {
1146 magic: u32,
1147 load_addr: u32,
1148 hdr_size: u16,
1149 _pad1: u16,
1150 img_size: u32,
1151 flags: u32,
1152 ver: ImageVersion,
1153 _pad2: u32,
1154}
1155
1156impl AsRaw for ImageHeader {}
1157
1158#[repr(C)]
1159pub struct ImageVersion {
1160 major: u8,
1161 minor: u8,
1162 revision: u16,
1163 build_num: u32,
1164}
1165
1166#[derive(Clone)]
1167pub struct SlotInfo {
1168 pub base_off: usize,
1169 pub trailer_off: usize,
1170 pub len: usize,
1171 pub dev_id: u8,
1172}
1173
David Brown5c9e0f12019-01-09 16:34:33 -07001174const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1175 0x60, 0xd2, 0xef, 0x7f,
1176 0x35, 0x52, 0x50, 0x0f,
1177 0x2c, 0xb6, 0x79, 0x80]);
1178
1179// Replicates defines found in bootutil.h
1180const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1181const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1182
1183const BOOT_FLAG_SET: Option<u8> = Some(1);
1184const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1185
1186/// Write out the magic so that the loader tries doing an upgrade.
David Brown76101572019-02-28 11:29:03 -07001187pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1188 let dev = flash.get_mut(&slot.dev_id).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001189 let offset = slot.trailer_off + c::boot_max_align() * 2;
David Brown76101572019-02-28 11:29:03 -07001190 dev.write(offset, MAGIC.unwrap()).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001191}
1192
1193/// Writes the image_ok flag which, guess what, tells the bootloader
1194/// the this image is ok (not a test, and no revert is to be performed).
David Brown76101572019-02-28 11:29:03 -07001195fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
1196 let dev = flash.get_mut(&slot.dev_id).unwrap();
1197 let mut ok = [dev.erased_val(); 8];
David Brown5c9e0f12019-01-09 16:34:33 -07001198 ok[0] = 1u8;
1199 let off = slot.trailer_off + c::boot_max_align();
David Brown76101572019-02-28 11:29:03 -07001200 let align = dev.align();
1201 dev.write(off, &ok[..align]).unwrap();
David Brown5c9e0f12019-01-09 16:34:33 -07001202}
1203
1204// Drop some pseudo-random gibberish onto the data.
1205fn splat(data: &mut [u8], seed: usize) {
1206 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1207 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1208 rng.fill_bytes(data);
1209}
1210
1211/// Return a read-only view into the raw bytes of this object
1212trait AsRaw : Sized {
1213 fn as_raw<'a>(&'a self) -> &'a [u8] {
1214 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1215 mem::size_of::<Self>()) }
1216 }
1217}
1218
1219pub fn show_sizes() {
1220 // This isn't panic safe.
1221 for min in &[1, 2, 4, 8] {
1222 let msize = c::boot_trailer_sz(*min);
1223 println!("{:2}: {} (0x{:x})", min, msize, msize);
1224 }
1225}