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