blob: eec754720c22eb790a8efbd0aff69428b7c0c9aa [file] [log] [blame]
David Browne2acfae2020-01-21 16:45:01 -07001// 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
David Brown2639e072017-10-11 11:18:44 -06007use docopt::Docopt;
David Brown5c9e0f12019-01-09 16:34:33 -07008use log::{warn, error};
David Brown10b5de12019-01-02 16:10:01 -07009use std::{
10 fmt,
David Brown10b5de12019-01-02 16:10:01 -070011 process,
David Brown10b5de12019-01-02 16:10:01 -070012};
13use serde_derive::Deserialize;
David Brown2639e072017-10-11 11:18:44 -060014
15mod caps;
David Brownc3898d62019-08-05 14:20:02 -060016mod depends;
David Brown5c9e0f12019-01-09 16:34:33 -070017mod image;
David Brown2639e072017-10-11 11:18:44 -060018mod tlv;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030019mod utils;
David Brownca7b5d32017-11-03 08:37:38 -060020pub mod testlog;
David Brown2639e072017-10-11 11:18:44 -060021
David Brownc3898d62019-08-05 14:20:02 -060022pub use crate::{
23 depends::{
24 DepTest,
25 DepType,
26 UpgradeInfo,
David Brown2ee5f7f2020-01-13 14:04:01 -070027 NO_DEPS,
28 REV_DEPS,
29 },
David Brownc3898d62019-08-05 14:20:02 -060030 image::{
31 ImagesBuilder,
David Brownfe5ab1c2019-08-13 15:35:23 -060032 Images,
David Brownc3898d62019-08-05 14:20:02 -060033 show_sizes,
34 },
David Brown5c9e0f12019-01-09 16:34:33 -070035};
David Brown2639e072017-10-11 11:18:44 -060036
David Brown1997f532021-03-10 05:04:05 -070037const USAGE: &str = "
David Brown2639e072017-10-11 11:18:44 -060038Mcuboot simulator
39
40Usage:
41 bootsim sizes
42 bootsim run --device TYPE [--align SIZE]
43 bootsim runall
44 bootsim (--help | --version)
45
46Options:
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)]
55struct Args {
David Brown2639e072017-10-11 11:18:44 -060056 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)]
Fabio Utzigc659ec52020-07-13 21:18:48 -030064pub enum DeviceName {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030065 Stm32f4,
66 K64f, K64fBig, K64fMulti,
67 Nrf52840, Nrf52840SpiFlash, Nrf52840UnequalSlots,
68 PSoC6
Fabio Utzigc659ec52020-07-13 21:18:48 -030069}
David Brown2639e072017-10-11 11:18:44 -060070
David Brown1997f532021-03-10 05:04:05 -070071pub static ALL_DEVICES: &[DeviceName] = &[
David Brown2639e072017-10-11 11:18:44 -060072 DeviceName::Stm32f4,
73 DeviceName::K64f,
74 DeviceName::K64fBig,
David Brown2bff6472019-03-05 13:58:35 -070075 DeviceName::K64fMulti,
David Brown2639e072017-10-11 11:18:44 -060076 DeviceName::Nrf52840,
Fabio Utzigafb2bc92018-11-19 16:11:52 -020077 DeviceName::Nrf52840SpiFlash,
Fabio Utzigc659ec52020-07-13 21:18:48 -030078 DeviceName::Nrf52840UnequalSlots,
Roman Okhrimenko977b3752022-03-31 14:40:48 +030079 DeviceName::PSoC6
David Brown2639e072017-10-11 11:18:44 -060080];
81
82impl fmt::Display for DeviceName {
David Brown10b5de12019-01-02 16:10:01 -070083 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
David Brown2639e072017-10-11 11:18:44 -060084 let name = match *self {
85 DeviceName::Stm32f4 => "stm32f4",
86 DeviceName::K64f => "k64f",
87 DeviceName::K64fBig => "k64fbig",
David Brown2bff6472019-03-05 13:58:35 -070088 DeviceName::K64fMulti => "k64fmulti",
David Brown2639e072017-10-11 11:18:44 -060089 DeviceName::Nrf52840 => "nrf52840",
Fabio Utzigafb2bc92018-11-19 16:11:52 -020090 DeviceName::Nrf52840SpiFlash => "Nrf52840SpiFlash",
Fabio Utzigc659ec52020-07-13 21:18:48 -030091 DeviceName::Nrf52840UnequalSlots => "Nrf52840UnequalSlots",
Roman Okhrimenko977b3752022-03-31 14:40:48 +030092 DeviceName::PSoC6 => "PSoC6"
David Brown2639e072017-10-11 11:18:44 -060093 };
94 f.write_str(name)
95 }
96}
97
98#[derive(Debug)]
David Brown5a317752019-11-15 09:53:39 -070099struct AlignArg(usize);
David Brown2639e072017-10-11 11:18:44 -0600100
101struct AlignArgVisitor;
102
103impl<'de> serde::de::Visitor<'de> for AlignArgVisitor {
104 type Value = AlignArg;
105
David Brown10b5de12019-01-02 16:10:01 -0700106 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
David Brown2639e072017-10-11 11:18:44 -0600107 formatter.write_str("1, 2, 4 or 8")
108 }
109
David Brown5a317752019-11-15 09:53:39 -0700110 fn visit_u32<E>(self, n: u32) -> Result<Self::Value, E>
David Brown2639e072017-10-11 11:18:44 -0600111 where E: serde::de::Error
112 {
113 Ok(match n {
David Brown5a317752019-11-15 09:53:39 -0700114 1 | 2 | 4 | 8 => AlignArg(n as usize),
David Brown2639e072017-10-11 11:18:44 -0600115 n => {
116 let err = format!("Could not deserialize '{}' as alignment", n);
117 return Err(E::custom(err));
118 }
119 })
120 }
121}
122
123impl<'de> serde::de::Deserialize<'de> for AlignArg {
124 fn deserialize<D>(d: D) -> Result<AlignArg, D::Error>
125 where D: serde::de::Deserializer<'de>
126 {
127 d.deserialize_u8(AlignArgVisitor)
128 }
129}
130
131pub fn main() {
132 let args: Args = Docopt::new(USAGE)
133 .and_then(|d| d.deserialize())
134 .unwrap_or_else(|e| e.exit());
135 // println!("args: {:#?}", args);
136
137 if args.cmd_sizes {
138 show_sizes();
139 return;
140 }
141
142 let mut status = RunStatus::new();
143 if args.cmd_run {
144
145 let align = args.flag_align.map(|x| x.0).unwrap_or(1);
146
147
148 let device = match args.flag_device {
149 None => panic!("Missing mandatory device argument"),
150 Some(dev) => dev,
151 };
152
Fabio Utzigea0290b2018-08-09 14:23:01 -0300153 status.run_single(device, align, 0xff);
David Brown2639e072017-10-11 11:18:44 -0600154 }
155
156 if args.cmd_runall {
157 for &dev in ALL_DEVICES {
158 for &align in &[1, 2, 4, 8] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300159 for &erased_val in &[0, 0xff] {
160 status.run_single(dev, align, erased_val);
161 }
David Brown2639e072017-10-11 11:18:44 -0600162 }
163 }
164 }
165
166 if status.failures > 0 {
167 error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
168 process::exit(1);
169 } else {
170 error!("{} Tests ran successfully", status.passes);
171 process::exit(0);
172 }
173}
174
David Brownfc8e3c52021-03-10 05:11:26 -0700175#[derive(Default)]
David Browndd2b1182017-11-02 15:39:21 -0600176pub struct RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600177 failures: usize,
178 passes: usize,
179}
180
181impl RunStatus {
David Browndd2b1182017-11-02 15:39:21 -0600182 pub fn new() -> RunStatus {
David Brown2639e072017-10-11 11:18:44 -0600183 RunStatus {
184 failures: 0,
185 passes: 0,
186 }
187 }
188
David Brown5a317752019-11-15 09:53:39 -0700189 pub fn run_single(&mut self, device: DeviceName, align: usize, erased_val: u8) {
David Brown2639e072017-10-11 11:18:44 -0600190 warn!("Running on device {} with alignment {}", device, align);
191
David Brown5bc62c62019-03-05 12:11:48 -0700192 let run = match ImagesBuilder::new(device, align, erased_val) {
Fabio Utzig114a6472019-11-28 10:24:09 -0300193 Ok(builder) => builder,
194 Err(msg) => {
195 warn!("Skipping {}: {}", device, msg);
David Brown5bc62c62019-03-05 12:11:48 -0700196 return;
197 }
198 };
David Brown2639e072017-10-11 11:18:44 -0600199
David Brown2639e072017-10-11 11:18:44 -0600200 let mut failed = false;
201
David Vincze2d736ad2019-02-18 11:50:22 +0100202 // Creates a badly signed image in the secondary slot to check that
203 // it is not upgraded to
David Brown01617af2019-02-28 10:45:12 -0700204 let bad_secondary_slot_image = run.clone().make_bad_secondary_slot_image();
David Brown2639e072017-10-11 11:18:44 -0600205
David Vincze2d736ad2019-02-18 11:50:22 +0100206 failed |= bad_secondary_slot_image.run_signfail_upgrade();
David Brown2639e072017-10-11 11:18:44 -0600207
David Brownc3898d62019-08-05 14:20:02 -0600208 let images = run.clone().make_no_upgrade_image(&NO_DEPS);
David Brown5f7ec2b2017-11-06 13:54:02 -0700209 failed |= images.run_norevert_newimage();
David Brown2639e072017-10-11 11:18:44 -0600210
David Brownc3898d62019-08-05 14:20:02 -0600211 let images = run.make_image(&NO_DEPS, true);
David Brown2639e072017-10-11 11:18:44 -0600212
David Brown5f7ec2b2017-11-06 13:54:02 -0700213 failed |= images.run_basic_revert();
David Brownc49811e2017-11-06 14:20:45 -0700214 failed |= images.run_revert_with_fails();
215 failed |= images.run_perm_with_fails();
216 failed |= images.run_perm_with_random_fails(5);
David Brown5f7ec2b2017-11-06 13:54:02 -0700217 failed |= images.run_norevert();
David Brown2639e072017-10-11 11:18:44 -0600218
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200219 failed |= images.run_with_status_fails_complete();
Fabio Utzigeedcc452017-11-24 10:48:52 -0200220 failed |= images.run_with_status_fails_with_reset();
Fabio Utzigb841f0a2017-11-24 08:11:05 -0200221
David Brown2639e072017-10-11 11:18:44 -0600222 //show_flash(&flash);
223
224 if failed {
225 self.failures += 1;
226 } else {
227 self.passes += 1;
228 }
229 }
David Browndd2b1182017-11-02 15:39:21 -0600230
231 pub fn failures(&self) -> usize {
232 self.failures
233 }
David Brown2639e072017-10-11 11:18:44 -0600234}