blob: f38d98ead9ba88717d8c4f0981808222bbc620bd [file] [log] [blame]
David Brownde7729e2017-01-09 10:41:35 -07001//! HAL api for MyNewt applications
2
Fabio Utzig8000e322019-08-05 08:14:32 -03003use crate::area::CAreaDesc;
David Brownde7729e2017-01-09 10:41:35 -07004use libc;
David Brown28215642019-01-02 11:42:39 -07005use log::{Level, log_enabled, warn};
Fabio Utzig8000e322019-08-05 08:14:32 -03006use simflash::{Result, Flash, FlashPtr};
David Brown28215642019-01-02 11:42:39 -07007use std::{
Fabio Utzig8000e322019-08-05 08:14:32 -03008 cell::RefCell,
David Brown28215642019-01-02 11:42:39 -07009 collections::HashMap,
10 mem,
Fabio Utzig8000e322019-08-05 08:14:32 -030011 ptr,
David Brown28215642019-01-02 11:42:39 -070012 slice,
David Brown28215642019-01-02 11:42:39 -070013};
David Brownde7729e2017-01-09 10:41:35 -070014
Fabio Utzig1c9aea52018-11-15 10:36:07 -020015/// A FlashMap maintain a table of [device_id -> Flash trait]
Fabio Utzigafb2bc92018-11-19 16:11:52 -020016pub type FlashMap = HashMap<u8, FlashPtr>;
Fabio Utzig1c9aea52018-11-15 10:36:07 -020017
Fabio Utzig8000e322019-08-05 08:14:32 -030018pub struct FlashParamsStruct {
Fabio Utzig73ffc442018-10-24 21:49:09 -030019 align: u8,
20 erased_val: u8,
21}
22
Fabio Utzig8000e322019-08-05 08:14:32 -030023pub type FlashParams = HashMap<u8, FlashParamsStruct>;
24
25pub struct CAreaDescPtr {
26 pub ptr: *const CAreaDesc,
27}
28
29pub struct FlashContext {
30 flash_map: FlashMap,
31 flash_params: FlashParams,
32 flash_areas: CAreaDescPtr,
33}
34
35impl FlashContext {
36 pub fn new() -> FlashContext {
37 FlashContext {
38 flash_map: HashMap::new(),
39 flash_params: HashMap::new(),
40 flash_areas: CAreaDescPtr{ptr: ptr::null()},
41 }
42 }
43}
44
45#[repr(C)]
46#[derive(Debug, Default)]
47pub struct CSimContext {
48 pub flash_counter: libc::c_int,
49 pub jumped: libc::c_int,
50 pub c_asserts: u8,
51 pub c_catch_asserts: u8,
52 // NOTE: Always leave boot_jmpbuf declaration at the end; this should
53 // store a "jmp_buf" which is arch specific and not defined by libc crate.
54 // The size below is enough to store data on a x86_64 machine.
55 pub boot_jmpbuf: [u64; 16],
56}
57
58pub struct CSimContextPtr {
59 pub ptr: *const CSimContext,
60}
61
62impl CSimContextPtr {
63 pub fn new() -> CSimContextPtr {
64 CSimContextPtr {
65 ptr: ptr::null(),
66 }
67 }
68}
69
70thread_local! {
71 pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
72 pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
Fabio Utzig73ffc442018-10-24 21:49:09 -030073}
74
David Brownbdb6db72017-07-06 10:14:37 -060075// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
David Brown28215642019-01-02 11:42:39 -070076pub unsafe fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
Fabio Utzig8000e322019-08-05 08:14:32 -030077 THREAD_CTX.with(|ctx| {
78 ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
79 align: dev.align() as u8,
80 erased_val: dev.erased_val(),
81 });
82 let dev: &'static mut dyn Flash = mem::transmute(dev);
83 ctx.borrow_mut().flash_map.insert(
84 dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
Fabio Utzig73ffc442018-10-24 21:49:09 -030085 });
David Brownbdb6db72017-07-06 10:14:37 -060086}
87
Fabio Utzig1c9aea52018-11-15 10:36:07 -020088pub unsafe fn clear_flash(dev_id: u8) {
Fabio Utzig8000e322019-08-05 08:14:32 -030089 THREAD_CTX.with(|ctx| {
90 ctx.borrow_mut().flash_map.remove(&dev_id);
91 });
David Brownbdb6db72017-07-06 10:14:37 -060092}
93
David Brownde7729e2017-01-09 10:41:35 -070094// This isn't meant to call directly, but by a wrapper.
95
96#[no_mangle]
Fabio Utzig8000e322019-08-05 08:14:32 -030097pub extern fn sim_get_flash_areas() -> *const CAreaDesc {
98 THREAD_CTX.with(|ctx| {
99 ctx.borrow().flash_areas.ptr
100 })
101}
102
103#[no_mangle]
104pub extern fn sim_set_flash_areas(areas: *const CAreaDesc) {
105 THREAD_CTX.with(|ctx| {
106 ctx.borrow_mut().flash_areas.ptr = areas;
107 });
108}
109
110#[no_mangle]
111pub extern fn sim_reset_flash_areas() {
112 THREAD_CTX.with(|ctx| {
113 ctx.borrow_mut().flash_areas.ptr = ptr::null();
114 });
115}
116
117#[no_mangle]
118pub extern fn sim_get_context() -> *const CSimContext {
119 SIM_CTX.with(|ctx| {
120 ctx.borrow().ptr
121 })
122}
123
124#[no_mangle]
125pub extern fn sim_set_context(ptr: *const CSimContext) {
126 SIM_CTX.with(|ctx| {
127 ctx.borrow_mut().ptr = ptr;
128 });
129}
130
131#[no_mangle]
132pub extern fn sim_reset_context() {
133 SIM_CTX.with(|ctx| {
134 ctx.borrow_mut().ptr = ptr::null();
135 });
136}
137
138#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200139pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300140 let mut rc: libc::c_int = -19;
141 THREAD_CTX.with(|ctx| {
142 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200143 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300144 rc = map_err(dev.erase(offset as usize, size as usize));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200145 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300146 });
147 rc
David Brownde7729e2017-01-09 10:41:35 -0700148}
149
150#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200151pub 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 -0300152 let mut rc: libc::c_int = -19;
153 THREAD_CTX.with(|ctx| {
154 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200155 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
156 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300157 rc = map_err(dev.read(offset as usize, &mut buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200158 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300159 });
160 rc
David Brownde7729e2017-01-09 10:41:35 -0700161}
162
163#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200164pub 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 -0300165 let mut rc: libc::c_int = -19;
166 THREAD_CTX.with(|ctx| {
167 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200168 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
169 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300170 rc = map_err(dev.write(offset as usize, &buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200171 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300172 });
173 rc
David Brownde7729e2017-01-09 10:41:35 -0700174}
175
Fabio Utzig73ffc442018-10-24 21:49:09 -0300176#[no_mangle]
177pub extern fn sim_flash_align(id: u8) -> u8 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300178 THREAD_CTX.with(|ctx| {
179 ctx.borrow().flash_params.get(&id).unwrap().align
180 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300181}
182
183#[no_mangle]
184pub extern fn sim_flash_erased_val(id: u8) -> u8 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300185 THREAD_CTX.with(|ctx| {
186 ctx.borrow().flash_params.get(&id).unwrap().erased_val
187 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300188}
189
David Brownde7729e2017-01-09 10:41:35 -0700190fn map_err(err: Result<()>) -> libc::c_int {
191 match err {
192 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300193 Err(e) => {
194 warn!("{}", e);
195 -1
196 },
David Brownde7729e2017-01-09 10:41:35 -0700197 }
198}
David Brown2d1d7cf2017-05-10 08:55:09 -0600199
200/// Called by C code to determine if we should log at this level. Levels are defined in
201/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
202/// for example, it can be enabled with something like:
203/// RUST_LOG=bootsim::api=info cargo run --release runall
204/// or
205/// RUST_LOG=bootsim=info cargo run --release runall
206#[no_mangle]
207pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
208 let res = match level {
David Brown28215642019-01-02 11:42:39 -0700209 1 => log_enabled!(Level::Error),
210 2 => log_enabled!(Level::Warn),
211 3 => log_enabled!(Level::Info),
212 4 => log_enabled!(Level::Trace),
David Brown2d1d7cf2017-05-10 08:55:09 -0600213 _ => false,
214 };
215 if res {
216 1
217 } else {
218 0
219 }
220}