blob: 1c34b5e113a18ede8d5b50098b2aa805ebca5901 [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 Brownde7729e2017-01-09 10:41:35 -07004use libc;
David Brown2d1d7cf2017-05-10 08:55:09 -06005use log::LogLevel;
David Brown63902772017-07-12 09:47:49 -06006use std::mem;
David Brownde7729e2017-01-09 10:41:35 -07007use std::slice;
Fabio Utzig73ffc442018-10-24 21:49:09 -03008use std::collections::HashMap;
9use std::sync::Mutex;
Fabio Utzig1c9aea52018-11-15 10:36:07 -020010use std::ops::Deref;
David Brownde7729e2017-01-09 10:41:35 -070011
Fabio Utzig1c9aea52018-11-15 10:36:07 -020012/// A FlashMap maintain a table of [device_id -> Flash trait]
13type FlashMap = HashMap<u8, FlashPtr>;
14
15lazy_static! {
16 static ref FLASH: Mutex<FlashMap> = {
17 Mutex::new(HashMap::new())
18 };
19}
David Brownbdb6db72017-07-06 10:14:37 -060020
Fabio Utzig73ffc442018-10-24 21:49:09 -030021struct FlashParams {
22 align: u8,
23 erased_val: u8,
24}
25
26lazy_static! {
27 static ref FLASH_PARAMS: Mutex<HashMap<u8, FlashParams>> = {
28 Mutex::new(HashMap::new())
29 };
30}
31
David Brownbdb6db72017-07-06 10:14:37 -060032// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
Fabio Utzig73ffc442018-10-24 21:49:09 -030033pub unsafe fn set_flash(dev_id: u8, dev: &mut Flash) {
34 let mut flash_params = FLASH_PARAMS.lock().unwrap();
35 flash_params.insert(dev_id, FlashParams {
36 align: dev.align() as u8,
37 erased_val: dev.erased_val(),
38 });
39
David Brown7ddec0b2017-07-06 10:47:35 -060040 let dev: &'static mut Flash = mem::transmute(dev);
Fabio Utzig1c9aea52018-11-15 10:36:07 -020041 let mut flash = FLASH.lock().unwrap();
42 flash.insert(dev_id, FlashPtr{ptr: dev as *mut Flash});
David Brownbdb6db72017-07-06 10:14:37 -060043}
44
Fabio Utzig1c9aea52018-11-15 10:36:07 -020045pub unsafe fn clear_flash(dev_id: u8) {
46 let mut flash = FLASH.lock().unwrap();
47 flash.remove(&dev_id);
David Brownbdb6db72017-07-06 10:14:37 -060048}
49
David Brownde7729e2017-01-09 10:41:35 -070050// This isn't meant to call directly, but by a wrapper.
51
52#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -020053pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
54 if let Ok(guard) = FLASH.lock() {
55 if let Some(flash) = guard.deref().get(&dev_id) {
56 let dev = unsafe { &mut *(flash.ptr) };
57 return map_err(dev.erase(offset as usize, size as usize));
58 }
59 }
60 -19
David Brownde7729e2017-01-09 10:41:35 -070061}
62
63#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -020064pub extern fn sim_flash_read(dev_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
65 if let Ok(guard) = FLASH.lock() {
66 if let Some(flash) = guard.deref().get(&dev_id) {
67 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
68 let dev = unsafe { &mut *(flash.ptr) };
69 return map_err(dev.read(offset as usize, &mut buf));
70 }
71 }
72 -19
David Brownde7729e2017-01-09 10:41:35 -070073}
74
75#[no_mangle]
Fabio Utzig1c9aea52018-11-15 10:36:07 -020076pub extern fn sim_flash_write(dev_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
77 if let Ok(guard) = FLASH.lock() {
78 if let Some(flash) = guard.deref().get(&dev_id) {
79 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
80 let dev = unsafe { &mut *(flash.ptr) };
81 return map_err(dev.write(offset as usize, &buf));
82 }
83 }
84 -19
David Brownde7729e2017-01-09 10:41:35 -070085}
86
Fabio Utzig73ffc442018-10-24 21:49:09 -030087#[no_mangle]
88pub extern fn sim_flash_align(id: u8) -> u8 {
89 let flash_params = FLASH_PARAMS.lock().unwrap();
90 let params = flash_params.get(&id).unwrap();
91 params.align
92}
93
94#[no_mangle]
95pub extern fn sim_flash_erased_val(id: u8) -> u8 {
96 let flash_params = FLASH_PARAMS.lock().unwrap();
97 let params = flash_params.get(&id).unwrap();
98 params.erased_val
99}
100
David Brownde7729e2017-01-09 10:41:35 -0700101fn map_err(err: Result<()>) -> libc::c_int {
102 match err {
103 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300104 Err(e) => {
105 warn!("{}", e);
106 -1
107 },
David Brownde7729e2017-01-09 10:41:35 -0700108 }
109}
David Brown2d1d7cf2017-05-10 08:55:09 -0600110
111/// Called by C code to determine if we should log at this level. Levels are defined in
112/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
113/// for example, it can be enabled with something like:
114/// RUST_LOG=bootsim::api=info cargo run --release runall
115/// or
116/// RUST_LOG=bootsim=info cargo run --release runall
117#[no_mangle]
118pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
119 let res = match level {
120 1 => log_enabled!(LogLevel::Error),
121 2 => log_enabled!(LogLevel::Warn),
122 3 => log_enabled!(LogLevel::Info),
123 4 => log_enabled!(LogLevel::Trace),
124 _ => false,
125 };
126 if res {
127 1
128 } else {
129 0
130 }
131}