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
+    }
+}