1 // Copyright (c) 2019-2021 Linaro LTD
2 // Copyright (c) 2019-2020 JUUL Labs
3 // Copyright (c) 2019-2023 Arm Limited
4 //
5 // SPDX-License-Identifier: Apache-2.0
6
7 use byteorder::{
8 LittleEndian, WriteBytesExt,
9 };
10 use log::{
11 Level::Info,
12 error,
13 info,
14 log_enabled,
15 warn,
16 };
17 use rand::{
18 Rng, RngCore, SeedableRng,
19 rngs::SmallRng,
20 };
21 use std::{
22 collections::{BTreeMap, HashSet}, io::{Cursor, Write}, mem, rc::Rc, slice
23 };
24 use aes::{
25 Aes128,
26 Aes128Ctr,
27 Aes256,
28 Aes256Ctr,
29 NewBlockCipher,
30 };
31 use cipher::{
32 FromBlockCipher,
33 generic_array::GenericArray,
34 StreamCipher,
35 };
36
37 use simflash::{Flash, SimFlash, SimMultiFlash};
38 use mcuboot_sys::{c, AreaDesc, FlashId, RamBlock};
39 use crate::{
40 ALL_DEVICES,
41 DeviceName,
42 };
43 use crate::caps::Caps;
44 use crate::depends::{
45 BoringDep,
46 Depender,
47 DepTest,
48 DepType,
49 NO_DEPS,
50 PairDep,
51 UpgradeInfo,
52 };
53 use crate::tlv::{ManifestGen, TlvGen, TlvFlags};
54 use crate::utils::align_up;
55 use typenum::{U32, U16};
56
57 /// For testing, use a non-zero offset for the ram-load, to make sure the offset is getting used
58 /// properly, but the value is not really that important.
59 const RAM_LOAD_ADDR: u32 = 1024;
60
61 /// A builder for Images. This describes a single run of the simulator,
62 /// capturing the configuration of a particular set of devices, including
63 /// the flash simulator(s) and the information about the slots.
64 #[derive(Clone)]
65 pub struct ImagesBuilder {
66 flash: SimMultiFlash,
67 areadesc: Rc<AreaDesc>,
68 slots: Vec<[SlotInfo; 2]>,
69 ram: RamData,
70 }
71
72 /// Images represents the state of a simulation for a given set of images.
73 /// The flash holds the state of the simulated flash, whereas primaries
74 /// and upgrades hold the expected contents of these images.
75 pub struct Images {
76 flash: SimMultiFlash,
77 areadesc: Rc<AreaDesc>,
78 images: Vec<OneImage>,
79 total_count: Option<i32>,
80 ram: RamData,
81 }
82
83 /// When doing multi-image, there is an instance of this information for
84 /// each of the images. Single image there will be one of these.
85 struct OneImage {
86 slots: [SlotInfo; 2],
87 primaries: ImageData,
88 upgrades: ImageData,
89 }
90
91 /// The Rust-side representation of an image. For unencrypted images, this
92 /// is just the unencrypted payload. For encrypted images, we store both
93 /// the encrypted and the plaintext.
94 struct ImageData {
95 size: usize,
96 plain: Vec<u8>,
97 cipher: Option<Vec<u8>>,
98 }
99
100 /// For the RamLoad test cases, we need a contiguous area of RAM to load these images into. For
101 /// multi-image builds, these may not correspond with the offsets. This has to be computed early,
102 /// before images are built, because each image contains the offset where the image is to be loaded
103 /// in the header, which is contained within the signature.
104 #[derive(Clone, Debug)]
105 struct RamData {
106 places: BTreeMap<SlotKey, SlotPlace>,
107 total: u32,
108 }
109
110 /// Every slot is indexed by this key.
111 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
112 struct SlotKey {
113 dev_id: u8,
114 base_off: usize,
115 }
116
117 #[derive(Clone, Debug)]
118 struct SlotPlace {
119 offset: u32,
120 size: u32,
121 }
122
123 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
124 pub enum ImageManipulation {
125 None,
126 BadSignature,
127 WrongOffset,
128 IgnoreRamLoadFlag,
129 /// True to use same address,
130 /// false to overlap by 1 byte
131 OverlapImages(bool),
132 CorruptHigherVersionImage,
133 }
134
135
136 impl ImagesBuilder {
137 /// Construct a new image builder for the given device. Returns
138 /// Some(builder) if is possible to test this configuration, or None if
139 /// not possible (for example, if there aren't enough image slots).
new(device: DeviceName, align: usize, erased_val: u8) -> Result<Self, String>140 pub fn new(device: DeviceName, align: usize, erased_val: u8) -> Result<Self, String> {
141 let (flash, areadesc, unsupported_caps) = Self::make_device(device, align, erased_val);
142
143 for cap in unsupported_caps {
144 if cap.present() {
145 return Err(format!("unsupported {:?}", cap));
146 }
147 }
148
149 let num_images = Caps::get_num_images();
150
151 let mut slots = Vec::with_capacity(num_images);
152 for image in 0..num_images {
153 // This mapping must match that defined in
154 // `boot/zephyr/include/sysflash/sysflash.h`.
155 let id0 = match image {
156 0 => FlashId::Image0,
157 1 => FlashId::Image2,
158 _ => panic!("More than 2 images not supported"),
159 };
160 let (primary_base, primary_len, primary_dev_id) = match areadesc.find(id0) {
161 Some(info) => info,
162 None => return Err("insufficient partitions".to_string()),
163 };
164 let id1 = match image {
165 0 => FlashId::Image1,
166 1 => FlashId::Image3,
167 _ => panic!("More than 2 images not supported"),
168 };
169 let (secondary_base, secondary_len, secondary_dev_id) = match areadesc.find(id1) {
170 Some(info) => info,
171 None => return Err("insufficient partitions".to_string()),
172 };
173
174 let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 4;
175
176 // Construct a primary image.
177 let primary = SlotInfo {
178 base_off: primary_base as usize,
179 trailer_off: primary_base + primary_len - offset_from_end,
180 len: primary_len as usize,
181 dev_id: primary_dev_id,
182 index: 0,
183 };
184
185 // And an upgrade image.
186 let secondary = SlotInfo {
187 base_off: secondary_base as usize,
188 trailer_off: secondary_base + secondary_len - offset_from_end,
189 len: secondary_len as usize,
190 dev_id: secondary_dev_id,
191 index: 1,
192 };
193
194 slots.push([primary, secondary]);
195 }
196
197 let ram = RamData::new(&slots);
198
199 Ok(ImagesBuilder {
200 flash,
201 areadesc,
202 slots,
203 ram,
204 })
205 }
206
each_device<F>(f: F) where F: Fn(Self)207 pub fn each_device<F>(f: F)
208 where F: Fn(Self)
209 {
210 for &dev in ALL_DEVICES {
211 for &align in test_alignments() {
212 for &erased_val in &[0, 0xff] {
213 match Self::new(dev, align, erased_val) {
214 Ok(run) => f(run),
215 Err(msg) => warn!("Skipping {}: {}", dev, msg),
216 }
217 }
218 }
219 }
220 }
221
222 /// Construct an `Images` that doesn't expect an upgrade to happen.
make_no_upgrade_image(self, deps: &DepTest, img_manipulation: ImageManipulation) -> Images223 pub fn make_no_upgrade_image(self, deps: &DepTest, img_manipulation: ImageManipulation) -> Images {
224 let num_images = self.num_images();
225 let mut flash = self.flash;
226 let ram = self.ram.clone(); // TODO: Avoid this clone.
227 let mut higher_version_corrupted = false;
228 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
229 let dep: Box<dyn Depender> = if num_images > 1 {
230 Box::new(PairDep::new(num_images, image_num, deps))
231 } else {
232 Box::new(BoringDep::new(image_num, deps))
233 };
234
235 let (primaries,upgrades) = if img_manipulation == ImageManipulation::CorruptHigherVersionImage && !higher_version_corrupted {
236 higher_version_corrupted = true;
237 let prim = install_image(&mut flash, &slots[0],
238 maximal(42784), &ram, &*dep, ImageManipulation::None, Some(0), false);
239 let upgr = match deps.depends[image_num] {
240 DepType::NoUpgrade => install_no_image(),
241 _ => install_image(&mut flash, &slots[1],
242 maximal(46928), &ram, &*dep, ImageManipulation::BadSignature, Some(0), true)
243 };
244 (prim, upgr)
245 } else {
246 let prim = install_image(&mut flash, &slots[0],
247 maximal(42784), &ram, &*dep, img_manipulation, Some(0), false);
248 let upgr = match deps.depends[image_num] {
249 DepType::NoUpgrade => install_no_image(),
250 _ => install_image(&mut flash, &slots[1],
251 maximal(46928), &ram, &*dep, img_manipulation, Some(0), true)
252 };
253 (prim, upgr)
254 };
255 OneImage {
256 slots,
257 primaries,
258 upgrades,
259 }}).collect();
260 install_ptable(&mut flash, &self.areadesc);
261 Images {
262 flash,
263 areadesc: self.areadesc,
264 images,
265 total_count: None,
266 ram: self.ram,
267 }
268 }
269
make_image(self, deps: &DepTest, permanent: bool) -> Images270 pub fn make_image(self, deps: &DepTest, permanent: bool) -> Images {
271 let mut images = self.make_no_upgrade_image(deps, ImageManipulation::None);
272 for image in &images.images {
273 mark_upgrade(&mut images.flash, &image.slots[1]);
274 }
275
276 // The count is meaningless if no flash operations are performed.
277 if !Caps::modifies_flash() {
278 return images;
279 }
280
281 // upgrades without fails, counts number of flash operations
282 let total_count = match images.run_basic_upgrade(permanent) {
283 Some(v) => v,
284 None =>
285 if deps.upgrades.iter().any(|u| *u == UpgradeInfo::Held) {
286 0
287 } else {
288 panic!("Unable to perform basic upgrade");
289 }
290 };
291
292 images.total_count = Some(total_count);
293 images
294 }
295
make_bad_secondary_slot_image(self) -> Images296 pub fn make_bad_secondary_slot_image(self) -> Images {
297 let mut bad_flash = self.flash;
298 let ram = self.ram.clone(); // TODO: Avoid this clone.
299 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
300 let dep = BoringDep::new(image_num, &NO_DEPS);
301 let primaries = install_image(&mut bad_flash, &slots[0],
302 maximal(32784), &ram, &dep, ImageManipulation::None, Some(0), false);
303 let upgrades = install_image(&mut bad_flash, &slots[1],
304 maximal(41928), &ram, &dep, ImageManipulation::BadSignature, Some(0), true);
305 OneImage {
306 slots,
307 primaries,
308 upgrades,
309 }}).collect();
310 Images {
311 flash: bad_flash,
312 areadesc: self.areadesc,
313 images,
314 total_count: None,
315 ram: self.ram,
316 }
317 }
318
make_oversized_secondary_slot_image(self) -> Images319 pub fn make_oversized_secondary_slot_image(self) -> Images {
320 let mut bad_flash = self.flash;
321 let ram = self.ram.clone(); // TODO: Avoid this clone.
322 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
323 let dep = BoringDep::new(image_num, &NO_DEPS);
324 let primaries = install_image(&mut bad_flash, &slots[0],
325 maximal(32784), &ram, &dep, ImageManipulation::None, Some(0), false);
326 let upgrades = install_image(&mut bad_flash, &slots[1],
327 ImageSize::Oversized, &ram, &dep, ImageManipulation::None, Some(0), true);
328 OneImage {
329 slots,
330 primaries,
331 upgrades,
332 }}).collect();
333 Images {
334 flash: bad_flash,
335 areadesc: self.areadesc,
336 images,
337 total_count: None,
338 ram: self.ram,
339 }
340 }
341
make_erased_secondary_image(self) -> Images342 pub fn make_erased_secondary_image(self) -> Images {
343 let mut flash = self.flash;
344 let ram = self.ram.clone(); // TODO: Avoid this clone.
345 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
346 let dep = BoringDep::new(image_num, &NO_DEPS);
347 let primaries = install_image(&mut flash, &slots[0],
348 maximal(32784), &ram, &dep,ImageManipulation::None, Some(0), false);
349 let upgrades = install_no_image();
350 OneImage {
351 slots,
352 primaries,
353 upgrades,
354 }}).collect();
355 Images {
356 flash,
357 areadesc: self.areadesc,
358 images,
359 total_count: None,
360 ram: self.ram,
361 }
362 }
363
make_bootstrap_image(self) -> Images364 pub fn make_bootstrap_image(self) -> Images {
365 let mut flash = self.flash;
366 let ram = self.ram.clone(); // TODO: Avoid this clone.
367 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
368 let dep = BoringDep::new(image_num, &NO_DEPS);
369 let primaries = install_no_image();
370 let upgrades = install_image(&mut flash, &slots[1],
371 maximal(32784), &ram, &dep, ImageManipulation::None, Some(0), true);
372 OneImage {
373 slots,
374 primaries,
375 upgrades,
376 }}).collect();
377 Images {
378 flash,
379 areadesc: self.areadesc,
380 images,
381 total_count: None,
382 ram: self.ram,
383 }
384 }
385
make_oversized_bootstrap_image(self) -> Images386 pub fn make_oversized_bootstrap_image(self) -> Images {
387 let mut flash = self.flash;
388 let ram = self.ram.clone(); // TODO: Avoid this clone.
389 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
390 let dep = BoringDep::new(image_num, &NO_DEPS);
391 let primaries = install_no_image();
392 let upgrades = install_image(&mut flash, &slots[1],
393 ImageSize::Oversized, &ram, &dep, ImageManipulation::None, Some(0), true);
394 OneImage {
395 slots,
396 primaries,
397 upgrades,
398 }}).collect();
399 Images {
400 flash,
401 areadesc: self.areadesc,
402 images,
403 total_count: None,
404 ram: self.ram,
405 }
406 }
407
408 /// If security_cnt is None then do not add a security counter TLV, otherwise add the specified value.
make_image_with_security_counter(self, security_cnt: Option<u32>) -> Images409 pub fn make_image_with_security_counter(self, security_cnt: Option<u32>) -> Images {
410 let mut flash = self.flash;
411 let ram = self.ram.clone(); // TODO: Avoid this clone.
412 let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
413 let dep = BoringDep::new(image_num, &NO_DEPS);
414 let primaries = install_image(&mut flash, &slots[0],
415 maximal(32784), &ram, &dep, ImageManipulation::None, security_cnt, false);
416 let upgrades = install_image(&mut flash, &slots[1],
417 maximal(41928), &ram, &dep, ImageManipulation::None, security_cnt.map(|v| v + 1), true);
418 OneImage {
419 slots,
420 primaries,
421 upgrades,
422 }}).collect();
423 Images {
424 flash,
425 areadesc: self.areadesc,
426 images,
427 total_count: None,
428 ram: self.ram,
429 }
430 }
431
432 /// Build the Flash and area descriptor for a given device.
make_device(device: DeviceName, align: usize, erased_val: u8) -> (SimMultiFlash, Rc<AreaDesc>, &'static [Caps])433 pub fn make_device(device: DeviceName, align: usize, erased_val: u8) -> (SimMultiFlash, Rc<AreaDesc>, &'static [Caps]) {
434 match device {
435 DeviceName::Stm32f4 => {
436 // STM style flash. Large sectors, with a large scratch area.
437 // The flash layout as described is not present in any real STM32F4 device, but it
438 // serves to exercise support for sectors of varying sizes inside a single slot,
439 // as long as they are compatible in both slots and all fit in the scratch.
440 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
441 32 * 1024, 32 * 1024, 64 * 1024,
442 32 * 1024, 32 * 1024, 64 * 1024,
443 128 * 1024],
444 align as usize, erased_val);
445 let dev_id = 0;
446 let mut areadesc = AreaDesc::new();
447 areadesc.add_flash_sectors(dev_id, &dev);
448 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
449 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
450 areadesc.add_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
451
452 let mut flash = SimMultiFlash::new();
453 flash.insert(dev_id, dev);
454 (flash, Rc::new(areadesc), &[Caps::SwapUsingMove, Caps::SwapUsingOffset])
455 }
456 DeviceName::K64f => {
457 // NXP style flash. Small sectors, one small sector for scratch.
458 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
459
460 let dev_id = 0;
461 let mut areadesc = AreaDesc::new();
462 areadesc.add_flash_sectors(dev_id, &dev);
463 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
464 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
465 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
466
467 let mut flash = SimMultiFlash::new();
468 flash.insert(dev_id, dev);
469 (flash, Rc::new(areadesc), &[])
470 }
471 DeviceName::K64fBig => {
472 // Simulating an STM style flash on top of an NXP style flash. Underlying flash device
473 // uses small sectors, but we tell the bootloader they are large.
474 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
475
476 let dev_id = 0;
477 let mut areadesc = AreaDesc::new();
478 areadesc.add_flash_sectors(dev_id, &dev);
479 areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0, dev_id);
480 areadesc.add_simple_image(0x040000, 0x020000, FlashId::Image1, dev_id);
481 areadesc.add_simple_image(0x060000, 0x020000, FlashId::ImageScratch, dev_id);
482
483 let mut flash = SimMultiFlash::new();
484 flash.insert(dev_id, dev);
485 (flash, Rc::new(areadesc), &[Caps::SwapUsingMove, Caps::SwapUsingOffset])
486 }
487 DeviceName::Nrf52840 => {
488 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
489 // does not divide into the image size.
490 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
491
492 let dev_id = 0;
493 let mut areadesc = AreaDesc::new();
494 areadesc.add_flash_sectors(dev_id, &dev);
495 areadesc.add_image(0x008000, 0x034000, FlashId::Image0, dev_id);
496 areadesc.add_image(0x03c000, 0x034000, FlashId::Image1, dev_id);
497 areadesc.add_image(0x070000, 0x00d000, FlashId::ImageScratch, dev_id);
498
499 let mut flash = SimMultiFlash::new();
500 flash.insert(dev_id, dev);
501 (flash, Rc::new(areadesc), &[])
502 }
503 DeviceName::Nrf52840UnequalSlots => {
504 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
505
506 let dev_id = 0;
507 let mut areadesc = AreaDesc::new();
508 areadesc.add_flash_sectors(dev_id, &dev);
509 areadesc.add_image(0x008000, 0x03c000, FlashId::Image0, dev_id);
510 areadesc.add_image(0x044000, 0x03b000, FlashId::Image1, dev_id);
511
512 let mut flash = SimMultiFlash::new();
513 flash.insert(dev_id, dev);
514 (flash, Rc::new(areadesc), &[Caps::SwapUsingScratch, Caps::OverwriteUpgrade, Caps::SwapUsingOffset])
515 }
516 DeviceName::Nrf52840UnequalSlotsLargerSlot1 => {
517 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
518
519 let dev_id = 0;
520 let mut areadesc = AreaDesc::new();
521 areadesc.add_flash_sectors(dev_id, &dev);
522 areadesc.add_image(0x008000, 0x03b000, FlashId::Image0, dev_id);
523 areadesc.add_image(0x043000, 0x03c000, FlashId::Image1, dev_id);
524
525 let mut flash = SimMultiFlash::new();
526 flash.insert(dev_id, dev);
527 (flash, Rc::new(areadesc), &[Caps::SwapUsingScratch, Caps::OverwriteUpgrade, Caps::SwapUsingMove, Caps::RamLoad, Caps::DirectXip])
528 }
529 DeviceName::Nrf52840SpiFlash => {
530 // Simulate nrf52840 with external SPI flash. The external SPI flash
531 // has a larger sector size so for now store scratch on that flash.
532 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
533 let dev1 = SimFlash::new(vec![8192; 64], align as usize, erased_val);
534
535 let mut areadesc = AreaDesc::new();
536 areadesc.add_flash_sectors(0, &dev0);
537 areadesc.add_flash_sectors(1, &dev1);
538
539 areadesc.add_image(0x008000, 0x068000, FlashId::Image0, 0);
540 areadesc.add_image(0x000000, 0x068000, FlashId::Image1, 1);
541 areadesc.add_image(0x068000, 0x018000, FlashId::ImageScratch, 1);
542
543 let mut flash = SimMultiFlash::new();
544 flash.insert(0, dev0);
545 flash.insert(1, dev1);
546 (flash, Rc::new(areadesc), &[Caps::SwapUsingMove, Caps::SwapUsingOffset])
547 }
548 DeviceName::K64fMulti => {
549 // NXP style flash, but larger, to support multiple images.
550 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
551
552 let dev_id = 0;
553 let mut areadesc = AreaDesc::new();
554 areadesc.add_flash_sectors(dev_id, &dev);
555 areadesc.add_image(0x020000, 0x020000, FlashId::Image0, dev_id);
556 areadesc.add_image(0x040000, 0x020000, FlashId::Image1, dev_id);
557 areadesc.add_image(0x060000, 0x001000, FlashId::ImageScratch, dev_id);
558 areadesc.add_image(0x080000, 0x020000, FlashId::Image2, dev_id);
559 areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, dev_id);
560
561 let mut flash = SimMultiFlash::new();
562 flash.insert(dev_id, dev);
563 (flash, Rc::new(areadesc), &[])
564 }
565 }
566 }
567
num_images(&self) -> usize568 pub fn num_images(&self) -> usize {
569 self.slots.len()
570 }
571 }
572
573 impl Images {
574 /// A simple upgrade without forced failures.
575 ///
576 /// Returns the number of flash operations which can later be used to
577 /// inject failures at chosen steps. Returns None if it was unable to
578 /// count the operations in a basic upgrade.
run_basic_upgrade(&self, permanent: bool) -> Option<i32>579 pub fn run_basic_upgrade(&self, permanent: bool) -> Option<i32> {
580 let (flash, total_count) = self.try_upgrade(None, permanent);
581 info!("Total flash operation count={}", total_count);
582
583 if !self.verify_images(&flash, 0, 1) {
584 warn!("Image mismatch after first boot");
585 None
586 } else {
587 Some(total_count)
588 }
589 }
590
run_bootstrap(&self) -> bool591 pub fn run_bootstrap(&self) -> bool {
592 let mut flash = self.flash.clone();
593 let mut fails = 0;
594
595 if Caps::Bootstrap.present() {
596 info!("Try bootstraping image in the primary");
597
598 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
599 warn!("Failed first boot");
600 fails += 1;
601 }
602
603 if !self.verify_images(&flash, 0, 1) {
604 warn!("Image in the first slot was not bootstrapped");
605 fails += 1;
606 }
607
608 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
609 BOOT_FLAG_SET, BOOT_FLAG_SET) {
610 warn!("Mismatched trailer for the primary slot");
611 fails += 1;
612 }
613 }
614
615 if fails > 0 {
616 error!("Expected trailer on secondary slot to be erased");
617 }
618
619 fails > 0
620 }
621
run_oversized_bootstrap(&self) -> bool622 pub fn run_oversized_bootstrap(&self) -> bool {
623 let mut flash = self.flash.clone();
624 let mut fails = 0;
625
626 if Caps::Bootstrap.present() {
627 info!("Try bootstraping image in the primary");
628
629 let boot_result = c::boot_go(&mut flash, &self.areadesc, None, None, false).interrupted();
630
631 if boot_result {
632 warn!("Failed first boot");
633 fails += 1;
634 }
635
636 if self.verify_images(&flash, 0, 1) {
637 warn!("Image in the first slot was not bootstrapped");
638 fails += 1;
639 }
640
641 if self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
642 BOOT_FLAG_SET, BOOT_FLAG_SET) {
643 warn!("Mismatched trailer for the primary slot");
644 fails += 1;
645 }
646 }
647
648 if fails > 0 {
649 error!("Expected trailer on secondary slot to be erased");
650 }
651
652 fails > 0
653 }
654
655
656 /// Test a simple upgrade, with dependencies given, and verify that the
657 /// image does as is described in the test.
run_check_deps(&self, deps: &DepTest) -> bool658 pub fn run_check_deps(&self, deps: &DepTest) -> bool {
659 if !Caps::modifies_flash() {
660 return false;
661 }
662
663 let (flash, _) = self.try_upgrade(None, true);
664
665 self.verify_dep_images(&flash, deps)
666 }
667
is_swap_upgrade(&self) -> bool668 fn is_swap_upgrade(&self) -> bool {
669 Caps::SwapUsingScratch.present() || Caps::SwapUsingMove.present() || Caps::SwapUsingOffset.present()
670 }
671
run_basic_revert(&self) -> bool672 pub fn run_basic_revert(&self) -> bool {
673 if Caps::OverwriteUpgrade.present() || !Caps::modifies_flash() {
674 return false;
675 }
676
677 let mut fails = 0;
678
679 // FIXME: this test would also pass if no swap is ever performed???
680 if self.is_swap_upgrade() {
681 for count in 2 .. 5 {
682 info!("Try revert: {}", count);
683 let flash = self.try_revert(count);
684 if !self.verify_images(&flash, 0, 0) {
685 error!("Revert failure on count {}", count);
686 fails += 1;
687 }
688 }
689 }
690
691 fails > 0
692 }
693
run_perm_with_fails(&self) -> bool694 pub fn run_perm_with_fails(&self) -> bool {
695 if !Caps::modifies_flash() {
696 return false;
697 }
698
699 let mut fails = 0;
700 let total_flash_ops = self.total_count.unwrap();
701
702 if skip_slow_test() {
703 return false;
704 }
705
706 // Let's try an image halfway through.
707 for i in 1 .. total_flash_ops {
708 info!("Try interruption at {}", i);
709 let (flash, count) = self.try_upgrade(Some(i), true);
710 info!("Second boot, count={}", count);
711 if !self.verify_images(&flash, 0, 1) {
712 warn!("FAIL at step {} of {}", i, total_flash_ops);
713 fails += 1;
714 }
715
716 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
717 BOOT_FLAG_SET, BOOT_FLAG_SET) {
718 warn!("Mismatched trailer for the primary slot");
719 fails += 1;
720 }
721
722 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
723 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
724 warn!("Mismatched trailer for the secondary slot");
725 fails += 1;
726 }
727
728 if self.is_swap_upgrade() && !self.verify_images(&flash, 1, 0) {
729 warn!("Secondary slot FAIL at step {} of {}",
730 i, total_flash_ops);
731 fails += 1;
732 }
733 }
734
735 if fails > 0 {
736 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
737 fails as f32 * 100.0 / total_flash_ops as f32);
738 }
739
740 fails > 0
741 }
742
run_perm_with_random_fails(&self, total_fails: usize) -> bool743 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
744 if !Caps::modifies_flash() {
745 return false;
746 }
747
748 let mut fails = 0;
749 let total_flash_ops = self.total_count.unwrap();
750 let (flash, total_counts) = self.try_random_fails(total_flash_ops, total_fails);
751 info!("Random interruptions at reset points={:?}", total_counts);
752
753 let primary_slot_ok = self.verify_images(&flash, 0, 1);
754 let secondary_slot_ok = if self.is_swap_upgrade() {
755 // TODO: This result is ignored.
756 self.verify_images(&flash, 1, 0)
757 } else {
758 true
759 };
760 if !primary_slot_ok || !secondary_slot_ok {
761 error!("Image mismatch after random interrupts: primary slot={} \
762 secondary slot={}",
763 if primary_slot_ok { "ok" } else { "fail" },
764 if secondary_slot_ok { "ok" } else { "fail" });
765 fails += 1;
766 }
767 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
768 BOOT_FLAG_SET, BOOT_FLAG_SET) {
769 error!("Mismatched trailer for the primary slot");
770 fails += 1;
771 }
772 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
773 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
774 error!("Mismatched trailer for the secondary slot");
775 fails += 1;
776 }
777
778 if fails > 0 {
779 error!("Error testing perm upgrade with {} fails", total_fails);
780 }
781
782 fails > 0
783 }
784
run_revert_with_fails(&self) -> bool785 pub fn run_revert_with_fails(&self) -> bool {
786 if Caps::OverwriteUpgrade.present() || !Caps::modifies_flash() {
787 return false;
788 }
789
790 let mut fails = 0;
791
792 if skip_slow_test() {
793 return false;
794 }
795
796 if self.is_swap_upgrade() {
797 for i in 1 .. self.total_count.unwrap() {
798 info!("Try interruption at {}", i);
799 if self.try_revert_with_fail_at(i) {
800 error!("Revert failed at interruption {}", i);
801 fails += 1;
802 }
803 }
804 }
805
806 fails > 0
807 }
808
run_norevert(&self) -> bool809 pub fn run_norevert(&self) -> bool {
810 if Caps::OverwriteUpgrade.present() || !Caps::modifies_flash() {
811 return false;
812 }
813
814 let mut flash = self.flash.clone();
815 let mut fails = 0;
816
817 info!("Try norevert");
818
819 // First do a normal upgrade...
820 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
821 warn!("Failed first boot");
822 fails += 1;
823 }
824
825 //FIXME: copy_done is written by boot_go, is it ok if no copy
826 // was ever done?
827
828 if !self.verify_images(&flash, 0, 1) {
829 warn!("Primary slot image verification FAIL");
830 fails += 1;
831 }
832 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
833 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
834 warn!("Mismatched trailer for the primary slot");
835 fails += 1;
836 }
837 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
838 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
839 warn!("Mismatched trailer for the secondary slot");
840 fails += 1;
841 }
842
843 // Marks image in the primary slot as permanent,
844 // no revert should happen...
845 self.mark_permanent_upgrades(&mut flash, 0);
846
847 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
848 BOOT_FLAG_SET, BOOT_FLAG_SET) {
849 warn!("Mismatched trailer for the primary slot");
850 fails += 1;
851 }
852
853 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
854 warn!("Failed second boot");
855 fails += 1;
856 }
857
858 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
859 BOOT_FLAG_SET, BOOT_FLAG_SET) {
860 warn!("Mismatched trailer for the primary slot");
861 fails += 1;
862 }
863 if !self.verify_images(&flash, 0, 1) {
864 warn!("Failed image verification");
865 fails += 1;
866 }
867
868 if fails > 0 {
869 error!("Error running upgrade without revert");
870 }
871
872 fails > 0
873 }
874
875 // Test taht too big upgrade image will be rejected
run_oversizefail_upgrade(&self) -> bool876 pub fn run_oversizefail_upgrade(&self) -> bool {
877 let mut flash = self.flash.clone();
878 let mut fails = 0;
879
880 info!("Try upgrade image with to big size");
881
882 // Only perform this test if an upgrade is expected to happen.
883 if !Caps::modifies_flash() {
884 info!("Skipping upgrade image with bad signature");
885 return false;
886 }
887
888 self.mark_upgrades(&mut flash, 0);
889 self.mark_permanent_upgrades(&mut flash, 0);
890 self.mark_upgrades(&mut flash, 1);
891
892 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
893 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
894 warn!("1. Mismatched trailer for the primary slot");
895 fails += 1;
896 }
897
898 // Run the bootloader...
899 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
900 warn!("Failed first boot");
901 fails += 1;
902 }
903
904 // State should not have changed
905 if !self.verify_images(&flash, 0, 0) {
906 warn!("Failed image verification");
907 fails += 1;
908 }
909 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
910 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
911 warn!("2. Mismatched trailer for the primary slot");
912 fails += 1;
913 }
914
915 if fails > 0 {
916 error!("Expected an upgrade failure when image has to big size");
917 }
918
919 fails > 0
920 }
921
922 // Test that an upgrade is rejected. Assumes that the image was build
923 // such that the upgrade is instead a downgrade.
run_nodowngrade(&self) -> bool924 pub fn run_nodowngrade(&self) -> bool {
925 if !Caps::DowngradePrevention.present() {
926 return false;
927 }
928
929 let mut flash = self.flash.clone();
930 let mut fails = 0;
931
932 info!("Try no downgrade");
933
934 // First, do a normal upgrade.
935 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
936 warn!("Failed first boot");
937 fails += 1;
938 }
939
940 if !self.verify_images(&flash, 0, 0) {
941 warn!("Failed verification after downgrade rejection");
942 fails += 1;
943 }
944
945 if fails > 0 {
946 error!("Error testing downgrade rejection");
947 }
948
949 fails > 0
950 }
951
952 // Tests a new image written to the primary slot that already has magic and
953 // image_ok set while there is no image on the secondary slot, so no revert
954 // should ever happen...
run_norevert_newimage(&self) -> bool955 pub fn run_norevert_newimage(&self) -> bool {
956 if !Caps::modifies_flash() {
957 info!("Skipping run_norevert_newimage, as configuration doesn't modify flash");
958 return false;
959 }
960
961 let mut flash = self.flash.clone();
962 let mut fails = 0;
963
964 info!("Try non-revert on imgtool generated image");
965
966 self.mark_upgrades(&mut flash, 0);
967
968 // This simulates writing an image created by imgtool to
969 // the primary slot
970 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
971 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
972 warn!("Mismatched trailer for the primary slot");
973 fails += 1;
974 }
975
976 // Run the bootloader...
977 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
978 warn!("Failed first boot");
979 fails += 1;
980 }
981
982 // State should not have changed
983 if !self.verify_images(&flash, 0, 0) {
984 warn!("Failed image verification");
985 fails += 1;
986 }
987 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
988 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
989 warn!("Mismatched trailer for the primary slot");
990 fails += 1;
991 }
992 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
993 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
994 warn!("Mismatched trailer for the secondary slot");
995 fails += 1;
996 }
997
998 if fails > 0 {
999 error!("Expected a non revert with new image");
1000 }
1001
1002 fails > 0
1003 }
1004
1005 // Tests a new image written to the primary slot that already has magic and
1006 // image_ok set while there is no image on the secondary slot, so no revert
1007 // should ever happen...
run_signfail_upgrade(&self) -> bool1008 pub fn run_signfail_upgrade(&self) -> bool {
1009 let mut flash = self.flash.clone();
1010 let mut fails = 0;
1011
1012 info!("Try upgrade image with bad signature");
1013
1014 // Only perform this test if an upgrade is expected to happen.
1015 if !Caps::modifies_flash() {
1016 info!("Skipping upgrade image with bad signature");
1017 return false;
1018 }
1019
1020 self.mark_upgrades(&mut flash, 0);
1021 self.mark_permanent_upgrades(&mut flash, 0);
1022 self.mark_upgrades(&mut flash, 1);
1023
1024 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
1025 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
1026 warn!("Mismatched trailer for the primary slot");
1027 fails += 1;
1028 }
1029
1030 // Run the bootloader...
1031 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
1032 warn!("Failed first boot");
1033 fails += 1;
1034 }
1035
1036 // State should not have changed
1037 if !self.verify_images(&flash, 0, 0) {
1038 warn!("Failed image verification");
1039 fails += 1;
1040 }
1041 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
1042 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
1043 warn!("Mismatched trailer for the primary slot");
1044 fails += 1;
1045 }
1046
1047 if fails > 0 {
1048 error!("Expected an upgrade failure when image has bad signature");
1049 }
1050
1051 fails > 0
1052 }
1053
1054 // Should detect there is a leftover trailer in an otherwise erased
1055 // secondary slot and erase its trailer.
run_secondary_leftover_trailer(&self) -> bool1056 pub fn run_secondary_leftover_trailer(&self) -> bool {
1057 if !Caps::modifies_flash() {
1058 return false;
1059 }
1060
1061 let mut flash = self.flash.clone();
1062 let mut fails = 0;
1063
1064 info!("Try with a leftover trailer in the secondary; must be erased");
1065
1066 // Add a trailer on the secondary slot
1067 self.mark_permanent_upgrades(&mut flash, 1);
1068 self.mark_upgrades(&mut flash, 1);
1069
1070 // Run the bootloader...
1071 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
1072 warn!("Failed first boot");
1073 fails += 1;
1074 }
1075
1076 // State should not have changed
1077 if !self.verify_images(&flash, 0, 0) {
1078 warn!("Failed image verification");
1079 fails += 1;
1080 }
1081 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
1082 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
1083 warn!("Mismatched trailer for the secondary slot");
1084 fails += 1;
1085 }
1086
1087 if fails > 0 {
1088 error!("Expected trailer on secondary slot to be erased");
1089 }
1090
1091 fails > 0
1092 }
1093
trailer_sz(&self, align: usize) -> usize1094 fn trailer_sz(&self, align: usize) -> usize {
1095 c::boot_trailer_sz(align as u32) as usize
1096 }
1097
status_sz(&self, align: usize) -> usize1098 fn status_sz(&self, align: usize) -> usize {
1099 c::boot_status_sz(align as u32) as usize
1100 }
1101
1102 /// This test runs a simple upgrade with no fails in the images, but
1103 /// allowing for fails in the status area. This should run to the end
1104 /// and warn that write fails were detected...
run_with_status_fails_complete(&self) -> bool1105 pub fn run_with_status_fails_complete(&self) -> bool {
1106 if !Caps::ValidatePrimarySlot.present() || !Caps::modifies_flash() {
1107 return false;
1108 }
1109
1110 let mut flash = self.flash.clone();
1111 let mut fails = 0;
1112
1113 info!("Try swap with status fails");
1114
1115 self.mark_permanent_upgrades(&mut flash, 1);
1116 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
1117
1118 let result = c::boot_go(&mut flash, &self.areadesc, None, None, true);
1119 if !result.success() {
1120 warn!("Failed!");
1121 fails += 1;
1122 }
1123
1124 // Failed writes to the marked "bad" region don't assert anymore.
1125 // Any detected assert() is happening in another part of the code.
1126 if result.asserts() != 0 {
1127 warn!("At least one assert() was called");
1128 fails += 1;
1129 }
1130
1131 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
1132 BOOT_FLAG_SET, BOOT_FLAG_SET) {
1133 warn!("Mismatched trailer for the primary slot");
1134 fails += 1;
1135 }
1136
1137 if !self.verify_images(&flash, 0, 1) {
1138 warn!("Failed image verification");
1139 fails += 1;
1140 }
1141
1142 info!("validate primary slot enabled; \
1143 re-run of boot_go should just work");
1144 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
1145 warn!("Failed!");
1146 fails += 1;
1147 }
1148
1149 if fails > 0 {
1150 error!("Error running upgrade with status write fails");
1151 }
1152
1153 fails > 0
1154 }
1155
1156 /// This test runs a simple upgrade with no fails in the images, but
1157 /// allowing for fails in the status area. This should run to the end
1158 /// and warn that write fails were detected...
run_with_status_fails_with_reset(&self) -> bool1159 pub fn run_with_status_fails_with_reset(&self) -> bool {
1160 if Caps::OverwriteUpgrade.present() || !Caps::modifies_flash() {
1161 false
1162 } else if Caps::ValidatePrimarySlot.present() {
1163
1164 let mut flash = self.flash.clone();
1165 let mut fails = 0;
1166 let mut count = self.total_count.unwrap() / 2;
1167
1168 //info!("count={}\n", count);
1169
1170 info!("Try interrupted swap with status fails");
1171
1172 self.mark_permanent_upgrades(&mut flash, 1);
1173 self.mark_bad_status_with_rate(&mut flash, 0, 0.5);
1174
1175 // Should not fail, writing to bad regions does not assert
1176 let asserts = c::boot_go(&mut flash, &self.areadesc,
1177 Some(&mut count), None, true).asserts();
1178 if asserts != 0 {
1179 warn!("At least one assert() was called");
1180 fails += 1;
1181 }
1182
1183 self.reset_bad_status(&mut flash, 0);
1184
1185 info!("Resuming an interrupted swap operation");
1186 let asserts = c::boot_go(&mut flash, &self.areadesc, None, None,
1187 true).asserts();
1188
1189 // This might throw no asserts, for large sector devices, where
1190 // a single failure writing is indistinguishable from no failure,
1191 // or throw a single assert for small sector devices that fail
1192 // multiple times...
1193 if asserts > 1 {
1194 warn!("Expected single assert validating the primary slot, \
1195 more detected {}", asserts);
1196 fails += 1;
1197 }
1198
1199 if fails > 0 {
1200 error!("Error running upgrade with status write fails");
1201 }
1202
1203 fails > 0
1204 } else {
1205 let mut flash = self.flash.clone();
1206 let mut fails = 0;
1207
1208 info!("Try interrupted swap with status fails");
1209
1210 self.mark_permanent_upgrades(&mut flash, 1);
1211 self.mark_bad_status_with_rate(&mut flash, 0, 1.0);
1212
1213 // This is expected to fail while writing to bad regions...
1214 let asserts = c::boot_go(&mut flash, &self.areadesc, None, None,
1215 true).asserts();
1216 if asserts == 0 {
1217 warn!("No assert() detected");
1218 fails += 1;
1219 }
1220
1221 fails > 0
1222 }
1223 }
1224
1225 /// Test the direct XIP configuration. With this mode, flash images are never moved, and the
1226 /// bootloader merely selects which partition is the proper one to boot.
run_direct_xip(&self) -> bool1227 pub fn run_direct_xip(&self) -> bool {
1228 if !Caps::DirectXip.present() {
1229 return false;
1230 }
1231
1232 // Clone the flash so we can tell if unchanged.
1233 let mut flash = self.flash.clone();
1234
1235 let result = c::boot_go(&mut flash, &self.areadesc, None, None, true);
1236
1237 // Ensure the boot was successful.
1238 let resp = if let Some(resp) = result.resp() {
1239 resp
1240 } else {
1241 panic!("Boot didn't return a valid result");
1242 };
1243
1244 // This configuration should always try booting from the first upgrade slot.
1245 if let Some((offset, _, dev_id)) = self.areadesc.find(FlashId::Image1) {
1246 assert_eq!(offset, resp.image_off as usize);
1247 assert_eq!(dev_id, resp.flash_dev_id);
1248 } else {
1249 panic!("Unable to find upgrade image");
1250 }
1251 false
1252 }
1253
1254 /// Test the ram-loading.
run_ram_load(&self) -> bool1255 pub fn run_ram_load(&self) -> bool {
1256 if !Caps::RamLoad.present() {
1257 return false;
1258 }
1259
1260 // Clone the flash so we can tell if unchanged.
1261 let mut flash = self.flash.clone();
1262
1263 // Setup ram based on the ram configuration we determined earlier for the images.
1264 let ram = RamBlock::new(self.ram.total - RAM_LOAD_ADDR, RAM_LOAD_ADDR);
1265
1266 // println!("Ram: {:#?}", self.ram);
1267
1268 // Verify that the images area loaded into this.
1269 let result = ram.invoke(|| c::boot_go(&mut flash, &self.areadesc, None,
1270 None, true));
1271 if !result.success() {
1272 error!("Failed to execute ram-load");
1273 return true;
1274 }
1275
1276 // Verify each image.
1277 for image in &self.images {
1278 let place = self.ram.lookup(&image.slots[0]);
1279 let ram_image = ram.borrow_part(place.offset as usize - RAM_LOAD_ADDR as usize,
1280 place.size as usize);
1281 let src_sz = image.upgrades.size();
1282 if src_sz > ram_image.len() {
1283 error!("Image ended up too large, nonsensical");
1284 return true;
1285 }
1286 let src_image = &image.upgrades.plain[0..src_sz];
1287 let ram_image = &ram_image[0..src_sz];
1288 if ram_image != src_image {
1289 error!("Image not loaded correctly");
1290 return true;
1291 }
1292
1293 }
1294
1295 return false;
1296 }
1297
1298 /// Test the split ram-loading.
run_split_ram_load(&self) -> bool1299 pub fn run_split_ram_load(&self) -> bool {
1300 if !Caps::RamLoad.present() {
1301 return false;
1302 }
1303
1304 // Clone the flash so we can tell if unchanged.
1305 let mut flash = self.flash.clone();
1306
1307 // Setup ram based on the ram configuration we determined earlier for the images.
1308 let ram = RamBlock::new(self.ram.total - RAM_LOAD_ADDR, RAM_LOAD_ADDR);
1309
1310 for (idx, _image) in (&self.images).iter().enumerate() {
1311 // Verify that the images area loaded into this.
1312 let result = ram.invoke(|| c::boot_go(&mut flash, &self.areadesc,
1313 None, Some(idx as i32), true));
1314 if !result.success() {
1315 error!("Failed to execute ram-load");
1316 return true;
1317 }
1318 }
1319
1320 // Verify each image.
1321 for image in &self.images {
1322 let place = self.ram.lookup(&image.slots[0]);
1323 let ram_image = ram.borrow_part(place.offset as usize - RAM_LOAD_ADDR as usize,
1324 place.size as usize);
1325 let src_sz = image.upgrades.size();
1326 if src_sz > ram_image.len() {
1327 error!("Image ended up too large, nonsensical");
1328 return true;
1329 }
1330 let src_image = &image.upgrades.plain[0..src_sz];
1331 let ram_image = &ram_image[0..src_sz];
1332 if ram_image != src_image {
1333 error!("Image not loaded correctly");
1334 return true;
1335 }
1336
1337 }
1338
1339 return false;
1340 }
1341
run_hw_rollback_prot(&self) -> bool1342 pub fn run_hw_rollback_prot(&self) -> bool {
1343 if !Caps::HwRollbackProtection.present() {
1344 return false;
1345 }
1346
1347 let mut flash = self.flash.clone();
1348
1349 // set the "stored" security counter to a fixed value.
1350 c::set_security_counter(0, 30);
1351
1352 let result = c::boot_go(&mut flash, &self.areadesc, None, None, true);
1353
1354 if result.success() {
1355 warn!("Successful boot when it did not suppose to happen!");
1356 return true;
1357 }
1358 let counter_val = c::get_security_counter(0);
1359 if counter_val != 30 {
1360 warn!("Counter was changed when it did not suppose to!");
1361 return true;
1362 }
1363
1364 false
1365 }
1366
run_ram_load_boot_with_result(&self, expected_result: bool) -> bool1367 pub fn run_ram_load_boot_with_result(&self, expected_result: bool) -> bool {
1368 if !Caps::RamLoad.present() {
1369 return false;
1370 }
1371 // Clone the flash so we can tell if unchanged.
1372 let mut flash = self.flash.clone();
1373
1374 // Create RAM config.
1375 let ram = RamBlock::new(self.ram.total - RAM_LOAD_ADDR, RAM_LOAD_ADDR);
1376
1377 // Run the bootloader, and verify that it couldn't run to completion.
1378 let result = ram.invoke(|| c::boot_go(&mut flash, &self.areadesc, None,
1379 None, true));
1380
1381 if result.success() != expected_result {
1382 error!("RAM load boot result was not of the expected value! (was: {}, expected: {})", result.success(), expected_result);
1383 return true;
1384 }
1385
1386 false
1387 }
1388
1389 /// Adds a new flash area that fails statistically
mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize, rate: f32)1390 fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
1391 rate: f32) {
1392 if Caps::OverwriteUpgrade.present() {
1393 return;
1394 }
1395
1396 // Set this for each image.
1397 for image in &self.images {
1398 let dev_id = &image.slots[slot].dev_id;
1399 let dev = flash.get_mut(&dev_id).unwrap();
1400 let align = dev.align();
1401 let off = &image.slots[slot].base_off;
1402 let len = &image.slots[slot].len;
1403 let status_off = off + len - self.trailer_sz(align);
1404
1405 // Mark the status area as a bad area
1406 let _ = dev.add_bad_region(status_off, self.status_sz(align), rate);
1407 }
1408 }
1409
reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize)1410 fn reset_bad_status(&self, flash: &mut SimMultiFlash, slot: usize) {
1411 if !Caps::ValidatePrimarySlot.present() {
1412 return;
1413 }
1414
1415 for image in &self.images {
1416 let dev_id = &image.slots[slot].dev_id;
1417 let dev = flash.get_mut(&dev_id).unwrap();
1418 dev.reset_bad_regions();
1419
1420 // Disabling write verification the only assert triggered by
1421 // boot_go should be checking for integrity of status bytes.
1422 dev.set_verify_writes(false);
1423 }
1424 }
1425
1426 /// Test a boot, optionally stopping after 'n' flash options. Returns a count
1427 /// of the number of flash operations done total.
try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32)1428 fn try_upgrade(&self, stop: Option<i32>, permanent: bool) -> (SimMultiFlash, i32) {
1429 // Clone the flash to have a new copy.
1430 let mut flash = self.flash.clone();
1431
1432 if permanent {
1433 self.mark_permanent_upgrades(&mut flash, 1);
1434 }
1435
1436 let mut counter = stop.unwrap_or(0);
1437
1438 let (first_interrupted, count) = match c::boot_go(&mut flash,
1439 &self.areadesc,
1440 Some(&mut counter),
1441 None, false) {
1442 x if x.interrupted() => (true, stop.unwrap()),
1443 x if x.success() => (false, -counter),
1444 x => panic!("Unknown return: {:?}", x),
1445 };
1446
1447 counter = 0;
1448 if first_interrupted {
1449 // fl.dump();
1450 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter),
1451 None, false) {
1452 x if x.interrupted() => panic!("Shouldn't stop again"),
1453 x if x.success() => (),
1454 x => panic!("Unknown return: {:?}", x),
1455 }
1456 }
1457
1458 (flash, count - counter)
1459 }
1460
try_revert(&self, count: usize) -> SimMultiFlash1461 fn try_revert(&self, count: usize) -> SimMultiFlash {
1462 let mut flash = self.flash.clone();
1463
1464 // fl.write_file("image0.bin").unwrap();
1465 for i in 0 .. count {
1466 info!("Running boot pass {}", i + 1);
1467 assert!(c::boot_go(&mut flash, &self.areadesc, None, None, false).success_no_asserts());
1468 }
1469 flash
1470 }
1471
try_revert_with_fail_at(&self, stop: i32) -> bool1472 fn try_revert_with_fail_at(&self, stop: i32) -> bool {
1473 let mut flash = self.flash.clone();
1474 let mut fails = 0;
1475
1476 let mut counter = stop;
1477 if !c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), None,
1478 false).interrupted() {
1479 warn!("Should have stopped test at interruption point");
1480 fails += 1;
1481 }
1482
1483 // In a multi-image setup, copy done might be set if any number of
1484 // images was already successfully swapped.
1485 if !self.verify_trailers_loose(&flash, 0, None, None, BOOT_FLAG_UNSET) {
1486 warn!("copy_done should be unset");
1487 fails += 1;
1488 }
1489
1490 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
1491 warn!("Should have finished test upgrade");
1492 fails += 1;
1493 }
1494
1495 if !self.verify_images(&flash, 0, 1) {
1496 warn!("Image in the primary slot before revert is invalid at stop={}",
1497 stop);
1498 fails += 1;
1499 }
1500 if !self.verify_images(&flash, 1, 0) {
1501 warn!("Image in the secondary slot before revert is invalid at stop={}",
1502 stop);
1503 fails += 1;
1504 }
1505 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
1506 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
1507 warn!("Mismatched trailer for the primary slot before revert");
1508 fails += 1;
1509 }
1510 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
1511 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
1512 warn!("Mismatched trailer for the secondary slot before revert");
1513 fails += 1;
1514 }
1515
1516 // Do Revert
1517 let mut counter = stop;
1518 if !c::boot_go(&mut flash, &self.areadesc, Some(&mut counter), None,
1519 false).interrupted() {
1520 warn!("Should have stopped revert at interruption point");
1521 fails += 1;
1522 }
1523
1524 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
1525 warn!("Should have finished revert upgrade");
1526 fails += 1;
1527 }
1528
1529 if !self.verify_images(&flash, 0, 0) {
1530 warn!("Image in the primary slot after revert is invalid at stop={}",
1531 stop);
1532 fails += 1;
1533 }
1534 if !self.verify_images(&flash, 1, 1) {
1535 warn!("Image in the secondary slot after revert is invalid at stop={}",
1536 stop);
1537 fails += 1;
1538 }
1539
1540 if !self.verify_trailers(&flash, 0, BOOT_MAGIC_GOOD,
1541 BOOT_FLAG_SET, BOOT_FLAG_SET) {
1542 warn!("Mismatched trailer for the primary slot after revert");
1543 fails += 1;
1544 }
1545 if !self.verify_trailers(&flash, 1, BOOT_MAGIC_UNSET,
1546 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
1547 warn!("Mismatched trailer for the secondary slot after revert");
1548 fails += 1;
1549 }
1550
1551 if !c::boot_go(&mut flash, &self.areadesc, None, None, false).success() {
1552 warn!("Should have finished 3rd boot");
1553 fails += 1;
1554 }
1555
1556 if !self.verify_images(&flash, 0, 0) {
1557 warn!("Image in the primary slot is invalid on 1st boot after revert");
1558 fails += 1;
1559 }
1560 if !self.verify_images(&flash, 1, 1) {
1561 warn!("Image in the secondary slot is invalid on 1st boot after revert");
1562 fails += 1;
1563 }
1564
1565 fails > 0
1566 }
1567
1568
try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>)1569 fn try_random_fails(&self, total_ops: i32, count: usize) -> (SimMultiFlash, Vec<i32>) {
1570 let mut flash = self.flash.clone();
1571
1572 self.mark_permanent_upgrades(&mut flash, 1);
1573
1574 let mut rng = rand::thread_rng();
1575 let mut resets = vec![0i32; count];
1576 let mut remaining_ops = total_ops;
1577 for reset in &mut resets {
1578 let reset_counter = rng.gen_range(1 ..= remaining_ops / 2);
1579 let mut counter = reset_counter;
1580 match c::boot_go(&mut flash, &self.areadesc, Some(&mut counter),
1581 None, false) {
1582 x if x.interrupted() => (),
1583 x => panic!("Unknown return: {:?}", x),
1584 }
1585 remaining_ops -= reset_counter;
1586 *reset = reset_counter;
1587 }
1588
1589 match c::boot_go(&mut flash, &self.areadesc, None, None, false) {
1590 x if x.interrupted() => panic!("Should not be have been interrupted!"),
1591 x if x.success() => (),
1592 x => panic!("Unknown return: {:?}", x),
1593 }
1594
1595 (flash, resets)
1596 }
1597
1598 /// Verify the image in the given flash device, the specified slot
1599 /// against the expected image.
verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool1600 fn verify_images(&self, flash: &SimMultiFlash, slot: usize, against: usize) -> bool {
1601 self.images.iter().all(|image| {
1602 verify_image(flash, &image.slots[slot],
1603 match against {
1604 0 => &image.primaries,
1605 1 => &image.upgrades,
1606 _ => panic!("Invalid 'against'")
1607 })
1608 })
1609 }
1610
1611 /// Verify the images, according to the dependency test.
verify_dep_images(&self, flash: &SimMultiFlash, deps: &DepTest) -> bool1612 fn verify_dep_images(&self, flash: &SimMultiFlash, deps: &DepTest) -> bool {
1613 for (image_num, (image, upgrade)) in self.images.iter().zip(deps.upgrades.iter()).enumerate() {
1614 info!("Upgrade: slot:{}, {:?}", image_num, upgrade);
1615 if !verify_image(flash, &image.slots[0],
1616 match upgrade {
1617 UpgradeInfo::Upgraded => &image.upgrades,
1618 UpgradeInfo::Held => &image.primaries,
1619 }) {
1620 error!("Failed to upgrade properly: image: {}, upgrade: {:?}", image_num, upgrade);
1621 return true;
1622 }
1623 }
1624
1625 false
1626 }
1627
1628 /// Verify that at least one of the trailers of the images have the
1629 /// specified values.
verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize, magic: Option<u8>, image_ok: Option<u8>, copy_done: Option<u8>) -> bool1630 fn verify_trailers_loose(&self, flash: &SimMultiFlash, slot: usize,
1631 magic: Option<u8>, image_ok: Option<u8>,
1632 copy_done: Option<u8>) -> bool {
1633 self.images.iter().any(|image| {
1634 verify_trailer(flash, &image.slots[slot],
1635 magic, image_ok, copy_done)
1636 })
1637 }
1638
1639 /// Verify that the trailers of the images have the specified
1640 /// values.
verify_trailers(&self, flash: &SimMultiFlash, slot: usize, magic: Option<u8>, image_ok: Option<u8>, copy_done: Option<u8>) -> bool1641 fn verify_trailers(&self, flash: &SimMultiFlash, slot: usize,
1642 magic: Option<u8>, image_ok: Option<u8>,
1643 copy_done: Option<u8>) -> bool {
1644 self.images.iter().all(|image| {
1645 verify_trailer(flash, &image.slots[slot],
1646 magic, image_ok, copy_done)
1647 })
1648 }
1649
1650 /// Mark each of the images for permanent upgrade.
mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize)1651 fn mark_permanent_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1652 for image in &self.images {
1653 mark_permanent_upgrade(flash, &image.slots[slot]);
1654 }
1655 }
1656
1657 /// Mark each of the images for permanent upgrade.
mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize)1658 fn mark_upgrades(&self, flash: &mut SimMultiFlash, slot: usize) {
1659 for image in &self.images {
1660 mark_upgrade(flash, &image.slots[slot]);
1661 }
1662 }
1663
1664 /// Dump out the flash image(s) to one or more files for debugging
1665 /// purposes. The names will be written as either "{prefix}.mcubin" or
1666 /// "{prefix}-001.mcubin" depending on how many images there are.
debug_dump(&self, prefix: &str)1667 pub fn debug_dump(&self, prefix: &str) {
1668 for (id, fdev) in &self.flash {
1669 let name = if self.flash.len() == 1 {
1670 format!("{}.mcubin", prefix)
1671 } else {
1672 format!("{}-{:>0}.mcubin", prefix, id)
1673 };
1674 fdev.write_file(&name).unwrap();
1675 }
1676 }
1677 }
1678
1679 impl RamData {
1680 // TODO: This is not correct. The second slot of each image should be at the same address as
1681 // the primary.
new(slots: &[[SlotInfo; 2]]) -> RamData1682 fn new(slots: &[[SlotInfo; 2]]) -> RamData {
1683 let mut addr = RAM_LOAD_ADDR;
1684 let mut places = BTreeMap::new();
1685 // println!("Setup:-------------");
1686 for imgs in slots {
1687 for si in imgs {
1688 // println!("Setup: si: {:?}", si);
1689 let offset = addr;
1690 let size = si.len as u32;
1691 places.insert(SlotKey {
1692 dev_id: si.dev_id,
1693 base_off: si.base_off,
1694 }, SlotPlace { offset, size });
1695 // println!(" load: offset: {}, size: {}", offset, size);
1696 }
1697 addr += imgs[0].len as u32;
1698 }
1699 RamData {
1700 places,
1701 total: addr,
1702 }
1703 }
1704
1705 /// Lookup the ram data associated with a given flash partition. We just panic if not present,
1706 /// because all slots used should be in the map.
lookup(&self, slot: &SlotInfo) -> &SlotPlace1707 fn lookup(&self, slot: &SlotInfo) -> &SlotPlace {
1708 self.places.get(&SlotKey{dev_id: slot.dev_id, base_off: slot.base_off})
1709 .expect("RamData should contain all slots")
1710 }
1711 }
1712
1713 /// Show the flash layout.
1714 #[allow(dead_code)]
show_flash(flash: &dyn Flash)1715 fn show_flash(flash: &dyn Flash) {
1716 println!("---- Flash configuration ----");
1717 for sector in flash.sector_iter() {
1718 println!(" {:3}: 0x{:08x}, 0x{:08x}",
1719 sector.num, sector.base, sector.size);
1720 }
1721 println!();
1722 }
1723
1724 #[derive(Debug)]
1725 enum ImageSize {
1726 /// Make the image the specified given size.
1727 Given(usize),
1728 /// Make the image as large as it can be for the partition/device.
1729 Largest,
1730 /// Make the image quite larger than it can be for the partition/device/
1731 Oversized,
1732 }
1733
1734 #[cfg(not(feature = "max-align-32"))]
tralier_estimation(dev: &dyn Flash) -> usize1735 fn tralier_estimation(dev: &dyn Flash) -> usize {
1736 c::boot_trailer_sz(dev.align() as u32) as usize
1737 }
1738
1739 #[cfg(feature = "max-align-32")]
tralier_estimation(dev: &dyn Flash) -> usize1740 fn tralier_estimation(dev: &dyn Flash) -> usize {
1741
1742 let sector_size = dev.sector_iter().next().unwrap().size as u32;
1743
1744 align_up(c::boot_trailer_sz(dev.align() as u32), sector_size) as usize
1745 }
1746
image_largest_trailer(dev: &dyn Flash) -> usize1747 fn image_largest_trailer(dev: &dyn Flash) -> usize {
1748 // Using the header size we know, the trailer size, and the slot size, we can compute
1749 // the largest image possible.
1750 let trailer = if Caps::OverwriteUpgrade.present() {
1751 // This computation is incorrect, and we need to figure out the correct size.
1752 // c::boot_status_sz(dev.align() as u32) as usize
1753 16 + 4 * dev.align()
1754 } else if Caps::SwapUsingOffset.present() || Caps::SwapUsingMove.present() {
1755 let sector_size = dev.sector_iter().next().unwrap().size as u32;
1756 align_up(c::boot_trailer_sz(dev.align() as u32), sector_size) as usize
1757 } else if Caps::SwapUsingScratch.present() {
1758 tralier_estimation(dev)
1759 } else {
1760 panic!("The maximum image size can't be calculated.")
1761 };
1762
1763 trailer
1764 }
1765
1766 /// Install a "program" into the given image. This fakes the image header, or at least all of the
1767 /// fields used by the given code. Returns a copy of the image that was written.
install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: ImageSize, ram: &RamData, deps: &dyn Depender, img_manipulation: ImageManipulation, security_counter:Option<u32>, secondary_slot:bool) -> ImageData1768 fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: ImageSize,
1769 ram: &RamData,
1770 deps: &dyn Depender, img_manipulation: ImageManipulation, security_counter:Option<u32>, secondary_slot:bool) -> ImageData {
1771 let mut offset = slot.base_off;
1772 let slot_len = slot.len;
1773 let dev_id = slot.dev_id;
1774 let dev = flash.get_mut(&dev_id).unwrap();
1775
1776 let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
1777
1778 if Caps::SwapUsingOffset.present() && secondary_slot {
1779 let sector_size = dev.sector_iter().next().unwrap().size as usize;
1780 offset += sector_size;
1781 }
1782
1783 if img_manipulation == ImageManipulation::IgnoreRamLoadFlag {
1784 tlv.set_ignore_ram_load_flag();
1785 }
1786
1787 tlv.set_security_counter(security_counter);
1788
1789
1790 // Add the dependencies early to the tlv.
1791 for dep in deps.my_deps(offset, slot.index) {
1792 tlv.add_dependency(deps.other_id(), &dep);
1793 }
1794
1795 const HDR_SIZE: usize = 32;
1796 let place = ram.lookup(&slot);
1797 let load_addr = if Caps::RamLoad.present() {
1798 match img_manipulation {
1799 ImageManipulation::WrongOffset => u32::MAX,
1800 ImageManipulation::OverlapImages(true) => RAM_LOAD_ADDR,
1801 ImageManipulation::OverlapImages(false) => place.offset - 1,
1802 _ => place.offset
1803 }
1804 } else {
1805 0
1806 };
1807
1808 let len = match len {
1809 ImageSize::Given(size) => size,
1810 ImageSize::Largest => {
1811 let trailer = image_largest_trailer(dev);
1812 let tlv_len = tlv.estimate_size();
1813 info!("slot: 0x{:x}, HDR: 0x{:x}, trailer: 0x{:x}",
1814 slot_len, HDR_SIZE, trailer);
1815 slot_len - HDR_SIZE - trailer - tlv_len
1816 },
1817 ImageSize::Oversized => {
1818 let trailer = image_largest_trailer(dev);
1819 let tlv_len = tlv.estimate_size();
1820 let mut sector_offset = 0;
1821
1822 if Caps::SwapUsingOffset.present() && secondary_slot {
1823 // This accounts for when both slots have the same size, it will not work where
1824 // the second slot is one sector larger than the primary
1825 sector_offset = dev.sector_iter().next().unwrap().size as usize;
1826 }
1827
1828 info!("slot: 0x{:x}, HDR: 0x{:x}, trailer: 0x{:x}",
1829 slot_len, HDR_SIZE, trailer);
1830 // the overflow size is rougly estimated to work for all
1831 // configurations. It might be precise if tlv_len will be maked precise.
1832 slot_len - HDR_SIZE - trailer - tlv_len - sector_offset + dev.align()*4
1833 }
1834
1835 };
1836
1837 // Generate a boot header. Note that the size doesn't include the header.
1838 let header = ImageHeader {
1839 magic: tlv.get_magic(),
1840 load_addr,
1841 hdr_size: HDR_SIZE as u16,
1842 protect_tlv_size: tlv.protect_size(),
1843 img_size: len as u32,
1844 flags: tlv.get_flags(),
1845 ver: deps.my_version(offset, slot.index),
1846 _pad2: 0,
1847 };
1848
1849 let mut b_header = [0; HDR_SIZE];
1850 b_header[..32].clone_from_slice(header.as_raw());
1851 assert_eq!(b_header.len(), HDR_SIZE);
1852
1853 tlv.add_bytes(&b_header);
1854
1855 // The core of the image itself is just pseudorandom data.
1856 let mut b_img = vec![0; len];
1857 splat(&mut b_img, offset);
1858
1859 // Add some information at the start of the payload to make it easier
1860 // to see what it is. This will fail if the image itself is too small.
1861 {
1862 let mut wr = Cursor::new(&mut b_img);
1863 writeln!(&mut wr, "offset: {:#x}, dev_id: {:#x}, slot_info: {:?}",
1864 offset, dev_id, slot).unwrap();
1865 writeln!(&mut wr, "version: {:?}", deps.my_version(offset, slot.index)).unwrap();
1866 }
1867
1868 // TLV signatures work over plain image
1869 tlv.add_bytes(&b_img);
1870
1871 // Generate encrypted images
1872 let flag = TlvFlags::ENCRYPTED_AES128 as u32 | TlvFlags::ENCRYPTED_AES256 as u32;
1873 let is_encrypted = (tlv.get_flags() & flag) != 0;
1874 let mut b_encimg = vec![];
1875 if is_encrypted {
1876 let flag = TlvFlags::ENCRYPTED_AES256 as u32;
1877 let aes256 = (tlv.get_flags() & flag) == flag;
1878 tlv.generate_enc_key();
1879 let enc_key = tlv.get_enc_key();
1880 let nonce = GenericArray::from_slice(&[0; 16]);
1881 b_encimg = b_img.clone();
1882 if aes256 {
1883 let key: &GenericArray<u8, U32> = GenericArray::from_slice(enc_key.as_slice());
1884 let block = Aes256::new(&key);
1885 let mut cipher = Aes256Ctr::from_block_cipher(block, &nonce);
1886 cipher.apply_keystream(&mut b_encimg);
1887 } else {
1888 let key: &GenericArray<u8, U16> = GenericArray::from_slice(enc_key.as_slice());
1889 let block = Aes128::new(&key);
1890 let mut cipher = Aes128Ctr::from_block_cipher(block, &nonce);
1891 cipher.apply_keystream(&mut b_encimg);
1892 }
1893 }
1894
1895 // Build the TLV itself.
1896 if img_manipulation == ImageManipulation::BadSignature {
1897 tlv.corrupt_sig();
1898 }
1899 let mut b_tlv = tlv.make_tlv();
1900
1901 let mut buf = vec![];
1902 buf.append(&mut b_header.to_vec());
1903 buf.append(&mut b_img);
1904 buf.append(&mut b_tlv.clone());
1905
1906 // Pad the buffer to a multiple of the flash alignment.
1907 let align = dev.align();
1908 let image_sz = buf.len();
1909 while buf.len() % align != 0 {
1910 buf.push(dev.erased_val());
1911 }
1912
1913 let mut encbuf = vec![];
1914 if is_encrypted {
1915 encbuf.append(&mut b_header.to_vec());
1916 encbuf.append(&mut b_encimg);
1917 encbuf.append(&mut b_tlv);
1918
1919 while encbuf.len() % align != 0 {
1920 encbuf.push(dev.erased_val());
1921 }
1922 }
1923
1924 // Since images are always non-encrypted in the primary slot, we first write
1925 // an encrypted image, re-read to use for verification, erase + flash
1926 // un-encrypted. In the secondary slot the image is written un-encrypted,
1927 // and if encryption is requested, it follows an erase + flash encrypted.
1928 //
1929 // In the case of ram-load when encryption is enabled both slots have to
1930 // be encrypted so in the event when the image is in the primary slot
1931 // the verification will fail as the image is not encrypted.
1932 if slot.index == 0 && !Caps::RamLoad.present() {
1933 let enc_copy: Option<Vec<u8>>;
1934
1935 if is_encrypted {
1936 dev.write(offset, &encbuf).unwrap();
1937
1938 let mut enc = vec![0u8; encbuf.len()];
1939 dev.read(offset, &mut enc).unwrap();
1940
1941 enc_copy = Some(enc);
1942
1943 dev.erase(offset, slot_len).unwrap();
1944 } else {
1945 enc_copy = None;
1946 }
1947
1948 dev.write(offset, &buf).unwrap();
1949
1950 let mut copy = vec![0u8; buf.len()];
1951 dev.read(offset, &mut copy).unwrap();
1952
1953 ImageData {
1954 size: image_sz,
1955 plain: copy,
1956 cipher: enc_copy,
1957 }
1958 } else {
1959
1960 dev.write(offset, &buf).unwrap();
1961
1962 let mut copy = vec![0u8; buf.len()];
1963 dev.read(offset, &mut copy).unwrap();
1964
1965 let enc_copy: Option<Vec<u8>>;
1966
1967 if is_encrypted {
1968 dev.erase(offset, slot_len).unwrap();
1969
1970 dev.write(offset, &encbuf).unwrap();
1971
1972 let mut enc = vec![0u8; encbuf.len()];
1973 dev.read(offset, &mut enc).unwrap();
1974
1975 enc_copy = Some(enc);
1976 } else {
1977 enc_copy = None;
1978 }
1979
1980 ImageData {
1981 size: image_sz,
1982 plain: copy,
1983 cipher: enc_copy,
1984 }
1985 }
1986 }
1987
1988 /// Install no image. This is used when no upgrade happens.
install_no_image() -> ImageData1989 fn install_no_image() -> ImageData {
1990 ImageData {
1991 size: 0,
1992 plain: vec![],
1993 cipher: None,
1994 }
1995 }
1996
1997 /// Construct a TLV generator based on how MCUboot is currently configured. The returned
1998 /// ManifestGen will generate the appropriate entries based on this configuration.
make_tlv() -> TlvGen1999 fn make_tlv() -> TlvGen {
2000 let aes_key_size = if Caps::Aes256.present() { 256 } else { 128 };
2001
2002 if Caps::EncKw.present() {
2003 if Caps::RSA2048.present() {
2004 TlvGen::new_rsa_kw(aes_key_size)
2005 } else if Caps::EcdsaP256.present() {
2006 TlvGen::new_ecdsa_kw(aes_key_size)
2007 } else {
2008 TlvGen::new_enc_kw(aes_key_size)
2009 }
2010 } else if Caps::EncRsa.present() {
2011 if Caps::RSA2048.present() {
2012 TlvGen::new_sig_enc_rsa(aes_key_size)
2013 } else {
2014 TlvGen::new_enc_rsa(aes_key_size)
2015 }
2016 } else if Caps::EncEc256.present() {
2017 if Caps::EcdsaP256.present() {
2018 TlvGen::new_ecdsa_ecies_p256(aes_key_size)
2019 } else {
2020 TlvGen::new_ecies_p256(aes_key_size)
2021 }
2022 } else if Caps::EncX25519.present() {
2023 if Caps::Ed25519.present() {
2024 TlvGen::new_ed25519_ecies_x25519(aes_key_size)
2025 } else {
2026 TlvGen::new_ecies_x25519(aes_key_size)
2027 }
2028 } else {
2029 // The non-encrypted configuration.
2030 if Caps::RSA2048.present() {
2031 TlvGen::new_rsa_pss()
2032 } else if Caps::RSA3072.present() {
2033 TlvGen::new_rsa3072_pss()
2034 } else if Caps::EcdsaP256.present() || Caps::EcdsaP384.present() {
2035 TlvGen::new_ecdsa()
2036 } else if Caps::Ed25519.present() {
2037 TlvGen::new_ed25519()
2038 } else if Caps::HwRollbackProtection.present() {
2039 TlvGen::new_sec_cnt()
2040 } else {
2041 TlvGen::new_hash_only()
2042 }
2043 }
2044 }
2045
2046 impl ImageData {
2047 /// Find the image contents for the given slot. This assumes that slot 0
2048 /// is unencrypted, and slot 1 is encrypted.
find(&self, slot: usize) -> &Vec<u8>2049 fn find(&self, slot: usize) -> &Vec<u8> {
2050 let encrypted = Caps::EncRsa.present() || Caps::EncKw.present() ||
2051 Caps::EncEc256.present() || Caps::EncX25519.present();
2052 match (encrypted, slot) {
2053 (false, _) => &self.plain,
2054 (true, 0) => &self.plain,
2055 (true, 1) => self.cipher.as_ref().expect("Invalid image"),
2056 _ => panic!("Invalid slot requested"),
2057 }
2058 }
2059
size(&self) -> usize2060 fn size(&self) -> usize {
2061 self.size
2062 }
2063 }
2064
2065 /// Verify that given image is present in the flash at the given offset.
verify_image(flash: &SimMultiFlash, slot: &SlotInfo, images: &ImageData) -> bool2066 fn verify_image(flash: &SimMultiFlash, slot: &SlotInfo, images: &ImageData) -> bool {
2067 let image = images.find(slot.index);
2068 let buf = image.as_slice();
2069 let dev_id = slot.dev_id;
2070
2071 let mut copy = vec![0u8; buf.len()];
2072 let offset = slot.base_off;
2073 let dev = flash.get(&dev_id).unwrap();
2074 dev.read(offset, &mut copy).unwrap();
2075
2076 if Caps::SwapUsingOffset.present() && (slot.index % 2) == 1 {
2077 let sector_size = dev.sector_iter().next().unwrap().size as usize;
2078 let mut copy_offset = vec![0u8; buf.len()];
2079 let offset_offset = slot.base_off + sector_size;
2080 dev.read(offset_offset, &mut copy_offset).unwrap();
2081
2082 if buf != ©[..] && buf != ©_offset[..] {
2083 for i in 0 .. buf.len() {
2084 if buf[i] != copy[i] && buf[i] != copy_offset[i] {
2085 info!("First failure for slot{} at {:#x} ({:#x} within) {:#x}!=({:#x} or {:#x})",
2086 slot.index, offset + i, i, buf[i], copy[i], copy_offset[i]);
2087 break;
2088 }
2089 }
2090 false
2091 } else {
2092 true
2093 }
2094 } else {
2095 if buf != ©[..] {
2096 for i in 0 .. buf.len() {
2097 if buf[i] != copy[i] {
2098 info!("First failure for slot{} at {:#x} ({:#x} within) {:#x}!={:#x}",
2099 slot.index, offset + i, i, buf[i], copy[i]);
2100 break;
2101 }
2102 }
2103 false
2104 } else {
2105 true
2106 }
2107 }
2108 }
2109
verify_trailer(flash: &SimMultiFlash, slot: &SlotInfo, magic: Option<u8>, image_ok: Option<u8>, copy_done: Option<u8>) -> bool2110 fn verify_trailer(flash: &SimMultiFlash, slot: &SlotInfo,
2111 magic: Option<u8>, image_ok: Option<u8>,
2112 copy_done: Option<u8>) -> bool {
2113 if Caps::OverwriteUpgrade.present() {
2114 return true;
2115 }
2116
2117 let offset = slot.trailer_off + c::boot_max_align();
2118 let dev_id = slot.dev_id;
2119 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 3];
2120 let mut failed = false;
2121
2122 let dev = flash.get(&dev_id).unwrap();
2123 let erased_val = dev.erased_val();
2124 dev.read(offset, &mut copy).unwrap();
2125
2126 failed |= match magic {
2127 Some(v) => {
2128 let magic_off = (c::boot_max_align() * 3) + (c::boot_magic_sz() - MAGIC.len());
2129 if v == 1 && ©[magic_off..] != MAGIC {
2130 warn!("\"magic\" mismatch at {:#x}", offset);
2131 true
2132 } else if v == 3 {
2133 let expected = [erased_val; 16];
2134 if copy[magic_off..] != expected {
2135 warn!("\"magic\" mismatch at {:#x}", offset);
2136 true
2137 } else {
2138 false
2139 }
2140 } else {
2141 false
2142 }
2143 },
2144 None => false,
2145 };
2146
2147 failed |= match image_ok {
2148 Some(v) => {
2149 let image_ok_off = c::boot_max_align() * 2;
2150 if (v == 1 && copy[image_ok_off] != v) || (v == 3 && copy[image_ok_off] != erased_val) {
2151 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[image_ok_off]);
2152 true
2153 } else {
2154 false
2155 }
2156 },
2157 None => false,
2158 };
2159
2160 failed |= match copy_done {
2161 Some(v) => {
2162 let copy_done_off = c::boot_max_align();
2163 if (v == 1 && copy[copy_done_off] != v) || (v == 3 && copy[copy_done_off] != erased_val) {
2164 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[copy_done_off]);
2165 true
2166 } else {
2167 false
2168 }
2169 },
2170 None => false,
2171 };
2172
2173 !failed
2174 }
2175
2176 /// Install a partition table. This is a simplified partition table that
2177 /// we write at the beginning of flash so make it easier for external tools
2178 /// to analyze these images.
install_ptable(flash: &mut SimMultiFlash, areadesc: &AreaDesc)2179 fn install_ptable(flash: &mut SimMultiFlash, areadesc: &AreaDesc) {
2180 let ids: HashSet<u8> = areadesc.iter_areas().map(|area| area.device_id).collect();
2181 for &id in &ids {
2182 // If there are any partitions in this device that start at 0, and
2183 // aren't marked as the BootLoader partition, avoid adding the
2184 // partition table. This makes it harder to view the image, but
2185 // avoids messing up images already written.
2186 let skip_ptable = areadesc
2187 .iter_areas()
2188 .any(|area| {
2189 area.device_id == id &&
2190 area.off == 0 &&
2191 area.flash_id != FlashId::BootLoader
2192 });
2193 if skip_ptable {
2194 if log_enabled!(Info) {
2195 let special: Vec<FlashId> = areadesc.iter_areas()
2196 .filter(|area| area.device_id == id && area.off == 0)
2197 .map(|area| area.flash_id)
2198 .collect();
2199 info!("Skipping partition table: {:?}", special);
2200 }
2201 break;
2202 }
2203
2204 let mut buf: Vec<u8> = vec![];
2205 write!(&mut buf, "mcuboot\0").unwrap();
2206
2207 // Iterate through all of the partitions in that device, and encode
2208 // into the table.
2209 let count = areadesc.iter_areas().filter(|area| area.device_id == id).count();
2210 buf.write_u32::<LittleEndian>(count as u32).unwrap();
2211
2212 for area in areadesc.iter_areas().filter(|area| area.device_id == id) {
2213 buf.write_u32::<LittleEndian>(area.flash_id as u32).unwrap();
2214 buf.write_u32::<LittleEndian>(area.off).unwrap();
2215 buf.write_u32::<LittleEndian>(area.size).unwrap();
2216 buf.write_u32::<LittleEndian>(0).unwrap();
2217 }
2218
2219 let dev = flash.get_mut(&id).unwrap();
2220
2221 // Pad to alignment.
2222 while buf.len() % dev.align() != 0 {
2223 buf.push(0);
2224 }
2225
2226 dev.write(0, &buf).unwrap();
2227 }
2228 }
2229
2230 /// The image header
2231 #[repr(C)]
2232 #[derive(Debug)]
2233 pub struct ImageHeader {
2234 magic: u32,
2235 load_addr: u32,
2236 hdr_size: u16,
2237 protect_tlv_size: u16,
2238 img_size: u32,
2239 flags: u32,
2240 ver: ImageVersion,
2241 _pad2: u32,
2242 }
2243
2244 impl AsRaw for ImageHeader {}
2245
2246 #[repr(C)]
2247 #[derive(Clone, Debug)]
2248 pub struct ImageVersion {
2249 pub major: u8,
2250 pub minor: u8,
2251 pub revision: u16,
2252 pub build_num: u32,
2253 }
2254
2255 #[derive(Clone, Debug)]
2256 pub struct SlotInfo {
2257 pub base_off: usize,
2258 pub trailer_off: usize,
2259 pub len: usize,
2260 // Which slot within this device.
2261 pub index: usize,
2262 pub dev_id: u8,
2263 }
2264
2265 #[cfg(not(feature = "max-align-32"))]
2266 const MAGIC: &[u8] = &[0x77, 0xc2, 0x95, 0xf3,
2267 0x60, 0xd2, 0xef, 0x7f,
2268 0x35, 0x52, 0x50, 0x0f,
2269 0x2c, 0xb6, 0x79, 0x80];
2270
2271 #[cfg(feature = "max-align-32")]
2272 const MAGIC: &[u8] = &[0x20, 0x00, 0x2d, 0xe1,
2273 0x5d, 0x29, 0x41, 0x0b,
2274 0x8d, 0x77, 0x67, 0x9c,
2275 0x11, 0x0f, 0x1f, 0x8a];
2276
2277 // Replicates defines found in bootutil.h
2278 const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
2279 const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
2280
2281 const BOOT_FLAG_SET: Option<u8> = Some(1);
2282 const BOOT_FLAG_UNSET: Option<u8> = Some(3);
2283
2284 /// Write out the magic so that the loader tries doing an upgrade.
mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo)2285 pub fn mark_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
2286 let dev = flash.get_mut(&slot.dev_id).unwrap();
2287 let align = dev.align();
2288 let offset = slot.trailer_off + c::boot_max_align() * 4;
2289 if offset % align != 0 || MAGIC.len() % align != 0 {
2290 // The write size is larger than the magic value. Fill a buffer
2291 // with the erased value, put the MAGIC in it, and write it in its
2292 // entirety.
2293 let mut buf = vec![dev.erased_val(); c::boot_max_align()];
2294 let magic_off = (offset % align) + (c::boot_magic_sz() - MAGIC.len());
2295 buf[magic_off..].copy_from_slice(MAGIC);
2296 dev.write(offset - (offset % align), &buf).unwrap();
2297 } else {
2298 dev.write(offset, MAGIC).unwrap();
2299 }
2300 }
2301
2302 /// Writes the image_ok flag which, guess what, tells the bootloader
2303 /// the this image is ok (not a test, and no revert is to be performed).
mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo)2304 fn mark_permanent_upgrade(flash: &mut SimMultiFlash, slot: &SlotInfo) {
2305 // Overwrite mode always is permanent, and only the magic is used in
2306 // the trailer. To avoid problems with large write sizes, don't try to
2307 // set anything in this case.
2308 if Caps::OverwriteUpgrade.present() {
2309 return;
2310 }
2311
2312 let dev = flash.get_mut(&slot.dev_id).unwrap();
2313 let align = dev.align();
2314 let mut ok = vec![dev.erased_val(); align];
2315 ok[0] = 1u8;
2316 let off = slot.trailer_off + c::boot_max_align() * 3;
2317 dev.write(off, &ok).unwrap();
2318 }
2319
2320 // Drop some pseudo-random gibberish onto the data.
splat(data: &mut [u8], seed: usize)2321 fn splat(data: &mut [u8], seed: usize) {
2322 let mut seed_block = [0u8; 32];
2323 let mut buf = Cursor::new(&mut seed_block[..]);
2324 buf.write_u32::<LittleEndian>(0x135782ea).unwrap();
2325 buf.write_u32::<LittleEndian>(0x92184728).unwrap();
2326 buf.write_u32::<LittleEndian>(data.len() as u32).unwrap();
2327 buf.write_u32::<LittleEndian>(seed as u32).unwrap();
2328 let mut rng: SmallRng = SeedableRng::from_seed(seed_block);
2329 rng.fill_bytes(data);
2330 }
2331
2332 /// Return a read-only view into the raw bytes of this object
2333 trait AsRaw : Sized {
as_raw(&self) -> &[u8]2334 fn as_raw(&self) -> &[u8] {
2335 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
2336 mem::size_of::<Self>()) }
2337 }
2338 }
2339
2340 /// Determine whether it makes sense to test this configuration with a maximally-sized image.
2341 /// Returns an ImageSize representing the best size to test, possibly just with the given size.
maximal(size: usize) -> ImageSize2342 fn maximal(size: usize) -> ImageSize {
2343 if Caps::OverwriteUpgrade.present() ||
2344 Caps::SwapUsingOffset.present() ||
2345 Caps::SwapUsingMove.present()
2346 {
2347 ImageSize::Given(size)
2348 } else {
2349 ImageSize::Largest
2350 }
2351 }
2352
show_sizes()2353 pub fn show_sizes() {
2354 // This isn't panic safe.
2355 for min in &[1, 2, 4, 8] {
2356 let msize = c::boot_trailer_sz(*min);
2357 println!("{:2}: {} (0x{:x})", min, msize, msize);
2358 }
2359 }
2360
2361 #[cfg(not(feature = "max-align-32"))]
test_alignments() -> &'static [usize]2362 fn test_alignments() -> &'static [usize] {
2363 &[1, 2, 4, 8]
2364 }
2365
2366 #[cfg(feature = "max-align-32")]
test_alignments() -> &'static [usize]2367 fn test_alignments() -> &'static [usize] {
2368 &[32]
2369 }
2370
2371 /// For testing, some of the tests are quite slow. This will query for an
2372 /// environment variable `MCUBOOT_SKIP_SLOW_TESTS`, which can be set to avoid
2373 /// running these tests.
skip_slow_test() -> bool2374 fn skip_slow_test() -> bool {
2375 if let Ok(_) = std::env::var("MCUBOOT_SKIP_SLOW_TESTS") {
2376 true
2377 } else {
2378 false
2379 }
2380 }
2381