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