aboutsummaryrefslogtreecommitdiff
path: root/platform/ext/target/arm/musca_s1/tfm_hal_isolation.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ext/target/arm/musca_s1/tfm_hal_isolation.c')
-rw-r--r--platform/ext/target/arm/musca_s1/tfm_hal_isolation.c332
1 files changed, 332 insertions, 0 deletions
diff --git a/platform/ext/target/arm/musca_s1/tfm_hal_isolation.c b/platform/ext/target/arm/musca_s1/tfm_hal_isolation.c
new file mode 100644
index 0000000000..e2c7dead04
--- /dev/null
+++ b/platform/ext/target/arm/musca_s1/tfm_hal_isolation.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon
+ * company) or an affiliate of Cypress Semiconductor Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arm_cmse.h>
+#include <stddef.h>
+#include <stdint.h>
+#include "array.h"
+#include "tfm_hal_device_header.h"
+#include "Driver_Common.h"
+#include "mmio_defs.h"
+#include "mpu_armv8m_drv.h"
+#include "region.h"
+#include "target_cfg.h"
+#include "tfm_hal_defs.h"
+#include "tfm_hal_isolation.h"
+#include "tfm_peripherals_def.h"
+#include "load/partition_defs.h"
+#include "load/asset_defs.h"
+#include "load/spm_load_api.h"
+
+/* It can be retrieved from the MPU_TYPE register. */
+#define MPU_REGION_NUM 8
+#define PROT_BOUNDARY_VAL \
+ ((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK)
+
+#ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
+static uint32_t n_configured_regions = 0;
+struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
+
+REGION_DECLARE(Image$$, ER_VENEER, $$Base);
+REGION_DECLARE(Image$$, VENEER_ALIGN, $$Limit);
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
+REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
+#ifdef CONFIG_TFM_PARTITION_META
+REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit);
+#endif
+
+#endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
+
+enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(
+ uintptr_t *p_spm_boundary)
+{
+ /* Set up isolation boundaries between SPE and NSPE */
+ sau_and_idau_cfg();
+
+ if (mpc_init_cfg() != ARM_DRIVER_OK) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+
+ if (ppc_init_cfg() != ARM_DRIVER_OK) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+
+ /* Set up static isolation boundaries inside SPE */
+#ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
+ struct mpu_armv8m_region_cfg_t region_cfg;
+
+ mpu_armv8m_clean(&dev_mpu_s);
+
+ /* Veneer region */
+ region_cfg.region_nr = n_configured_regions;
+ region_cfg.region_base = (uint32_t)&REGION_NAME(Image$$, ER_VENEER, $$Base);
+ region_cfg.region_limit =
+ (uint32_t)&REGION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1;
+ region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_CODE_IDX;
+ 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, &region_cfg) != MPU_ARMV8M_OK) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+ n_configured_regions++;
+
+ /* TFM Core unprivileged code region */
+ region_cfg.region_nr = n_configured_regions;
+ region_cfg.region_base =
+ (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
+ region_cfg.region_limit =
+ (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit) - 1;
+ region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_CODE_IDX;
+ 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, &region_cfg) != MPU_ARMV8M_OK) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+ n_configured_regions++;
+
+ /* RO region */
+ region_cfg.region_nr = n_configured_regions;
+ region_cfg.region_base =
+ (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
+ region_cfg.region_limit =
+ (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1;
+ region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_CODE_IDX;
+ 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, &region_cfg) != MPU_ARMV8M_OK) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+ n_configured_regions++;
+
+ /* RW, ZI and stack as one region */
+ region_cfg.region_nr = n_configured_regions;
+ region_cfg.region_base =
+ (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
+ region_cfg.region_limit =
+ (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1;
+ region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
+ 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, &region_cfg) != MPU_ARMV8M_OK) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+ n_configured_regions++;
+
+#ifdef CONFIG_TFM_PARTITION_META
+ /* TFM partition metadata pointer region */
+ region_cfg.region_nr = n_configured_regions;
+ region_cfg.region_base =
+ (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
+ region_cfg.region_limit =
+ (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) - 1;
+ region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
+ 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, &region_cfg) != MPU_ARMV8M_OK) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+ n_configured_regions++;
+#endif
+
+ mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+ HARDFAULT_NMI_ENABLE);
+#endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
+
+ *p_spm_boundary = (uintptr_t)PROT_BOUNDARY_VAL;
+
+ return TFM_HAL_SUCCESS;
+}
+
+/*
+ * Implementation of tfm_hal_bind_boundary() on MUSCA_S1:
+ *
+ * The API encodes some attributes into a handle and returns it to SPM.
+ * The attributes include isolation boundaries, privilege, and MMIO information.
+ * When scheduler switches running partitions, SPM compares the handle between
+ * partitions to know if boundary update is necessary. If update is required,
+ * SPM passes the handle to platform to do platform settings and update
+ * isolation boundaries.
+ */
+enum tfm_hal_status_t tfm_hal_bind_boundary(
+ const struct partition_load_info_t *p_ldinf,
+ uintptr_t *p_boundary)
+{
+ uint32_t i, j;
+ bool privileged;
+ bool ns_agent;
+ uint32_t partition_attrs = 0;
+ const struct asset_desc_t *p_asset;
+ struct platform_data_t *plat_data_ptr;
+#if TFM_ISOLATION_LEVEL == 2
+ struct mpu_armv8m_region_cfg_t localcfg;
+#endif
+ if (!p_ldinf || !p_boundary) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+
+#if TFM_ISOLATION_LEVEL == 1
+ privileged = true;
+#else
+ privileged = IS_PSA_ROT(p_ldinf);
+#endif
+
+ ns_agent = IS_NS_AGENT(p_ldinf);
+ p_asset = LOAD_INFO_ASSET(p_ldinf);
+
+ /*
+ * Validate if partition MMIO is allowed by the platform. Below cases are
+ * allowed:
+ * 1. A named mmio is matched.
+ * 2. It is a memory asset.
+ *
+ * NOTE: Add validation of numbered MMIO if platform requires.
+ */
+ for (i = 0; i < p_ldinf->nassets; i++) {
+ if (!(p_asset[i].attr & ASSET_ATTR_NAMED_MMIO)) {
+ continue;
+ }
+ for (j = 0; j < ARRAY_SIZE(partition_named_mmio_list); j++) {
+ if (p_asset[i].dev.dev_ref == partition_named_mmio_list[j]) {
+ break;
+ }
+ }
+
+ if (j == ARRAY_SIZE(partition_named_mmio_list)) {
+ /* The MMIO asset is not in the allowed list of platform. */
+ return TFM_HAL_ERROR_GENERIC;
+ }
+ /* Assume PPC & MPC settings are required even under level 1 */
+ plat_data_ptr = REFERENCE_TO_PTR(p_asset[i].dev.dev_ref,
+ struct platform_data_t *);
+
+ if (plat_data_ptr->periph_ppc_bank != PPC_SP_DO_NOT_CONFIGURE) {
+ ppc_configure_to_secure(plat_data_ptr->periph_ppc_bank,
+ plat_data_ptr->periph_ppc_loc);
+ if (privileged) {
+ ppc_clr_secure_unpriv(plat_data_ptr->periph_ppc_bank,
+ plat_data_ptr->periph_ppc_loc);
+ } else {
+ ppc_en_secure_unpriv(plat_data_ptr->periph_ppc_bank,
+ plat_data_ptr->periph_ppc_loc);
+ }
+ }
+#if TFM_ISOLATION_LEVEL == 2
+ /*
+ * Static boundaries are set. Set up MPU region for MMIO.
+ * Setup regions for unprivileged assets only.
+ */
+ if (!privileged) {
+ localcfg.region_base = plat_data_ptr->periph_start;
+ localcfg.region_limit = plat_data_ptr->periph_limit;
+ localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
+ localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+ localcfg.attr_sh = MPU_ARMV8M_SH_NONE;
+ localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+ localcfg.region_nr = n_configured_regions++;
+
+ if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg)
+ != MPU_ARMV8M_OK) {
+ return TFM_HAL_ERROR_GENERIC;
+ }
+ }
+#endif
+ }
+
+ partition_attrs = ((uint32_t)privileged << HANDLE_ATTR_PRIV_POS) &
+ HANDLE_ATTR_PRIV_MASK;
+ partition_attrs |= ((uint32_t)ns_agent << HANDLE_ATTR_NS_POS) &
+ HANDLE_ATTR_NS_MASK;
+ *p_boundary = (uintptr_t)partition_attrs;
+
+ return TFM_HAL_SUCCESS;
+}
+
+enum tfm_hal_status_t tfm_hal_activate_boundary(
+ const struct partition_load_info_t *p_ldinf,
+ uintptr_t boundary)
+{
+ CONTROL_Type ctrl;
+ bool privileged = !!(((uint32_t)boundary) & HANDLE_ATTR_PRIV_MASK);
+
+ /* Privileged level is required to be set always */
+ ctrl.w = __get_CONTROL();
+ ctrl.b.nPRIV = privileged ? 0 : 1;
+ __set_CONTROL(ctrl.w);
+
+ return TFM_HAL_SUCCESS;
+}
+
+enum tfm_hal_status_t tfm_hal_memory_check(uintptr_t boundary, uintptr_t base,
+ size_t size, uint32_t access_type)
+{
+ int flags = 0;
+
+ /* If size is zero, this indicates an empty buffer and base is ignored */
+ if (size == 0) {
+ return TFM_HAL_SUCCESS;
+ }
+
+ if (!base) {
+ return TFM_HAL_ERROR_INVALID_INPUT;
+ }
+
+ if ((access_type & TFM_HAL_ACCESS_READWRITE) == TFM_HAL_ACCESS_READWRITE) {
+ flags |= CMSE_MPU_READWRITE;
+ } else if (access_type & TFM_HAL_ACCESS_READABLE) {
+ flags |= CMSE_MPU_READ;
+ } else {
+ return TFM_HAL_ERROR_INVALID_INPUT;
+ }
+
+ if (!((uint32_t)boundary & HANDLE_ATTR_PRIV_MASK)) {
+ flags |= CMSE_MPU_UNPRIV;
+ }
+
+ if ((uint32_t)boundary & HANDLE_ATTR_NS_MASK) {
+ CONTROL_Type ctrl;
+ ctrl.w = __TZ_get_CONTROL_NS();
+ if (ctrl.b.nPRIV == 1) {
+ flags |= CMSE_MPU_UNPRIV;
+ } else {
+ flags &= ~CMSE_MPU_UNPRIV;
+ }
+ flags |= CMSE_NONSECURE;
+ }
+
+ if (cmse_check_address_range((void *)base, size, flags) != NULL) {
+ return TFM_HAL_SUCCESS;
+ } else {
+ return TFM_HAL_ERROR_MEM_FAULT;
+ }
+}
+
+bool tfm_hal_boundary_need_switch(uintptr_t boundary_from,
+ uintptr_t boundary_to)
+{
+ if (boundary_from == boundary_to) {
+ return false;
+ }
+
+ if (((uint32_t)boundary_from & HANDLE_ATTR_PRIV_MASK) &&
+ ((uint32_t)boundary_to & HANDLE_ATTR_PRIV_MASK)) {
+ return false;
+ }
+ return true;
+}