Platform: Move isolation hw code to SPM hal
Moves code related to hardware specific aspects of MPU, PPC, MPC and SAU
to SPM hal. Leaves the code parts that use cmse defined interface to
access these peripherals in secure_sw folder.
Change-Id: I594847686cac51ee0f9fae217152b6e90723bb9e
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
diff --git a/platform/ext/Mps2AN519.cmake b/platform/ext/Mps2AN519.cmake
index 74cbb9a..a890294 100755
--- a/platform/ext/Mps2AN519.cmake
+++ b/platform/ext/Mps2AN519.cmake
@@ -96,7 +96,9 @@
message(FATAL_ERROR "Configuration variable BUILD_TARGET_CFG (true|false) is undefined!")
elseif(BUILD_TARGET_CFG)
list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an519/target_cfg.c")
- list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an519/spm_hal.c")
+ list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an519/spm_hal.c")
+ list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an519/native_drivers/mpu_armv8m_drv.c")
+ embedded_include_directories(PATH "${PLATFORM_DIR}/common" ABSOLUTE)
endif()
if (NOT DEFINED BUILD_TARGET_HARDWARE_KEYS)
diff --git a/platform/ext/Mps2AN521.cmake b/platform/ext/Mps2AN521.cmake
index f44db7b..0b388ce 100755
--- a/platform/ext/Mps2AN521.cmake
+++ b/platform/ext/Mps2AN521.cmake
@@ -113,7 +113,9 @@
message(FATAL_ERROR "Configuration variable BUILD_TARGET_CFG (true|false) is undefined!")
elseif(BUILD_TARGET_CFG)
list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an521/target_cfg.c")
- list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an521/spm_hal.c")
+ list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an521/spm_hal.c")
+ list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an521/native_drivers/mpu_armv8m_drv.c")
+ embedded_include_directories(PATH "${PLATFORM_DIR}/common" ABSOLUTE)
endif()
if (NOT DEFINED BUILD_TARGET_HARDWARE_KEYS)
diff --git a/platform/ext/musca_a.cmake b/platform/ext/musca_a.cmake
index 3789170..985c3bc 100755
--- a/platform/ext/musca_a.cmake
+++ b/platform/ext/musca_a.cmake
@@ -96,7 +96,9 @@
message(FATAL_ERROR "Configuration variable BUILD_TARGET_CFG (true|false) is undefined!")
elseif(BUILD_TARGET_CFG)
list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_a/target_cfg.c")
- list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_a/spm_hal.c")
+ list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_a/spm_hal.c")
+ list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_a/Native_Driver/mpu_armv8m_drv.c")
+ embedded_include_directories(PATH "${PLATFORM_DIR}/common" ABSOLUTE)
endif()
if (NOT DEFINED BUILD_TARGET_HARDWARE_KEYS)
diff --git a/platform/ext/target/mps2/an519/native_drivers/mpu_armv8m_drv.c b/platform/ext/target/mps2/an519/native_drivers/mpu_armv8m_drv.c
new file mode 100644
index 0000000..e540be2
--- /dev/null
+++ b/platform/ext/target/mps2/an519/native_drivers/mpu_armv8m_drv.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "mpu_armv8m_drv.h"
+#include "cmsis_cpu.h"
+
+/*
+ * FixMe:
+ * This is a beta quality driver for MPU in v8M. To be finalized.
+ */
+
+enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
+ uint32_t privdef_en,
+ uint32_t hfnmi_en)
+{
+ /*No error checking*/
+
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ mpu->CTRL =
+ (privdef_en ? MPU_CTRL_PRIVDEFENA_Msk : 0) |
+ (hfnmi_en ? MPU_CTRL_HFNMIENA_Msk : 0);
+
+ /*Ensure all configuration is written before enable*/
+
+ mpu->CTRL |= MPU_CTRL_ENABLE_Msk;
+
+ /* Enable MPU before next instruction */
+ __asm("DSB");
+ __asm("ISB");
+ return MPU_ARMV8M_OK;
+}
+
+enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ /* Reset all fields as enable does full setup */
+ mpu->CTRL = 0;
+
+ return MPU_ARMV8M_OK;
+}
+
+
+enum mpu_armv8m_error_t mpu_armv8m_region_enable(
+ struct mpu_armv8m_dev_t *dev,
+ struct mpu_armv8m_region_cfg_t *region_cfg)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
+ uint32_t ctrl_before;
+ uint32_t base_cfg;
+ uint32_t limit_cfg;
+
+ /*FIXME : Add complete error checking*/
+ if ((region_cfg->region_base & ~MPU_RBAR_ADDR_Msk) != 0) {
+ return MPU_ARMV8M_ERROR;
+ }
+ /* region_limit doesn't need to be aligned but the scatter
+ * file needs to be setup to ensure that partitions do not overlap.
+ */
+
+ ctrl_before = mpu->CTRL;
+ mpu->CTRL = 0;
+
+ mpu->RNR = region_cfg->region_nr & MPU_RNR_REGION_Msk;
+
+ /* This 0s the lower bits of the base address */
+ base_cfg = region_cfg->region_base & MPU_RBAR_ADDR_Msk;
+ base_cfg |= (region_cfg->attr_sh << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk;
+ base_cfg |= (region_cfg->attr_access << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk;
+ base_cfg |= (region_cfg->attr_exec << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk;
+
+ mpu->RBAR = base_cfg;
+
+ /*This 0s the lower bits of base address but they are treated as 1 */
+ limit_cfg = (region_cfg->region_limit-1) & MPU_RLAR_LIMIT_Msk;
+
+ /*FIXME: Enable the memory attr setting */
+ limit_cfg |= MPU_RLAR_EN_Msk;
+
+ mpu->RLAR = limit_cfg;
+
+ /*Restore main MPU control*/
+ mpu->CTRL = ctrl_before;
+
+ /* Enable MPU before the next instruction */
+ __asm("DSB");
+ __asm("ISB");
+
+ return ret_val;
+}
+
+
+enum mpu_armv8m_error_t mpu_armv8m_region_disable(
+ struct mpu_armv8m_dev_t *dev,
+ uint32_t region_nr)
+{
+
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
+ uint32_t ctrl_before;
+
+ /*FIXME : Add complete error checking*/
+
+ ctrl_before = mpu->CTRL;
+ mpu->CTRL = 0;
+
+ mpu->RNR = region_nr & MPU_RNR_REGION_Msk;
+
+ mpu->RBAR = 0;
+ mpu->RLAR = 0;
+
+ /*Restore main MPU control*/
+ mpu->CTRL = ctrl_before;
+
+ return ret_val;
+}
+
+enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+ uint32_t i = (mpu->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
+
+ while (i > 0) {
+ mpu_armv8m_region_disable(dev, i-1);
+ i--;
+ }
+
+ return MPU_ARMV8M_OK;
+
+}
diff --git a/platform/ext/target/mps2/an519/native_drivers/mpu_armv8m_drv.h b/platform/ext/target/mps2/an519/native_drivers/mpu_armv8m_drv.h
new file mode 100644
index 0000000..0abf7fd
--- /dev/null
+++ b/platform/ext/target/mps2/an519/native_drivers/mpu_armv8m_drv.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __MPU_ARMV8M_DRV_H__
+#define __MPU_ARMV8M_DRV_H__
+
+#include <stdint.h>
+
+#include "cmsis.h"
+
+#define PRIVILEGED_DEFAULT_ENABLE 1
+#define HARDFAULT_NMI_ENABLE 1
+
+struct mpu_armv8m_dev_t {
+ const uint32_t base;
+};
+
+enum mpu_armv8m_error_t {
+ MPU_ARMV8M_OK,
+ MPU_ARMV8M_ERROR
+};
+
+enum mpu_armv8m_attr_exec_t {
+ MPU_ARMV8M_XN_EXEC_OK,
+ MPU_ARMV8M_XN_EXEC_NEVER
+};
+
+enum mpu_armv8m_attr_access_t {
+ MPU_ARMV8M_AP_RW_PRIV_ONLY,
+ MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
+ MPU_ARMV8M_AP_RO_PRIV_ONLY,
+ MPU_ARMV8M_AP_RO_PRIV_UNPRIV
+};
+
+enum mpu_armv8m_attr_shared_t {
+ MPU_ARMV8M_SH_NONE,
+ MPU_ARMV8M_SH_UNUSED,
+ MPU_ARMV8M_SH_OUTER,
+ MPU_ARMV8M_SH_INNER
+};
+
+struct mpu_armv8m_region_cfg_t {
+ uint32_t region_nr;
+ uint32_t region_base;
+ uint32_t region_limit;
+ enum mpu_armv8m_attr_exec_t attr_exec;
+ enum mpu_armv8m_attr_access_t attr_access;
+ enum mpu_armv8m_attr_shared_t attr_sh;
+};
+
+struct mpu_armv8m_region_cfg_raw_t {
+ uint32_t region_nr;
+ uint32_t region_base;
+ uint32_t region_limit;
+};
+
+
+/**
+ * \brief Enable MPU
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] privdef_en privilege default region 1:enable 0:disable
+ * \param[in] hfnmi_en mpu for hard fault & nmi 1:enable 0:disable
+ *
+ * \return Error code \ref mpu_armv8m_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+
+enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
+ uint32_t privdef_en,
+ uint32_t hfnmi_en);
+
+/**
+ * \brief Disable MPU
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev);
+
+/**
+ * \brief Disable MPU and clean all regions
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev);
+
+/**
+ * \brief Enable MPU Region
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] region_cfg MPU region config \ref mpu_armv8m_region_cfg_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_region_enable(
+ struct mpu_armv8m_dev_t *dev,
+ struct mpu_armv8m_region_cfg_t *region_cfg);
+
+/**
+ * \brief Disable MPU Region
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] region_nr Region number
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_region_disable(
+ struct mpu_armv8m_dev_t *dev,
+ uint32_t region_nr);
+
+#endif /* __MPU_ARMV8M_DRV_H__ */
diff --git a/platform/ext/target/mps2/an519/spm_hal.c b/platform/ext/target/mps2/an519/spm_hal.c
index 6f98696..a520043 100644
--- a/platform/ext/target/mps2/an519/spm_hal.c
+++ b/platform/ext/target/mps2/an519/spm_hal.c
@@ -5,15 +5,301 @@
*
*/
+#include <stdio.h>
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
+#include "tfm_platform_api.h"
+#include "target_cfg.h"
+#include "Driver_MPC.h"
+#include "mpu_armv8m_drv.h"
+#include "region_defs.h"
+#include "secure_utilities.h"
-void tfm_spm_hal_init_platform_data(uint32_t partition_id,
- struct tfm_spm_partition_platform_data_t *platform_data)
+/* Import MPC driver */
+extern ARM_DRIVER_MPC Driver_SRAM1_MPC;
+
+struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
+
+void tfm_spm_hal_init_isolation_hw(void)
{
- platform_data->periph_start = 0;
- platform_data->periph_limit = 0;
- platform_data->periph_ppc_bank = 0;
- platform_data->periph_ppc_loc = 0;
+ /* Configures non-secure memory spaces in the target */
+ sau_and_idau_cfg();
+ mpc_init_cfg();
+ ppc_init_cfg();
}
+
+void tfm_spm_hal_configure_default_isolation(
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ if (platform_data) {
+ ppc_configure_to_secure(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+}
+
+#if TFM_LVL != 1
+
+#define MPU_REGION_VENEERS 0
+#define MPU_REGION_TFM_UNPRIV_CODE 1
+#define MPU_REGION_TFM_UNPRIV_DATA 2
+#define MPU_REGION_NS_DATA 3
+#define PARTITION_REGION_RO 4
+#define PARTITION_REGION_RW_STACK 5
+#define PARTITION_REGION_PERIPH 6
+#define PARTITION_REGION_SHARE 7
+
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
+REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+static enum spm_err_t tfm_spm_mpu_init(void)
+{
+ struct mpu_armv8m_region_cfg_t region_cfg;
+
+ mpu_armv8m_clean(&dev_mpu_s);
+
+ /* Veneer region */
+ region_cfg.region_nr = MPU_REGION_VENEERS;
+ region_cfg.region_base = CMSE_VENEER_REGION_START;
+ region_cfg.region_limit = CMSE_VENEER_REGION_LIMIT;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged code region */
+ region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_CODE;
+ region_cfg.region_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
+ region_cfg.region_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged data region */
+ region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_DATA;
+ region_cfg.region_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
+ region_cfg.region_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged non-secure data region */
+ region_cfg.region_nr = MPU_REGION_NS_DATA;
+ region_cfg.region_base = NS_DATA_START;
+ region_cfg.region_limit = NS_DATA_LIMIT;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+enum spm_err_t tfm_spm_hal_partition_sandbox_config(
+ const struct tfm_spm_partition_memory_data_t *memory_data,
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ /* This function takes a partition id and enables the
+ * SPM partition for that partition
+ */
+
+ struct mpu_armv8m_region_cfg_t region_cfg;
+
+ mpu_armv8m_disable(&dev_mpu_s);
+
+ /* Configure Regions */
+ if (memory_data->ro_start) {
+ /* RO region */
+ region_cfg.region_nr = PARTITION_REGION_RO;
+ region_cfg.region_base = memory_data->ro_start;
+ region_cfg.region_limit = memory_data->ro_limit;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg)
+ != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+ }
+
+ /* RW, ZI and stack as one region */
+ region_cfg.region_nr = PARTITION_REGION_RW_STACK;
+ region_cfg.region_base = memory_data->rw_start;
+ region_cfg.region_limit = memory_data->stack_top;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ if (platform_data) {
+ /* Peripheral */
+ region_cfg.region_nr = PARTITION_REGION_PERIPH;
+ region_cfg.region_base = platform_data->periph_start;
+ region_cfg.region_limit = platform_data->periph_limit;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg)
+ != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ ppc_en_secure_unpriv(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+enum spm_err_t tfm_spm_hal_partition_sandbox_deconfig(
+ const struct tfm_spm_partition_memory_data_t *memory_data,
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ /* This function takes a partition id and disables the
+ * SPM partition for that partition
+ */
+
+ if (platform_data) {
+ /* Peripheral */
+ ppc_clr_secure_unpriv(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+
+ mpu_armv8m_disable(&dev_mpu_s);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_RO);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_RW_STACK);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_PERIPH);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_SHARE);
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+/**
+ * Set share region to which the partition needs access
+ */
+enum spm_err_t tfm_spm_hal_set_share_region(
+ enum tfm_buffer_share_region_e share)
+{
+ struct mpu_armv8m_region_cfg_t region_cfg;
+ enum spm_err_t res = SPM_ERR_INVALID_CONFIG;
+ uint32_t scratch_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+ uint32_t scratch_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+ mpu_armv8m_disable(&dev_mpu_s);
+
+ if (share == TFM_BUFFER_SHARE_DISABLE) {
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_SHARE);
+ } else {
+
+ region_cfg.region_nr = PARTITION_REGION_SHARE;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ switch (share) {
+ case TFM_BUFFER_SHARE_SCRATCH:
+ /* Use scratch area for SP-to-SP data sharing */
+ region_cfg.region_base = scratch_base;
+ region_cfg.region_limit = scratch_limit;
+ res = SPM_ERR_OK;
+ break;
+ case TFM_BUFFER_SHARE_NS_CODE:
+ region_cfg.region_base = NS_CODE_START;
+ region_cfg.region_limit = NS_CODE_LIMIT;
+ /* Only allow read access to NS code region and keep
+ * exec.never attribute
+ */
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ res = SPM_ERR_OK;
+ break;
+ default:
+ /* Leave res to be set to SPM_ERR_INVALID_CONFIG */
+ break;
+ }
+ if (res == SPM_ERR_OK) {
+ mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg);
+ }
+ }
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return res;
+}
+
+#endif /* TFM_LVL != 1 */
+
+void tfm_spm_hal_setup_isolation_hw(void)
+{
+#if TFM_LVL != 1
+ if (tfm_spm_mpu_init() != SPM_ERR_OK) {
+ ERROR_MSG("Failed to set up initial MPU configuration! Halting.");
+ while (1) {
+ ;
+ }
+ }
+#endif
+}
+
+void MPC_Handler(void)
+{
+ /* Clear MPC interrupt flag and pending MPC IRQ */
+ Driver_SRAM1_MPC.ClearInterrupt();
+ NVIC_ClearPendingIRQ(MPC_IRQn);
+
+ /* Print fault message and block execution */
+ LOG_MSG("Oops... MPC fault!!!");
+
+ /* Inform TF-M core that isolation boundary has been violated */
+ tfm_access_violation_handler();
+}
+
+void PPC_Handler(void)
+{
+ /*
+ * Due to an issue on the FVP, the PPC fault doesn't trigger a
+ * PPC IRQ which is handled by the PPC_handler.
+ * In the FVP execution, this code is not execute.
+ */
+
+ /* Clear PPC interrupt flag and pending PPC IRQ */
+ ppc_clear_irq();
+ NVIC_ClearPendingIRQ(PPC_IRQn);
+
+ /* Print fault message*/
+ LOG_MSG("Oops... PPC fault!!!");
+
+ /* Inform TF-M core that isolation boundary has been violated */
+ tfm_access_violation_handler();
+}
+
diff --git a/platform/ext/target/mps2/an519/target_cfg.c b/platform/ext/target/mps2/an519/target_cfg.c
index e73378b..edc9bb3 100644
--- a/platform/ext/target/mps2/an519/target_cfg.c
+++ b/platform/ext/target/mps2/an519/target_cfg.c
@@ -31,6 +31,20 @@
#define PERIPHERALS_BASE_NS_START (0x40000000)
#define PERIPHERALS_BASE_NS_END (0x4FFFFFFF)
+struct tfm_spm_partition_platform_data_t tfm_peripheral_uart1 = {
+ UART1_BASE_S,
+ UART1_BASE_S + 0xFFF,
+ PPC_SP_APB_PPC_EXP1,
+ CMSDK_UART1_APB_PPC_POS
+};
+
+struct tfm_spm_partition_platform_data_t tfm_peripheral_fpga_io = {
+ MPS2_IO_FPGAIO_BASE_S,
+ MPS2_IO_FPGAIO_BASE_S + 0xFFF,
+ PPC_SP_APB_PPC_EXP2,
+ CMSDK_FPGA_IO_PPC_POS
+};
+
void enable_fault_handlers(void)
{
/* Fault handles enable registers are not present in a baseline
diff --git a/platform/ext/target/mps2/an519/target_cfg.h b/platform/ext/target/mps2/an519/target_cfg.h
index 39280c7..e60a866 100644
--- a/platform/ext/target/mps2/an519/target_cfg.h
+++ b/platform/ext/target/mps2/an519/target_cfg.h
@@ -17,6 +17,8 @@
#ifndef __SSE200_TARGET_CFG_H__
#define __SSE200_TARGET_CFG_H__
+#include "tfm_peripherals_def.h"
+
/**
* \brief Defines the word offsets of Slave Peripheral Protection Controller
* Registers
@@ -42,24 +44,15 @@
};
/**
- * \brief BusFault, UsageFault, MemManageFault and SecureFault
- * are not present on AN519 so the body of this function
- * is empty
+ * Holds the data necessary to do isolation for a specific peripheral.
*/
-void enable_fault_handlers(void);
-
-/**
- * \brief Configures all external interrupts to target the
- * NS state, apart for the ones associated to secure
- * peripherals (plus MPC and PPC)
- */
-void nvic_interrupt_target_state_cfg();
-
-/**
- * \brief This function enable the interrupts associated
- * to the secure peripherals (plus MPC and PPC)
- */
-void nvic_interrupt_enable();
+struct tfm_spm_partition_platform_data_t
+{
+ uint32_t periph_start;
+ uint32_t periph_limit;
+ uint16_t periph_ppc_bank;
+ uint16_t periph_ppc_loc;
+};
/**
* \brief Configures the Memory Protection Controller.
diff --git a/platform/ext/target/mps2/an519/tfm_peripherals_def.h b/platform/ext/target/mps2/an519/tfm_peripherals_def.h
new file mode 100644
index 0000000..ca09d67
--- /dev/null
+++ b/platform/ext/target/mps2/an519/tfm_peripherals_def.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_PERIPHERALS_DEF_H__
+#define __TFM_PERIPHERALS_DEF_H__
+
+struct tfm_spm_partition_platform_data_t;
+
+extern struct tfm_spm_partition_platform_data_t tfm_peripheral_uart1;
+extern struct tfm_spm_partition_platform_data_t tfm_peripheral_fpga_io;
+
+#define TFM_PERIPHERAL_FPGA_IO (&tfm_peripheral_fpga_io)
+#define TFM_PERIPHERAL_UART1 (&tfm_peripheral_uart1)
+
+#endif /* __TFM_PERIPHERALS_DEF_H__ */
diff --git a/platform/ext/target/mps2/an521/native_drivers/mpu_armv8m_drv.c b/platform/ext/target/mps2/an521/native_drivers/mpu_armv8m_drv.c
new file mode 100644
index 0000000..e540be2
--- /dev/null
+++ b/platform/ext/target/mps2/an521/native_drivers/mpu_armv8m_drv.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "mpu_armv8m_drv.h"
+#include "cmsis_cpu.h"
+
+/*
+ * FixMe:
+ * This is a beta quality driver for MPU in v8M. To be finalized.
+ */
+
+enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
+ uint32_t privdef_en,
+ uint32_t hfnmi_en)
+{
+ /*No error checking*/
+
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ mpu->CTRL =
+ (privdef_en ? MPU_CTRL_PRIVDEFENA_Msk : 0) |
+ (hfnmi_en ? MPU_CTRL_HFNMIENA_Msk : 0);
+
+ /*Ensure all configuration is written before enable*/
+
+ mpu->CTRL |= MPU_CTRL_ENABLE_Msk;
+
+ /* Enable MPU before next instruction */
+ __asm("DSB");
+ __asm("ISB");
+ return MPU_ARMV8M_OK;
+}
+
+enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ /* Reset all fields as enable does full setup */
+ mpu->CTRL = 0;
+
+ return MPU_ARMV8M_OK;
+}
+
+
+enum mpu_armv8m_error_t mpu_armv8m_region_enable(
+ struct mpu_armv8m_dev_t *dev,
+ struct mpu_armv8m_region_cfg_t *region_cfg)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
+ uint32_t ctrl_before;
+ uint32_t base_cfg;
+ uint32_t limit_cfg;
+
+ /*FIXME : Add complete error checking*/
+ if ((region_cfg->region_base & ~MPU_RBAR_ADDR_Msk) != 0) {
+ return MPU_ARMV8M_ERROR;
+ }
+ /* region_limit doesn't need to be aligned but the scatter
+ * file needs to be setup to ensure that partitions do not overlap.
+ */
+
+ ctrl_before = mpu->CTRL;
+ mpu->CTRL = 0;
+
+ mpu->RNR = region_cfg->region_nr & MPU_RNR_REGION_Msk;
+
+ /* This 0s the lower bits of the base address */
+ base_cfg = region_cfg->region_base & MPU_RBAR_ADDR_Msk;
+ base_cfg |= (region_cfg->attr_sh << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk;
+ base_cfg |= (region_cfg->attr_access << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk;
+ base_cfg |= (region_cfg->attr_exec << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk;
+
+ mpu->RBAR = base_cfg;
+
+ /*This 0s the lower bits of base address but they are treated as 1 */
+ limit_cfg = (region_cfg->region_limit-1) & MPU_RLAR_LIMIT_Msk;
+
+ /*FIXME: Enable the memory attr setting */
+ limit_cfg |= MPU_RLAR_EN_Msk;
+
+ mpu->RLAR = limit_cfg;
+
+ /*Restore main MPU control*/
+ mpu->CTRL = ctrl_before;
+
+ /* Enable MPU before the next instruction */
+ __asm("DSB");
+ __asm("ISB");
+
+ return ret_val;
+}
+
+
+enum mpu_armv8m_error_t mpu_armv8m_region_disable(
+ struct mpu_armv8m_dev_t *dev,
+ uint32_t region_nr)
+{
+
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
+ uint32_t ctrl_before;
+
+ /*FIXME : Add complete error checking*/
+
+ ctrl_before = mpu->CTRL;
+ mpu->CTRL = 0;
+
+ mpu->RNR = region_nr & MPU_RNR_REGION_Msk;
+
+ mpu->RBAR = 0;
+ mpu->RLAR = 0;
+
+ /*Restore main MPU control*/
+ mpu->CTRL = ctrl_before;
+
+ return ret_val;
+}
+
+enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+ uint32_t i = (mpu->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
+
+ while (i > 0) {
+ mpu_armv8m_region_disable(dev, i-1);
+ i--;
+ }
+
+ return MPU_ARMV8M_OK;
+
+}
diff --git a/platform/ext/target/mps2/an521/native_drivers/mpu_armv8m_drv.h b/platform/ext/target/mps2/an521/native_drivers/mpu_armv8m_drv.h
new file mode 100644
index 0000000..0abf7fd
--- /dev/null
+++ b/platform/ext/target/mps2/an521/native_drivers/mpu_armv8m_drv.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __MPU_ARMV8M_DRV_H__
+#define __MPU_ARMV8M_DRV_H__
+
+#include <stdint.h>
+
+#include "cmsis.h"
+
+#define PRIVILEGED_DEFAULT_ENABLE 1
+#define HARDFAULT_NMI_ENABLE 1
+
+struct mpu_armv8m_dev_t {
+ const uint32_t base;
+};
+
+enum mpu_armv8m_error_t {
+ MPU_ARMV8M_OK,
+ MPU_ARMV8M_ERROR
+};
+
+enum mpu_armv8m_attr_exec_t {
+ MPU_ARMV8M_XN_EXEC_OK,
+ MPU_ARMV8M_XN_EXEC_NEVER
+};
+
+enum mpu_armv8m_attr_access_t {
+ MPU_ARMV8M_AP_RW_PRIV_ONLY,
+ MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
+ MPU_ARMV8M_AP_RO_PRIV_ONLY,
+ MPU_ARMV8M_AP_RO_PRIV_UNPRIV
+};
+
+enum mpu_armv8m_attr_shared_t {
+ MPU_ARMV8M_SH_NONE,
+ MPU_ARMV8M_SH_UNUSED,
+ MPU_ARMV8M_SH_OUTER,
+ MPU_ARMV8M_SH_INNER
+};
+
+struct mpu_armv8m_region_cfg_t {
+ uint32_t region_nr;
+ uint32_t region_base;
+ uint32_t region_limit;
+ enum mpu_armv8m_attr_exec_t attr_exec;
+ enum mpu_armv8m_attr_access_t attr_access;
+ enum mpu_armv8m_attr_shared_t attr_sh;
+};
+
+struct mpu_armv8m_region_cfg_raw_t {
+ uint32_t region_nr;
+ uint32_t region_base;
+ uint32_t region_limit;
+};
+
+
+/**
+ * \brief Enable MPU
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] privdef_en privilege default region 1:enable 0:disable
+ * \param[in] hfnmi_en mpu for hard fault & nmi 1:enable 0:disable
+ *
+ * \return Error code \ref mpu_armv8m_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+
+enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
+ uint32_t privdef_en,
+ uint32_t hfnmi_en);
+
+/**
+ * \brief Disable MPU
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev);
+
+/**
+ * \brief Disable MPU and clean all regions
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev);
+
+/**
+ * \brief Enable MPU Region
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] region_cfg MPU region config \ref mpu_armv8m_region_cfg_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_region_enable(
+ struct mpu_armv8m_dev_t *dev,
+ struct mpu_armv8m_region_cfg_t *region_cfg);
+
+/**
+ * \brief Disable MPU Region
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] region_nr Region number
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_region_disable(
+ struct mpu_armv8m_dev_t *dev,
+ uint32_t region_nr);
+
+#endif /* __MPU_ARMV8M_DRV_H__ */
diff --git a/platform/ext/target/mps2/an521/spm_hal.c b/platform/ext/target/mps2/an521/spm_hal.c
index 6f98696..e26496a 100644
--- a/platform/ext/target/mps2/an521/spm_hal.c
+++ b/platform/ext/target/mps2/an521/spm_hal.c
@@ -5,15 +5,301 @@
*
*/
+#include <stdio.h>
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
+#include "tfm_platform_api.h"
+#include "target_cfg.h"
+#include "Driver_MPC.h"
+#include "mpu_armv8m_drv.h"
+#include "region_defs.h"
+#include "secure_utilities.h"
-void tfm_spm_hal_init_platform_data(uint32_t partition_id,
- struct tfm_spm_partition_platform_data_t *platform_data)
+/* Import MPC driver */
+extern ARM_DRIVER_MPC Driver_SRAM1_MPC;
+
+struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
+
+void tfm_spm_hal_init_isolation_hw(void)
{
- platform_data->periph_start = 0;
- platform_data->periph_limit = 0;
- platform_data->periph_ppc_bank = 0;
- platform_data->periph_ppc_loc = 0;
+ /* Configures non-secure memory spaces in the target */
+ sau_and_idau_cfg();
+ mpc_init_cfg();
+ ppc_init_cfg();
}
+
+void tfm_spm_hal_configure_default_isolation(
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ if (platform_data) {
+ ppc_configure_to_secure(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+}
+
+#if TFM_LVL != 1
+
+#define MPU_REGION_VENEERS 0
+#define MPU_REGION_TFM_UNPRIV_CODE 1
+#define MPU_REGION_TFM_UNPRIV_DATA 2
+#define MPU_REGION_NS_DATA 3
+#define PARTITION_REGION_RO 4
+#define PARTITION_REGION_RW_STACK 5
+#define PARTITION_REGION_PERIPH 6
+#define PARTITION_REGION_SHARE 7
+
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
+REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+static enum spm_err_t tfm_spm_mpu_init(void)
+{
+ struct mpu_armv8m_region_cfg_t region_cfg;
+
+ mpu_armv8m_clean(&dev_mpu_s);
+
+ /* Veneer region */
+ region_cfg.region_nr = MPU_REGION_VENEERS;
+ region_cfg.region_base = CMSE_VENEER_REGION_START;
+ region_cfg.region_limit = CMSE_VENEER_REGION_LIMIT;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged code region */
+ region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_CODE;
+ region_cfg.region_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
+ region_cfg.region_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged data region */
+ region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_DATA;
+ region_cfg.region_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
+ region_cfg.region_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged non-secure data region */
+ region_cfg.region_nr = MPU_REGION_NS_DATA;
+ region_cfg.region_base = NS_DATA_START;
+ region_cfg.region_limit = NS_DATA_LIMIT;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+enum spm_err_t tfm_spm_hal_partition_sandbox_config(
+ const struct tfm_spm_partition_memory_data_t *memory_data,
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ /* This function takes a partition id and enables the
+ * SPM partition for that partition
+ */
+
+ struct mpu_armv8m_region_cfg_t region_cfg;
+
+ mpu_armv8m_disable(&dev_mpu_s);
+
+ /* Configure Regions */
+ if (memory_data->ro_start) {
+ /* RO region */
+ region_cfg.region_nr = PARTITION_REGION_RO;
+ region_cfg.region_base = memory_data->ro_start;
+ region_cfg.region_limit = memory_data->ro_limit;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg)
+ != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+ }
+
+ /* RW, ZI and stack as one region */
+ region_cfg.region_nr = PARTITION_REGION_RW_STACK;
+ region_cfg.region_base = memory_data->rw_start;
+ region_cfg.region_limit = memory_data->stack_top;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ if (platform_data) {
+ /* Peripheral */
+ region_cfg.region_nr = PARTITION_REGION_PERIPH;
+ region_cfg.region_base = platform_data->periph_start;
+ region_cfg.region_limit = platform_data->periph_limit;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg)
+ != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ ppc_en_secure_unpriv(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+enum spm_err_t tfm_spm_hal_partition_sandbox_deconfig(
+ const struct tfm_spm_partition_memory_data_t *memory_data,
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ /* This function takes a partition id and disables the
+ * SPM partition for that partition
+ */
+
+ if (platform_data) {
+ /* Peripheral */
+ ppc_clr_secure_unpriv(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+
+ mpu_armv8m_disable(&dev_mpu_s);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_RO);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_RW_STACK);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_PERIPH);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_SHARE);
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+/**
+ * Set share region to which the partition needs access
+ */
+enum spm_err_t tfm_spm_hal_set_share_region(
+ enum tfm_buffer_share_region_e share)
+{
+ struct mpu_armv8m_region_cfg_t region_cfg;
+ enum spm_err_t res = SPM_ERR_INVALID_CONFIG;
+ uint32_t scratch_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+ uint32_t scratch_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+ mpu_armv8m_disable(&dev_mpu_s);
+
+ if (share == TFM_BUFFER_SHARE_DISABLE) {
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_SHARE);
+ } else {
+
+ region_cfg.region_nr = PARTITION_REGION_SHARE;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ switch (share) {
+ case TFM_BUFFER_SHARE_SCRATCH:
+ /* Use scratch area for SP-to-SP data sharing */
+ region_cfg.region_base = scratch_base;
+ region_cfg.region_limit = scratch_limit;
+ res = SPM_ERR_OK;
+ break;
+ case TFM_BUFFER_SHARE_NS_CODE:
+ region_cfg.region_base = NS_CODE_START;
+ region_cfg.region_limit = NS_CODE_LIMIT;
+ /* Only allow read access to NS code region and keep
+ * exec.never attribute
+ */
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ res = SPM_ERR_OK;
+ break;
+ default:
+ /* Leave res to be set to SPM_ERR_INVALID_CONFIG */
+ break;
+ }
+ if (res == SPM_ERR_OK) {
+ mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg);
+ }
+ }
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return res;
+}
+
+#endif /* TFM_LVL != 1 */
+
+void tfm_spm_hal_setup_isolation_hw(void)
+{
+#if TFM_LVL != 1
+ if (tfm_spm_mpu_init() != SPM_ERR_OK) {
+ ERROR_MSG("Failed to set up initial MPU configuration! Halting.");
+ while (1) {
+ ;
+ }
+ }
+#endif
+}
+
+void MPC_Handler(void)
+{
+ /* Clear MPC interrupt flag and pending MPC IRQ */
+ Driver_SRAM1_MPC.ClearInterrupt();
+ NVIC_ClearPendingIRQ(MPC_IRQn);
+
+ /* Print fault message and block execution */
+ LOG_MSG("Oops... MPC fault!!!");
+
+ /* Inform TF-M core that isolation boundary has been violated */
+ tfm_access_violation_handler();
+}
+
+void PPC_Handler(void)
+{
+ /*
+ * Due to an issue on the FVP, the PPC fault doesn't trigger a
+ * PPC IRQ which is handled by the PPC_handler.
+ * In the FVP execution, this code is not execute.
+ */
+
+ /* Clear PPC interrupt flag and pending PPC IRQ */
+ ppc_clear_irq();
+ NVIC_ClearPendingIRQ(PPC_IRQn);
+
+ /* Print fault message*/
+ LOG_MSG("Oops... PPC fault!!!");
+
+ /* Inform TF-M core that isolation boundary has been violated */
+ tfm_access_violation_handler();
+}
+
diff --git a/platform/ext/target/mps2/an521/target_cfg.c b/platform/ext/target/mps2/an521/target_cfg.c
index 4d69786..54ea719 100644
--- a/platform/ext/target/mps2/an521/target_cfg.c
+++ b/platform/ext/target/mps2/an521/target_cfg.c
@@ -31,6 +31,20 @@
#define PERIPHERALS_BASE_NS_START (0x40000000)
#define PERIPHERALS_BASE_NS_END (0x4FFFFFFF)
+struct tfm_spm_partition_platform_data_t tfm_peripheral_uart1 = {
+ UART1_BASE_S,
+ UART1_BASE_S + 0xFFF,
+ PPC_SP_APB_PPC_EXP1,
+ CMSDK_UART1_APB_PPC_POS
+};
+
+struct tfm_spm_partition_platform_data_t tfm_peripheral_fpga_io = {
+ MPS2_IO_FPGAIO_BASE_S,
+ MPS2_IO_FPGAIO_BASE_S + 0xFFF,
+ PPC_SP_APB_PPC_EXP2,
+ CMSDK_FPGA_IO_PPC_POS
+};
+
void enable_fault_handlers(void)
{
/* Enables BUS, MEM, USG and Secure faults */
diff --git a/platform/ext/target/mps2/an521/target_cfg.h b/platform/ext/target/mps2/an521/target_cfg.h
index 26c5cda..1b9e050 100644
--- a/platform/ext/target/mps2/an521/target_cfg.h
+++ b/platform/ext/target/mps2/an521/target_cfg.h
@@ -17,6 +17,8 @@
#ifndef __SSE200_TARGET_CFG_H__
#define __SSE200_TARGET_CFG_H__
+#include "tfm_peripherals_def.h"
+
enum ppc_bank_e
{
PPC_SP_AHB_PPC0 = 0,
@@ -38,23 +40,15 @@
};
/**
- * \brief Enables the fault handlers BusFault, UsageFault,
- * MemManageFault and SecureFault.
+ * Holds the data necessary to do isolation for a specific peripheral.
*/
-void enable_fault_handlers(void);
-
-/**
- * \brief Configures all external interrupts to target the
- * NS state, apart for the ones associated to secure
- * peripherals (plus MPC and PPC)
- */
-void nvic_interrupt_target_state_cfg();
-
-/**
- * \brief This function enable the interrupts associated
- * to the secure peripherals (plus MPC and PPC)
- */
-void nvic_interrupt_enable();
+struct tfm_spm_partition_platform_data_t
+{
+ uint32_t periph_start;
+ uint32_t periph_limit;
+ uint16_t periph_ppc_bank;
+ uint16_t periph_ppc_loc;
+};
/**
* \brief Configures the Memory Protection Controller.
diff --git a/platform/ext/target/mps2/an521/tfm_peripherals_def.h b/platform/ext/target/mps2/an521/tfm_peripherals_def.h
new file mode 100644
index 0000000..ca09d67
--- /dev/null
+++ b/platform/ext/target/mps2/an521/tfm_peripherals_def.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_PERIPHERALS_DEF_H__
+#define __TFM_PERIPHERALS_DEF_H__
+
+struct tfm_spm_partition_platform_data_t;
+
+extern struct tfm_spm_partition_platform_data_t tfm_peripheral_uart1;
+extern struct tfm_spm_partition_platform_data_t tfm_peripheral_fpga_io;
+
+#define TFM_PERIPHERAL_FPGA_IO (&tfm_peripheral_fpga_io)
+#define TFM_PERIPHERAL_UART1 (&tfm_peripheral_uart1)
+
+#endif /* __TFM_PERIPHERALS_DEF_H__ */
diff --git a/platform/ext/target/musca_a/Native_Driver/mpu_armv8m_drv.c b/platform/ext/target/musca_a/Native_Driver/mpu_armv8m_drv.c
new file mode 100644
index 0000000..e540be2
--- /dev/null
+++ b/platform/ext/target/musca_a/Native_Driver/mpu_armv8m_drv.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "mpu_armv8m_drv.h"
+#include "cmsis_cpu.h"
+
+/*
+ * FixMe:
+ * This is a beta quality driver for MPU in v8M. To be finalized.
+ */
+
+enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
+ uint32_t privdef_en,
+ uint32_t hfnmi_en)
+{
+ /*No error checking*/
+
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ mpu->CTRL =
+ (privdef_en ? MPU_CTRL_PRIVDEFENA_Msk : 0) |
+ (hfnmi_en ? MPU_CTRL_HFNMIENA_Msk : 0);
+
+ /*Ensure all configuration is written before enable*/
+
+ mpu->CTRL |= MPU_CTRL_ENABLE_Msk;
+
+ /* Enable MPU before next instruction */
+ __asm("DSB");
+ __asm("ISB");
+ return MPU_ARMV8M_OK;
+}
+
+enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ /* Reset all fields as enable does full setup */
+ mpu->CTRL = 0;
+
+ return MPU_ARMV8M_OK;
+}
+
+
+enum mpu_armv8m_error_t mpu_armv8m_region_enable(
+ struct mpu_armv8m_dev_t *dev,
+ struct mpu_armv8m_region_cfg_t *region_cfg)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
+ uint32_t ctrl_before;
+ uint32_t base_cfg;
+ uint32_t limit_cfg;
+
+ /*FIXME : Add complete error checking*/
+ if ((region_cfg->region_base & ~MPU_RBAR_ADDR_Msk) != 0) {
+ return MPU_ARMV8M_ERROR;
+ }
+ /* region_limit doesn't need to be aligned but the scatter
+ * file needs to be setup to ensure that partitions do not overlap.
+ */
+
+ ctrl_before = mpu->CTRL;
+ mpu->CTRL = 0;
+
+ mpu->RNR = region_cfg->region_nr & MPU_RNR_REGION_Msk;
+
+ /* This 0s the lower bits of the base address */
+ base_cfg = region_cfg->region_base & MPU_RBAR_ADDR_Msk;
+ base_cfg |= (region_cfg->attr_sh << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk;
+ base_cfg |= (region_cfg->attr_access << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk;
+ base_cfg |= (region_cfg->attr_exec << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk;
+
+ mpu->RBAR = base_cfg;
+
+ /*This 0s the lower bits of base address but they are treated as 1 */
+ limit_cfg = (region_cfg->region_limit-1) & MPU_RLAR_LIMIT_Msk;
+
+ /*FIXME: Enable the memory attr setting */
+ limit_cfg |= MPU_RLAR_EN_Msk;
+
+ mpu->RLAR = limit_cfg;
+
+ /*Restore main MPU control*/
+ mpu->CTRL = ctrl_before;
+
+ /* Enable MPU before the next instruction */
+ __asm("DSB");
+ __asm("ISB");
+
+ return ret_val;
+}
+
+
+enum mpu_armv8m_error_t mpu_armv8m_region_disable(
+ struct mpu_armv8m_dev_t *dev,
+ uint32_t region_nr)
+{
+
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+
+ enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
+ uint32_t ctrl_before;
+
+ /*FIXME : Add complete error checking*/
+
+ ctrl_before = mpu->CTRL;
+ mpu->CTRL = 0;
+
+ mpu->RNR = region_nr & MPU_RNR_REGION_Msk;
+
+ mpu->RBAR = 0;
+ mpu->RLAR = 0;
+
+ /*Restore main MPU control*/
+ mpu->CTRL = ctrl_before;
+
+ return ret_val;
+}
+
+enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev)
+{
+ MPU_Type *mpu = (MPU_Type *)dev->base;
+ uint32_t i = (mpu->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
+
+ while (i > 0) {
+ mpu_armv8m_region_disable(dev, i-1);
+ i--;
+ }
+
+ return MPU_ARMV8M_OK;
+
+}
diff --git a/platform/ext/target/musca_a/Native_Driver/mpu_armv8m_drv.h b/platform/ext/target/musca_a/Native_Driver/mpu_armv8m_drv.h
new file mode 100644
index 0000000..0abf7fd
--- /dev/null
+++ b/platform/ext/target/musca_a/Native_Driver/mpu_armv8m_drv.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __MPU_ARMV8M_DRV_H__
+#define __MPU_ARMV8M_DRV_H__
+
+#include <stdint.h>
+
+#include "cmsis.h"
+
+#define PRIVILEGED_DEFAULT_ENABLE 1
+#define HARDFAULT_NMI_ENABLE 1
+
+struct mpu_armv8m_dev_t {
+ const uint32_t base;
+};
+
+enum mpu_armv8m_error_t {
+ MPU_ARMV8M_OK,
+ MPU_ARMV8M_ERROR
+};
+
+enum mpu_armv8m_attr_exec_t {
+ MPU_ARMV8M_XN_EXEC_OK,
+ MPU_ARMV8M_XN_EXEC_NEVER
+};
+
+enum mpu_armv8m_attr_access_t {
+ MPU_ARMV8M_AP_RW_PRIV_ONLY,
+ MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
+ MPU_ARMV8M_AP_RO_PRIV_ONLY,
+ MPU_ARMV8M_AP_RO_PRIV_UNPRIV
+};
+
+enum mpu_armv8m_attr_shared_t {
+ MPU_ARMV8M_SH_NONE,
+ MPU_ARMV8M_SH_UNUSED,
+ MPU_ARMV8M_SH_OUTER,
+ MPU_ARMV8M_SH_INNER
+};
+
+struct mpu_armv8m_region_cfg_t {
+ uint32_t region_nr;
+ uint32_t region_base;
+ uint32_t region_limit;
+ enum mpu_armv8m_attr_exec_t attr_exec;
+ enum mpu_armv8m_attr_access_t attr_access;
+ enum mpu_armv8m_attr_shared_t attr_sh;
+};
+
+struct mpu_armv8m_region_cfg_raw_t {
+ uint32_t region_nr;
+ uint32_t region_base;
+ uint32_t region_limit;
+};
+
+
+/**
+ * \brief Enable MPU
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] privdef_en privilege default region 1:enable 0:disable
+ * \param[in] hfnmi_en mpu for hard fault & nmi 1:enable 0:disable
+ *
+ * \return Error code \ref mpu_armv8m_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+
+enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
+ uint32_t privdef_en,
+ uint32_t hfnmi_en);
+
+/**
+ * \brief Disable MPU
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev);
+
+/**
+ * \brief Disable MPU and clean all regions
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev);
+
+/**
+ * \brief Enable MPU Region
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] region_cfg MPU region config \ref mpu_armv8m_region_cfg_t
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_region_enable(
+ struct mpu_armv8m_dev_t *dev,
+ struct mpu_armv8m_region_cfg_t *region_cfg);
+
+/**
+ * \brief Disable MPU Region
+ *
+ * \param[in] dev MPU device \ref mpu_armv8m_dev_t
+ * \param[in] region_nr Region number
+ *
+ * \return Error code \ref arm_mpu_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mpu_armv8m_error_t mpu_armv8m_region_disable(
+ struct mpu_armv8m_dev_t *dev,
+ uint32_t region_nr);
+
+#endif /* __MPU_ARMV8M_DRV_H__ */
diff --git a/platform/ext/target/musca_a/spm_hal.c b/platform/ext/target/musca_a/spm_hal.c
index 6f98696..a520043 100644
--- a/platform/ext/target/musca_a/spm_hal.c
+++ b/platform/ext/target/musca_a/spm_hal.c
@@ -5,15 +5,301 @@
*
*/
+#include <stdio.h>
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
+#include "tfm_platform_api.h"
+#include "target_cfg.h"
+#include "Driver_MPC.h"
+#include "mpu_armv8m_drv.h"
+#include "region_defs.h"
+#include "secure_utilities.h"
-void tfm_spm_hal_init_platform_data(uint32_t partition_id,
- struct tfm_spm_partition_platform_data_t *platform_data)
+/* Import MPC driver */
+extern ARM_DRIVER_MPC Driver_SRAM1_MPC;
+
+struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
+
+void tfm_spm_hal_init_isolation_hw(void)
{
- platform_data->periph_start = 0;
- platform_data->periph_limit = 0;
- platform_data->periph_ppc_bank = 0;
- platform_data->periph_ppc_loc = 0;
+ /* Configures non-secure memory spaces in the target */
+ sau_and_idau_cfg();
+ mpc_init_cfg();
+ ppc_init_cfg();
}
+
+void tfm_spm_hal_configure_default_isolation(
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ if (platform_data) {
+ ppc_configure_to_secure(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+}
+
+#if TFM_LVL != 1
+
+#define MPU_REGION_VENEERS 0
+#define MPU_REGION_TFM_UNPRIV_CODE 1
+#define MPU_REGION_TFM_UNPRIV_DATA 2
+#define MPU_REGION_NS_DATA 3
+#define PARTITION_REGION_RO 4
+#define PARTITION_REGION_RW_STACK 5
+#define PARTITION_REGION_PERIPH 6
+#define PARTITION_REGION_SHARE 7
+
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
+REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+static enum spm_err_t tfm_spm_mpu_init(void)
+{
+ struct mpu_armv8m_region_cfg_t region_cfg;
+
+ mpu_armv8m_clean(&dev_mpu_s);
+
+ /* Veneer region */
+ region_cfg.region_nr = MPU_REGION_VENEERS;
+ region_cfg.region_base = CMSE_VENEER_REGION_START;
+ region_cfg.region_limit = CMSE_VENEER_REGION_LIMIT;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged code region */
+ region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_CODE;
+ region_cfg.region_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
+ region_cfg.region_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged data region */
+ region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_DATA;
+ region_cfg.region_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
+ region_cfg.region_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ /* TFM Core unprivileged non-secure data region */
+ region_cfg.region_nr = MPU_REGION_NS_DATA;
+ region_cfg.region_base = NS_DATA_START;
+ region_cfg.region_limit = NS_DATA_LIMIT;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+enum spm_err_t tfm_spm_hal_partition_sandbox_config(
+ const struct tfm_spm_partition_memory_data_t *memory_data,
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ /* This function takes a partition id and enables the
+ * SPM partition for that partition
+ */
+
+ struct mpu_armv8m_region_cfg_t region_cfg;
+
+ mpu_armv8m_disable(&dev_mpu_s);
+
+ /* Configure Regions */
+ if (memory_data->ro_start) {
+ /* RO region */
+ region_cfg.region_nr = PARTITION_REGION_RO;
+ region_cfg.region_base = memory_data->ro_start;
+ region_cfg.region_limit = memory_data->ro_limit;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg)
+ != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+ }
+
+ /* RW, ZI and stack as one region */
+ region_cfg.region_nr = PARTITION_REGION_RW_STACK;
+ region_cfg.region_base = memory_data->rw_start;
+ region_cfg.region_limit = memory_data->stack_top;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg) != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ if (platform_data) {
+ /* Peripheral */
+ region_cfg.region_nr = PARTITION_REGION_PERIPH;
+ region_cfg.region_base = platform_data->periph_start;
+ region_cfg.region_limit = platform_data->periph_limit;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ if (mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg)
+ != MPU_ARMV8M_OK) {
+ return SPM_ERR_INVALID_CONFIG;
+ }
+
+ ppc_en_secure_unpriv(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+enum spm_err_t tfm_spm_hal_partition_sandbox_deconfig(
+ const struct tfm_spm_partition_memory_data_t *memory_data,
+ const struct tfm_spm_partition_platform_data_t *platform_data)
+{
+ /* This function takes a partition id and disables the
+ * SPM partition for that partition
+ */
+
+ if (platform_data) {
+ /* Peripheral */
+ ppc_clr_secure_unpriv(platform_data->periph_ppc_bank,
+ platform_data->periph_ppc_loc);
+ }
+
+ mpu_armv8m_disable(&dev_mpu_s);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_RO);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_RW_STACK);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_PERIPH);
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_SHARE);
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return SPM_ERR_OK;
+}
+
+/**
+ * Set share region to which the partition needs access
+ */
+enum spm_err_t tfm_spm_hal_set_share_region(
+ enum tfm_buffer_share_region_e share)
+{
+ struct mpu_armv8m_region_cfg_t region_cfg;
+ enum spm_err_t res = SPM_ERR_INVALID_CONFIG;
+ uint32_t scratch_base =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+ uint32_t scratch_limit =
+ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+ mpu_armv8m_disable(&dev_mpu_s);
+
+ if (share == TFM_BUFFER_SHARE_DISABLE) {
+ mpu_armv8m_region_disable(&dev_mpu_s, PARTITION_REGION_SHARE);
+ } else {
+
+ region_cfg.region_nr = PARTITION_REGION_SHARE;
+ region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ switch (share) {
+ case TFM_BUFFER_SHARE_SCRATCH:
+ /* Use scratch area for SP-to-SP data sharing */
+ region_cfg.region_base = scratch_base;
+ region_cfg.region_limit = scratch_limit;
+ res = SPM_ERR_OK;
+ break;
+ case TFM_BUFFER_SHARE_NS_CODE:
+ region_cfg.region_base = NS_CODE_START;
+ region_cfg.region_limit = NS_CODE_LIMIT;
+ /* Only allow read access to NS code region and keep
+ * exec.never attribute
+ */
+ region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+ res = SPM_ERR_OK;
+ break;
+ default:
+ /* Leave res to be set to SPM_ERR_INVALID_CONFIG */
+ break;
+ }
+ if (res == SPM_ERR_OK) {
+ mpu_armv8m_region_enable(&dev_mpu_s, ®ion_cfg);
+ }
+ }
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+
+ return res;
+}
+
+#endif /* TFM_LVL != 1 */
+
+void tfm_spm_hal_setup_isolation_hw(void)
+{
+#if TFM_LVL != 1
+ if (tfm_spm_mpu_init() != SPM_ERR_OK) {
+ ERROR_MSG("Failed to set up initial MPU configuration! Halting.");
+ while (1) {
+ ;
+ }
+ }
+#endif
+}
+
+void MPC_Handler(void)
+{
+ /* Clear MPC interrupt flag and pending MPC IRQ */
+ Driver_SRAM1_MPC.ClearInterrupt();
+ NVIC_ClearPendingIRQ(MPC_IRQn);
+
+ /* Print fault message and block execution */
+ LOG_MSG("Oops... MPC fault!!!");
+
+ /* Inform TF-M core that isolation boundary has been violated */
+ tfm_access_violation_handler();
+}
+
+void PPC_Handler(void)
+{
+ /*
+ * Due to an issue on the FVP, the PPC fault doesn't trigger a
+ * PPC IRQ which is handled by the PPC_handler.
+ * In the FVP execution, this code is not execute.
+ */
+
+ /* Clear PPC interrupt flag and pending PPC IRQ */
+ ppc_clear_irq();
+ NVIC_ClearPendingIRQ(PPC_IRQn);
+
+ /* Print fault message*/
+ LOG_MSG("Oops... PPC fault!!!");
+
+ /* Inform TF-M core that isolation boundary has been violated */
+ tfm_access_violation_handler();
+}
+
diff --git a/platform/ext/target/musca_a/target_cfg.h b/platform/ext/target/musca_a/target_cfg.h
index 6e93ff5..3d59934 100755
--- a/platform/ext/target/musca_a/target_cfg.h
+++ b/platform/ext/target/musca_a/target_cfg.h
@@ -17,6 +17,8 @@
#ifndef __TARGET_CFG_H__
#define __TARGET_CFG_H__
+#include "tfm_peripherals_def.h"
+
enum ppc_bank_e
{
PPC_SP_AHB_PPC0 = 0,
@@ -38,23 +40,15 @@
};
/**
- * \brief Enables the fault handlers BusFault, UsageFault,
- * MemManageFault and SecureFault.
+ * Holds the data necessary to do isolation for a specific peripheral.
*/
-void enable_fault_handlers(void);
-
-/**
- * \brief Configures all external interrupts to target the
- * NS state, apart for the ones associated to secure
- * peripherals (plus MPC and PPC)
- */
-void nvic_interrupt_target_state_cfg();
-
-/**
- * \brief This function enables the interrupts associated
- * to the secure peripherals (plus MPC and PPC)
- */
-void nvic_interrupt_enable();
+struct tfm_spm_partition_platform_data_t
+{
+ uint32_t periph_start;
+ uint32_t periph_limit;
+ uint16_t periph_ppc_bank;
+ uint16_t periph_ppc_loc;
+};
/**
* \brief Configures the Memory Protection Controller.
diff --git a/platform/ext/target/musca_a/tfm_peripherals_def.h b/platform/ext/target/musca_a/tfm_peripherals_def.h
new file mode 100644
index 0000000..2bd251e
--- /dev/null
+++ b/platform/ext/target/musca_a/tfm_peripherals_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_PERIPHERALS_DEF_H__
+#define __TFM_PERIPHERALS_DEF_H__
+
+struct tfm_spm_partition_platform_data_t;
+
+#endif /* __TFM_PERIPHERALS_DEF_H__ */
diff --git a/platform/include/tfm_spm_hal.h b/platform/include/tfm_spm_hal.h
index bbd0001..24e987b 100644
--- a/platform/include/tfm_spm_hal.h
+++ b/platform/include/tfm_spm_hal.h
@@ -9,26 +9,143 @@
#define __TFM_SPM_HAL_H__
#include <stdint.h>
+#include "tfm_secure_api.h"
+#include "spm_api.h"
/**
- * Holds the data necessary to do isolation for a specific peripheral.
- */
-struct tfm_spm_partition_platform_data_t
-{
- uint32_t periph_start;
- uint32_t periph_limit;
- uint16_t periph_ppc_bank;
- uint16_t periph_ppc_loc;
-};
-
-/**
- * \brief Initialise the platform related fields of a partition DB record.
+ * \brief Holds peripheral specific data fields required to manage the
+ * peripherals isolation
*
- * \param[in] partition_id The id of the partition
- * \param[in] platform_data The platform fields of the partition DB record to
- * init
+ * This structure has to be defined in the platform directory, and may have
+ * different definition for each platform. The structure should contain fields
+ * that describe the peripheral for the functions that are prototyped in this
+ * file and are responsible for configuring the isolation of the peripherals.
+ *
+ * Pointers to structures of this type are managed by the SPM, and passed to the
+ * necessary function on isolation request. The pointers are also defined by the
+ * platform in the header file tfm_peripherals_def.h. For details on this, see
+ * the documentation of that file.
*/
-void tfm_spm_hal_init_platform_data(uint32_t partition_id,
- struct tfm_spm_partition_platform_data_t *platform_data);
+struct tfm_spm_partition_platform_data_t;
+
+#if TFM_LVL != 1
+/**
+ * \brief Holds SPM db fields that define the memory regions used by a
+ * partition.
+ */
+struct tfm_spm_partition_memory_data_t
+{
+ uint32_t code_start; /*!< Start of the code memory of this partition. */
+ uint32_t code_limit; /*!< Address of the byte beyond the end of the code
+ * memory of this partition.
+ */
+ uint32_t ro_start; /*!< Start of the read only memory of this
+ * partition.
+ */
+ uint32_t ro_limit; /*!< Address of the byte beyond the end of the read
+ * only memory of this partition.
+ */
+ uint32_t rw_start; /*!< Start of the data region of this partition. */
+ uint32_t rw_limit; /*!< Address of the byte beyond the end of the data
+ * region of this partition.
+ */
+ uint32_t zi_start; /*!< Start of the zero initialised data region of
+ * this partition.
+ */
+ uint32_t zi_limit; /*!< Address of the byte beyond the end of the zero
+ * initialised region of this partition.
+ */
+ uint32_t stack_bottom; /*!< The bottom of the stack for the partition. */
+ uint32_t stack_top; /*!< The top of the stack for the partition. */
+};
+#endif
+
+/**
+ * \brief This function initialises the HW used for isolation, and sets the
+ * default configuration for them.
+ *
+ * This function is called during TF-M core early startup, before DB init
+ */
+void tfm_spm_hal_init_isolation_hw(void);
+
+/**
+ * \brief This function initialises the HW used for isolation, and sets the
+ * default configuration for them.
+ * This function is called during TF-M core early startup, after DB init
+ */
+void tfm_spm_hal_setup_isolation_hw(void);
+
+/**
+ * \brief Configure peripherals for a partition based on the platfotm data from
+ * the DB
+ *
+ * This function is called during partition initialisation (before calling the
+ * init function for the partition)
+ *
+ * \param[in] platform_data The platform fields of the partition DB record to
+ * be used for configuration. Can be NULL.
+ */
+void tfm_spm_hal_configure_default_isolation(
+ const struct tfm_spm_partition_platform_data_t *platform_data);
+
+/**
+ * \brief Enables the fault handlers
+ */
+void enable_fault_handlers(void);
+
+/**
+ * \brief Configures all external interrupts to target the
+ * NS state, apart for the ones associated to secure
+ * peripherals (plus MPC and PPC)
+ */
+void nvic_interrupt_target_state_cfg(void);
+
+/**
+ * \brief This function enable the interrupts associated
+ * to the secure peripherals (plus the isolation boundary violation
+ * interrupts)
+ */
+void nvic_interrupt_enable(void);
+
+
+#if TFM_LVL != 1
+/**
+ * \brief Configure the sandbox for a partition.
+ *
+ * \param[in] memory_data The memory ranges from the partition DB for this
+ * partition
+ * \param[in] platform_data The platform fields of the partition DB record
+ * for this partition. Can be NULL.
+ *
+ * \return Returns the result operation as per \ref spm_err_t
+ */
+enum spm_err_t tfm_spm_hal_partition_sandbox_config(
+ const struct tfm_spm_partition_memory_data_t *memory_data,
+ const struct tfm_spm_partition_platform_data_t *platform_data);
+
+/**
+ * \brief Deconfigure the sandbox for a partition.
+ *
+ * \param[in] memory_data The memory ranges from the partition DB for this
+ * partition
+ * \param[in] platform_data The platform fields of the partition DB record
+ * for this partition. Can be NULL.
+ *
+ * \return Returns the result operation as per \ref spm_err_t
+ */
+enum spm_err_t tfm_spm_hal_partition_sandbox_deconfig(
+ const struct tfm_spm_partition_memory_data_t *memory_data,
+ const struct tfm_spm_partition_platform_data_t *platform_data);
+
+/**
+ * \brief Set the share region mode
+ *
+ * \param[in] share The mode to set
+ *
+ * \return Returns the result operation as per \ref spm_err_t
+ */
+enum spm_err_t tfm_spm_hal_set_share_region(
+ enum tfm_buffer_share_region_e share);
+#endif
#endif /* __TFM_SPM_HAL_H__ */
diff --git a/platform/readme.md b/platform/readme.md
index 6e75bc5..6233895 100644
--- a/platform/readme.md
+++ b/platform/readme.md
@@ -3,6 +3,33 @@
`NOTE` This folder and subfolders, especially the target folder, are likely to
be refactored and updated to improve the overall structure of dependencies.
+## Interfacing with TF-M core
+
+### platform/ext/target/<target_platform>/tfm_peripherals_def.h
+This file should enumerate the hardware peripherals that are available for TF-M
+on the platform. The name of the peripheral used by a service is set in its
+manifest file. The platform have to provide a macro for each of the provided
+peripherals, that is substituted to a pointer to type
+`struct tfm_spm_partition_platform_data_t`. The memory that the pointer points
+to is allocated by the platform code. The pointer gets stored in the partitions
+database in SPM, and it is provided to the SPM HAL functions.
+
+#### Peripherals currently used by the services in TF-M
+ - `TFM_PERIPHERAL_FPGA_IO` FPGA system control and I/O
+ - `TFM_PERIPHERAL_UART1` UART1
+
+`NOTE` If a platform doesn't support a peripheral, that is used by a service,
+then the service cannot be used on the given platform. Using a peripheral in
+TF-M that is not supported by the platform results in compile error.
+
+### platform/include/tfm_spm_hal.h
+This file contains the declarations of functions that a platform implementation
+has to provide for TF-M. For details see the comments in the file.
+
+### secure_fw/core/tfm_platform_api.h
+This file contains declarations of functions that can be or have to be called
+from platform implementations. For details see the comments in the file.
+
## Sub-folders
### include
@@ -18,4 +45,4 @@
--------------
-*Copyright (c) 2017, Arm Limited. All rights reserved.*
+*Copyright (c) 2017-2018, Arm Limited. All rights reserved.*