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;