Allow multiple flash devices in bootutil wrapper

A new type `FlashMap` that stores a HashMap of [device_id -> Flash trait]
was added, which enables multi-flash devices to be passed around.

The previously existing static FLASH value that was used to simulate the
raw device, was updated to using a FlashMap which enables bootutil to
interface with more than one flash device.

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/sim/mcuboot-sys/src/api.rs b/sim/mcuboot-sys/src/api.rs
index 0205164..1c34b5e 100644
--- a/sim/mcuboot-sys/src/api.rs
+++ b/sim/mcuboot-sys/src/api.rs
@@ -1,15 +1,22 @@
 //! HAL api for MyNewt applications
 
-use simflash::{Result, Flash};
+use simflash::{Result, Flash, FlashPtr};
 use libc;
 use log::LogLevel;
 use std::mem;
 use std::slice;
 use std::collections::HashMap;
 use std::sync::Mutex;
+use std::ops::Deref;
 
-// The current active flash device.  The 'static is a lie, and we manage the lifetime ourselves.
-static mut FLASH: Option<*mut Flash> = None;
+/// A FlashMap maintain a table of [device_id -> Flash trait]
+type FlashMap = HashMap<u8, FlashPtr>;
+
+lazy_static! {
+    static ref FLASH: Mutex<FlashMap> = {
+        Mutex::new(HashMap::new())
+    };
+}
 
 struct FlashParams {
     align: u8,
@@ -31,44 +38,50 @@
     });
 
     let dev: &'static mut Flash = mem::transmute(dev);
-    FLASH = Some(dev as *mut Flash);
+    let mut flash = FLASH.lock().unwrap();
+    flash.insert(dev_id, FlashPtr{ptr: dev as *mut Flash});
 }
 
-pub unsafe fn clear_flash() {
-    FLASH = None;
-}
-
-// Retrieve the flash, returning an error from the enclosing function.  We can't panic here because
-// we've called through C and unwinding is prohibited (it seems to just exit the program).
-macro_rules! get_flash {
-    () => {
-        match FLASH {
-            Some(x) => &mut *x,
-            None => return -19,
-        }
-    }
+pub unsafe fn clear_flash(dev_id: u8) {
+    let mut flash = FLASH.lock().unwrap();
+    flash.remove(&dev_id);
 }
 
 // This isn't meant to call directly, but by a wrapper.
 
 #[no_mangle]
-pub extern fn sim_flash_erase(_id: u8, offset: u32, size: u32) -> libc::c_int {
-    let dev = unsafe { get_flash!() };
-    map_err(dev.erase(offset as usize, size as usize))
+pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
+    if let Ok(guard) = FLASH.lock() {
+        if let Some(flash) = guard.deref().get(&dev_id) {
+            let dev = unsafe { &mut *(flash.ptr) };
+            return map_err(dev.erase(offset as usize, size as usize));
+        }
+    }
+    -19
 }
 
 #[no_mangle]
-pub extern fn sim_flash_read(_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
-    let dev = unsafe { get_flash!() };
-    let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
-    map_err(dev.read(offset as usize, &mut buf))
+pub extern fn sim_flash_read(dev_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
+    if let Ok(guard) = FLASH.lock() {
+        if let Some(flash) = guard.deref().get(&dev_id) {
+            let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
+            let dev = unsafe { &mut *(flash.ptr) };
+            return map_err(dev.read(offset as usize, &mut buf));
+        }
+    }
+    -19
 }
 
 #[no_mangle]
-pub extern fn sim_flash_write(_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
-    let dev = unsafe { get_flash!() };
-    let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
-    map_err(dev.write(offset as usize, &buf))
+pub extern fn sim_flash_write(dev_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
+    if let Ok(guard) = FLASH.lock() {
+        if let Some(flash) = guard.deref().get(&dev_id) {
+            let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
+            let dev = unsafe { &mut *(flash.ptr) };
+            return map_err(dev.write(offset as usize, &buf));
+        }
+    }
+    -19
 }
 
 #[no_mangle]