1 // Copyright (c) 2017-2019 Linaro LTD
2 // Copyright (c) 2017-2019 JUUL Labs
3 // Copyright (c) 2019 Arm Limited
4 //
5 // SPDX-License-Identifier: Apache-2.0
6 
7 use docopt::Docopt;
8 use log::{warn, error};
9 use std::{
10     fmt,
11     process,
12 };
13 use serde_derive::Deserialize;
14 
15 mod caps;
16 mod depends;
17 mod image;
18 mod tlv;
19 mod utils;
20 pub mod testlog;
21 
22 pub use crate::{
23     depends::{
24         DepTest,
25         DepType,
26         UpgradeInfo,
27         NO_DEPS,
28         REV_DEPS,
29     },
30     image::{
31         ImagesBuilder,
32         Images,
33         show_sizes,
34     },
35 };
36 
37 const USAGE: &str = "
38 Mcuboot simulator
39 
40 Usage:
41   bootsim sizes
42   bootsim run --device TYPE [--align SIZE]
43   bootsim runall
44   bootsim (--help | --version)
45 
46 Options:
47   -h, --help         Show this message
48   --version          Version
49   --device TYPE      MCU to simulate
50                      Valid values: stm32f4, k64f
51   --align SIZE       Flash write alignment
52 ";
53 
54 #[derive(Debug, Deserialize)]
55 struct Args {
56     flag_device: Option<DeviceName>,
57     flag_align: Option<AlignArg>,
58     cmd_sizes: bool,
59     cmd_run: bool,
60     cmd_runall: bool,
61 }
62 
63 #[derive(Copy, Clone, Debug, Deserialize)]
64 pub enum DeviceName {
65     Stm32f4, K64f, K64fBig, K64fMulti, Nrf52840, Nrf52840SpiFlash,
66     Nrf52840UnequalSlots,
67 }
68 
69 pub static ALL_DEVICES: &[DeviceName] = &[
70     DeviceName::Stm32f4,
71     DeviceName::K64f,
72     DeviceName::K64fBig,
73     DeviceName::K64fMulti,
74     DeviceName::Nrf52840,
75     DeviceName::Nrf52840SpiFlash,
76     DeviceName::Nrf52840UnequalSlots,
77 ];
78 
79 impl fmt::Display for DeviceName {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result80     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81         let name = match *self {
82             DeviceName::Stm32f4 => "stm32f4",
83             DeviceName::K64f => "k64f",
84             DeviceName::K64fBig => "k64fbig",
85             DeviceName::K64fMulti => "k64fmulti",
86             DeviceName::Nrf52840 => "nrf52840",
87             DeviceName::Nrf52840SpiFlash => "Nrf52840SpiFlash",
88             DeviceName::Nrf52840UnequalSlots => "Nrf52840UnequalSlots",
89         };
90         f.write_str(name)
91     }
92 }
93 
94 #[derive(Debug)]
95 struct AlignArg(usize);
96 
97 struct AlignArgVisitor;
98 
99 impl<'de> serde::de::Visitor<'de> for AlignArgVisitor {
100     type Value = AlignArg;
101 
expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result102     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
103         formatter.write_str("1, 2, 4 or 8")
104     }
105 
visit_u32<E>(self, n: u32) -> Result<Self::Value, E> where E: serde::de::Error106     fn visit_u32<E>(self, n: u32) -> Result<Self::Value, E>
107         where E: serde::de::Error
108     {
109         Ok(match n {
110             1 | 2 | 4 | 8 => AlignArg(n as usize),
111             n => {
112                 let err = format!("Could not deserialize '{}' as alignment", n);
113                 return Err(E::custom(err));
114             }
115         })
116     }
117 }
118 
119 impl<'de> serde::de::Deserialize<'de> for AlignArg {
deserialize<D>(d: D) -> Result<AlignArg, D::Error> where D: serde::de::Deserializer<'de>120     fn deserialize<D>(d: D) -> Result<AlignArg, D::Error>
121         where D: serde::de::Deserializer<'de>
122     {
123         d.deserialize_u8(AlignArgVisitor)
124     }
125 }
126 
main()127 pub fn main() {
128     let args: Args = Docopt::new(USAGE)
129         .and_then(|d| d.deserialize())
130         .unwrap_or_else(|e| e.exit());
131     // println!("args: {:#?}", args);
132 
133     if args.cmd_sizes {
134         show_sizes();
135         return;
136     }
137 
138     let mut status = RunStatus::new();
139     if args.cmd_run {
140 
141         let align = args.flag_align.map(|x| x.0).unwrap_or(1);
142 
143 
144         let device = match args.flag_device {
145             None => panic!("Missing mandatory device argument"),
146             Some(dev) => dev,
147         };
148 
149         status.run_single(device, align, 0xff);
150     }
151 
152     if args.cmd_runall {
153         for &dev in ALL_DEVICES {
154             for &align in &[1, 2, 4, 8] {
155                 for &erased_val in &[0, 0xff] {
156                     status.run_single(dev, align, erased_val);
157                 }
158             }
159         }
160     }
161 
162     if status.failures > 0 {
163         error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
164         process::exit(1);
165     } else {
166         error!("{} Tests ran successfully", status.passes);
167         process::exit(0);
168     }
169 }
170 
171 #[derive(Default)]
172 pub struct RunStatus {
173     failures: usize,
174     passes: usize,
175 }
176 
177 impl RunStatus {
new() -> RunStatus178     pub fn new() -> RunStatus {
179         RunStatus {
180             failures: 0,
181             passes: 0,
182         }
183     }
184 
run_single(&mut self, device: DeviceName, align: usize, erased_val: u8)185     pub fn run_single(&mut self, device: DeviceName, align: usize, erased_val: u8) {
186         warn!("Running on device {} with alignment {}", device, align);
187 
188         let run = match ImagesBuilder::new(device, align, erased_val) {
189             Ok(builder) => builder,
190             Err(msg) => {
191                 warn!("Skipping {}: {}", device, msg);
192                 return;
193             }
194         };
195 
196         let mut failed = false;
197 
198         // Creates a badly signed image in the secondary slot to check that
199         // it is not upgraded to
200         let bad_secondary_slot_image = run.clone().make_bad_secondary_slot_image();
201 
202         failed |= bad_secondary_slot_image.run_signfail_upgrade();
203 
204         let images = run.clone().make_no_upgrade_image(&NO_DEPS);
205         failed |= images.run_norevert_newimage();
206 
207         let images = run.make_image(&NO_DEPS, true);
208 
209         failed |= images.run_basic_revert();
210         failed |= images.run_revert_with_fails();
211         failed |= images.run_perm_with_fails();
212         failed |= images.run_perm_with_random_fails(5);
213         failed |= images.run_norevert();
214 
215         failed |= images.run_with_status_fails_complete();
216         failed |= images.run_with_status_fails_with_reset();
217 
218         //show_flash(&flash);
219 
220         if failed {
221             self.failures += 1;
222         } else {
223             self.passes += 1;
224         }
225     }
226 
failures(&self) -> usize227     pub fn failures(&self) -> usize {
228         self.failures
229     }
230 }
231