blob: db8564d3cbae39760d145b4fc48febb0a7a4b721 [file] [log] [blame]
David Brownc8d62012021-10-27 15:03:48 -06001// Copyright (c) 2017-2021 Linaro LTD
David Browne2acfae2020-01-21 16:45:01 -07002// Copyright (c) 2018-2019 JUUL Labs
Roland Mikheld6703522023-04-27 14:24:30 +02003// Copyright (c) 2023 Arm Limited
David Browne2acfae2020-01-21 16:45:01 -07004//
5// SPDX-License-Identifier: Apache-2.0
6
David Brownde7729e2017-01-09 10:41:35 -07007//! HAL api for MyNewt applications
8
Fabio Utzig8000e322019-08-05 08:14:32 -03009use crate::area::CAreaDesc;
David Brown28215642019-01-02 11:42:39 -070010use log::{Level, log_enabled, warn};
Fabio Utzig8000e322019-08-05 08:14:32 -030011use simflash::{Result, Flash, FlashPtr};
David Brown28215642019-01-02 11:42:39 -070012use std::{
Fabio Utzig8000e322019-08-05 08:14:32 -030013 cell::RefCell,
David Brown28215642019-01-02 11:42:39 -070014 collections::HashMap,
15 mem,
Fabio Utzig8000e322019-08-05 08:14:32 -030016 ptr,
David Brown28215642019-01-02 11:42:39 -070017 slice,
David Brown28215642019-01-02 11:42:39 -070018};
David Brownde7729e2017-01-09 10:41:35 -070019
Fabio Utzig1c9aea52018-11-15 10:36:07 -020020/// A FlashMap maintain a table of [device_id -> Flash trait]
Fabio Utzigafb2bc92018-11-19 16:11:52 -020021pub type FlashMap = HashMap<u8, FlashPtr>;
Fabio Utzig1c9aea52018-11-15 10:36:07 -020022
Fabio Utzig8000e322019-08-05 08:14:32 -030023pub struct FlashParamsStruct {
Gustavo Henrique Nihei4aa286d2021-11-24 14:54:56 -030024 align: u32,
Fabio Utzig73ffc442018-10-24 21:49:09 -030025 erased_val: u8,
26}
27
Fabio Utzig8000e322019-08-05 08:14:32 -030028pub type FlashParams = HashMap<u8, FlashParamsStruct>;
29
David Brownd216b202021-06-04 10:14:33 -060030/// The `boot_rsp` structure used by boot_go.
31#[repr(C)]
32#[derive(Debug)]
33pub struct BootRsp {
34 pub br_hdr: *const ImageHeader,
35 pub flash_dev_id: u8,
36 pub image_off: u32,
37}
38
39// TODO: Don't duplicate this image header declaration.
40#[repr(C)]
41#[derive(Debug)]
42pub struct ImageHeader {
43 magic: u32,
44 load_addr: u32,
45 hdr_size: u16,
46 protect_tlv_size: u16,
47 img_size: u32,
48 flags: u32,
49 ver: ImageVersion,
50 _pad2: u32,
51}
52
53#[repr(C)]
54#[derive(Debug)]
55pub struct ImageVersion {
56 pub major: u8,
57 pub minor: u8,
58 pub revision: u16,
59 pub build_num: u32,
60}
61
Fabio Utzig8000e322019-08-05 08:14:32 -030062pub struct CAreaDescPtr {
63 pub ptr: *const CAreaDesc,
64}
65
66pub struct FlashContext {
67 flash_map: FlashMap,
68 flash_params: FlashParams,
69 flash_areas: CAreaDescPtr,
70}
71
72impl FlashContext {
73 pub fn new() -> FlashContext {
74 FlashContext {
75 flash_map: HashMap::new(),
76 flash_params: HashMap::new(),
77 flash_areas: CAreaDescPtr{ptr: ptr::null()},
78 }
79 }
80}
81
David Brownfc8e3c52021-03-10 05:11:26 -070082impl Default for FlashContext {
83 fn default() -> FlashContext {
84 FlashContext {
85 flash_map: HashMap::new(),
86 flash_params: HashMap::new(),
87 flash_areas: CAreaDescPtr{ptr: ptr::null()},
88 }
89 }
90}
91
Fabio Utzig8000e322019-08-05 08:14:32 -030092#[repr(C)]
93#[derive(Debug, Default)]
94pub struct CSimContext {
95 pub flash_counter: libc::c_int,
96 pub jumped: libc::c_int,
97 pub c_asserts: u8,
98 pub c_catch_asserts: u8,
99 // NOTE: Always leave boot_jmpbuf declaration at the end; this should
100 // store a "jmp_buf" which is arch specific and not defined by libc crate.
101 // The size below is enough to store data on a x86_64 machine.
102 pub boot_jmpbuf: [u64; 16],
103}
104
105pub struct CSimContextPtr {
106 pub ptr: *const CSimContext,
107}
108
109impl CSimContextPtr {
110 pub fn new() -> CSimContextPtr {
111 CSimContextPtr {
112 ptr: ptr::null(),
113 }
114 }
115}
116
David Brownfc8e3c52021-03-10 05:11:26 -0700117impl Default for CSimContextPtr {
118 fn default() -> CSimContextPtr {
119 CSimContextPtr {
120 ptr: ptr::null(),
121 }
122 }
123}
124
David Brown8a4e23b2021-06-11 10:29:01 -0600125/// This struct describes the RAM layout of the current device. It will be stashed, per test
126/// thread, and queried by the C code.
127#[repr(C)]
128#[derive(Debug, Default)]
129pub struct BootsimRamInfo {
130 pub start: u32,
131 pub size: u32,
132 pub base: usize,
133}
134
Roland Mikheld6703522023-04-27 14:24:30 +0200135/// This struct stores the non-volatile security counter per image. It will be stored per test thread,
136/// and the C code will set / get the values here.
137#[repr(C)]
138#[derive(Debug, Default)]
139pub struct NvCounterStorage {
140 pub storage: Vec<u32>,
141}
142
143impl NvCounterStorage {
144 pub fn new() -> Self {
145 let count = if cfg!(feature = "multiimage") {
146 2
147 } else {
148 1
149 };
150 Self {
151 storage: vec![0; count]
152 }
153 }
154}
155
Fabio Utzig8000e322019-08-05 08:14:32 -0300156thread_local! {
157 pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
158 pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
David Brown8a4e23b2021-06-11 10:29:01 -0600159 pub static RAM_CTX: RefCell<BootsimRamInfo> = RefCell::new(BootsimRamInfo::default());
Roland Mikheld6703522023-04-27 14:24:30 +0200160 pub static NV_COUNTER_CTX: RefCell<NvCounterStorage> = RefCell::new(NvCounterStorage::new());
Fabio Utzig73ffc442018-10-24 21:49:09 -0300161}
162
David Brown7cc45262021-03-10 05:13:44 -0700163/// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
164///
165/// # Safety
166///
167/// This uses mem::transmute to stash a Rust pointer into a C value to
168/// retrieve later. It should be safe to use this.
169pub fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300170 THREAD_CTX.with(|ctx| {
171 ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
Gustavo Henrique Nihei4aa286d2021-11-24 14:54:56 -0300172 align: dev.align() as u32,
Fabio Utzig8000e322019-08-05 08:14:32 -0300173 erased_val: dev.erased_val(),
174 });
David Brown7cc45262021-03-10 05:13:44 -0700175 unsafe {
176 let dev: &'static mut dyn Flash = mem::transmute(dev);
177 ctx.borrow_mut().flash_map.insert(
178 dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
179 }
Fabio Utzig73ffc442018-10-24 21:49:09 -0300180 });
David Brownbdb6db72017-07-06 10:14:37 -0600181}
182
David Brown7cc45262021-03-10 05:13:44 -0700183pub fn clear_flash(dev_id: u8) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300184 THREAD_CTX.with(|ctx| {
185 ctx.borrow_mut().flash_map.remove(&dev_id);
186 });
David Brownbdb6db72017-07-06 10:14:37 -0600187}
188
David Brownde7729e2017-01-09 10:41:35 -0700189// This isn't meant to call directly, but by a wrapper.
190
191#[no_mangle]
Fabio Utzig8000e322019-08-05 08:14:32 -0300192pub extern fn sim_get_flash_areas() -> *const CAreaDesc {
193 THREAD_CTX.with(|ctx| {
194 ctx.borrow().flash_areas.ptr
195 })
196}
197
198#[no_mangle]
199pub extern fn sim_set_flash_areas(areas: *const CAreaDesc) {
200 THREAD_CTX.with(|ctx| {
201 ctx.borrow_mut().flash_areas.ptr = areas;
202 });
203}
204
205#[no_mangle]
206pub extern fn sim_reset_flash_areas() {
207 THREAD_CTX.with(|ctx| {
208 ctx.borrow_mut().flash_areas.ptr = ptr::null();
209 });
210}
211
212#[no_mangle]
213pub extern fn sim_get_context() -> *const CSimContext {
214 SIM_CTX.with(|ctx| {
215 ctx.borrow().ptr
216 })
217}
218
219#[no_mangle]
220pub extern fn sim_set_context(ptr: *const CSimContext) {
221 SIM_CTX.with(|ctx| {
222 ctx.borrow_mut().ptr = ptr;
223 });
224}
225
226#[no_mangle]
227pub extern fn sim_reset_context() {
228 SIM_CTX.with(|ctx| {
229 ctx.borrow_mut().ptr = ptr::null();
230 });
231}
232
233#[no_mangle]
David Brown8a4e23b2021-06-11 10:29:01 -0600234pub extern "C" fn bootsim_get_ram_info() -> *const BootsimRamInfo {
235 RAM_CTX.with(|ctx| {
236 if ctx.borrow().base == 0 {
237 // Option is messier to get a pointer out of, so just check if the base has been set to
238 // anything.
239 panic!("ram info not set, but being used");
240 }
241 ctx.as_ptr()
242 })
243}
244
245/// Store a copy of this RAM info.
246pub fn set_ram_info(info: BootsimRamInfo) {
247 RAM_CTX.with(|ctx| {
248 ctx.replace(info);
249 });
250}
251
252/// Clear out the ram info.
253pub fn clear_ram_info() {
254 RAM_CTX.with(|ctx| {
255 ctx.borrow_mut().base = 0;
256 });
257}
258
259#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200260pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300261 let mut rc: libc::c_int = -19;
262 THREAD_CTX.with(|ctx| {
263 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200264 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300265 rc = map_err(dev.erase(offset as usize, size as usize));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200266 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300267 });
268 rc
David Brownde7729e2017-01-09 10:41:35 -0700269}
270
271#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200272pub extern fn sim_flash_read(dev_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300273 let mut rc: libc::c_int = -19;
274 THREAD_CTX.with(|ctx| {
275 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200276 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
277 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300278 rc = map_err(dev.read(offset as usize, &mut buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200279 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300280 });
281 rc
David Brownde7729e2017-01-09 10:41:35 -0700282}
283
284#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200285pub extern fn sim_flash_write(dev_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300286 let mut rc: libc::c_int = -19;
287 THREAD_CTX.with(|ctx| {
288 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200289 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
290 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300291 rc = map_err(dev.write(offset as usize, &buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200292 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300293 });
294 rc
David Brownde7729e2017-01-09 10:41:35 -0700295}
296
Fabio Utzig73ffc442018-10-24 21:49:09 -0300297#[no_mangle]
Gustavo Henrique Nihei4aa286d2021-11-24 14:54:56 -0300298pub extern fn sim_flash_align(id: u8) -> u32 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300299 THREAD_CTX.with(|ctx| {
300 ctx.borrow().flash_params.get(&id).unwrap().align
301 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300302}
303
304#[no_mangle]
305pub extern fn sim_flash_erased_val(id: u8) -> u8 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300306 THREAD_CTX.with(|ctx| {
307 ctx.borrow().flash_params.get(&id).unwrap().erased_val
308 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300309}
310
David Brownde7729e2017-01-09 10:41:35 -0700311fn map_err(err: Result<()>) -> libc::c_int {
312 match err {
313 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300314 Err(e) => {
315 warn!("{}", e);
316 -1
317 },
David Brownde7729e2017-01-09 10:41:35 -0700318 }
319}
David Brown2d1d7cf2017-05-10 08:55:09 -0600320
321/// Called by C code to determine if we should log at this level. Levels are defined in
322/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
323/// for example, it can be enabled with something like:
324/// RUST_LOG=bootsim::api=info cargo run --release runall
325/// or
326/// RUST_LOG=bootsim=info cargo run --release runall
327#[no_mangle]
328pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
329 let res = match level {
David Brown28215642019-01-02 11:42:39 -0700330 1 => log_enabled!(Level::Error),
331 2 => log_enabled!(Level::Warn),
332 3 => log_enabled!(Level::Info),
Fabio Utzige92df932019-12-10 14:29:17 -0300333 4 => log_enabled!(Level::Debug),
334 5 => log_enabled!(Level::Trace), // log level == SIM
David Brown2d1d7cf2017-05-10 08:55:09 -0600335 _ => false,
336 };
337 if res {
338 1
339 } else {
340 0
341 }
342}
Roland Mikheld6703522023-04-27 14:24:30 +0200343
344#[no_mangle]
345pub extern "C" fn sim_set_nv_counter_for_image(image_index: u32, security_counter_value: u32) -> libc::c_int {
346 let mut rc = 0;
347 NV_COUNTER_CTX.with(|ctx| {
348 let mut counter_storage = ctx.borrow_mut();
349 if image_index as usize >= counter_storage.storage.len() {
350 rc = -1;
351 return;
352 }
353 if counter_storage.storage[image_index as usize] > security_counter_value {
354 rc = -2;
355 warn!("Failed to set security counter value ({}) for image index {}", security_counter_value, image_index);
356 return;
357 }
358
359 counter_storage.storage[image_index as usize] = security_counter_value;
360 });
361
362 return rc;
363}
364
365#[no_mangle]
366pub extern "C" fn sim_get_nv_counter_for_image(image_index: u32, security_counter_value: *mut u32) -> libc::c_int {
367 let mut rc = 0;
368 NV_COUNTER_CTX.with(|ctx| {
369 let counter_storage = ctx.borrow();
370 if image_index as usize >= counter_storage.storage.len() {
371 rc = -1;
372 return;
373 }
374 unsafe { *security_counter_value = counter_storage.storage[image_index as usize] };
375
376 });
377 return rc;
378}