blob: 8b180cf8c50d61e9c1912b2476ba23f55abac420 [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 Brownde7729e2017-01-09 10:41:35 -07009use libc;
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 {
Fabio Utzig1edb7882020-10-04 11:51:53 -030024 align: u16,
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
30pub struct CAreaDescPtr {
31 pub ptr: *const CAreaDesc,
32}
33
34pub struct FlashContext {
35 flash_map: FlashMap,
36 flash_params: FlashParams,
37 flash_areas: CAreaDescPtr,
38}
39
40impl FlashContext {
41 pub fn new() -> FlashContext {
42 FlashContext {
43 flash_map: HashMap::new(),
44 flash_params: HashMap::new(),
45 flash_areas: CAreaDescPtr{ptr: ptr::null()},
46 }
47 }
48}
49
50#[repr(C)]
51#[derive(Debug, Default)]
52pub struct CSimContext {
53 pub flash_counter: libc::c_int,
54 pub jumped: libc::c_int,
55 pub c_asserts: u8,
56 pub c_catch_asserts: u8,
57 // NOTE: Always leave boot_jmpbuf declaration at the end; this should
58 // store a "jmp_buf" which is arch specific and not defined by libc crate.
59 // The size below is enough to store data on a x86_64 machine.
60 pub boot_jmpbuf: [u64; 16],
61}
62
63pub struct CSimContextPtr {
64 pub ptr: *const CSimContext,
65}
66
67impl CSimContextPtr {
68 pub fn new() -> CSimContextPtr {
69 CSimContextPtr {
70 ptr: ptr::null(),
71 }
72 }
73}
74
75thread_local! {
76 pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
77 pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
Fabio Utzig73ffc442018-10-24 21:49:09 -030078}
79
David Brownbdb6db72017-07-06 10:14:37 -060080// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
David Brown28215642019-01-02 11:42:39 -070081pub unsafe fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
Fabio Utzig8000e322019-08-05 08:14:32 -030082 THREAD_CTX.with(|ctx| {
83 ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
Fabio Utzig1edb7882020-10-04 11:51:53 -030084 align: dev.align() as u16,
Fabio Utzig8000e322019-08-05 08:14:32 -030085 erased_val: dev.erased_val(),
86 });
87 let dev: &'static mut dyn Flash = mem::transmute(dev);
88 ctx.borrow_mut().flash_map.insert(
89 dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
Fabio Utzig73ffc442018-10-24 21:49:09 -030090 });
David Brownbdb6db72017-07-06 10:14:37 -060091}
92
Fabio Utzig1c9aea52018-11-15 10:36:07 -020093pub unsafe fn clear_flash(dev_id: u8) {
Fabio Utzig8000e322019-08-05 08:14:32 -030094 THREAD_CTX.with(|ctx| {
95 ctx.borrow_mut().flash_map.remove(&dev_id);
96 });
David Brownbdb6db72017-07-06 10:14:37 -060097}
98
David Brownde7729e2017-01-09 10:41:35 -070099// This isn't meant to call directly, but by a wrapper.
100
101#[no_mangle]
Fabio Utzig8000e322019-08-05 08:14:32 -0300102pub extern fn sim_get_flash_areas() -> *const CAreaDesc {
103 THREAD_CTX.with(|ctx| {
104 ctx.borrow().flash_areas.ptr
105 })
106}
107
108#[no_mangle]
109pub extern fn sim_set_flash_areas(areas: *const CAreaDesc) {
110 THREAD_CTX.with(|ctx| {
111 ctx.borrow_mut().flash_areas.ptr = areas;
112 });
113}
114
115#[no_mangle]
116pub extern fn sim_reset_flash_areas() {
117 THREAD_CTX.with(|ctx| {
118 ctx.borrow_mut().flash_areas.ptr = ptr::null();
119 });
120}
121
122#[no_mangle]
123pub extern fn sim_get_context() -> *const CSimContext {
124 SIM_CTX.with(|ctx| {
125 ctx.borrow().ptr
126 })
127}
128
129#[no_mangle]
130pub extern fn sim_set_context(ptr: *const CSimContext) {
131 SIM_CTX.with(|ctx| {
132 ctx.borrow_mut().ptr = ptr;
133 });
134}
135
136#[no_mangle]
137pub extern fn sim_reset_context() {
138 SIM_CTX.with(|ctx| {
139 ctx.borrow_mut().ptr = ptr::null();
140 });
141}
142
143#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200144pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
Fabio Utzig8000e322019-08-05 08:14:32 -0300145 let mut rc: libc::c_int = -19;
146 THREAD_CTX.with(|ctx| {
147 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200148 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300149 rc = map_err(dev.erase(offset as usize, size as usize));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200150 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300151 });
152 rc
David Brownde7729e2017-01-09 10:41:35 -0700153}
154
155#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200156pub 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 -0300157 let mut rc: libc::c_int = -19;
158 THREAD_CTX.with(|ctx| {
159 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200160 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
161 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300162 rc = map_err(dev.read(offset as usize, &mut buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200163 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300164 });
165 rc
David Brownde7729e2017-01-09 10:41:35 -0700166}
167
168#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200169pub 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 -0300170 let mut rc: libc::c_int = -19;
171 THREAD_CTX.with(|ctx| {
172 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200173 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
174 let dev = unsafe { &mut *(flash.ptr) };
Fabio Utzig8000e322019-08-05 08:14:32 -0300175 rc = map_err(dev.write(offset as usize, &buf));
Fabio Utzig1c9aea52018-11-15 10:36:07 -0200176 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300177 });
178 rc
David Brownde7729e2017-01-09 10:41:35 -0700179}
180
Fabio Utzig73ffc442018-10-24 21:49:09 -0300181#[no_mangle]
Fabio Utzig1edb7882020-10-04 11:51:53 -0300182pub extern fn sim_flash_align(id: u8) -> u16 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300183 THREAD_CTX.with(|ctx| {
184 ctx.borrow().flash_params.get(&id).unwrap().align
185 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300186}
187
188#[no_mangle]
189pub extern fn sim_flash_erased_val(id: u8) -> u8 {
Fabio Utzig8000e322019-08-05 08:14:32 -0300190 THREAD_CTX.with(|ctx| {
191 ctx.borrow().flash_params.get(&id).unwrap().erased_val
192 })
Fabio Utzig73ffc442018-10-24 21:49:09 -0300193}
194
David Brownde7729e2017-01-09 10:41:35 -0700195fn map_err(err: Result<()>) -> libc::c_int {
196 match err {
197 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300198 Err(e) => {
199 warn!("{}", e);
200 -1
201 },
David Brownde7729e2017-01-09 10:41:35 -0700202 }
203}
David Brown2d1d7cf2017-05-10 08:55:09 -0600204
205/// Called by C code to determine if we should log at this level. Levels are defined in
206/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
207/// for example, it can be enabled with something like:
208/// RUST_LOG=bootsim::api=info cargo run --release runall
209/// or
210/// RUST_LOG=bootsim=info cargo run --release runall
211#[no_mangle]
212pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
213 let res = match level {
David Brown28215642019-01-02 11:42:39 -0700214 1 => log_enabled!(Level::Error),
215 2 => log_enabled!(Level::Warn),
216 3 => log_enabled!(Level::Info),
Fabio Utzige92df932019-12-10 14:29:17 -0300217 4 => log_enabled!(Level::Debug),
218 5 => log_enabled!(Level::Trace), // log level == SIM
David Brown2d1d7cf2017-05-10 08:55:09 -0600219 _ => false,
220 };
221 if res {
222 1
223 } else {
224 0
225 }
226}