blob: 0a098ffb3fc32e94dcfc6c5e4d33cc4e4b9f053a [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)]
David Browna7063172024-06-25 10:00:31 -060093#[derive(Debug)]
Fabio Utzig8000e322019-08-05 08:14:32 -030094pub 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.
David Browna7063172024-06-25 10:00:31 -0600102 pub boot_jmpbuf: [u64; 48],
103}
104
105impl Default for CSimContext {
106 fn default() -> Self {
107 CSimContext {
108 flash_counter: 0,
109 jumped: 0,
110 c_asserts: 0,
111 c_catch_asserts: 0,
112 boot_jmpbuf: [0; 48],
113 }
114 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300115}
116
117pub struct CSimContextPtr {
118 pub ptr: *const CSimContext,
119}
120
121impl CSimContextPtr {
122 pub fn new() -> CSimContextPtr {
123 CSimContextPtr {
124 ptr: ptr::null(),
125 }
126 }
127}
128
David Brownfc8e3c52021-03-10 05:11:26 -0700129impl Default for CSimContextPtr {
130 fn default() -> CSimContextPtr {
131 CSimContextPtr {
132 ptr: ptr::null(),
133 }
134 }
135}
136
David Brown8a4e23b2021-06-11 10:29:01 -0600137/// This struct describes the RAM layout of the current device. It will be stashed, per test
138/// thread, and queried by the C code.
139#[repr(C)]
140#[derive(Debug, Default)]
141pub struct BootsimRamInfo {
142 pub start: u32,
143 pub size: u32,
144 pub base: usize,
145}
146
Roland Mikheld6703522023-04-27 14:24:30 +0200147/// This struct stores the non-volatile security counter per image. It will be stored per test thread,
148/// and the C code will set / get the values here.
149#[repr(C)]
150#[derive(Debug, Default)]
151pub struct NvCounterStorage {
152 pub storage: Vec<u32>,
153}
154
155impl NvCounterStorage {
156 pub fn new() -> Self {
157 let count = if cfg!(feature = "multiimage") {
158 2
159 } else {
160 1
161 };
162 Self {
163 storage: vec![0; count]
164 }
165 }
166}
167
Fabio Utzig8000e322019-08-05 08:14:32 -0300168thread_local! {
169 pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
170 pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
David Brown8a4e23b2021-06-11 10:29:01 -0600171 pub static RAM_CTX: RefCell<BootsimRamInfo> = RefCell::new(BootsimRamInfo::default());
Roland Mikheld6703522023-04-27 14:24:30 +0200172 pub static NV_COUNTER_CTX: RefCell<NvCounterStorage> = RefCell::new(NvCounterStorage::new());
Fabio Utzig73ffc442018-10-24 21:49:09 -0300173}
174
David Brown7cc45262021-03-10 05:13:44 -0700175/// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
176///
177/// # Safety
178///
179/// This uses mem::transmute to stash a Rust pointer into a C value to
180/// retrieve later. It should be safe to use this.
181pub fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300182 THREAD_CTX.with(|ctx| {
183 ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
Gustavo Henrique Nihei4aa286d2021-11-24 14:54:56 -0300184 align: dev.align() as u32,
Fabio Utzig8000e322019-08-05 08:14:32 -0300185 erased_val: dev.erased_val(),
186 });
David Brown7cc45262021-03-10 05:13:44 -0700187 unsafe {
188 let dev: &'static mut dyn Flash = mem::transmute(dev);
189 ctx.borrow_mut().flash_map.insert(
190 dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
191 }
Fabio Utzig73ffc442018-10-24 21:49:09 -0300192 });
David Brownbdb6db72017-07-06 10:14:37 -0600193}
194
David Brown7cc45262021-03-10 05:13:44 -0700195pub fn clear_flash(dev_id: u8) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300196 THREAD_CTX.with(|ctx| {
197 ctx.borrow_mut().flash_map.remove(&dev_id);
198 });
David Brownbdb6db72017-07-06 10:14:37 -0600199}
200
David Brownde7729e2017-01-09 10:41:35 -0700201// This isn't meant to call directly, but by a wrapper.
202
203#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600204pub extern "C" fn sim_get_flash_areas() -> *const CAreaDesc {
Fabio Utzig8000e322019-08-05 08:14:32 -0300205 THREAD_CTX.with(|ctx| {
206 ctx.borrow().flash_areas.ptr
207 })
208}
209
210#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600211pub extern "C" fn sim_set_flash_areas(areas: *const CAreaDesc) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300212 THREAD_CTX.with(|ctx| {
213 ctx.borrow_mut().flash_areas.ptr = areas;
214 });
215}
216
217#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600218pub extern "C" fn sim_reset_flash_areas() {
Fabio Utzig8000e322019-08-05 08:14:32 -0300219 THREAD_CTX.with(|ctx| {
220 ctx.borrow_mut().flash_areas.ptr = ptr::null();
221 });
222}
223
224#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600225pub extern "C" fn sim_get_context() -> *const CSimContext {
Fabio Utzig8000e322019-08-05 08:14:32 -0300226 SIM_CTX.with(|ctx| {
227 ctx.borrow().ptr
228 })
229}
230
231#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600232pub extern "C" fn sim_set_context(ptr: *const CSimContext) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300233 SIM_CTX.with(|ctx| {
234 ctx.borrow_mut().ptr = ptr;
235 });
236}
237
238#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600239pub extern "C" fn sim_reset_context() {
Fabio Utzig8000e322019-08-05 08:14:32 -0300240 SIM_CTX.with(|ctx| {
241 ctx.borrow_mut().ptr = ptr::null();
242 });
243}
244
245#[no_mangle]
David Brown8a4e23b2021-06-11 10:29:01 -0600246pub extern "C" fn bootsim_get_ram_info() -> *const BootsimRamInfo {
247 RAM_CTX.with(|ctx| {
248 if ctx.borrow().base == 0 {
249 // Option is messier to get a pointer out of, so just check if the base has been set to
250 // anything.
251 panic!("ram info not set, but being used");
252 }
253 ctx.as_ptr()
254 })
255}
256
257/// Store a copy of this RAM info.
258pub fn set_ram_info(info: BootsimRamInfo) {
259 RAM_CTX.with(|ctx| {
260 ctx.replace(info);
261 });
262}
263
264/// Clear out the ram info.
265pub fn clear_ram_info() {
266 RAM_CTX.with(|ctx| {
267 ctx.borrow_mut().base = 0;
268 });
269}
270
271#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600272pub extern "C" fn sim_flash_erase(dev_id: u8, offset: u32, 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 dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300277 rc = map_err(dev.erase(offset as usize, size as usize));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200278 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300279 });
280 rc
David Brownde7729e2017-01-09 10:41:35 -0700281}
282
283#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600284pub extern "C" fn sim_flash_read(dev_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300285 let mut rc: libc::c_int = -19;
286 THREAD_CTX.with(|ctx| {
287 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200288 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
289 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300290 rc = map_err(dev.read(offset as usize, &mut buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200291 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300292 });
293 rc
David Brownde7729e2017-01-09 10:41:35 -0700294}
295
296#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600297pub extern "C" fn sim_flash_write(dev_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300298 let mut rc: libc::c_int = -19;
299 THREAD_CTX.with(|ctx| {
300 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200301 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
302 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300303 rc = map_err(dev.write(offset as usize, &buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200304 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300305 });
306 rc
David Brownde7729e2017-01-09 10:41:35 -0700307}
308
Fabio Utzig73ffc442018-10-24 21:49:09 -0300309#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600310pub extern "C" fn sim_flash_align(id: u8) -> u32 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300311 THREAD_CTX.with(|ctx| {
312 ctx.borrow().flash_params.get(&id).unwrap().align
313 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300314}
315
316#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600317pub extern "C" fn sim_flash_erased_val(id: u8) -> u8 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300318 THREAD_CTX.with(|ctx| {
319 ctx.borrow().flash_params.get(&id).unwrap().erased_val
320 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300321}
322
David Brownde7729e2017-01-09 10:41:35 -0700323fn map_err(err: Result<()>) -> libc::c_int {
324 match err {
325 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300326 Err(e) => {
327 warn!("{}", e);
328 -1
329 },
David Brownde7729e2017-01-09 10:41:35 -0700330 }
331}
David Brown2d1d7cf2017-05-10 08:55:09 -0600332
333/// Called by C code to determine if we should log at this level. Levels are defined in
334/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
335/// for example, it can be enabled with something like:
336/// RUST_LOG=bootsim::api=info cargo run --release runall
337/// or
338/// RUST_LOG=bootsim=info cargo run --release runall
339#[no_mangle]
David Brown847548a2024-06-12 14:32:34 -0600340pub extern "C" fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
David Brown2d1d7cf2017-05-10 08:55:09 -0600341 let res = match level {
David Brown28215642019-01-02 11:42:39 -0700342 1 => log_enabled!(Level::Error),
343 2 => log_enabled!(Level::Warn),
344 3 => log_enabled!(Level::Info),
Fabio Utzige92df932019-12-10 14:29:17 -0300345 4 => log_enabled!(Level::Debug),
346 5 => log_enabled!(Level::Trace), // log level == SIM
David Brown2d1d7cf2017-05-10 08:55:09 -0600347 _ => false,
348 };
349 if res {
350 1
351 } else {
352 0
353 }
354}
Roland Mikheld6703522023-04-27 14:24:30 +0200355
356#[no_mangle]
357pub extern "C" fn sim_set_nv_counter_for_image(image_index: u32, security_counter_value: u32) -> libc::c_int {
358 let mut rc = 0;
359 NV_COUNTER_CTX.with(|ctx| {
360 let mut counter_storage = ctx.borrow_mut();
361 if image_index as usize >= counter_storage.storage.len() {
362 rc = -1;
363 return;
364 }
365 if counter_storage.storage[image_index as usize] > security_counter_value {
366 rc = -2;
367 warn!("Failed to set security counter value ({}) for image index {}", security_counter_value, image_index);
368 return;
369 }
370
371 counter_storage.storage[image_index as usize] = security_counter_value;
372 });
373
374 return rc;
375}
376
377#[no_mangle]
378pub extern "C" fn sim_get_nv_counter_for_image(image_index: u32, security_counter_value: *mut u32) -> libc::c_int {
379 let mut rc = 0;
380 NV_COUNTER_CTX.with(|ctx| {
381 let counter_storage = ctx.borrow();
382 if image_index as usize >= counter_storage.storage.len() {
383 rc = -1;
384 return;
385 }
386 unsafe { *security_counter_value = counter_storage.storage[image_index as usize] };
387
388 });
389 return rc;
390}