diff options
author | Shawn Shan <Shawn.Shan@arm.com> | 2021-08-23 11:33:51 +0800 |
---|---|---|
committer | Shawn Shan <Shawn.Shan@arm.com> | 2021-09-17 10:12:17 +0800 |
commit | e92ab1ceb899d4280942258319db8554665734a3 (patch) | |
tree | 7b24a8fb25fc108070f71890c24699053701171a /platform | |
parent | 04d7a8b3f55580ac750c9b27bbf4ca82c45b8bf4 (diff) | |
download | trusted-firmware-m-e92ab1ceb899d4280942258319db8554665734a3.tar.gz |
Platform: STM: Introduce platform binding HAL
This API (tfm_hal_bind_boundaries) binds partition with platform by
a p_boundaries handle, to let platform records partition info and apply
specific settings. Check the API comment for details.
The patch also changes the boundary update HAL API.
Change-Id: Ia4a2fd2af1283d5c61c4fea5a111b787da51b626
Signed-off-by: Shawn Shan <Shawn.Shan@arm.com>
Diffstat (limited to 'platform')
4 files changed, 308 insertions, 60 deletions
diff --git a/platform/ext/target/stm/common/stm32l5xx/boards/mmio_defs.h b/platform/ext/target/stm/common/stm32l5xx/boards/mmio_defs.h new file mode 100644 index 0000000000..e1c8952f97 --- /dev/null +++ b/platform/ext/target/stm/common/stm32l5xx/boards/mmio_defs.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __MMIO_DEFS_H__ +#define __MMIO_DEFS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include "tfm_peripherals_def.h" + +/* Boundary handle binding macros. */ +#define HANDLE_PER_ATTR_BITS (0x4) +#define HANDLE_ATTR_PRIV_MASK ((1 << HANDLE_PER_ATTR_BITS) - 1) +#if TFM_LVL == 3 +#define HANDLE_ATTR_RW_POS (1 << (HANDLE_PER_ATTR_BITS - 1)) +#define HANDLE_ATTR_INDEX_MASK (HANDLE_ATTR_RW_POS - 1) +#define HANDLE_INDEX_BITS (0x8) +#define HANDLE_INDEX_MASK (((1 << HANDLE_INDEX_BITS) -1) << 24) +#define HANDLE_ENCODE_INDEX(attr, idx) \ + do { \ + (attr) |= (((idx) << 24) & HANDLE_INDEX_MASK); \ + (idx)++; \ + } while (0) +#endif + +/* Allowed named MMIO of this platform */ +const uintptr_t partition_named_mmio_list[] = { + (uintptr_t)TFM_PERIPHERAL_TIMER0, + (uintptr_t)TFM_PERIPHERAL_STD_UART, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __MMIO_DEFS_H__ */ diff --git a/platform/ext/target/stm/common/stm32l5xx/secure/spm_hal.c b/platform/ext/target/stm/common/stm32l5xx/secure/spm_hal.c index 42af56ee77..8ba64b0a4c 100644 --- a/platform/ext/target/stm/common/stm32l5xx/secure/spm_hal.c +++ b/platform/ext/target/stm/common/stm32l5xx/secure/spm_hal.c @@ -5,27 +5,16 @@ * */ -#include <stdio.h> #include "tfm_spm_hal.h" #include "tfm_platform_core_api.h" #include "target_cfg.h" #include "Driver_MPC.h" -#include "mpu_armv8m_drv.h" -#include "region_defs.h" #include "utilities.h" #include "region.h" /* Get address of memory regions to configure MPU */ extern const struct memory_region_limits memory_regions; -enum tfm_plat_err_t tfm_spm_hal_configure_default_isolation( - bool privileged, - const struct platform_data_t *platform_data) -{ - /* plat data are ignored */ - return TFM_PLAT_ERR_SUCCESS; -} - uint32_t tfm_spm_hal_get_ns_VTOR(void) { return memory_regions.non_secure_code_start; @@ -106,3 +95,15 @@ enum tfm_plat_err_t tfm_spm_hal_nvic_interrupt_enable(void) /* return nvic_interrupt_enable();*/ return TFM_PLAT_ERR_SUCCESS; } + +#ifndef TFM_PSA_API + +enum tfm_plat_err_t tfm_spm_hal_configure_default_isolation( + bool privileged, + const struct platform_data_t *platform_data) +{ + /* plat data are ignored */ + return TFM_PLAT_ERR_SUCCESS; +} + +#endif /* TFM_PSA_API */ diff --git a/platform/ext/target/stm/common/stm32l5xx/secure/tfm_hal_isolation.c b/platform/ext/target/stm/common/stm32l5xx/secure/tfm_hal_isolation.c index 1118750ed7..34b075da6e 100644 --- a/platform/ext/target/stm/common/stm32l5xx/secure/tfm_hal_isolation.c +++ b/platform/ext/target/stm/common/stm32l5xx/secure/tfm_hal_isolation.c @@ -5,15 +5,29 @@ * */ +#include "array.h" #include "cmsis.h" #include "Driver_Common.h" +#include "mmio_defs.h" #include "mpu_armv8m_drv.h" #include "region.h" #include "target_cfg.h" #include "tfm_hal_isolation.h" #include "tfm_plat_defs.h" +#include "tfm_peripherals_def.h" +#include "tfm_core_utils.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 + #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT +static uint32_t n_configured_regions = 0; +struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE }; #if TFM_LVL == 3 +static uint32_t idx_boundary_handle = 0; REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Base); REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Limit); REGION_DECLARE(Image$$, PT_RO_START, $$Base); @@ -21,9 +35,7 @@ REGION_DECLARE(Image$$, PT_RO_END, $$Base); REGION_DECLARE(Image$$, PT_PRIV_RWZI_START, $$Base); REGION_DECLARE(Image$$, PT_PRIV_RWZI_END, $$Base); -static uint32_t g_static_region_cnt; - -static struct mpu_armv8m_region_cfg_t isolation_regions[] = { +const static struct mpu_armv8m_region_cfg_t isolation_regions[] = { { 0, /* will be updated before using */ (uint32_t)®ION_NAME(Load$$LR$$, LR_VENEER, $$Base), @@ -43,7 +55,7 @@ static struct mpu_armv8m_region_cfg_t isolation_regions[] = { MPU_ARMV8M_SH_NONE, }, /* For isolation Level 3, set up static isolation for privileged data. - * Unprivileged data is dynamically set during Partition sheduling. + * Unprivileged data is dynamically set during Partition scheduling. */ { 0, /* will be updated before using */ @@ -56,16 +68,6 @@ static struct mpu_armv8m_region_cfg_t isolation_regions[] = { }, }; #else /* TFM_LVL == 3 */ -#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) - -#define MPU_REGION_VENEERS 0 -#define MPU_REGION_TFM_UNPRIV_CODE 1 -#define MPU_REGION_NS_STACK 2 -#define PARTITION_REGION_RO 3 -#define PARTITION_REGION_RW_STACK 4 -#ifdef TFM_SP_META_PTR_ENABLE -#define MPU_REGION_SP_META_PTR 7 -#endif /* TFM_SP_META_PTR_ENABLE */ REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Base); REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Limit); @@ -85,7 +87,7 @@ REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$RW$$Limit); const struct mpu_armv8m_region_cfg_t region_cfg[] = { /* Veneer region */ { - MPU_REGION_VENEERS, + 0, /* will be updated before using */ (uint32_t)®ION_NAME(Load$$LR$$, LR_VENEER, $$Base), (uint32_t)®ION_NAME(Load$$LR$$, LR_VENEER, $$Limit), MPU_ARMV8M_MAIR_ATTR_CODE_IDX, @@ -95,7 +97,7 @@ const struct mpu_armv8m_region_cfg_t region_cfg[] = { }, /* TFM Core unprivileged code region */ { - MPU_REGION_TFM_UNPRIV_CODE, + 0, /* will be updated before using */ (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base), (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit), MPU_ARMV8M_MAIR_ATTR_CODE_IDX, @@ -105,7 +107,7 @@ const struct mpu_armv8m_region_cfg_t region_cfg[] = { }, /* NSPM PSP */ { - MPU_REGION_NS_STACK, + 0, /* will be updated before using */ (uint32_t)®ION_NAME(Image$$, ER_INITIAL_PSP, $$ZI$$Base), (uint32_t)®ION_NAME(Image$$, ER_INITIAL_PSP, $$ZI$$Limit), MPU_ARMV8M_MAIR_ATTR_DATA_IDX, @@ -115,7 +117,7 @@ const struct mpu_armv8m_region_cfg_t region_cfg[] = { }, /* RO region */ { - PARTITION_REGION_RO, + 0, /* will be updated before using */ (uint32_t)®ION_NAME(Image$$, TFM_APP_CODE_START, $$Base), (uint32_t)®ION_NAME(Image$$, TFM_APP_CODE_END, $$Base), MPU_ARMV8M_MAIR_ATTR_CODE_IDX, @@ -125,7 +127,7 @@ const struct mpu_armv8m_region_cfg_t region_cfg[] = { }, /* RW, ZI and stack as one region */ { - PARTITION_REGION_RW_STACK, + 0, /* will be updated before using */ (uint32_t)®ION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base), (uint32_t)®ION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base), MPU_ARMV8M_MAIR_ATTR_DATA_IDX, @@ -136,7 +138,7 @@ const struct mpu_armv8m_region_cfg_t region_cfg[] = { #ifdef TFM_SP_META_PTR_ENABLE /* TFM partition metadata pointer region */ { - MPU_REGION_SP_META_PTR, + 0, /* will be updated before using */ (uint32_t)®ION_NAME(Image$$, TFM_SP_META_PTR, $$RW$$Base), (uint32_t)®ION_NAME(Image$$, TFM_SP_META_PTR, $$RW$$Limit), MPU_ARMV8M_MAIR_ATTR_DATA_IDX, @@ -158,34 +160,44 @@ enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(void) /* Set up static isolation boundaries inside SPE */ #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT + struct mpu_armv8m_region_cfg_t localcfg; int32_t i; - struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE }; mpu_armv8m_clean(&dev_mpu_s); #if TFM_LVL == 3 - uint32_t cnt; - - /* Update MPU region numbers. The numbers start from 0 and are continuous */ - cnt = sizeof(isolation_regions) / sizeof(isolation_regions[0]); - g_static_region_cnt = cnt; - for (i = 0; i < cnt; i++) { + /* + * Update MPU region numbers. The numbers start from 0 and are continuous. + * Under isolation level 3, at lease one MPU region is reserved for private + * data asset. + */ + if (ARRAY_SIZE(isolation_regions) >= MPU_REGION_NUM) { + return TFM_HAL_ERROR_GENERIC; + } + for (i = 0; i < ARRAY_SIZE(isolation_regions); i++) { + spm_memcpy(&localcfg, &isolation_regions[i], sizeof(localcfg)); /* Update region number */ - isolation_regions[i].region_nr = i; + localcfg.region_nr = i; /* Enable regions */ - if (mpu_armv8m_region_enable(&dev_mpu_s, &isolation_regions[i]) - != MPU_ARMV8M_OK) { + if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg) != MPU_ARMV8M_OK) { return TFM_HAL_ERROR_GENERIC; } + n_configured_regions = i; } #else /* TFM_LVL == 3 */ + if (ARRAY_SIZE(region_cfg) > MPU_REGION_NUM) { + return TFM_HAL_ERROR_GENERIC; + } for (i = 0; i < ARRAY_SIZE(region_cfg); i++) { + spm_memcpy(&localcfg, ®ion_cfg[i], sizeof(localcfg)); + localcfg.region_nr = i; if (mpu_armv8m_region_enable(&dev_mpu_s, - (struct mpu_armv8m_region_cfg_t *)®ion_cfg[i]) + (struct mpu_armv8m_region_cfg_t *)&localcfg) != MPU_ARMV8M_OK) { return TFM_HAL_ERROR_GENERIC; } } + n_configured_regions = i; #endif /* TFM_LVL == 3 */ /* Enable MPU */ @@ -199,26 +211,218 @@ enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(void) return TFM_HAL_SUCCESS; } +/* + * Implementation of tfm_hal_bind_boundaries() on STM: + * + * 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. + * + * The handle should be unique under isolation level 3. The implementation + * encodes an index at the highest 8 bits to assure handle uniqueness. While + * under isolation level 1/2, handles may not be unique. + * + * The encoding format assignment: + * - For isolation level 3 + * BIT | 31 24 | 23 20 | ... | 7 4 | 3 0 | + * | Unique Index | Region Attr 5 | ... | Region Attr 1 | Privileged | + * + * In which the "Region Attr i" is: + * BIT | 3 | 2 0 | + * | 1: RW, 0: RO | MMIO Index | + * + * - For isolation level 1/2 + * BIT | 31 0 | + * | 1: privileged, 0: unprivileged | + * + * This is a reference implementation on STM, and may have some limitations. + * 1. The maximum number of allowed MMIO regions is 5. + * 2. Highest 8 bits are for index. It supports 256 unique handles at most. + */ + +enum tfm_hal_status_t tfm_hal_bind_boundaries( + + const struct partition_load_info_t *p_ldinf, + void **pp_boundaries) +{ + uint32_t i, j; + bool privileged; + const struct asset_desc_t *p_asset; +#if TFM_LVL == 2 + struct platform_data_t *plat_data_ptr; + struct mpu_armv8m_region_cfg_t localcfg; +#elif TFM_LVL == 3 + uint32_t partition_attrs = 0; +#endif + + if (!p_ldinf || !pp_boundaries) { + return TFM_HAL_ERROR_GENERIC; + } + +#if TFM_LVL == 1 + privileged = true; +#else + privileged = !!(p_ldinf->flags & SPM_PART_FLAG_PSA_ROT); +#endif + + p_asset = (const struct asset_desc_t *)LOAD_INFO_ASSET(p_ldinf); + + /* + * Validate if the named MMIO of partition is allowed by the platform. + * Otherwise, skip validation. + * + * NOTE: Need to 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; + } +#if TFM_LVL == 2 + plat_data_ptr = REFERENCE_TO_PTR(p_asset[i].dev.dev_ref, + struct platform_data_t *); + /* + * 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; + } + } +#elif TFM_LVL == 3 + /* Encode MMIO attributes into the "partition_attrs". */ + partition_attrs <<= HANDLE_PER_ATTR_BITS; + partition_attrs |= ((j + 1) & HANDLE_ATTR_INDEX_MASK); + if (p_asset[i].attr & ASSET_ATTR_READ_WRITE) { + partition_attrs |= HANDLE_ATTR_RW_POS; + } +#endif + } + #if TFM_LVL == 3 -enum tfm_hal_status_t tfm_hal_mpu_update_partition_boundary(uintptr_t start, - uintptr_t end) + partition_attrs <<= HANDLE_PER_ATTR_BITS; + partition_attrs |= ((uint8_t)privileged) & HANDLE_ATTR_PRIV_MASK; + /* + * Highest 8 bits are reserved for index, if they are non-zero, MMIO numbers + * must have exceeded the limit of 5. + */ + if (partition_attrs & HANDLE_INDEX_MASK) { + return TFM_HAL_ERROR_GENERIC; + } + HANDLE_ENCODE_INDEX(partition_attrs, idx_boundary_handle); + *pp_boundaries = (void *)partition_attrs; +#else + *pp_boundaries = (void *)(((uint32_t)privileged) & HANDLE_ATTR_PRIV_MASK); +#endif + + return TFM_HAL_SUCCESS; +} + +enum tfm_hal_status_t tfm_hal_update_boundaries( + const struct partition_load_info_t *p_ldinf, + void *p_boundaries) { - struct mpu_armv8m_region_cfg_t cfg; - enum mpu_armv8m_error_t mpu_err; - struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE }; - - /* Partition boundary regions is right after static regions */ - cfg.region_nr = g_static_region_cnt; - cfg.region_base = start; - cfg.region_limit = end; - cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX; - cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV; - cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER; - cfg.attr_sh = MPU_ARMV8M_SH_NONE; - mpu_err = mpu_armv8m_region_enable(&dev_mpu_s, &cfg); - if (mpu_err != MPU_ARMV8M_OK) { + CONTROL_Type ctrl; + uint32_t local_handle = (uint32_t)p_boundaries; + bool privileged = !!(local_handle & HANDLE_ATTR_PRIV_MASK); +#if TFM_LVL == 3 + struct mpu_armv8m_region_cfg_t localcfg; + uint32_t i, mmio_index; + struct platform_data_t *plat_data_ptr; + struct asset_desc_t *rt_mem; +#endif + + /* Privileged level is required to be set always */ + ctrl.w = __get_CONTROL(); + ctrl.b.nPRIV = privileged ? 0 : 1; + __set_CONTROL(ctrl.w); + +#if TFM_LVL == 3 + if (!p_ldinf) { return TFM_HAL_ERROR_GENERIC; } + + /* Update regions, for unprivileged partitions only */ + if (privileged) { + return TFM_HAL_SUCCESS; + } + + /* Setup runtime memory first */ + localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER; + localcfg.attr_sh = MPU_ARMV8M_SH_NONE; + localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX; + localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV; + rt_mem = (struct asset_desc_t *)LOAD_INFO_ASSET(p_ldinf); + /* + * STM shortcut: The first item is the only runtime memory asset. + * Platforms with many memory assets please check this part. + */ + for (i = 0; + i < p_ldinf->nassets && !(rt_mem[i].attr & ASSET_ATTR_MMIO); + i++) { + localcfg.region_nr = n_configured_regions + i; + localcfg.region_base = rt_mem[i].mem.start; + localcfg.region_limit = rt_mem[i].mem.limit; + + if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg) != MPU_ARMV8M_OK) { + return TFM_HAL_ERROR_GENERIC; + } + } + + /* Named MMIO part */ + local_handle = local_handle & (~HANDLE_INDEX_MASK); + local_handle >>= HANDLE_PER_ATTR_BITS; + mmio_index = local_handle & HANDLE_ATTR_INDEX_MASK; + + localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX; + + i = n_configured_regions + i; + while (mmio_index && i < MPU_REGION_NUM) { + plat_data_ptr = + (struct platform_data_t *)partition_named_mmio_list[mmio_index - 1]; + localcfg.region_nr = i++; + localcfg.attr_access = (local_handle & HANDLE_ATTR_RW_POS)? + MPU_ARMV8M_AP_RW_PRIV_UNPRIV : + MPU_ARMV8M_AP_RO_PRIV_UNPRIV; + localcfg.region_base = plat_data_ptr->periph_start; + localcfg.region_limit = plat_data_ptr->periph_limit; + + if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg) != MPU_ARMV8M_OK) { + return TFM_HAL_ERROR_GENERIC; + } + + local_handle >>= HANDLE_PER_ATTR_BITS; + mmio_index = local_handle & HANDLE_ATTR_INDEX_MASK; + } + + /* Disable unused regions */ + while (i < MPU_REGION_NUM) { + if (mpu_armv8m_region_disable(&dev_mpu_s, i++)!= MPU_ARMV8M_OK) { + return TFM_HAL_ERROR_GENERIC; + } + } +#endif return TFM_HAL_SUCCESS; } -#endif /* TFM_LVL == 3 */ diff --git a/platform/ext/target/stm/stm32l562e_dk/readme.rst b/platform/ext/target/stm/stm32l562e_dk/readme.rst index 7dd0e880d2..4a8704a757 100644 --- a/platform/ext/target/stm/stm32l562e_dk/readme.rst +++ b/platform/ext/target/stm/stm32l562e_dk/readme.rst @@ -11,7 +11,7 @@ and build the selected configuration as follow. ``> mkdir build && cd build`` -``> cmake .. -DTFM_PLATFORM=stm/stm32l562e-dk -DTFM_TOOLCHAIN_FILE=../toolchain_GNUARM.cmake -G"Unix Makefiles"`` +``> cmake .. -DTFM_PLATFORM=stm/stm32l562e_dk -DTFM_TOOLCHAIN_FILE=../toolchain_GNUARM.cmake -G"Unix Makefiles"`` ``> cmake --build ./ -- install`` |