diff options
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.c | 332 |
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)®ION_NAME(Image$$, ER_VENEER, $$Base); + region_cfg.region_limit = + (uint32_t)®ION_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, ®ion_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)®ION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base); + region_cfg.region_limit = + (uint32_t)®ION_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, ®ion_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)®ION_NAME(Image$$, TFM_APP_CODE_START, $$Base); + region_cfg.region_limit = + (uint32_t)®ION_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, ®ion_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)®ION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base); + region_cfg.region_limit = + (uint32_t)®ION_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, ®ion_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)®ION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base); + region_cfg.region_limit = + (uint32_t)®ION_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, ®ion_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; +} |