1 // Copyright (c) 2017-2019 Linaro LTD
2 // Copyright (c) 2018-2019 JUUL Labs
3 //
4 // SPDX-License-Identifier: Apache-2.0
5
6 //! HAL api for MyNewt applications
7
8 use crate::area::CAreaDesc;
9 use log::{Level, log_enabled, warn};
10 use simflash::{Result, Flash, FlashPtr};
11 use std::{
12 cell::RefCell,
13 collections::HashMap,
14 mem,
15 ptr,
16 slice,
17 };
18
19 /// A FlashMap maintain a table of [device_id -> Flash trait]
20 pub type FlashMap = HashMap<u8, FlashPtr>;
21
22 pub struct FlashParamsStruct {
23 align: u16,
24 erased_val: u8,
25 }
26
27 pub type FlashParams = HashMap<u8, FlashParamsStruct>;
28
29 pub struct CAreaDescPtr {
30 pub ptr: *const CAreaDesc,
31 }
32
33 pub struct FlashContext {
34 flash_map: FlashMap,
35 flash_params: FlashParams,
36 flash_areas: CAreaDescPtr,
37 }
38
39 impl FlashContext {
new() -> FlashContext40 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
49 impl Default for FlashContext {
default() -> FlashContext50 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
59 #[repr(C)]
60 #[derive(Debug, Default)]
61 pub 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
72 pub struct CSimContextPtr {
73 pub ptr: *const CSimContext,
74 }
75
76 impl CSimContextPtr {
new() -> CSimContextPtr77 pub fn new() -> CSimContextPtr {
78 CSimContextPtr {
79 ptr: ptr::null(),
80 }
81 }
82 }
83
84 impl Default for CSimContextPtr {
default() -> CSimContextPtr85 fn default() -> CSimContextPtr {
86 CSimContextPtr {
87 ptr: ptr::null(),
88 }
89 }
90 }
91
92 thread_local! {
93 pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
94 pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
95 }
96
97 /// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
98 ///
99 /// # Safety
100 ///
101 /// This uses mem::transmute to stash a Rust pointer into a C value to
102 /// retrieve later. It should be safe to use this.
set_flash(dev_id: u8, dev: &mut dyn Flash)103 pub fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
104 THREAD_CTX.with(|ctx| {
105 ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
106 align: dev.align() as u16,
107 erased_val: dev.erased_val(),
108 });
109 unsafe {
110 let dev: &'static mut dyn Flash = mem::transmute(dev);
111 ctx.borrow_mut().flash_map.insert(
112 dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
113 }
114 });
115 }
116
clear_flash(dev_id: u8)117 pub fn clear_flash(dev_id: u8) {
118 THREAD_CTX.with(|ctx| {
119 ctx.borrow_mut().flash_map.remove(&dev_id);
120 });
121 }
122
123 // This isn't meant to call directly, but by a wrapper.
124
125 #[no_mangle]
sim_get_flash_areas() -> *const CAreaDesc126 pub extern fn sim_get_flash_areas() -> *const CAreaDesc {
127 THREAD_CTX.with(|ctx| {
128 ctx.borrow().flash_areas.ptr
129 })
130 }
131
132 #[no_mangle]
sim_set_flash_areas(areas: *const CAreaDesc)133 pub extern fn sim_set_flash_areas(areas: *const CAreaDesc) {
134 THREAD_CTX.with(|ctx| {
135 ctx.borrow_mut().flash_areas.ptr = areas;
136 });
137 }
138
139 #[no_mangle]
sim_reset_flash_areas()140 pub extern fn sim_reset_flash_areas() {
141 THREAD_CTX.with(|ctx| {
142 ctx.borrow_mut().flash_areas.ptr = ptr::null();
143 });
144 }
145
146 #[no_mangle]
sim_get_context() -> *const CSimContext147 pub extern fn sim_get_context() -> *const CSimContext {
148 SIM_CTX.with(|ctx| {
149 ctx.borrow().ptr
150 })
151 }
152
153 #[no_mangle]
sim_set_context(ptr: *const CSimContext)154 pub extern fn sim_set_context(ptr: *const CSimContext) {
155 SIM_CTX.with(|ctx| {
156 ctx.borrow_mut().ptr = ptr;
157 });
158 }
159
160 #[no_mangle]
sim_reset_context()161 pub extern fn sim_reset_context() {
162 SIM_CTX.with(|ctx| {
163 ctx.borrow_mut().ptr = ptr::null();
164 });
165 }
166
167 #[no_mangle]
sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int168 pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
169 let mut rc: libc::c_int = -19;
170 THREAD_CTX.with(|ctx| {
171 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
172 let dev = unsafe { &mut *(flash.ptr) };
173 rc = map_err(dev.erase(offset as usize, size as usize));
174 }
175 });
176 rc
177 }
178
179 #[no_mangle]
sim_flash_read(dev_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int180 pub extern fn sim_flash_read(dev_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
181 let mut rc: libc::c_int = -19;
182 THREAD_CTX.with(|ctx| {
183 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
184 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
185 let dev = unsafe { &mut *(flash.ptr) };
186 rc = map_err(dev.read(offset as usize, &mut buf));
187 }
188 });
189 rc
190 }
191
192 #[no_mangle]
sim_flash_write(dev_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int193 pub extern fn sim_flash_write(dev_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
194 let mut rc: libc::c_int = -19;
195 THREAD_CTX.with(|ctx| {
196 if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
197 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
198 let dev = unsafe { &mut *(flash.ptr) };
199 rc = map_err(dev.write(offset as usize, &buf));
200 }
201 });
202 rc
203 }
204
205 #[no_mangle]
sim_flash_align(id: u8) -> u16206 pub extern fn sim_flash_align(id: u8) -> u16 {
207 THREAD_CTX.with(|ctx| {
208 ctx.borrow().flash_params.get(&id).unwrap().align
209 })
210 }
211
212 #[no_mangle]
sim_flash_erased_val(id: u8) -> u8213 pub extern fn sim_flash_erased_val(id: u8) -> u8 {
214 THREAD_CTX.with(|ctx| {
215 ctx.borrow().flash_params.get(&id).unwrap().erased_val
216 })
217 }
218
map_err(err: Result<()>) -> libc::c_int219 fn map_err(err: Result<()>) -> libc::c_int {
220 match err {
221 Ok(()) => 0,
222 Err(e) => {
223 warn!("{}", e);
224 -1
225 },
226 }
227 }
228
229 /// Called by C code to determine if we should log at this level. Levels are defined in
230 /// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
231 /// for example, it can be enabled with something like:
232 /// RUST_LOG=bootsim::api=info cargo run --release runall
233 /// or
234 /// RUST_LOG=bootsim=info cargo run --release runall
235 #[no_mangle]
sim_log_enabled(level: libc::c_int) -> libc::c_int236 pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
237 let res = match level {
238 1 => log_enabled!(Level::Error),
239 2 => log_enabled!(Level::Warn),
240 3 => log_enabled!(Level::Info),
241 4 => log_enabled!(Level::Debug),
242 5 => log_enabled!(Level::Trace), // log level == SIM
243 _ => false,
244 };
245 if res {
246 1
247 } else {
248 0
249 }
250 }
251