Infineon: Add cyw20829 platform, shared slot feature, json memory map, psoc6 xip
Based in 1.8.0 release of MCUBoot library
This commit adds CYW20829 Infineon platform support with following capabilities:
1. Overwrite and swap upgrade mode support
2. Multi-image with up to 4 images
3. Hardware security counter is supported for CYW20829 platform
Add XIP support for PSOC6 platform - place BOOT slot in external memory and execute it in place using SMIF in XIP mode
and some new features for Infineon devices.
1. Shared upgrade slot feature - use one shared area for upgrade slots of multiple images
2. Memory map defined using JSON file - define memory regions for bootloader and user app in conventional way using JSON file
diff --git a/sim/mcuboot-sys/src/api.rs b/sim/mcuboot-sys/src/api.rs
index a6acd53..8d1140d 100644
--- a/sim/mcuboot-sys/src/api.rs
+++ b/sim/mcuboot-sys/src/api.rs
@@ -26,6 +26,38 @@
pub type FlashParams = HashMap<u8, FlashParamsStruct>;
+/// The `boot_rsp` structure used by boot_go.
+#[repr(C)]
+#[derive(Debug)]
+pub struct BootRsp {
+ pub br_hdr: *const ImageHeader,
+ pub flash_dev_id: u8,
+ pub image_off: u32,
+}
+
+// TODO: Don't duplicate this image header declaration.
+#[repr(C)]
+#[derive(Debug)]
+pub struct ImageHeader {
+ magic: u32,
+ load_addr: u32,
+ hdr_size: u16,
+ protect_tlv_size: u16,
+ img_size: u32,
+ flags: u32,
+ ver: ImageVersion,
+ _pad2: u32,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct ImageVersion {
+ pub major: u8,
+ pub minor: u8,
+ pub revision: u16,
+ pub build_num: u32,
+}
+
pub struct CAreaDescPtr {
pub ptr: *const CAreaDesc,
}
@@ -89,9 +121,20 @@
}
}
+/// This struct describes the RAM layout of the current device. It will be stashed, per test
+/// thread, and queried by the C code.
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct BootsimRamInfo {
+ pub start: u32,
+ pub size: u32,
+ pub base: usize,
+}
+
thread_local! {
pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
+ pub static RAM_CTX: RefCell<BootsimRamInfo> = RefCell::new(BootsimRamInfo::default());
}
/// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
@@ -165,6 +208,32 @@
}
#[no_mangle]
+pub extern "C" fn bootsim_get_ram_info() -> *const BootsimRamInfo {
+ RAM_CTX.with(|ctx| {
+ if ctx.borrow().base == 0 {
+ // Option is messier to get a pointer out of, so just check if the base has been set to
+ // anything.
+ panic!("ram info not set, but being used");
+ }
+ ctx.as_ptr()
+ })
+}
+
+/// Store a copy of this RAM info.
+pub fn set_ram_info(info: BootsimRamInfo) {
+ RAM_CTX.with(|ctx| {
+ ctx.replace(info);
+ });
+}
+
+/// Clear out the ram info.
+pub fn clear_ram_info() {
+ RAM_CTX.with(|ctx| {
+ ctx.borrow_mut().base = 0;
+ });
+}
+
+#[no_mangle]
pub extern fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
let mut rc: libc::c_int = -19;
THREAD_CTX.with(|ctx| {
diff --git a/sim/mcuboot-sys/src/area.rs b/sim/mcuboot-sys/src/area.rs
index f151fe4..cfbebda 100644
--- a/sim/mcuboot-sys/src/area.rs
+++ b/sim/mcuboot-sys/src/area.rs
@@ -189,8 +189,8 @@
ImageScratch = 3,
Image2 = 4,
Image3 = 5,
- //ImageSwapStatus = 7,
- //ImageSwapStatus = 3,
+// Not_used = 6,
+ ImageSwapStatus = 7,
}
impl Default for FlashId {
diff --git a/sim/mcuboot-sys/src/c.rs b/sim/mcuboot-sys/src/c.rs
index 5f518f5..5c791b8 100644
--- a/sim/mcuboot-sys/src/c.rs
+++ b/sim/mcuboot-sys/src/c.rs
@@ -1,6 +1,6 @@
// Copyright (c) 2017-2019 Linaro LTD
// Copyright (c) 2017-2019 JUUL Labs
-// Copyright (c) 2019 Arm Limited
+// Copyright (c) 2019-2021 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0
@@ -10,9 +10,61 @@
use simflash::SimMultiFlash;
use crate::api;
+/// The result of an invocation of `boot_go`. This is intentionally opaque so that we can provide
+/// accessors for everything we need from this.
+#[derive(Debug)]
+pub enum BootGoResult {
+ /// This run was stopped by the flash simulation mechanism.
+ Stopped,
+ /// The bootloader ran to completion with the following data.
+ Normal {
+ result: i32,
+ asserts: u8,
+
+ resp: api::BootRsp,
+ },
+}
+
+impl BootGoResult {
+ /// Was this run interrupted.
+ pub fn interrupted(&self) -> bool {
+ matches!(self, BootGoResult::Stopped)
+ }
+
+ /// Was this boot run successful (returned 0)
+ pub fn success(&self) -> bool {
+ matches!(self, BootGoResult::Normal { result: 0, .. })
+ }
+
+ /// Success, but also no asserts.
+ pub fn success_no_asserts(&self) -> bool {
+ matches!(self, BootGoResult::Normal {
+ result: 0,
+ asserts: 0,
+ ..
+ })
+ }
+
+ /// Get the asserts count. An interrupted run will be considered to have no asserts.
+ pub fn asserts(&self) -> u8 {
+ match self {
+ BootGoResult::Normal { asserts, .. } => *asserts,
+ _ => 0,
+ }
+ }
+
+ /// Retrieve the 'resp' field that is filled in.
+ pub fn resp(&self) -> Option<&api::BootRsp> {
+ match self {
+ BootGoResult::Normal { resp, .. } => Some(resp),
+ _ => None,
+ }
+ }
+}
+
/// 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) {
+ counter: Option<&mut i32>, catch_asserts: bool) -> BootGoResult {
for (&dev_id, flash) in multiflash.iter_mut() {
api::set_flash(dev_id, flash);
}
@@ -26,8 +78,14 @@
c_catch_asserts: if catch_asserts { 1 } else { 0 },
boot_jmpbuf: [0; 16],
};
+ let mut rsp = api::BootRsp {
+ br_hdr: std::ptr::null(),
+ flash_dev_id: 0,
+ image_off: 0,
+ };
let result = unsafe {
- raw::invoke_boot_go(&mut sim_ctx as *mut _, &areadesc.get_c() as *const _) as i32
+ raw::invoke_boot_go(&mut sim_ctx as *mut _, &areadesc.get_c() as *const _,
+ &mut rsp as *mut _) as i32
};
let asserts = sim_ctx.c_asserts;
if let Some(c) = counter {
@@ -36,7 +94,11 @@
for &dev_id in multiflash.keys() {
api::clear_flash(dev_id);
}
- (result, asserts)
+ if result == -0x13579 {
+ BootGoResult::Stopped
+ } else {
+ BootGoResult::Normal { result, asserts, resp: rsp }
+ }
}
pub fn boot_trailer_sz(align: u32) -> u32 {
@@ -67,9 +129,12 @@
}
}
-pub fn kw_encrypt(kek: &[u8], seckey: &[u8]) -> Result<[u8; 24], &'static str> {
+pub fn kw_encrypt(kek: &[u8], seckey: &[u8], keylen: u32) -> Result<Vec<u8>, &'static str> {
unsafe {
- let mut encbuf = [0u8; 24];
+ let mut encbuf = vec![0u8; 24];
+ if keylen == 32 {
+ encbuf = vec![0u8; 40];
+ }
if raw::kw_encrypt_(kek.as_ptr(), seckey.as_ptr(), encbuf.as_mut_ptr()) == 0 {
return Ok(encbuf);
}
@@ -79,13 +144,14 @@
mod raw {
use crate::area::CAreaDesc;
- use crate::api::CSimContext;
+ use crate::api::{BootRsp, CSimContext};
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(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc) -> libc::c_int;
+ pub fn invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc,
+ rsp: *mut BootRsp) -> libc::c_int;
pub fn boot_trailer_sz(min_write_sz: u32) -> u32;
pub fn boot_status_sz(min_write_sz: u32) -> u32;
diff --git a/sim/mcuboot-sys/src/lib.rs b/sim/mcuboot-sys/src/lib.rs
index 8acb246..bc3fc49 100644
--- a/sim/mcuboot-sys/src/lib.rs
+++ b/sim/mcuboot-sys/src/lib.rs
@@ -10,3 +10,43 @@
pub mod api;
pub use crate::area::{AreaDesc, FlashId};
+
+/// For testing the ram load feature, we need to emulate a block of RAM and be able to pass that
+/// down to the C code. The call down to boot_go should go through this object so that the buffer
+/// itself is managed properly.
+pub struct RamBlock {
+ ram: Vec<u8>,
+ offset: u32, // 32-bit offset.
+}
+
+impl RamBlock {
+ pub fn new(size: u32, offset: u32) -> RamBlock {
+ RamBlock {
+ ram: vec![0; size as usize],
+ offset: offset,
+ }
+ }
+
+ /// Borrow the RAM buffer, with 'offset' being the beginning of the buffer.
+ pub fn borrow(&self) -> &[u8] {
+ &self.ram
+ }
+
+ /// Borrow a piece of the ram, with 'offset' being the beginning of the buffer.
+ pub fn borrow_part(&self, base: usize, size: usize) -> &[u8] {
+ &self.ram[base..base+size]
+ }
+
+ pub fn invoke<F, R>(&self, act: F) -> R
+ where F: FnOnce() -> R
+ {
+ api::set_ram_info(api::BootsimRamInfo {
+ start: self.offset,
+ size: self.ram.len() as u32,
+ base: &self.ram[0] as *const u8 as usize - self.offset as usize,
+ });
+ let result = act();
+ api::clear_ram_info();
+ result
+ }
+}