Remove global test thread locking

With the recent changes in bootutil, now there is no need to lock the
test threads to run sequentially, so the global lock was removed. The
locking now happens to access resources such as flash, flash params,
simulator context, etc on a per thread basis. Some of the global
variables that were used by the simulator itself (FFI) were made into a
context struct passed in to invoke_go.

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/sim/Cargo.lock b/sim/Cargo.lock
index 314b5f3..35dc156 100644
--- a/sim/Cargo.lock
+++ b/sim/Cargo.lock
@@ -248,7 +248,6 @@
 version = "0.1.0"
 dependencies = [
  "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "simflash 0.1.0",
diff --git a/sim/mcuboot-sys/Cargo.toml b/sim/mcuboot-sys/Cargo.toml
index 4f20725..d20a169 100644
--- a/sim/mcuboot-sys/Cargo.toml
+++ b/sim/mcuboot-sys/Cargo.toml
@@ -46,7 +46,6 @@
 cc = "1.0.25"
 
 [dependencies]
-lazy_static = "1.2"
 libc = "0.2.0"
 log = "0.4"
 simflash = { path = "../simflash" }
diff --git a/sim/mcuboot-sys/csupport/run.c b/sim/mcuboot-sys/csupport/run.c
index 32f43c2..d355c6e 100644
--- a/sim/mcuboot-sys/csupport/run.c
+++ b/sim/mcuboot-sys/csupport/run.c
@@ -27,6 +27,16 @@
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
+struct area_desc;
+extern struct area_desc *sim_get_flash_areas(void);
+extern void sim_set_flash_areas(struct area_desc *areas);
+extern void sim_reset_flash_areas(void);
+
+struct sim_context;
+extern struct sim_context *sim_get_context(void);
+extern void sim_set_context(struct sim_context *ctx);
+extern void sim_reset_context(void);
+
 extern int sim_flash_erase(uint8_t flash_id, uint32_t offset, uint32_t size);
 extern int sim_flash_read(uint8_t flash_id, uint32_t offset, uint8_t *dest,
         uint32_t size);
@@ -35,12 +45,13 @@
 extern uint8_t sim_flash_align(uint8_t flash_id);
 extern uint8_t sim_flash_erased_val(uint8_t flash_id);
 
-static jmp_buf boot_jmpbuf;
-int flash_counter;
-
-int jumped = 0;
-uint8_t c_asserts = 0;
-uint8_t c_catch_asserts = 0;
+struct sim_context {
+    int flash_counter;
+    int jumped;
+    uint8_t c_asserts;
+    uint8_t c_catch_asserts;
+    jmp_buf boot_jmpbuf;
+};
 
 #ifdef MCUBOOT_ENCRYPT_RSA
 static int
@@ -213,25 +224,33 @@
     uint32_t num_slots;
 };
 
-static struct area_desc *flash_areas;
-
-int invoke_boot_go(struct area_desc *adesc)
+int invoke_boot_go(struct sim_context *ctx, struct area_desc *adesc)
 {
     int res;
     struct boot_rsp rsp;
+    struct boot_loader_state *state;
 
 #if defined(MCUBOOT_SIGN_RSA)
     mbedtls_platform_set_calloc_free(calloc, free);
 #endif
 
-    flash_areas = adesc;
-    if (setjmp(boot_jmpbuf) == 0) {
-        res = boot_go(&rsp);
-        flash_areas = NULL;
+    // NOTE: cleared internally by context_boot_go
+    state = malloc(sizeof(struct boot_loader_state));
+
+    sim_set_flash_areas(adesc);
+    sim_set_context(ctx);
+
+    if (setjmp(ctx->boot_jmpbuf) == 0) {
+        res = context_boot_go(state, &rsp);
+        sim_reset_flash_areas();
+        sim_reset_context();
+        free(state);
         /* printf("boot_go off: %d (0x%08x)\n", res, rsp.br_image_off); */
         return res;
     } else {
-        flash_areas = NULL;
+        sim_reset_flash_areas();
+        sim_reset_context();
+        free(state);
         return -0x13579;
     }
 }
@@ -257,7 +276,9 @@
 int flash_area_open(uint8_t id, const struct flash_area **area)
 {
     uint32_t i;
+    struct area_desc *flash_areas;
 
+    flash_areas = sim_get_flash_areas();
     for (i = 0; i < flash_areas->num_slots; i++) {
         if (flash_areas->slots[i].id == id)
             break;
@@ -293,9 +314,10 @@
 {
     BOOT_LOG_DBG("%s: area=%d, off=%x, len=%x", __func__,
                  area->fa_id, off, len);
-    if (--flash_counter == 0) {
-        jumped++;
-        longjmp(boot_jmpbuf, 1);
+    struct sim_context *ctx = sim_get_context();
+    if (--(ctx->flash_counter) == 0) {
+        ctx->jumped++;
+        longjmp(ctx->boot_jmpbuf, 1);
     }
     return sim_flash_write(area->fa_device_id, area->fa_off + off, src, len);
 }
@@ -304,9 +326,10 @@
 {
     BOOT_LOG_DBG("%s: area=%d, off=%x, len=%x", __func__,
                  area->fa_id, off, len);
-    if (--flash_counter == 0) {
-        jumped++;
-        longjmp(boot_jmpbuf, 1);
+    struct sim_context *ctx = sim_get_context();
+    if (--(ctx->flash_counter) == 0) {
+        ctx->jumped++;
+        longjmp(ctx->boot_jmpbuf, 1);
     }
     return sim_flash_erase(area->fa_device_id, area->fa_off + off, len);
 }
@@ -338,7 +361,9 @@
 {
     uint32_t i;
     struct area *slot;
+    struct area_desc *flash_areas;
 
+    flash_areas = sim_get_flash_areas();
     for (i = 0; i < flash_areas->num_slots; i++) {
         if (flash_areas->slots[i].id == idx)
             break;
@@ -366,7 +391,9 @@
 {
     uint32_t i;
     struct area *slot;
+    struct area_desc *flash_areas;
 
+    flash_areas = sim_get_flash_areas();
     for (i = 0; i < flash_areas->num_slots; i++) {
         if (flash_areas->slots[i].id == fa_id)
             break;
@@ -409,8 +436,9 @@
 void sim_assert(int x, const char *assertion, const char *file, unsigned int line, const char *function)
 {
     if (!(x)) {
-        if (c_catch_asserts) {
-            c_asserts++;
+        struct sim_context *ctx = sim_get_context();
+        if (ctx->c_catch_asserts) {
+            ctx->c_asserts++;
         } else {
             BOOT_LOG_ERR("%s:%d: %s: Assertion `%s' failed.", file, line, function, assertion);
 
diff --git a/sim/mcuboot-sys/src/api.rs b/sim/mcuboot-sys/src/api.rs
index 78a1bbd..f38d98e 100644
--- a/sim/mcuboot-sys/src/api.rs
+++ b/sim/mcuboot-sys/src/api.rs
@@ -1,104 +1,190 @@
 //! HAL api for MyNewt applications
 
-use simflash::{Result, Flash, FlashPtr};
-use lazy_static::lazy_static;
+use crate::area::CAreaDesc;
 use libc;
 use log::{Level, log_enabled, warn};
+use simflash::{Result, Flash, FlashPtr};
 use std::{
+    cell::RefCell,
     collections::HashMap,
     mem,
-    ops::Deref,
+    ptr,
     slice,
-    sync::Mutex,
 };
 
 /// A FlashMap maintain a table of [device_id -> Flash trait]
 pub type FlashMap = HashMap<u8, FlashPtr>;
 
-lazy_static! {
-    static ref FLASH: Mutex<FlashMap> = {
-        Mutex::new(HashMap::new())
-    };
-}
-
-struct FlashParams {
+pub struct FlashParamsStruct {
     align: u8,
     erased_val: u8,
 }
 
-lazy_static! {
-    static ref FLASH_PARAMS: Mutex<HashMap<u8, FlashParams>> = {
-        Mutex::new(HashMap::new())
-    };
+pub type FlashParams = HashMap<u8, FlashParamsStruct>;
+
+pub struct CAreaDescPtr {
+   pub ptr: *const CAreaDesc,
+}
+
+pub struct FlashContext {
+    flash_map: FlashMap,
+    flash_params: FlashParams,
+    flash_areas: CAreaDescPtr,
+}
+
+impl FlashContext {
+    pub fn new() -> FlashContext {
+        FlashContext {
+            flash_map: HashMap::new(),
+            flash_params: HashMap::new(),
+            flash_areas: CAreaDescPtr{ptr: ptr::null()},
+        }
+    }
+}
+
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct CSimContext {
+    pub flash_counter: libc::c_int,
+    pub jumped: libc::c_int,
+    pub c_asserts: u8,
+    pub c_catch_asserts: u8,
+    // NOTE: Always leave boot_jmpbuf declaration at the end; this should
+    // store a "jmp_buf" which is arch specific and not defined by libc crate.
+    // The size below is enough to store data on a x86_64 machine.
+    pub boot_jmpbuf: [u64; 16],
+}
+
+pub struct CSimContextPtr {
+   pub ptr: *const CSimContext,
+}
+
+impl CSimContextPtr {
+    pub fn new() -> CSimContextPtr {
+        CSimContextPtr {
+            ptr: ptr::null(),
+        }
+    }
+}
+
+thread_local! {
+    pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
+    pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
 }
 
 // Set the flash device to be used by the simulation.  The pointer is unsafely stashed away.
 pub unsafe fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
-    let mut flash_params = FLASH_PARAMS.lock().unwrap();
-    flash_params.insert(dev_id, FlashParams {
-        align: dev.align() as u8,
-        erased_val: dev.erased_val(),
+    THREAD_CTX.with(|ctx| {
+        ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
+            align: dev.align() as u8,
+            erased_val: dev.erased_val(),
+        });
+        let dev: &'static mut dyn Flash = mem::transmute(dev);
+        ctx.borrow_mut().flash_map.insert(
+            dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
     });
-
-    let dev: &'static mut dyn Flash = mem::transmute(dev);
-    let mut flash = FLASH.lock().unwrap();
-    flash.insert(dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
 }
 
 pub unsafe fn clear_flash(dev_id: u8) {
-    let mut flash = FLASH.lock().unwrap();
-    flash.remove(&dev_id);
+    THREAD_CTX.with(|ctx| {
+        ctx.borrow_mut().flash_map.remove(&dev_id);
+    });
 }
 
 // This isn't meant to call directly, but by a wrapper.
 
 #[no_mangle]
+pub extern fn sim_get_flash_areas() -> *const CAreaDesc {
+    THREAD_CTX.with(|ctx| {
+        ctx.borrow().flash_areas.ptr
+    })
+}
+
+#[no_mangle]
+pub extern fn sim_set_flash_areas(areas: *const CAreaDesc) {
+    THREAD_CTX.with(|ctx| {
+        ctx.borrow_mut().flash_areas.ptr = areas;
+    });
+}
+
+#[no_mangle]
+pub extern fn sim_reset_flash_areas() {
+    THREAD_CTX.with(|ctx| {
+        ctx.borrow_mut().flash_areas.ptr = ptr::null();
+    });
+}
+
+#[no_mangle]
+pub extern fn sim_get_context() -> *const CSimContext {
+    SIM_CTX.with(|ctx| {
+        ctx.borrow().ptr
+    })
+}
+
+#[no_mangle]
+pub extern fn sim_set_context(ptr: *const CSimContext) {
+    SIM_CTX.with(|ctx| {
+        ctx.borrow_mut().ptr = ptr;
+    });
+}
+
+#[no_mangle]
+pub extern fn sim_reset_context() {
+    SIM_CTX.with(|ctx| {
+        ctx.borrow_mut().ptr = ptr::null();
+    });
+}
+
+#[no_mangle]
 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 mut rc: libc::c_int = -19;
+    THREAD_CTX.with(|ctx| {
+        if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
             let dev = unsafe { &mut *(flash.ptr) };
-            return map_err(dev.erase(offset as usize, size as usize));
+            rc = map_err(dev.erase(offset as usize, size as usize));
         }
-    }
-    -19
+    });
+    rc
 }
 
 #[no_mangle]
 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 rc: libc::c_int = -19;
+    THREAD_CTX.with(|ctx| {
+        if let Some(flash) = ctx.borrow().flash_map.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));
+            rc = map_err(dev.read(offset as usize, &mut buf));
         }
-    }
-    -19
+    });
+    rc
 }
 
 #[no_mangle]
 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 mut rc: libc::c_int = -19;
+    THREAD_CTX.with(|ctx| {
+        if let Some(flash) = ctx.borrow().flash_map.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));
+            rc = map_err(dev.write(offset as usize, &buf));
         }
-    }
-    -19
+    });
+    rc
 }
 
 #[no_mangle]
 pub extern fn sim_flash_align(id: u8) -> u8 {
-    let flash_params = FLASH_PARAMS.lock().unwrap();
-    let params = flash_params.get(&id).unwrap();
-    params.align
+    THREAD_CTX.with(|ctx| {
+        ctx.borrow().flash_params.get(&id).unwrap().align
+    })
 }
 
 #[no_mangle]
 pub extern fn sim_flash_erased_val(id: u8) -> u8 {
-    let flash_params = FLASH_PARAMS.lock().unwrap();
-    let params = flash_params.get(&id).unwrap();
-    params.erased_val
+    THREAD_CTX.with(|ctx| {
+        ctx.borrow().flash_params.get(&id).unwrap().erased_val
+    })
 }
 
 fn map_err(err: Result<()>) -> libc::c_int {
diff --git a/sim/mcuboot-sys/src/c.rs b/sim/mcuboot-sys/src/c.rs
index 08b8813..6f92c34 100644
--- a/sim/mcuboot-sys/src/c.rs
+++ b/sim/mcuboot-sys/src/c.rs
@@ -2,37 +2,33 @@
 
 use crate::area::AreaDesc;
 use simflash::SimMultiFlash;
-use lazy_static::lazy_static;
 use libc;
 use crate::api;
-use std::sync::Mutex;
-
-lazy_static! {
-    /// Mutex to lock the simulation.  The C code for the bootloader uses
-    /// global variables, and is therefore non-reentrant.
-    static ref BOOT_LOCK: Mutex<()> = Mutex::new(());
-}
 
 /// Invoke the bootloader on this flash device.
 pub fn boot_go(multiflash: &mut SimMultiFlash, areadesc: &AreaDesc,
                counter: Option<&mut i32>, catch_asserts: bool) -> (i32, u8) {
-    let _lock = BOOT_LOCK.lock().unwrap();
-
     unsafe {
         for (&dev_id, flash) in multiflash.iter_mut() {
             api::set_flash(dev_id, flash);
         }
-        raw::c_catch_asserts = if catch_asserts { 1 } else { 0 };
-        raw::c_asserts = 0u8;
-        raw::flash_counter = match counter {
+    }
+    let mut sim_ctx = api::CSimContext {
+        flash_counter: match counter {
             None => 0,
             Some(ref c) => **c as libc::c_int
-        };
-    }
-    let result = unsafe { raw::invoke_boot_go(&areadesc.get_c() as *const _) as i32 };
-    let asserts = unsafe { raw::c_asserts };
+        },
+        jumped: 0,
+        c_asserts: 0,
+        c_catch_asserts: if catch_asserts { 1 } else { 0 },
+        boot_jmpbuf: [0; 16],
+    };
+    let result = unsafe {
+        raw::invoke_boot_go(&mut sim_ctx as *mut _, &areadesc.get_c() as *const _) as i32
+    };
+    let asserts = sim_ctx.c_asserts;
+    counter.map(|c| *c = sim_ctx.flash_counter);
     unsafe {
-        counter.map(|c| *c = raw::flash_counter as i32);
         for (&dev_id, _) in multiflash {
             api::clear_flash(dev_id);
         }
@@ -76,16 +72,14 @@
 
 mod raw {
     use crate::area::CAreaDesc;
+    use crate::api::CSimContext;
     use libc;
 
     extern "C" {
         // This generates a warning about `CAreaDesc` not being foreign safe.  There doesn't appear to
         // be any way to get rid of this warning.  See https://github.com/rust-lang/rust/issues/34798
         // for information and tracking.
-        pub fn invoke_boot_go(areadesc: *const CAreaDesc) -> libc::c_int;
-        pub static mut flash_counter: libc::c_int;
-        pub static mut c_asserts: u8;
-        pub static mut c_catch_asserts: u8;
+        pub fn invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc) -> libc::c_int;
 
         pub fn boot_trailer_sz(min_write_sz: u8) -> u32;