blob: bc857d4c2f55dc38180730657b3e32cc455fe7c6 [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 Browne5133242019-02-28 11:05:19 -070019use simflash::{Flash, SimFlash, SimFlashMap};
20use 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 {
33 flashmap: SimFlashMap,
34 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.
39/// The flashmap holds the state of the simulated flash, whereas primaries
40/// and upgrades hold the expected contents of these images.
41pub struct Images {
42 pub flashmap: SimFlashMap,
43 pub areadesc: AreaDesc,
44 pub slots: [SlotInfo; 2],
45 pub primaries: [Option<Vec<u8>>; 2],
46 pub upgrades: [Option<Vec<u8>>; 2],
47 pub total_count: Option<i32>,
48}
49
David Browne5133242019-02-28 11:05:19 -070050impl ImagesBuilder {
51 pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Self {
52 let (flashmap, areadesc) = Self::make_device(device, align, erased_val);
53
54 let (slot0_base, slot0_len, slot0_dev_id) = areadesc.find(FlashId::Image0);
55 let (slot1_base, slot1_len, slot1_dev_id) = areadesc.find(FlashId::Image1);
56
57 // NOTE: not accounting "swap_size" because it is not used by sim...
58 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 2;
59
60 // Construct a primary image.
61 let slot0 = SlotInfo {
62 base_off: slot0_base as usize,
63 trailer_off: slot0_base + slot0_len - offset_from_end,
64 len: slot0_len as usize,
65 dev_id: slot0_dev_id,
66 };
67
68 // And an upgrade image.
69 let slot1 = SlotInfo {
70 base_off: slot1_base as usize,
71 trailer_off: slot1_base + slot1_len - offset_from_end,
72 len: slot1_len as usize,
73 dev_id: slot1_dev_id,
74 };
75
76 ImagesBuilder {
77 flashmap: flashmap,
78 areadesc: areadesc,
79 slots: [slot0, slot1],
80 }
81 }
82
83 pub fn each_device<F>(f: F)
84 where F: Fn(Self)
85 {
86 for &dev in ALL_DEVICES {
87 for &align in &[1, 2, 4, 8] {
88 for &erased_val in &[0, 0xff] {
89 let run = Self::new(dev, align, erased_val);
90 f(run);
91 }
92 }
93 }
94 }
95
96 /// Construct an `Images` that doesn't expect an upgrade to happen.
97 pub fn make_no_upgrade_image(self) -> Images {
98 let mut flashmap = self.flashmap;
99 let primaries = install_image(&mut flashmap, &self.slots, 0, 32784, false);
100 let upgrades = install_image(&mut flashmap, &self.slots, 1, 41928, false);
101 Images {
102 flashmap: flashmap,
103 areadesc: self.areadesc,
104 slots: self.slots,
105 primaries: primaries,
106 upgrades: upgrades,
107 total_count: None,
108 }
109 }
110
111 /// Construct an `Images` for normal testing.
112 pub fn make_image(self) -> Images {
113 let mut images = self.make_no_upgrade_image();
114 mark_upgrade(&mut images.flashmap, &images.slots[1]);
115
116 // upgrades without fails, counts number of flash operations
117 let total_count = match images.run_basic_upgrade() {
118 Ok(v) => v,
119 Err(_) => {
120 panic!("Unable to perform basic upgrade");
121 },
122 };
123
124 images.total_count = Some(total_count);
125 images
126 }
127
128 pub fn make_bad_secondary_slot_image(self) -> Images {
129 let mut bad_flashmap = self.flashmap;
130 let primaries = install_image(&mut bad_flashmap, &self.slots, 0, 32784, false);
131 let upgrades = install_image(&mut bad_flashmap, &self.slots, 1, 41928, true);
132 Images {
133 flashmap: bad_flashmap,
134 areadesc: self.areadesc,
135 slots: self.slots,
136 primaries: primaries,
137 upgrades: upgrades,
138 total_count: None,
139 }
140 }
141
142 /// Build the Flash and area descriptor for a given device.
143 pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimFlashMap, AreaDesc) {
144 match device {
145 DeviceName::Stm32f4 => {
146 // STM style flash. Large sectors, with a large scratch area.
147 let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
148 64 * 1024,
149 128 * 1024, 128 * 1024, 128 * 1024],
150 align as usize, erased_val);
151 let dev_id = 0;
152 let mut areadesc = AreaDesc::new();
153 areadesc.add_flash_sectors(dev_id, &flash);
154 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
155 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
156 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
157
158 let mut flashmap = SimFlashMap::new();
159 flashmap.insert(dev_id, flash);
160 (flashmap, areadesc)
161 }
162 DeviceName::K64f => {
163 // NXP style flash. Small sectors, one small sector for scratch.
164 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
165
166 let dev_id = 0;
167 let mut areadesc = AreaDesc::new();
168 areadesc.add_flash_sectors(dev_id, &flash);
169 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
170 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
171 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
172
173 let mut flashmap = SimFlashMap::new();
174 flashmap.insert(dev_id, flash);
175 (flashmap, areadesc)
176 }
177 DeviceName::K64fBig => {
178 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
179 // uses small sectors, but we tell the bootloader they are large.
180 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
181
182 let dev_id = 0;
183 let mut areadesc = AreaDesc::new();
184 areadesc.add_flash_sectors(dev_id, &flash);
185 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
186 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
187 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
188
189 let mut flashmap = SimFlashMap::new();
190 flashmap.insert(dev_id, flash);
191 (flashmap, areadesc)
192 }
193 DeviceName::Nrf52840 => {
194 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
195 // does not divide into the image size.
196 let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
197
198 let dev_id = 0;
199 let mut areadesc = AreaDesc::new();
200 areadesc.add_flash_sectors(dev_id, &flash);
201 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
202 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
203 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
204
205 let mut flashmap = SimFlashMap::new();
206 flashmap.insert(dev_id, flash);
207 (flashmap, areadesc)
208 }
209 DeviceName::Nrf52840SpiFlash => {
210 // Simulate nrf52840 with external SPI flash. The external SPI flash
211 // has a larger sector size so for now store scratch on that flash.
212 let flash0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
213 let flash1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
214
215 let mut areadesc = AreaDesc::new();
216 areadesc.add_flash_sectors(0, &flash0);
217 areadesc.add_flash_sectors(1, &flash1);
218
219 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
220 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
221 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
222
223 let mut flashmap = SimFlashMap::new();
224 flashmap.insert(0, flash0);
225 flashmap.insert(1, flash1);
226 (flashmap, areadesc)
227 }
228 }
229 }
230}
231
David Brown5c9e0f12019-01-09 16:34:33 -0700232impl Images {
233 /// A simple upgrade without forced failures.
234 ///
235 /// Returns the number of flash operations which can later be used to
236 /// inject failures at chosen steps.
237 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
238 let (flashmap, total_count) = try_upgrade(&self.flashmap, &self, None);
239 info!("Total flash operation count={}", total_count);
240
241 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
242 warn!("Image mismatch after first boot");
243 Err(())
244 } else {
245 Ok(total_count)
246 }
247 }
248
David Brown5c9e0f12019-01-09 16:34:33 -0700249 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700250 if Caps::OverwriteUpgrade.present() {
251 return false;
252 }
David Brown5c9e0f12019-01-09 16:34:33 -0700253
David Brown5c9e0f12019-01-09 16:34:33 -0700254 let mut fails = 0;
255
256 // FIXME: this test would also pass if no swap is ever performed???
257 if Caps::SwapUpgrade.present() {
258 for count in 2 .. 5 {
259 info!("Try revert: {}", count);
260 let flashmap = try_revert(&self.flashmap, &self.areadesc, count);
261 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
262 error!("Revert failure on count {}", count);
263 fails += 1;
264 }
265 }
266 }
267
268 fails > 0
269 }
270
271 pub fn run_perm_with_fails(&self) -> bool {
272 let mut fails = 0;
273 let total_flash_ops = self.total_count.unwrap();
274
275 // Let's try an image halfway through.
276 for i in 1 .. total_flash_ops {
277 info!("Try interruption at {}", i);
278 let (flashmap, count) = try_upgrade(&self.flashmap, &self, Some(i));
279 info!("Second boot, count={}", count);
280 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
281 warn!("FAIL at step {} of {}", i, total_flash_ops);
282 fails += 1;
283 }
284
285 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
286 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100287 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700288 fails += 1;
289 }
290
291 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
292 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100293 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700294 fails += 1;
295 }
296
297 if Caps::SwapUpgrade.present() {
298 if !verify_image(&flashmap, &self.slots, 1, &self.primaries) {
David Vincze2d736ad2019-02-18 11:50:22 +0100299 warn!("Secondary slot FAIL at step {} of {}",
300 i, total_flash_ops);
David Brown5c9e0f12019-01-09 16:34:33 -0700301 fails += 1;
302 }
303 }
304 }
305
306 if fails > 0 {
307 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
308 fails as f32 * 100.0 / total_flash_ops as f32);
309 }
310
311 fails > 0
312 }
313
314 pub fn run_perm_with_random_fails_5(&self) -> bool {
315 self.run_perm_with_random_fails(5)
316 }
317
318 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
319 let mut fails = 0;
320 let total_flash_ops = self.total_count.unwrap();
321 let (flashmap, total_counts) = try_random_fails(&self.flashmap, &self,
322 total_flash_ops, total_fails);
323 info!("Random interruptions at reset points={:?}", total_counts);
324
David Vincze2d736ad2019-02-18 11:50:22 +0100325 let primary_slot_ok = verify_image(&flashmap, &self.slots,
326 0, &self.upgrades);
327 let secondary_slot_ok = if Caps::SwapUpgrade.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700328 verify_image(&flashmap, &self.slots, 1, &self.primaries)
329 } else {
330 true
331 };
David Vincze2d736ad2019-02-18 11:50:22 +0100332 if !primary_slot_ok || !secondary_slot_ok {
333 error!("Image mismatch after random interrupts: primary slot={} \
334 secondary slot={}",
335 if primary_slot_ok { "ok" } else { "fail" },
336 if secondary_slot_ok { "ok" } else { "fail" });
David Brown5c9e0f12019-01-09 16:34:33 -0700337 fails += 1;
338 }
339 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
340 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100341 error!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700342 fails += 1;
343 }
344 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
345 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100346 error!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700347 fails += 1;
348 }
349
350 if fails > 0 {
351 error!("Error testing perm upgrade with {} fails", total_fails);
352 }
353
354 fails > 0
355 }
356
David Brown5c9e0f12019-01-09 16:34:33 -0700357 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700358 if Caps::OverwriteUpgrade.present() {
359 return false;
360 }
David Brown5c9e0f12019-01-09 16:34:33 -0700361
David Brown5c9e0f12019-01-09 16:34:33 -0700362 let mut fails = 0;
363
364 if Caps::SwapUpgrade.present() {
365 for i in 1 .. (self.total_count.unwrap() - 1) {
366 info!("Try interruption at {}", i);
367 if try_revert_with_fail_at(&self.flashmap, &self, i) {
368 error!("Revert failed at interruption {}", i);
369 fails += 1;
370 }
371 }
372 }
373
374 fails > 0
375 }
376
David Brown5c9e0f12019-01-09 16:34:33 -0700377 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700378 if Caps::OverwriteUpgrade.present() {
379 return false;
380 }
David Brown5c9e0f12019-01-09 16:34:33 -0700381
David Brown5c9e0f12019-01-09 16:34:33 -0700382 let mut flashmap = self.flashmap.clone();
383 let mut fails = 0;
384
385 info!("Try norevert");
386
387 // First do a normal upgrade...
388 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
389 if result != 0 {
390 warn!("Failed first boot");
391 fails += 1;
392 }
393
394 //FIXME: copy_done is written by boot_go, is it ok if no copy
395 // was ever done?
396
397 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
David Vincze2d736ad2019-02-18 11:50:22 +0100398 warn!("Primary slot image verification FAIL");
David Brown5c9e0f12019-01-09 16:34:33 -0700399 fails += 1;
400 }
401 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
402 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100403 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700404 fails += 1;
405 }
406 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
407 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100408 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700409 fails += 1;
410 }
411
David Vincze2d736ad2019-02-18 11:50:22 +0100412 // Marks image in the primary slot as permanent,
413 // no revert should happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700414 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
415
416 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
417 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100418 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700419 fails += 1;
420 }
421
422 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
423 if result != 0 {
424 warn!("Failed second boot");
425 fails += 1;
426 }
427
428 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
429 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100430 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700431 fails += 1;
432 }
433 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
434 warn!("Failed image verification");
435 fails += 1;
436 }
437
438 if fails > 0 {
439 error!("Error running upgrade without revert");
440 }
441
442 fails > 0
443 }
444
David Vincze2d736ad2019-02-18 11:50:22 +0100445 // Tests a new image written to the primary slot that already has magic and
446 // image_ok set while there is no image on the secondary slot, so no revert
447 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700448 pub fn run_norevert_newimage(&self) -> bool {
449 let mut flashmap = self.flashmap.clone();
450 let mut fails = 0;
451
452 info!("Try non-revert on imgtool generated image");
453
454 mark_upgrade(&mut flashmap, &self.slots[0]);
455
David Vincze2d736ad2019-02-18 11:50:22 +0100456 // This simulates writing an image created by imgtool to
457 // the primary slot
David Brown5c9e0f12019-01-09 16:34:33 -0700458 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
459 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100460 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700461 fails += 1;
462 }
463
464 // Run the bootloader...
465 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
466 if result != 0 {
467 warn!("Failed first boot");
468 fails += 1;
469 }
470
471 // State should not have changed
472 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
473 warn!("Failed image verification");
474 fails += 1;
475 }
476 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
477 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100478 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700479 fails += 1;
480 }
481 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
482 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100483 warn!("Mismatched trailer for the secondary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700484 fails += 1;
485 }
486
487 if fails > 0 {
488 error!("Expected a non revert with new image");
489 }
490
491 fails > 0
492 }
493
David Vincze2d736ad2019-02-18 11:50:22 +0100494 // Tests a new image written to the primary slot that already has magic and
495 // image_ok set while there is no image on the secondary slot, so no revert
496 // should ever happen...
David Brown5c9e0f12019-01-09 16:34:33 -0700497 pub fn run_signfail_upgrade(&self) -> bool {
498 let mut flashmap = self.flashmap.clone();
499 let mut fails = 0;
500
501 info!("Try upgrade image with bad signature");
502
503 mark_upgrade(&mut flashmap, &self.slots[0]);
504 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
505 mark_upgrade(&mut flashmap, &self.slots[1]);
506
507 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
508 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
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 }
512
513 // Run the bootloader...
514 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
515 if result != 0 {
516 warn!("Failed first boot");
517 fails += 1;
518 }
519
520 // State should not have changed
521 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
522 warn!("Failed image verification");
523 fails += 1;
524 }
525 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
526 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100527 warn!("Mismatched trailer for the primary slot");
David Brown5c9e0f12019-01-09 16:34:33 -0700528 fails += 1;
529 }
530
531 if fails > 0 {
532 error!("Expected an upgrade failure when image has bad signature");
533 }
534
535 fails > 0
536 }
537
David Brown5c9e0f12019-01-09 16:34:33 -0700538 fn trailer_sz(&self, align: usize) -> usize {
539 c::boot_trailer_sz(align as u8) as usize
540 }
541
542 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700543 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700544 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
545 32
546 } else {
547 0
548 };
David Brown5c9e0f12019-01-09 16:34:33 -0700549
David Brown9930a3e2019-01-11 12:28:26 -0700550 self.trailer_sz(align) - (16 + 24 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700551 }
552
553 /// This test runs a simple upgrade with no fails in the images, but
554 /// allowing for fails in the status area. This should run to the end
555 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700556 pub fn run_with_status_fails_complete(&self) -> bool {
David Vincze2d736ad2019-02-18 11:50:22 +0100557 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700558 return false;
559 }
560
David Brown5c9e0f12019-01-09 16:34:33 -0700561 let mut flashmap = self.flashmap.clone();
562 let mut fails = 0;
563
564 info!("Try swap with status fails");
565
566 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
567 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
568
569 let (result, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
570 if result != 0 {
571 warn!("Failed!");
572 fails += 1;
573 }
574
575 // Failed writes to the marked "bad" region don't assert anymore.
576 // Any detected assert() is happening in another part of the code.
577 if asserts != 0 {
578 warn!("At least one assert() was called");
579 fails += 1;
580 }
581
582 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
583 BOOT_FLAG_SET, BOOT_FLAG_SET) {
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 }
587
588 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
589 warn!("Failed image verification");
590 fails += 1;
591 }
592
David Vincze2d736ad2019-02-18 11:50:22 +0100593 info!("validate primary slot enabled; \
594 re-run of boot_go should just work");
David Brown5c9e0f12019-01-09 16:34:33 -0700595 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
596 if result != 0 {
597 warn!("Failed!");
598 fails += 1;
599 }
600
601 if fails > 0 {
602 error!("Error running upgrade with status write fails");
603 }
604
605 fails > 0
606 }
607
608 /// This test runs a simple upgrade with no fails in the images, but
609 /// allowing for fails in the status area. This should run to the end
610 /// and warn that write fails were detected...
David Brown5c9e0f12019-01-09 16:34:33 -0700611 pub fn run_with_status_fails_with_reset(&self) -> bool {
David Brown85904a82019-01-11 13:45:12 -0700612 if Caps::OverwriteUpgrade.present() {
613 false
David Vincze2d736ad2019-02-18 11:50:22 +0100614 } else if Caps::ValidatePrimarySlot.present() {
David Brown5c9e0f12019-01-09 16:34:33 -0700615
David Brown85904a82019-01-11 13:45:12 -0700616 let mut flashmap = self.flashmap.clone();
617 let mut fails = 0;
618 let mut count = self.total_count.unwrap() / 2;
David Brown5c9e0f12019-01-09 16:34:33 -0700619
David Brown85904a82019-01-11 13:45:12 -0700620 //info!("count={}\n", count);
David Brown5c9e0f12019-01-09 16:34:33 -0700621
David Brown85904a82019-01-11 13:45:12 -0700622 info!("Try interrupted swap with status fails");
David Brown5c9e0f12019-01-09 16:34:33 -0700623
David Brown85904a82019-01-11 13:45:12 -0700624 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
625 self.mark_bad_status_with_rate(&mut flashmap, 0, 0.5);
626
627 // Should not fail, writing to bad regions does not assert
628 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, Some(&mut count), true);
629 if asserts != 0 {
630 warn!("At least one assert() was called");
631 fails += 1;
632 }
633
634 self.reset_bad_status(&mut flashmap, 0);
635
636 info!("Resuming an interrupted swap operation");
637 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
638
639 // This might throw no asserts, for large sector devices, where
640 // a single failure writing is indistinguishable from no failure,
641 // or throw a single assert for small sector devices that fail
642 // multiple times...
643 if asserts > 1 {
David Vincze2d736ad2019-02-18 11:50:22 +0100644 warn!("Expected single assert validating the primary slot, \
645 more detected {}", asserts);
David Brown85904a82019-01-11 13:45:12 -0700646 fails += 1;
647 }
648
649 if fails > 0 {
650 error!("Error running upgrade with status write fails");
651 }
652
653 fails > 0
654 } else {
655 let mut flashmap = self.flashmap.clone();
656 let mut fails = 0;
657
658 info!("Try interrupted swap with status fails");
659
660 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
661 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
662
663 // This is expected to fail while writing to bad regions...
664 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
665 if asserts == 0 {
666 warn!("No assert() detected");
667 fails += 1;
668 }
669
670 fails > 0
David Brown5c9e0f12019-01-09 16:34:33 -0700671 }
David Brown5c9e0f12019-01-09 16:34:33 -0700672 }
673
674 /// Adds a new flash area that fails statistically
David Brown5c9e0f12019-01-09 16:34:33 -0700675 fn mark_bad_status_with_rate(&self, flashmap: &mut SimFlashMap, slot: usize,
676 rate: f32) {
David Brown85904a82019-01-11 13:45:12 -0700677 if Caps::OverwriteUpgrade.present() {
678 return;
679 }
680
David Brown5c9e0f12019-01-09 16:34:33 -0700681 let dev_id = &self.slots[slot].dev_id;
682 let flash = flashmap.get_mut(&dev_id).unwrap();
683 let align = flash.align();
684 let off = &self.slots[0].base_off;
685 let len = &self.slots[0].len;
686 let status_off = off + len - self.trailer_sz(align);
687
688 // Mark the status area as a bad area
689 let _ = flash.add_bad_region(status_off, self.status_sz(align), rate);
690 }
691
David Brown5c9e0f12019-01-09 16:34:33 -0700692 fn reset_bad_status(&self, flashmap: &mut SimFlashMap, slot: usize) {
David Vincze2d736ad2019-02-18 11:50:22 +0100693 if !Caps::ValidatePrimarySlot.present() {
David Brown85904a82019-01-11 13:45:12 -0700694 return;
695 }
696
David Brown5c9e0f12019-01-09 16:34:33 -0700697 let dev_id = &self.slots[slot].dev_id;
698 let flash = flashmap.get_mut(&dev_id).unwrap();
699 flash.reset_bad_regions();
700
701 // Disabling write verification the only assert triggered by
702 // boot_go should be checking for integrity of status bytes.
703 flash.set_verify_writes(false);
704 }
705
David Brown5c9e0f12019-01-09 16:34:33 -0700706}
707
708/// Test a boot, optionally stopping after 'n' flash options. Returns a count
709/// of the number of flash operations done total.
710fn try_upgrade(flashmap: &SimFlashMap, images: &Images,
711 stop: Option<i32>) -> (SimFlashMap, i32) {
712 // Clone the flash to have a new copy.
713 let mut flashmap = flashmap.clone();
714
715 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
716
717 let mut counter = stop.unwrap_or(0);
718
719 let (first_interrupted, count) = match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
720 (-0x13579, _) => (true, stop.unwrap()),
721 (0, _) => (false, -counter),
722 (x, _) => panic!("Unknown return: {}", x),
723 };
724
725 counter = 0;
726 if first_interrupted {
727 // fl.dump();
728 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
729 (-0x13579, _) => panic!("Shouldn't stop again"),
730 (0, _) => (),
731 (x, _) => panic!("Unknown return: {}", x),
732 }
733 }
734
735 (flashmap, count - counter)
736}
737
David Brown5c9e0f12019-01-09 16:34:33 -0700738fn try_revert(flashmap: &SimFlashMap, areadesc: &AreaDesc, count: usize) -> SimFlashMap {
739 let mut flashmap = flashmap.clone();
740
741 // fl.write_file("image0.bin").unwrap();
742 for i in 0 .. count {
743 info!("Running boot pass {}", i + 1);
744 assert_eq!(c::boot_go(&mut flashmap, &areadesc, None, false), (0, 0));
745 }
746 flashmap
747}
748
David Brown5c9e0f12019-01-09 16:34:33 -0700749fn try_revert_with_fail_at(flashmap: &SimFlashMap, images: &Images,
750 stop: i32) -> bool {
751 let mut flashmap = flashmap.clone();
752 let mut fails = 0;
753
754 let mut counter = stop;
755 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false);
756 if x != -0x13579 {
757 warn!("Should have stopped at interruption point");
758 fails += 1;
759 }
760
761 if !verify_trailer(&flashmap, &images.slots, 0, None, None, BOOT_FLAG_UNSET) {
762 warn!("copy_done should be unset");
763 fails += 1;
764 }
765
766 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
767 if x != 0 {
768 warn!("Should have finished upgrade");
769 fails += 1;
770 }
771
772 if !verify_image(&flashmap, &images.slots, 0, &images.upgrades) {
David Vincze2d736ad2019-02-18 11:50:22 +0100773 warn!("Image in the primary slot before revert is invalid at stop={}",
774 stop);
David Brown5c9e0f12019-01-09 16:34:33 -0700775 fails += 1;
776 }
777 if !verify_image(&flashmap, &images.slots, 1, &images.primaries) {
David Vincze2d736ad2019-02-18 11:50:22 +0100778 warn!("Image in the secondary slot before revert is invalid at stop={}",
779 stop);
David Brown5c9e0f12019-01-09 16:34:33 -0700780 fails += 1;
781 }
782 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
783 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100784 warn!("Mismatched trailer for the primary slot before revert");
David Brown5c9e0f12019-01-09 16:34:33 -0700785 fails += 1;
786 }
787 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
788 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100789 warn!("Mismatched trailer for the secondary slot before revert");
David Brown5c9e0f12019-01-09 16:34:33 -0700790 fails += 1;
791 }
792
793 // Do Revert
794 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
795 if x != 0 {
796 warn!("Should have finished a revert");
797 fails += 1;
798 }
799
800 if !verify_image(&flashmap, &images.slots, 0, &images.primaries) {
David Vincze2d736ad2019-02-18 11:50:22 +0100801 warn!("Image in the primary slot after revert is invalid at stop={}",
802 stop);
David Brown5c9e0f12019-01-09 16:34:33 -0700803 fails += 1;
804 }
805 if !verify_image(&flashmap, &images.slots, 1, &images.upgrades) {
David Vincze2d736ad2019-02-18 11:50:22 +0100806 warn!("Image in the secondary slot after revert is invalid at stop={}",
807 stop);
David Brown5c9e0f12019-01-09 16:34:33 -0700808 fails += 1;
809 }
810 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
811 BOOT_FLAG_SET, BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100812 warn!("Mismatched trailer for the secondary slot after revert");
David Brown5c9e0f12019-01-09 16:34:33 -0700813 fails += 1;
814 }
815 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
816 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
David Vincze2d736ad2019-02-18 11:50:22 +0100817 warn!("Mismatched trailer for the secondary slot after revert");
David Brown5c9e0f12019-01-09 16:34:33 -0700818 fails += 1;
819 }
820
821 fails > 0
822}
823
824fn try_random_fails(flashmap: &SimFlashMap, images: &Images,
825 total_ops: i32, count: usize) -> (SimFlashMap, Vec<i32>) {
826 let mut flashmap = flashmap.clone();
827
828 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
829
830 let mut rng = rand::thread_rng();
831 let mut resets = vec![0i32; count];
832 let mut remaining_ops = total_ops;
833 for i in 0 .. count {
834 let ops = Range::new(1, remaining_ops / 2);
835 let reset_counter = ops.ind_sample(&mut rng);
836 let mut counter = reset_counter;
837 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
838 (0, _) | (-0x13579, _) => (),
839 (x, _) => panic!("Unknown return: {}", x),
840 }
841 remaining_ops -= reset_counter;
842 resets[i] = reset_counter;
843 }
844
845 match c::boot_go(&mut flashmap, &images.areadesc, None, false) {
846 (-0x13579, _) => panic!("Should not be have been interrupted!"),
847 (0, _) => (),
848 (x, _) => panic!("Unknown return: {}", x),
849 }
850
851 (flashmap, resets)
852}
853
854/// Show the flash layout.
855#[allow(dead_code)]
856fn show_flash(flash: &dyn Flash) {
857 println!("---- Flash configuration ----");
858 for sector in flash.sector_iter() {
859 println!(" {:3}: 0x{:08x}, 0x{:08x}",
860 sector.num, sector.base, sector.size);
861 }
862 println!("");
863}
864
865/// Install a "program" into the given image. This fakes the image header, or at least all of the
866/// fields used by the given code. Returns a copy of the image that was written.
867pub fn install_image(flashmap: &mut SimFlashMap, slots: &[SlotInfo], slot: usize, len: usize,
868 bad_sig: bool) -> [Option<Vec<u8>>; 2] {
869 let offset = slots[slot].base_off;
870 let slot_len = slots[slot].len;
871 let dev_id = slots[slot].dev_id;
872
David Brown43643dd2019-01-11 15:43:28 -0700873 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
David Brown5c9e0f12019-01-09 16:34:33 -0700874
875 const HDR_SIZE: usize = 32;
876
877 // Generate a boot header. Note that the size doesn't include the header.
878 let header = ImageHeader {
David Brownac46e262019-01-11 15:46:18 -0700879 magic: tlv.get_magic(),
David Brown5c9e0f12019-01-09 16:34:33 -0700880 load_addr: 0,
881 hdr_size: HDR_SIZE as u16,
882 _pad1: 0,
883 img_size: len as u32,
884 flags: tlv.get_flags(),
885 ver: ImageVersion {
886 major: (offset / (128 * 1024)) as u8,
887 minor: 0,
888 revision: 1,
889 build_num: offset as u32,
890 },
891 _pad2: 0,
892 };
893
894 let mut b_header = [0; HDR_SIZE];
895 b_header[..32].clone_from_slice(header.as_raw());
896 assert_eq!(b_header.len(), HDR_SIZE);
897
898 tlv.add_bytes(&b_header);
899
900 // The core of the image itself is just pseudorandom data.
901 let mut b_img = vec![0; len];
902 splat(&mut b_img, offset);
903
904 // TLV signatures work over plain image
905 tlv.add_bytes(&b_img);
906
907 // Generate encrypted images
908 let flag = TlvFlags::ENCRYPTED as u32;
909 let is_encrypted = (tlv.get_flags() & flag) == flag;
910 let mut b_encimg = vec![];
911 if is_encrypted {
912 let key = GenericArray::from_slice(AES_SEC_KEY);
913 let nonce = GenericArray::from_slice(&[0; 16]);
914 let mut cipher = Aes128Ctr::new(&key, &nonce);
915 b_encimg = b_img.clone();
916 cipher.apply_keystream(&mut b_encimg);
917 }
918
919 // Build the TLV itself.
920 let mut b_tlv = if bad_sig {
921 let good_sig = &mut tlv.make_tlv();
922 vec![0; good_sig.len()]
923 } else {
924 tlv.make_tlv()
925 };
926
927 // Pad the block to a flash alignment (8 bytes).
928 while b_tlv.len() % 8 != 0 {
929 //FIXME: should be erase_val?
930 b_tlv.push(0xFF);
931 }
932
933 let mut buf = vec![];
934 buf.append(&mut b_header.to_vec());
935 buf.append(&mut b_img);
936 buf.append(&mut b_tlv.clone());
937
938 let mut encbuf = vec![];
939 if is_encrypted {
940 encbuf.append(&mut b_header.to_vec());
941 encbuf.append(&mut b_encimg);
942 encbuf.append(&mut b_tlv);
943 }
944
945 let result: [Option<Vec<u8>>; 2];
946
David Vincze2d736ad2019-02-18 11:50:22 +0100947 // Since images are always non-encrypted in the primary slot, we first write
948 // an encrypted image, re-read to use for verification, erase + flash
949 // un-encrypted. In the secondary slot the image is written un-encrypted,
950 // and if encryption is requested, it follows an erase + flash encrypted.
David Brown5c9e0f12019-01-09 16:34:33 -0700951
952 let flash = flashmap.get_mut(&dev_id).unwrap();
953
954 if slot == 0 {
955 let enc_copy: Option<Vec<u8>>;
956
957 if is_encrypted {
958 flash.write(offset, &encbuf).unwrap();
959
960 let mut enc = vec![0u8; encbuf.len()];
961 flash.read(offset, &mut enc).unwrap();
962
963 enc_copy = Some(enc);
964
965 flash.erase(offset, slot_len).unwrap();
966 } else {
967 enc_copy = None;
968 }
969
970 flash.write(offset, &buf).unwrap();
971
972 let mut copy = vec![0u8; buf.len()];
973 flash.read(offset, &mut copy).unwrap();
974
975 result = [Some(copy), enc_copy];
976 } else {
977
978 flash.write(offset, &buf).unwrap();
979
980 let mut copy = vec![0u8; buf.len()];
981 flash.read(offset, &mut copy).unwrap();
982
983 let enc_copy: Option<Vec<u8>>;
984
985 if is_encrypted {
986 flash.erase(offset, slot_len).unwrap();
987
988 flash.write(offset, &encbuf).unwrap();
989
990 let mut enc = vec![0u8; encbuf.len()];
991 flash.read(offset, &mut enc).unwrap();
992
993 enc_copy = Some(enc);
994 } else {
995 enc_copy = None;
996 }
997
998 result = [Some(copy), enc_copy];
999 }
1000
1001 result
1002}
1003
David Brown5c9e0f12019-01-09 16:34:33 -07001004fn make_tlv() -> TlvGen {
David Brownb8882112019-01-11 14:04:11 -07001005 if Caps::EcdsaP224.present() {
1006 panic!("Ecdsa P224 not supported in Simulator");
1007 }
David Brown5c9e0f12019-01-09 16:34:33 -07001008
David Brownb8882112019-01-11 14:04:11 -07001009 if Caps::EncKw.present() {
1010 if Caps::RSA2048.present() {
1011 TlvGen::new_rsa_kw()
1012 } else if Caps::EcdsaP256.present() {
1013 TlvGen::new_ecdsa_kw()
1014 } else {
1015 TlvGen::new_enc_kw()
1016 }
1017 } else if Caps::EncRsa.present() {
1018 if Caps::RSA2048.present() {
1019 TlvGen::new_sig_enc_rsa()
1020 } else {
1021 TlvGen::new_enc_rsa()
1022 }
1023 } else {
1024 // The non-encrypted configuration.
1025 if Caps::RSA2048.present() {
1026 TlvGen::new_rsa_pss()
1027 } else if Caps::EcdsaP256.present() {
1028 TlvGen::new_ecdsa()
1029 } else {
1030 TlvGen::new_hash_only()
1031 }
1032 }
David Brown5c9e0f12019-01-09 16:34:33 -07001033}
1034
David Brown5c9e0f12019-01-09 16:34:33 -07001035fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
David Brownf38bc342019-01-11 14:07:58 -07001036 let slot = if Caps::EncRsa.present() || Caps::EncKw.present() {
1037 slot
1038 } else {
1039 0
1040 };
David Brown5c9e0f12019-01-09 16:34:33 -07001041
David Brown5c9e0f12019-01-09 16:34:33 -07001042 match &images[slot] {
1043 Some(image) => return image,
1044 None => panic!("Invalid image"),
1045 }
1046}
1047
David Brown5c9e0f12019-01-09 16:34:33 -07001048/// Verify that given image is present in the flash at the given offset.
1049fn verify_image(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
1050 images: &[Option<Vec<u8>>; 2]) -> bool {
1051 let image = find_image(images, slot);
1052 let buf = image.as_slice();
1053 let dev_id = slots[slot].dev_id;
1054
1055 let mut copy = vec![0u8; buf.len()];
1056 let offset = slots[slot].base_off;
1057 let flash = flashmap.get(&dev_id).unwrap();
1058 flash.read(offset, &mut copy).unwrap();
1059
1060 if buf != &copy[..] {
1061 for i in 0 .. buf.len() {
1062 if buf[i] != copy[i] {
1063 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
1064 slot, offset + i, buf[i], copy[i]);
1065 break;
1066 }
1067 }
1068 false
1069 } else {
1070 true
1071 }
1072}
1073
David Brown5c9e0f12019-01-09 16:34:33 -07001074fn verify_trailer(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
1075 magic: Option<u8>, image_ok: Option<u8>,
1076 copy_done: Option<u8>) -> bool {
David Brown61a540d2019-01-11 14:29:14 -07001077 if Caps::OverwriteUpgrade.present() {
1078 return true;
1079 }
David Brown5c9e0f12019-01-09 16:34:33 -07001080
David Brown5c9e0f12019-01-09 16:34:33 -07001081 let offset = slots[slot].trailer_off;
1082 let dev_id = slots[slot].dev_id;
1083 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
1084 let mut failed = false;
1085
1086 let flash = flashmap.get(&dev_id).unwrap();
1087 let erased_val = flash.erased_val();
1088 flash.read(offset, &mut copy).unwrap();
1089
1090 failed |= match magic {
1091 Some(v) => {
1092 if v == 1 && &copy[16..] != MAGIC.unwrap() {
1093 warn!("\"magic\" mismatch at {:#x}", offset);
1094 true
1095 } else if v == 3 {
1096 let expected = [erased_val; 16];
1097 if &copy[16..] != expected {
1098 warn!("\"magic\" mismatch at {:#x}", offset);
1099 true
1100 } else {
1101 false
1102 }
1103 } else {
1104 false
1105 }
1106 },
1107 None => false,
1108 };
1109
1110 failed |= match image_ok {
1111 Some(v) => {
1112 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
1113 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
1114 true
1115 } else {
1116 false
1117 }
1118 },
1119 None => false,
1120 };
1121
1122 failed |= match copy_done {
1123 Some(v) => {
1124 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
1125 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
1126 true
1127 } else {
1128 false
1129 }
1130 },
1131 None => false,
1132 };
1133
1134 !failed
1135}
1136
1137/// The image header
1138#[repr(C)]
1139pub struct ImageHeader {
1140 magic: u32,
1141 load_addr: u32,
1142 hdr_size: u16,
1143 _pad1: u16,
1144 img_size: u32,
1145 flags: u32,
1146 ver: ImageVersion,
1147 _pad2: u32,
1148}
1149
1150impl AsRaw for ImageHeader {}
1151
1152#[repr(C)]
1153pub struct ImageVersion {
1154 major: u8,
1155 minor: u8,
1156 revision: u16,
1157 build_num: u32,
1158}
1159
1160#[derive(Clone)]
1161pub struct SlotInfo {
1162 pub base_off: usize,
1163 pub trailer_off: usize,
1164 pub len: usize,
1165 pub dev_id: u8,
1166}
1167
David Brown5c9e0f12019-01-09 16:34:33 -07001168const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
1169 0x60, 0xd2, 0xef, 0x7f,
1170 0x35, 0x52, 0x50, 0x0f,
1171 0x2c, 0xb6, 0x79, 0x80]);
1172
1173// Replicates defines found in bootutil.h
1174const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1175const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1176
1177const BOOT_FLAG_SET: Option<u8> = Some(1);
1178const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1179
1180/// Write out the magic so that the loader tries doing an upgrade.
1181pub fn mark_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
1182 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
1183 let offset = slot.trailer_off + c::boot_max_align() * 2;
1184 flash.write(offset, MAGIC.unwrap()).unwrap();
1185}
1186
1187/// Writes the image_ok flag which, guess what, tells the bootloader
1188/// the this image is ok (not a test, and no revert is to be performed).
1189fn mark_permanent_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
1190 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
1191 let mut ok = [flash.erased_val(); 8];
1192 ok[0] = 1u8;
1193 let off = slot.trailer_off + c::boot_max_align();
1194 let align = flash.align();
1195 flash.write(off, &ok[..align]).unwrap();
1196}
1197
1198// Drop some pseudo-random gibberish onto the data.
1199fn splat(data: &mut [u8], seed: usize) {
1200 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1201 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1202 rng.fill_bytes(data);
1203}
1204
1205/// Return a read-only view into the raw bytes of this object
1206trait AsRaw : Sized {
1207 fn as_raw<'a>(&'a self) -> &'a [u8] {
1208 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1209 mem::size_of::<Self>()) }
1210 }
1211}
1212
1213pub fn show_sizes() {
1214 // This isn't panic safe.
1215 for min in &[1, 2, 4, 8] {
1216 let msize = c::boot_trailer_sz(*min);
1217 println!("{:2}: {} (0x{:x})", min, msize, msize);
1218 }
1219}