blob: 7bd4fc40437827c33dd840dbe0b124397e3b3f7a [file] [log] [blame]
David Browne2acfae2020-01-21 16:45:01 -07001// Copyright (c) 2017-2019 Linaro LTD
2// 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
29pub struct CAreaDescPtr {
30 pub ptr: *const CAreaDesc,
31}
32
33pub struct FlashContext {
34 flash_map: FlashMap,
35 flash_params: FlashParams,
36 flash_areas: CAreaDescPtr,
37}
38
39impl FlashContext {
40 pub fn new() -> FlashContext {
41 FlashContext {
42 flash_map: HashMap::new(),
43 flash_params: HashMap::new(),
44 flash_areas: CAreaDescPtr{ptr: ptr::null()},
45 }
46 }
47}
48
David Brownfc8e3c52021-03-10 05:11:26 -070049impl Default for FlashContext {
50 fn default() -> FlashContext {
51 FlashContext {
52 flash_map: HashMap::new(),
53 flash_params: HashMap::new(),
54 flash_areas: CAreaDescPtr{ptr: ptr::null()},
55 }
56 }
57}
58
Fabio Utzig8000e322019-08-05 08:14:32 -030059#[repr(C)]
60#[derive(Debug, Default)]
61pub struct CSimContext {
62 pub flash_counter: libc::c_int,
63 pub jumped: libc::c_int,
64 pub c_asserts: u8,
65 pub c_catch_asserts: u8,
66 // NOTE: Always leave boot_jmpbuf declaration at the end; this should
67 // store a "jmp_buf" which is arch specific and not defined by libc crate.
68 // The size below is enough to store data on a x86_64 machine.
69 pub boot_jmpbuf: [u64; 16],
70}
71
72pub struct CSimContextPtr {
73 pub ptr: *const CSimContext,
74}
75
76impl CSimContextPtr {
77 pub fn new() -> CSimContextPtr {
78 CSimContextPtr {
79 ptr: ptr::null(),
80 }
81 }
82}
83
David Brownfc8e3c52021-03-10 05:11:26 -070084impl Default for CSimContextPtr {
85 fn default() -> CSimContextPtr {
86 CSimContextPtr {
87 ptr: ptr::null(),
88 }
89 }
90}
91
Fabio Utzig8000e322019-08-05 08:14:32 -030092thread_local! {
93 pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
94 pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
Fabio Utzig73ffc442018-10-24 21:49:09 -030095}
96
David Brownbdb6db72017-07-06 10:14:37 -060097// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
David Brown28215642019-01-02 11:42:39 -070098pub unsafe fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
Fabio Utzig8000e322019-08-05 08:14:32 -030099 THREAD_CTX.with(|ctx| {
100 ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
Fabio Utzig1edb7882020-10-04 11:51:53 -0300101 align: dev.align() as u16,
Fabio Utzig8000e322019-08-05 08:14:32 -0300102 erased_val: dev.erased_val(),
103 });
104 let dev: &'static mut dyn Flash = mem::transmute(dev);
105 ctx.borrow_mut().flash_map.insert(
106 dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
Fabio Utzig73ffc442018-10-24 21:49:09 -0300107 });
David Brownbdb6db72017-07-06 10:14:37 -0600108}
109
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200110pub unsafe fn clear_flash(dev_id: u8) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300111 THREAD_CTX.with(|ctx| {
112 ctx.borrow_mut().flash_map.remove(&dev_id);
113 });
David Brownbdb6db72017-07-06 10:14:37 -0600114}
115
David Brownde7729e2017-01-09 10:41:35 -0700116// This isn't meant to call directly, but by a wrapper.
117
118#[no_mangle]
Fabio Utzig8000e322019-08-05 08:14:32 -0300119pub extern fn sim_get_flash_areas() -> *const CAreaDesc {
120 THREAD_CTX.with(|ctx| {
121 ctx.borrow().flash_areas.ptr
122 })
123}
124
125#[no_mangle]
126pub extern fn sim_set_flash_areas(areas: *const CAreaDesc) {
127 THREAD_CTX.with(|ctx| {
128 ctx.borrow_mut().flash_areas.ptr = areas;
129 });
130}
131
132#[no_mangle]
133pub extern fn sim_reset_flash_areas() {
134 THREAD_CTX.with(|ctx| {
135 ctx.borrow_mut().flash_areas.ptr = ptr::null();
136 });
137}
138
139#[no_mangle]
140pub extern fn sim_get_context() -> *const CSimContext {
141 SIM_CTX.with(|ctx| {
142 ctx.borrow().ptr
143 })
144}
145
146#[no_mangle]
147pub extern fn sim_set_context(ptr: *const CSimContext) {
148 SIM_CTX.with(|ctx| {
149 ctx.borrow_mut().ptr = ptr;
150 });
151}
152
153#[no_mangle]
154pub extern fn sim_reset_context() {
155 SIM_CTX.with(|ctx| {
156 ctx.borrow_mut().ptr = ptr::null();
157 });
158}
159
160#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200161pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300162 let mut rc: libc::c_int = -19;
163 THREAD_CTX.with(|ctx| {
164 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200165 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300166 rc = map_err(dev.erase(offset as usize, size as usize));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200167 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300168 });
169 rc
David Brownde7729e2017-01-09 10:41:35 -0700170}
171
172#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200173pub 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 -0300174 let mut rc: libc::c_int = -19;
175 THREAD_CTX.with(|ctx| {
176 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200177 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
178 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300179 rc = map_err(dev.read(offset as usize, &mut buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200180 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300181 });
182 rc
David Brownde7729e2017-01-09 10:41:35 -0700183}
184
185#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200186pub 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 -0300187 let mut rc: libc::c_int = -19;
188 THREAD_CTX.with(|ctx| {
189 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200190 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
191 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300192 rc = map_err(dev.write(offset as usize, &buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200193 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300194 });
195 rc
David Brownde7729e2017-01-09 10:41:35 -0700196}
197
Fabio Utzig73ffc442018-10-24 21:49:09 -0300198#[no_mangle]
Fabio Utzig1edb7882020-10-04 11:51:53 -0300199pub extern fn sim_flash_align(id: u8) -> u16 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300200 THREAD_CTX.with(|ctx| {
201 ctx.borrow().flash_params.get(&id).unwrap().align
202 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300203}
204
205#[no_mangle]
206pub extern fn sim_flash_erased_val(id: u8) -> u8 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300207 THREAD_CTX.with(|ctx| {
208 ctx.borrow().flash_params.get(&id).unwrap().erased_val
209 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300210}
211
David Brownde7729e2017-01-09 10:41:35 -0700212fn map_err(err: Result<()>) -> libc::c_int {
213 match err {
214 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300215 Err(e) => {
216 warn!("{}", e);
217 -1
218 },
David Brownde7729e2017-01-09 10:41:35 -0700219 }
220}
David Brown2d1d7cf2017-05-10 08:55:09 -0600221
222/// Called by C code to determine if we should log at this level. Levels are defined in
223/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
224/// for example, it can be enabled with something like:
225/// RUST_LOG=bootsim::api=info cargo run --release runall
226/// or
227/// RUST_LOG=bootsim=info cargo run --release runall
228#[no_mangle]
229pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
230 let res = match level {
David Brown28215642019-01-02 11:42:39 -0700231 1 => log_enabled!(Level::Error),
232 2 => log_enabled!(Level::Warn),
233 3 => log_enabled!(Level::Info),
Fabio Utzige92df932019-12-10 14:29:17 -0300234 4 => log_enabled!(Level::Debug),
235 5 => log_enabled!(Level::Trace), // log level == SIM
David Brown2d1d7cf2017-05-10 08:55:09 -0600236 _ => false,
237 };
238 if res {
239 1
240 } else {
241 0
242 }
243}