blob: 02051644e8093a3390e9d996dd23cc07847d1f0e [file] [log] [blame]
David Brownde7729e2017-01-09 10:41:35 -07001//! HAL api for MyNewt applications
2
David Brown2cbc4702017-07-06 14:18:58 -06003use simflash::{Result, Flash};
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;
David Brownde7729e2017-01-09 10:41:35 -070010
David Brownbdb6db72017-07-06 10:14:37 -060011// The current active flash device. The 'static is a lie, and we manage the lifetime ourselves.
12static mut FLASH: Option<*mut Flash> = None;
13
Fabio Utzig73ffc442018-10-24 21:49:09 -030014struct FlashParams {
15 align: u8,
16 erased_val: u8,
17}
18
19lazy_static! {
20 static ref FLASH_PARAMS: Mutex<HashMap<u8, FlashParams>> = {
21 Mutex::new(HashMap::new())
22 };
23}
24
David Brownbdb6db72017-07-06 10:14:37 -060025// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
Fabio Utzig73ffc442018-10-24 21:49:09 -030026pub unsafe fn set_flash(dev_id: u8, dev: &mut Flash) {
27 let mut flash_params = FLASH_PARAMS.lock().unwrap();
28 flash_params.insert(dev_id, FlashParams {
29 align: dev.align() as u8,
30 erased_val: dev.erased_val(),
31 });
32
David Brown7ddec0b2017-07-06 10:47:35 -060033 let dev: &'static mut Flash = mem::transmute(dev);
34 FLASH = Some(dev as *mut Flash);
David Brownbdb6db72017-07-06 10:14:37 -060035}
36
37pub unsafe fn clear_flash() {
38 FLASH = None;
39}
40
41// Retrieve the flash, returning an error from the enclosing function. We can't panic here because
42// we've called through C and unwinding is prohibited (it seems to just exit the program).
43macro_rules! get_flash {
44 () => {
45 match FLASH {
46 Some(x) => &mut *x,
47 None => return -19,
48 }
49 }
50}
51
David Brownde7729e2017-01-09 10:41:35 -070052// This isn't meant to call directly, but by a wrapper.
53
54#[no_mangle]
Fabio Utzig99dfc782018-10-15 15:10:55 -070055pub extern fn sim_flash_erase(_id: u8, offset: u32, size: u32) -> libc::c_int {
David Brownbdb6db72017-07-06 10:14:37 -060056 let dev = unsafe { get_flash!() };
David Brownde7729e2017-01-09 10:41:35 -070057 map_err(dev.erase(offset as usize, size as usize))
58}
59
60#[no_mangle]
Fabio Utzig99dfc782018-10-15 15:10:55 -070061pub extern fn sim_flash_read(_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
David Brownbdb6db72017-07-06 10:14:37 -060062 let dev = unsafe { get_flash!() };
David Brownde7729e2017-01-09 10:41:35 -070063 let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
64 map_err(dev.read(offset as usize, &mut buf))
65}
66
67#[no_mangle]
Fabio Utzig99dfc782018-10-15 15:10:55 -070068pub extern fn sim_flash_write(_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
David Brownbdb6db72017-07-06 10:14:37 -060069 let dev = unsafe { get_flash!() };
David Brownde7729e2017-01-09 10:41:35 -070070 let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
71 map_err(dev.write(offset as usize, &buf))
72}
73
Fabio Utzig73ffc442018-10-24 21:49:09 -030074#[no_mangle]
75pub extern fn sim_flash_align(id: u8) -> u8 {
76 let flash_params = FLASH_PARAMS.lock().unwrap();
77 let params = flash_params.get(&id).unwrap();
78 params.align
79}
80
81#[no_mangle]
82pub extern fn sim_flash_erased_val(id: u8) -> u8 {
83 let flash_params = FLASH_PARAMS.lock().unwrap();
84 let params = flash_params.get(&id).unwrap();
85 params.erased_val
86}
87
David Brownde7729e2017-01-09 10:41:35 -070088fn map_err(err: Result<()>) -> libc::c_int {
89 match err {
90 Ok(()) => 0,
Fabio Utzig19b2c1a2017-04-20 07:32:44 -030091 Err(e) => {
92 warn!("{}", e);
93 -1
94 },
David Brownde7729e2017-01-09 10:41:35 -070095 }
96}
David Brown2d1d7cf2017-05-10 08:55:09 -060097
98/// Called by C code to determine if we should log at this level. Levels are defined in
99/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
100/// for example, it can be enabled with something like:
101/// RUST_LOG=bootsim::api=info cargo run --release runall
102/// or
103/// RUST_LOG=bootsim=info cargo run --release runall
104#[no_mangle]
105pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
106 let res = match level {
107 1 => log_enabled!(LogLevel::Error),
108 2 => log_enabled!(LogLevel::Warn),
109 3 => log_enabled!(LogLevel::Info),
110 4 => log_enabled!(LogLevel::Trace),
111 _ => false,
112 };
113 if res {
114 1
115 } else {
116 0
117 }
118}