blob: 78a1bbdf14e9f72459e35ec383f79dc8bf199585 [file] [log] [blame]
David Brownde7729e2017-01-09 10:41:35 -07001//! HAL api for MyNewt applications
2
Fabio Utzig1c9aea52018-11-15 10:36:07 -02003use simflash::{Result, Flash, FlashPtr};
David Brown28215642019-01-02 11:42:39 -07004use lazy_static::lazy_static;
David Brownde7729e2017-01-09 10:41:35 -07005use libc;
David Brown28215642019-01-02 11:42:39 -07006use log::{Level, log_enabled, warn};
7use std::{
8 collections::HashMap,
9 mem,
10 ops::Deref,
11 slice,
12 sync::Mutex,
13};
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
18lazy_static! {
19 static ref FLASH: Mutex<FlashMap> = {
20 Mutex::new(HashMap::new())
21 };
22}
David Brownbdb6db72017-07-06 10:14:37 -060023
Fabio Utzig73ffc442018-10-24 21:49:09 -030024struct FlashParams {
25 align: u8,
26 erased_val: u8,
27}
28
29lazy_static! {
30 static ref FLASH_PARAMS: Mutex<HashMap<u8, FlashParams>> = {
31 Mutex::new(HashMap::new())
32 };
33}
34
David Brownbdb6db72017-07-06 10:14:37 -060035// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
David Brown28215642019-01-02 11:42:39 -070036pub unsafe fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
Fabio Utzig73ffc442018-10-24 21:49:09 -030037 let mut flash_params = FLASH_PARAMS.lock().unwrap();
38 flash_params.insert(dev_id, FlashParams {
39 align: dev.align() as u8,
40 erased_val: dev.erased_val(),
41 });
42
David Brown28215642019-01-02 11:42:39 -070043 let dev: &'static mut dyn Flash = mem::transmute(dev);
Fabio Utzig1c9aea52018-11-15 10:36:07 -020044 let mut flash = FLASH.lock().unwrap();
David Brown28215642019-01-02 11:42:39 -070045 flash.insert(dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
David Brownbdb6db72017-07-06 10:14:37 -060046}
47
Fabio Utzig1c9aea52018-11-15 10:36:07 -020048pub unsafe fn clear_flash(dev_id: u8) {
49 let mut flash = FLASH.lock().unwrap();
50 flash.remove(&dev_id);
David Brownbdb6db72017-07-06 10:14:37 -060051}
52
David Brownde7729e2017-01-09 10:41:35 -070053// This isn't meant to call directly, but by a wrapper.
54
55#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -020056pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
57 if let Ok(guard) = FLASH.lock() {
58 if let Some(flash) = guard.deref().get(&dev_id) {
59 let dev = unsafe { &mut *(flash.ptr) };
60 return map_err(dev.erase(offset as usize, size as usize));
61 }
62 }
63 -19
David Brownde7729e2017-01-09 10:41:35 -070064}
65
66#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -020067pub extern fn sim_flash_read(dev_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
68 if let Ok(guard) = FLASH.lock() {
69 if let Some(flash) = guard.deref().get(&dev_id) {
70 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
71 let dev = unsafe { &mut *(flash.ptr) };
72 return map_err(dev.read(offset as usize, &mut buf));
73 }
74 }
75 -19
David Brownde7729e2017-01-09 10:41:35 -070076}
77
78#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -020079pub extern fn sim_flash_write(dev_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
80 if let Ok(guard) = FLASH.lock() {
81 if let Some(flash) = guard.deref().get(&dev_id) {
82 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
83 let dev = unsafe { &mut *(flash.ptr) };
84 return map_err(dev.write(offset as usize, &buf));
85 }
86 }
87 -19
David Brownde7729e2017-01-09 10:41:35 -070088}
89
Fabio Utzig73ffc442018-10-24 21:49:09 -030090#[no_mangle]
91pub extern fn sim_flash_align(id: u8) -> u8 {
92 let flash_params = FLASH_PARAMS.lock().unwrap();
93 let params = flash_params.get(&id).unwrap();
94 params.align
95}
96
97#[no_mangle]
98pub extern fn sim_flash_erased_val(id: u8) -> u8 {
99 let flash_params = FLASH_PARAMS.lock().unwrap();
100 let params = flash_params.get(&id).unwrap();
101 params.erased_val
102}
103
David Brownde7729e2017-01-09 10:41:35 -0700104fn map_err(err: Result<()>) -> libc::c_int {
105 match err {
106 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300107 Err(e) => {
108 warn!("{}", e);
109 -1
110 },
David Brownde7729e2017-01-09 10:41:35 -0700111 }
112}
David Brown2d1d7cf2017-05-10 08:55:09 -0600113
114/// Called by C code to determine if we should log at this level. Levels are defined in
115/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
116/// for example, it can be enabled with something like:
117/// RUST_LOG=bootsim::api=info cargo run --release runall
118/// or
119/// RUST_LOG=bootsim=info cargo run --release runall
120#[no_mangle]
121pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
122 let res = match level {
David Brown28215642019-01-02 11:42:39 -0700123 1 => log_enabled!(Level::Error),
124 2 => log_enabled!(Level::Warn),
125 3 => log_enabled!(Level::Info),
126 4 => log_enabled!(Level::Trace),
David Brown2d1d7cf2017-05-10 08:55:09 -0600127 _ => false,
128 };
129 if res {
130 1
131 } else {
132 0
133 }
134}