blob: fb5559557e379d6e894abab3a7f543c98169944f [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
3//
4// SPDX-License-Identifier: Apache-2.0
5
David Brownde7729e2017-01-09 10:41:35 -07006//! HAL api for MyNewt applications
7
Fabio Utzig8000e322019-08-05 08:14:32 -03008use crate::area::CAreaDesc;
David Brown28215642019-01-02 11:42:39 -07009use log::{Level, log_enabled, warn};
Fabio Utzig8000e322019-08-05 08:14:32 -030010use simflash::{Result, Flash, FlashPtr};
David Brown28215642019-01-02 11:42:39 -070011use std::{
Fabio Utzig8000e322019-08-05 08:14:32 -030012 cell::RefCell,
David Brown28215642019-01-02 11:42:39 -070013 collections::HashMap,
14 mem,
Fabio Utzig8000e322019-08-05 08:14:32 -030015 ptr,
David Brown28215642019-01-02 11:42:39 -070016 slice,
David Brown28215642019-01-02 11:42:39 -070017};
David Brownde7729e2017-01-09 10:41:35 -070018
Fabio Utzig1c9aea52018-11-15 10:36:07 -020019/// A FlashMap maintain a table of [device_id -> Flash trait]
Fabio Utzigafb2bc92018-11-19 16:11:52 -020020pub type FlashMap = HashMap<u8, FlashPtr>;
Fabio Utzig1c9aea52018-11-15 10:36:07 -020021
Fabio Utzig8000e322019-08-05 08:14:32 -030022pub struct FlashParamsStruct {
Fabio Utzig1edb7882020-10-04 11:51:53 -030023 align: u16,
Fabio Utzig73ffc442018-10-24 21:49:09 -030024 erased_val: u8,
25}
26
Fabio Utzig8000e322019-08-05 08:14:32 -030027pub type FlashParams = HashMap<u8, FlashParamsStruct>;
28
David Brownd216b202021-06-04 10:14:33 -060029/// The `boot_rsp` structure used by boot_go.
30#[repr(C)]
31#[derive(Debug)]
32pub struct BootRsp {
33 pub br_hdr: *const ImageHeader,
34 pub flash_dev_id: u8,
35 pub image_off: u32,
36}
37
38// TODO: Don't duplicate this image header declaration.
39#[repr(C)]
40#[derive(Debug)]
41pub struct ImageHeader {
42 magic: u32,
43 load_addr: u32,
44 hdr_size: u16,
45 protect_tlv_size: u16,
46 img_size: u32,
47 flags: u32,
48 ver: ImageVersion,
49 _pad2: u32,
50}
51
52#[repr(C)]
53#[derive(Debug)]
54pub struct ImageVersion {
55 pub major: u8,
56 pub minor: u8,
57 pub revision: u16,
58 pub build_num: u32,
59}
60
Fabio Utzig8000e322019-08-05 08:14:32 -030061pub struct CAreaDescPtr {
62 pub ptr: *const CAreaDesc,
63}
64
65pub struct FlashContext {
66 flash_map: FlashMap,
67 flash_params: FlashParams,
68 flash_areas: CAreaDescPtr,
69}
70
71impl FlashContext {
72 pub fn new() -> FlashContext {
73 FlashContext {
74 flash_map: HashMap::new(),
75 flash_params: HashMap::new(),
76 flash_areas: CAreaDescPtr{ptr: ptr::null()},
77 }
78 }
79}
80
David Brownfc8e3c52021-03-10 05:11:26 -070081impl Default for FlashContext {
82 fn default() -> FlashContext {
83 FlashContext {
84 flash_map: HashMap::new(),
85 flash_params: HashMap::new(),
86 flash_areas: CAreaDescPtr{ptr: ptr::null()},
87 }
88 }
89}
90
Fabio Utzig8000e322019-08-05 08:14:32 -030091#[repr(C)]
92#[derive(Debug, Default)]
93pub struct CSimContext {
94 pub flash_counter: libc::c_int,
95 pub jumped: libc::c_int,
96 pub c_asserts: u8,
97 pub c_catch_asserts: u8,
98 // NOTE: Always leave boot_jmpbuf declaration at the end; this should
99 // store a "jmp_buf" which is arch specific and not defined by libc crate.
100 // The size below is enough to store data on a x86_64 machine.
101 pub boot_jmpbuf: [u64; 16],
102}
103
104pub struct CSimContextPtr {
105 pub ptr: *const CSimContext,
106}
107
108impl CSimContextPtr {
109 pub fn new() -> CSimContextPtr {
110 CSimContextPtr {
111 ptr: ptr::null(),
112 }
113 }
114}
115
David Brownfc8e3c52021-03-10 05:11:26 -0700116impl Default for CSimContextPtr {
117 fn default() -> CSimContextPtr {
118 CSimContextPtr {
119 ptr: ptr::null(),
120 }
121 }
122}
123
David Brown8a4e23b2021-06-11 10:29:01 -0600124/// This struct describes the RAM layout of the current device. It will be stashed, per test
125/// thread, and queried by the C code.
126#[repr(C)]
127#[derive(Debug, Default)]
128pub struct BootsimRamInfo {
129 pub start: u32,
130 pub size: u32,
131 pub base: usize,
132}
133
Fabio Utzig8000e322019-08-05 08:14:32 -0300134thread_local! {
135 pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
136 pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
David Brown8a4e23b2021-06-11 10:29:01 -0600137 pub static RAM_CTX: RefCell<BootsimRamInfo> = RefCell::new(BootsimRamInfo::default());
Fabio Utzig73ffc442018-10-24 21:49:09 -0300138}
139
David Brown7cc45262021-03-10 05:13:44 -0700140/// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
141///
142/// # Safety
143///
144/// This uses mem::transmute to stash a Rust pointer into a C value to
145/// retrieve later. It should be safe to use this.
146pub fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300147 THREAD_CTX.with(|ctx| {
148 ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
Fabio Utzig1edb7882020-10-04 11:51:53 -0300149 align: dev.align() as u16,
Fabio Utzig8000e322019-08-05 08:14:32 -0300150 erased_val: dev.erased_val(),
151 });
David Brown7cc45262021-03-10 05:13:44 -0700152 unsafe {
153 let dev: &'static mut dyn Flash = mem::transmute(dev);
154 ctx.borrow_mut().flash_map.insert(
155 dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
156 }
Fabio Utzig73ffc442018-10-24 21:49:09 -0300157 });
David Brownbdb6db72017-07-06 10:14:37 -0600158}
159
David Brown7cc45262021-03-10 05:13:44 -0700160pub fn clear_flash(dev_id: u8) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300161 THREAD_CTX.with(|ctx| {
162 ctx.borrow_mut().flash_map.remove(&dev_id);
163 });
David Brownbdb6db72017-07-06 10:14:37 -0600164}
165
David Brownde7729e2017-01-09 10:41:35 -0700166// This isn't meant to call directly, but by a wrapper.
167
168#[no_mangle]
Fabio Utzig8000e322019-08-05 08:14:32 -0300169pub extern fn sim_get_flash_areas() -> *const CAreaDesc {
170 THREAD_CTX.with(|ctx| {
171 ctx.borrow().flash_areas.ptr
172 })
173}
174
175#[no_mangle]
176pub extern fn sim_set_flash_areas(areas: *const CAreaDesc) {
177 THREAD_CTX.with(|ctx| {
178 ctx.borrow_mut().flash_areas.ptr = areas;
179 });
180}
181
182#[no_mangle]
183pub extern fn sim_reset_flash_areas() {
184 THREAD_CTX.with(|ctx| {
185 ctx.borrow_mut().flash_areas.ptr = ptr::null();
186 });
187}
188
189#[no_mangle]
190pub extern fn sim_get_context() -> *const CSimContext {
191 SIM_CTX.with(|ctx| {
192 ctx.borrow().ptr
193 })
194}
195
196#[no_mangle]
197pub extern fn sim_set_context(ptr: *const CSimContext) {
198 SIM_CTX.with(|ctx| {
199 ctx.borrow_mut().ptr = ptr;
200 });
201}
202
203#[no_mangle]
204pub extern fn sim_reset_context() {
205 SIM_CTX.with(|ctx| {
206 ctx.borrow_mut().ptr = ptr::null();
207 });
208}
209
210#[no_mangle]
David Brown8a4e23b2021-06-11 10:29:01 -0600211pub extern "C" fn bootsim_get_ram_info() -> *const BootsimRamInfo {
212 RAM_CTX.with(|ctx| {
213 if ctx.borrow().base == 0 {
214 // Option is messier to get a pointer out of, so just check if the base has been set to
215 // anything.
216 panic!("ram info not set, but being used");
217 }
218 ctx.as_ptr()
219 })
220}
221
222/// Store a copy of this RAM info.
223pub fn set_ram_info(info: BootsimRamInfo) {
224 RAM_CTX.with(|ctx| {
225 ctx.replace(info);
226 });
227}
228
229/// Clear out the ram info.
230pub fn clear_ram_info() {
231 RAM_CTX.with(|ctx| {
232 ctx.borrow_mut().base = 0;
233 });
234}
235
236#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200237pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300238 let mut rc: libc::c_int = -19;
239 THREAD_CTX.with(|ctx| {
240 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200241 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300242 rc = map_err(dev.erase(offset as usize, size as usize));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200243 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300244 });
245 rc
David Brownde7729e2017-01-09 10:41:35 -0700246}
247
248#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200249pub 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 -0300250 let mut rc: libc::c_int = -19;
251 THREAD_CTX.with(|ctx| {
252 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200253 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
254 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300255 rc = map_err(dev.read(offset as usize, &mut buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200256 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300257 });
258 rc
David Brownde7729e2017-01-09 10:41:35 -0700259}
260
261#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200262pub 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 -0300263 let mut rc: libc::c_int = -19;
264 THREAD_CTX.with(|ctx| {
265 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200266 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
267 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300268 rc = map_err(dev.write(offset as usize, &buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200269 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300270 });
271 rc
David Brownde7729e2017-01-09 10:41:35 -0700272}
273
Fabio Utzig73ffc442018-10-24 21:49:09 -0300274#[no_mangle]
Fabio Utzig1edb7882020-10-04 11:51:53 -0300275pub extern fn sim_flash_align(id: u8) -> u16 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300276 THREAD_CTX.with(|ctx| {
277 ctx.borrow().flash_params.get(&id).unwrap().align
278 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300279}
280
281#[no_mangle]
282pub extern fn sim_flash_erased_val(id: u8) -> u8 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300283 THREAD_CTX.with(|ctx| {
284 ctx.borrow().flash_params.get(&id).unwrap().erased_val
285 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300286}
287
David Brownde7729e2017-01-09 10:41:35 -0700288fn map_err(err: Result<()>) -> libc::c_int {
289 match err {
290 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300291 Err(e) => {
292 warn!("{}", e);
293 -1
294 },
David Brownde7729e2017-01-09 10:41:35 -0700295 }
296}
David Brown2d1d7cf2017-05-10 08:55:09 -0600297
298/// Called by C code to determine if we should log at this level. Levels are defined in
299/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
300/// for example, it can be enabled with something like:
301/// RUST_LOG=bootsim::api=info cargo run --release runall
302/// or
303/// RUST_LOG=bootsim=info cargo run --release runall
304#[no_mangle]
305pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
306 let res = match level {
David Brown28215642019-01-02 11:42:39 -0700307 1 => log_enabled!(Level::Error),
308 2 => log_enabled!(Level::Warn),
309 3 => log_enabled!(Level::Info),
Fabio Utzige92df932019-12-10 14:29:17 -0300310 4 => log_enabled!(Level::Debug),
311 5 => log_enabled!(Level::Trace), // log level == SIM
David Brown2d1d7cf2017-05-10 08:55:09 -0600312 _ => false,
313 };
314 if res {
315 1
316 } else {
317 0
318 }
319}