sim: Naive move of binding into mcuboot-sys

Create a crate `mcuboot-sys` to hold the building and binding of the
mcuboot code.  There aren't any substantive code changes here, just
moving the code into a separate crate.

Signed-off-by: David Brown <david.brown@linaro.org>
diff --git a/sim/mcuboot-sys/src/api.rs b/sim/mcuboot-sys/src/api.rs
new file mode 100644
index 0000000..4e744e2
--- /dev/null
+++ b/sim/mcuboot-sys/src/api.rs
@@ -0,0 +1,85 @@
+//! HAL api for MyNewt applications
+
+use simflash::{Result, Flash};
+use libc;
+use log::LogLevel;
+use std::mem;
+use std::slice;
+
+// The current active flash device.  The 'static is a lie, and we manage the lifetime ourselves.
+static mut FLASH: Option<*mut Flash> = None;
+
+// Set the flash device to be used by the simulation.  The pointer is unsafely stashed away.
+pub unsafe fn set_flash(dev: &mut Flash) {
+    let dev: &'static mut Flash = mem::transmute(dev);
+    FLASH = Some(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,
+        }
+    }
+}
+
+// This isn't meant to call directly, but by a wrapper.
+
+#[no_mangle]
+pub extern fn sim_flash_erase(offset: u32, size: u32) -> libc::c_int {
+    let dev = unsafe { get_flash!() };
+    map_err(dev.erase(offset as usize, size as usize))
+}
+
+#[no_mangle]
+pub extern fn sim_flash_read(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))
+}
+
+#[no_mangle]
+pub extern fn sim_flash_write(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))
+}
+
+fn map_err(err: Result<()>) -> libc::c_int {
+    match err {
+        Ok(()) => 0,
+        Err(e) => {
+            warn!("{}", e);
+            -1
+        },
+    }
+}
+
+/// Called by C code to determine if we should log at this level.  Levels are defined in
+/// bootutil/bootutil_log.h.  This makes the logging from the C code controlled by bootsim::api, so
+/// for example, it can be enabled with something like:
+///     RUST_LOG=bootsim::api=info cargo run --release runall
+/// or
+///     RUST_LOG=bootsim=info cargo run --release runall
+#[no_mangle]
+pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
+    let res = match level {
+        1 => log_enabled!(LogLevel::Error),
+        2 => log_enabled!(LogLevel::Warn),
+        3 => log_enabled!(LogLevel::Info),
+        4 => log_enabled!(LogLevel::Trace),
+        _ => false,
+    };
+    if res {
+        1
+    } else {
+        0
+    }
+}
diff --git a/sim/mcuboot-sys/src/area.rs b/sim/mcuboot-sys/src/area.rs
new file mode 100644
index 0000000..5a1ef6c
--- /dev/null
+++ b/sim/mcuboot-sys/src/area.rs
@@ -0,0 +1,192 @@
+//! Describe flash areas.
+
+use simflash::{Flash, SimFlash, Sector};
+use std::ptr;
+
+/// Structure to build up the boot area table.
+#[derive(Debug)]
+pub struct AreaDesc {
+    areas: Vec<Vec<FlashArea>>,
+    whole: Vec<FlashArea>,
+    sectors: Vec<Sector>,
+}
+
+impl AreaDesc {
+    pub fn new(flash: &SimFlash) -> AreaDesc {
+        AreaDesc {
+            areas: vec![],
+            whole: vec![],
+            sectors: flash.sector_iter().collect(),
+        }
+    }
+
+    /// Add a slot to the image.  The slot must align with erasable units in the flash device.
+    /// Panics if the description is not valid.  There are also bootloader assumptions that the
+    /// slots are SLOT0, SLOT1, and SCRATCH in that order.
+    pub fn add_image(&mut self, base: usize, len: usize, id: FlashId) {
+        let nid = id as usize;
+        let orig_base = base;
+        let orig_len = len;
+        let mut base = base;
+        let mut len = len;
+
+        while nid > self.areas.len() {
+            self.areas.push(vec![]);
+            self.whole.push(Default::default());
+        }
+
+        if nid != self.areas.len() {
+            panic!("Flash areas not added in order");
+        }
+
+        let mut area = vec![];
+
+        for sector in &self.sectors {
+            if len == 0 {
+                break;
+            };
+            if base > sector.base + sector.size - 1 {
+                continue;
+            }
+            if sector.base != base {
+                panic!("Image does not start on a sector boundary");
+            }
+
+            area.push(FlashArea {
+                flash_id: id,
+                device_id: 42,
+                pad16: 0,
+                off: sector.base as u32,
+                size: sector.size as u32,
+            });
+
+            base += sector.size;
+            len -= sector.size;
+        }
+
+        if len != 0 {
+            panic!("Image goes past end of device");
+        }
+
+        self.areas.push(area);
+        self.whole.push(FlashArea {
+            flash_id: id,
+            device_id: 42,
+            pad16: 0,
+            off: orig_base as u32,
+            size: orig_len as u32,
+        });
+    }
+
+    // Add a simple slot to the image.  This ignores the device layout, and just adds the area as a
+    // single unit.  It assumes that the image lines up with image boundaries.  This tests
+    // configurations where the partition table uses larger sectors than the underlying flash
+    // device.
+    pub fn add_simple_image(&mut self, base: usize, len: usize, id: FlashId) {
+        let area = vec![FlashArea {
+            flash_id: id,
+            device_id: 42,
+            pad16: 0,
+            off: base as u32,
+            size: len as u32,
+        }];
+
+        self.areas.push(area);
+        self.whole.push(FlashArea {
+            flash_id: id,
+            device_id: 42,
+            pad16: 0,
+            off: base as u32,
+            size: len as u32,
+        });
+    }
+
+    // Look for the image with the given ID, and return its base and size.  Panics if the area is
+    // not present.
+    pub fn find(&self, id: FlashId) -> (usize, usize) {
+        for area in &self.whole {
+            if area.flash_id == id {
+                return (area.off as usize, area.size as usize);
+            }
+        }
+        panic!("Requesting area that is not present in flash");
+    }
+
+    pub fn get_c(&self) -> CAreaDesc {
+        let mut areas: CAreaDesc = Default::default();
+
+        assert_eq!(self.areas.len(), self.whole.len());
+
+        for (i, area) in self.areas.iter().enumerate() {
+            if area.len() > 0 {
+                areas.slots[i].areas = &area[0];
+                areas.slots[i].whole = self.whole[i].clone();
+                areas.slots[i].num_areas = area.len() as u32;
+                areas.slots[i].id = area[0].flash_id;
+            }
+        }
+
+        areas.num_slots = self.areas.len() as u32;
+
+        areas
+    }
+}
+
+/// The area descriptor, C format.
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct CAreaDesc {
+    slots: [CArea; 16],
+    num_slots: u32,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct CArea {
+    whole: FlashArea,
+    areas: *const FlashArea,
+    num_areas: u32,
+    id: FlashId,
+}
+
+impl Default for CArea {
+    fn default() -> CArea {
+        CArea {
+            areas: ptr::null(),
+            whole: Default::default(),
+            id: FlashId::BootLoader,
+            num_areas: 0,
+        }
+    }
+}
+
+/// Flash area map.
+#[repr(u8)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[allow(dead_code)]
+pub enum FlashId {
+    BootLoader = 0,
+    Image0 = 1,
+    Image1 = 2,
+    ImageScratch = 3,
+    Nffs = 4,
+    Core = 5,
+    RebootLog = 6
+}
+
+impl Default for FlashId {
+    fn default() -> FlashId {
+        FlashId::BootLoader
+    }
+}
+
+#[repr(C)]
+#[derive(Debug, Clone, Default)]
+pub struct FlashArea {
+    flash_id: FlashId,
+    device_id: u8,
+    pad16: u16,
+    off: u32,
+    size: u32,
+}
+
diff --git a/sim/mcuboot-sys/src/c.rs b/sim/mcuboot-sys/src/c.rs
new file mode 100644
index 0000000..a3a6b4f
--- /dev/null
+++ b/sim/mcuboot-sys/src/c.rs
@@ -0,0 +1,64 @@
+/// Interface wrappers to C API entering to the bootloader
+
+use area::AreaDesc;
+use simflash::Flash;
+use libc;
+use api;
+
+/// Invoke the bootloader on this flash device.
+pub fn boot_go(flash: &mut Flash, areadesc: &AreaDesc) -> i32 {
+    unsafe { api::set_flash(flash) };
+    let result = unsafe { raw::invoke_boot_go(&areadesc.get_c() as *const _) as i32 };
+    unsafe { api::clear_flash(); };
+    result
+}
+
+/// Setter/getter for the flash counter.  This isn't thread safe.
+pub fn get_flash_counter() -> i32 {
+    unsafe { raw::flash_counter as i32 }
+}
+
+/// Set the flash counter.  Zero indicates the flash should not be interrupted.  The counter will
+/// then go negative for each flash operation.
+pub fn set_flash_counter(counter: i32) {
+    unsafe { raw::flash_counter = counter as libc::c_int };
+}
+
+pub fn boot_trailer_sz() -> u32 {
+    unsafe { raw::boot_slots_trailer_sz(raw::sim_flash_align) }
+}
+
+pub fn get_sim_flash_align() -> u8 {
+    unsafe { raw::sim_flash_align }
+}
+
+pub fn set_sim_flash_align(align: u8) {
+    unsafe { raw::sim_flash_align = align };
+}
+
+pub fn boot_magic_sz() -> usize {
+    unsafe { raw::BOOT_MAGIC_SZ as usize }
+}
+
+pub fn boot_max_align() -> usize {
+    unsafe { raw::BOOT_MAX_ALIGN as usize }
+}
+
+mod raw {
+    use area::CAreaDesc;
+    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 sim_flash_align: u8;
+        pub fn boot_slots_trailer_sz(min_write_sz: u8) -> u32;
+
+        pub static BOOT_MAGIC_SZ: u32;
+        pub static BOOT_MAX_ALIGN: u32;
+    }
+}
diff --git a/sim/mcuboot-sys/src/lib.rs b/sim/mcuboot-sys/src/lib.rs
new file mode 100644
index 0000000..2da90ef
--- /dev/null
+++ b/sim/mcuboot-sys/src/lib.rs
@@ -0,0 +1,7 @@
+extern crate libc;
+#[macro_use] extern crate log;
+extern crate simflash;
+
+pub mod area;
+pub mod c;
+pub mod api;