Core: Split memory access check from tfm_secure_api.c/.h
Diverse topologies require different memory access check
implementations. Split single Armv8-M memory access functions and
API definitions from common TF-M secure operations.
Thus different topologies can continue sharing the same TF-M secure
operations in tfm_secure_api.c and implement own memory access
functionalities.
Change-Id: I789e712a5d0e3b4127e6710846f2a2b0f612dba7
Signed-off-by: David Hu <david.hu@arm.com>
diff --git a/secure_fw/core/CMakeLists.inc b/secure_fw/core/CMakeLists.inc
index 22a742a..8603ab8 100644
--- a/secure_fw/core/CMakeLists.inc
+++ b/secure_fw/core/CMakeLists.inc
@@ -39,6 +39,7 @@
"${SS_CORE_DIR}/tfm_nspm.c"
"${SS_CORE_DIR}/tfm_boot_data.c"
"${SS_CORE_DIR}/tfm_utils.c"
+ "${SS_CORE_DIR}/tfm_core_mem_check.c"
)
#Append all our source files to global lists.
diff --git a/secure_fw/core/ipc/CMakeLists.inc b/secure_fw/core/ipc/CMakeLists.inc
index c2e385a..027a882 100644
--- a/secure_fw/core/ipc/CMakeLists.inc
+++ b/secure_fw/core/ipc/CMakeLists.inc
@@ -47,6 +47,7 @@
"${SS_IPC_DIR}/../tfm_handler.c"
"${SS_IPC_DIR}/../tfm_nspm.c"
"${SS_IPC_DIR}/../tfm_boot_data.c"
+ "${SS_IPC_DIR}/../tfm_core_mem_check.c"
)
endif()
diff --git a/secure_fw/core/tfm_core_mem_check.c b/secure_fw/core/tfm_core_mem_check.c
new file mode 100644
index 0000000..d6d7354
--- /dev/null
+++ b/secure_fw/core/tfm_core_mem_check.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arm_cmse.h>
+#include "region_defs.h"
+#include "secure_fw/spm/spm_api.h"
+#include "tfm_api.h"
+
+#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
+/* Macros to pick linker symbols and allow references to sections */
+#define REGION(a, b, c) a##b##c
+#define REGION_NAME(a, b, c) REGION(a, b, c)
+#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
+
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+#endif /* !defined(TFM_PSA_API) */
+
+/**
+ * \brief Check whether the current partition has access to a memory range
+ *
+ * This function assumes, that the current MPU configuration is set for the
+ * partition to be checked. The flags should contain information of the
+ * execution mode of the partition code (priv/unpriv), and access type
+ * (read/write) as specified in "ARMv8-M Security Extensions: Requirements on
+ * Development Tools" chapter "Address range check intrinsic"
+ *
+ * \param[in] p The start address of the range to check
+ * \param[in] s The size of the range to check
+ * \param[in] flags The flags to pass to the cmse_check_address_range func
+ *
+ * \return TFM_SUCCESS if the partition has access to the memory range,
+ * TFM_ERROR_GENERIC otherwise.
+ */
+static enum tfm_status_e has_access_to_region(const void *p, size_t s,
+ int flags)
+{
+ int32_t range_access_allowed_by_mpu;
+
+#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
+ 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);
+#endif /* !defined(TFM_PSA_API) */
+
+ /* Use the TT instruction to check access to the partition's regions*/
+ range_access_allowed_by_mpu =
+ cmse_check_address_range((void *)p, s, flags) != NULL;
+
+ if (range_access_allowed_by_mpu) {
+ return TFM_SUCCESS;
+ }
+
+#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
+ /* If the check for the current MPU settings fails, check for the share
+ * region, only if the partition is secure
+ */
+ if ((flags & CMSE_NONSECURE) == 0) {
+ if (check_address_range(p, s, scratch_base,
+ scratch_limit) == TFM_SUCCESS) {
+ return TFM_SUCCESS;
+ }
+ }
+#endif /* !defined(TFM_PSA_API) */
+
+ /* If all else fails, check whether the region is in the non-secure
+ * memory
+ */
+ if ((check_address_range(p, s, NS_CODE_START,
+ NS_CODE_LIMIT) == TFM_SUCCESS) ||
+ (check_address_range(p, s, NS_DATA_START,
+ NS_DATA_LIMIT) == TFM_SUCCESS)) {
+ return TFM_SUCCESS;
+ } else {
+ return TFM_ERROR_GENERIC;
+ }
+}
+
+enum tfm_status_e tfm_core_has_read_access_to_region(const void *p, size_t s,
+ uint32_t ns_caller,
+ uint32_t privileged)
+{
+ int flags = CMSE_MPU_READ;
+
+ if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
+ flags |= CMSE_MPU_UNPRIV;
+ }
+
+ if (ns_caller) {
+ flags |= CMSE_NONSECURE;
+ }
+
+ return has_access_to_region(p, s, flags);
+}
+
+enum tfm_status_e tfm_core_has_write_access_to_region(const void *p, size_t s,
+ uint32_t ns_caller,
+ uint32_t privileged)
+{
+ int flags = CMSE_MPU_READWRITE;
+
+ if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
+ flags |= CMSE_MPU_UNPRIV;
+ }
+
+ if (ns_caller) {
+ flags |= CMSE_NONSECURE;
+ }
+
+ return has_access_to_region(p, s, flags);
+}
diff --git a/secure_fw/core/tfm_core_mem_check.h b/secure_fw/core/tfm_core_mem_check.h
new file mode 100644
index 0000000..b90c439
--- /dev/null
+++ b/secure_fw/core/tfm_core_mem_check.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_CORE_MEM_CHECK_H__
+#define __TFM_CORE_MEM_CHECK_H__
+
+#include "tfm_api.h"
+
+/**
+ * \brief Check whether the current partition has read access to a memory range
+ *
+ * This function assumes, that the current MPU configuration is set for the
+ * partition to be checked.
+ *
+ * \param[in] p The start address of the range to check
+ * \param[in] s The size of the range to check
+ * \param[in] ns_caller Whether the current partition is non-secure
+ * \param[in] privileged Privileged mode or unprivileged mode:
+ * \ref TFM_PARTITION_UNPRIVILEGED_MODE
+ * \ref TFM_PARTITION_PRIVILEGED_MODE
+ *
+ * \return TFM_SUCCESS if the partition has access to the memory range,
+ * TFM_ERROR_GENERIC otherwise.
+ */
+enum tfm_status_e tfm_core_has_read_access_to_region(const void *p, size_t s,
+ uint32_t ns_caller,
+ uint32_t privileged);
+
+/**
+ * \brief Check whether the current partition has write access to a memory range
+ *
+ * This function assumes, that the current MPU configuration is set for the
+ * partition to be checked.
+ *
+ * \param[in] p The start address of the range to check
+ * \param[in] s The size of the range to check
+ * \param[in] ns_caller Whether the current partition is non-secure
+ * \param[in] privileged Privileged mode or unprivileged mode:
+ * \ref TFM_PARTITION_UNPRIVILEGED_MODE
+ * \ref TFM_PARTITION_PRIVILEGED_MODE
+ *
+ * \return TFM_SUCCESS if the partition has access to the memory range,
+ * TFM_ERROR_GENERIC otherwise.
+ */
+enum tfm_status_e tfm_core_has_write_access_to_region(const void *p, size_t s,
+ uint32_t ns_caller,
+ uint32_t privileged);
+
+#endif /* __TFM_CORE_MEM_CHECK_H__ */
diff --git a/secure_fw/core/tfm_func_api.c b/secure_fw/core/tfm_func_api.c
index 8f08508..6d067c1 100644
--- a/secure_fw/core/tfm_func_api.c
+++ b/secure_fw/core/tfm_func_api.c
@@ -10,7 +10,6 @@
#include <stdint.h>
#include <stdbool.h>
#include <arm_cmse.h>
-#include "tfm_secure_api.h"
#include "tfm_nspm.h"
#include "secure_utilities.h"
#include "uart_stdout.h"
@@ -21,6 +20,7 @@
#include "platform/include/tfm_spm_hal.h"
#include "tfm_irq_list.h"
#include "psa/service.h"
+#include "tfm_core_mem_check.h"
#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
#define EXC_RETURN_SECURE_HANDLER 0xFFFFFFF1
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index 6555fcb..f713b03 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -5,32 +5,9 @@
*
*/
-#include <stdio.h>
-#include <string.h>
#include <stdbool.h>
-#include <arm_cmse.h>
+#include "secure_utilities.h"
#include "tfm_secure_api.h"
-#include "tfm_nspm.h"
-#include "uart_stdout.h"
-#include "secure_fw/spm/spm_api.h"
-#include "region_defs.h"
-#include "tfm_api.h"
-
-#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
-
-#ifndef TFM_LVL
-#error TFM_LVL is not defined!
-#endif
-
-/* Macros to pick linker symbols and allow references to sections */
-#define REGION(a, b, c) a##b##c
-#define REGION_NAME(a, b, c) REGION(a, b, c)
-#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
-
-#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
-REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
-REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
-#endif /* !defined(TFM_PSA_API) */
/* This is the "Big Lock" on the secure side, to guarantee single entry
* to SPE
@@ -52,27 +29,14 @@
return ((n && !(n & (n-1))) ? true : false);
}
-/**
- * \brief Check whether a memory range is inside a memory region.
- *
- * \param[in] p The start address of the range to check
- * \param[in] s The size of the range to check
- * \param[in] region_start The start address of the region, which should
- * contain the range
- * \param[in] region_len The size of the region, which should contain the
- * range
- *
- * \return TFM_SUCCESS if the region contains the range,
- * TFM_ERROR_GENERIC otherwise.
- */
-static enum tfm_status_e check_address_range(const void *p, size_t s,
- uintptr_t region_start,
- uint32_t region_len)
+enum tfm_status_e check_address_range(const void *p, size_t s,
+ uintptr_t region_start,
+ uintptr_t region_limit)
{
int32_t range_in_region;
/* Check for overflow in the range parameters */
- if ((uintptr_t)p > UINTPTR_MAX-s) {
+ if ((uintptr_t)p > UINTPTR_MAX - s) {
return TFM_ERROR_GENERIC;
}
@@ -80,7 +44,7 @@
/* Calculate the result */
range_in_region = ((uintptr_t)p >= region_start) &&
- ((uintptr_t)p+s <= region_start+region_len);
+ ((uintptr_t)(p + s - 1) <= region_limit);
if (range_in_region) {
return TFM_SUCCESS;
} else {
@@ -88,101 +52,6 @@
}
}
-/**
- * \brief Check whether the current partition has access to a memory range
- *
- * This function assumes, that the current MPU configuration is set for the
- * partition to be checked. The flags should contain information of the
- * execution mode of the partition code (priv/unpriv), and access type
- * (read/write) as specified in "ARMv8-M Security Extensions: Requirements on
- * Development Tools" chapter "Address range check intrinsic"
- *
- * \param[in] p The start address of the range to check
- * \param[in] s The size of the range to check
- * \param[in] flags The flags to pass to the cmse_check_address_range func
- *
- * \return TFM_SUCCESS if the partition has access to the memory range,
- * TFM_ERROR_GENERIC otherwise.
- */
-static enum tfm_status_e has_access_to_region(const void *p, size_t s,
- int flags)
-{
- int32_t range_access_allowed_by_mpu;
-
-#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
- 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);
-#endif /* !defined(TFM_PSA_API) */
-
- /* Use the TT instruction to check access to the partition's regions*/
- range_access_allowed_by_mpu =
- cmse_check_address_range((void *)p, s, flags) != NULL;
-
- if (range_access_allowed_by_mpu) {
- return TFM_SUCCESS;
- }
-
-#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
- /* If the check for the current MPU settings fails, check for the share
- * region, only if the partition is secure
- */
- if ((flags & CMSE_NONSECURE) == 0) {
- if (check_address_range(p, s, scratch_base,
- scratch_limit+1-scratch_base) == TFM_SUCCESS) {
- return TFM_SUCCESS;
- }
- }
-#endif /* !defined(TFM_PSA_API) */
-
- /* If all else fails, check whether the region is in the non-secure
- * memory
- */
- if (check_address_range(p, s, NS_CODE_START,
- NS_CODE_LIMIT+1-NS_CODE_START) == TFM_SUCCESS ||
- check_address_range(p, s, NS_DATA_START,
- NS_DATA_LIMIT+1-NS_DATA_START) == TFM_SUCCESS) {
- return TFM_SUCCESS;
- } else {
- return TFM_ERROR_GENERIC;
- }
-}
-
-enum tfm_status_e tfm_core_has_read_access_to_region(const void *p, size_t s,
- uint32_t ns_caller,
- uint32_t privileged)
-{
- int flags = CMSE_MPU_READ;
-
- if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
- flags |= CMSE_MPU_UNPRIV;
- }
-
- if (ns_caller) {
- flags |= CMSE_NONSECURE;
- }
-
- return has_access_to_region(p, s, flags);
-}
-
-enum tfm_status_e tfm_core_has_write_access_to_region(const void *p, size_t s,
- uint32_t ns_caller,
- uint32_t privileged)
-{
- int flags = CMSE_MPU_READWRITE;
-
- if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
- flags |= CMSE_MPU_UNPRIV;
- }
-
- if (ns_caller) {
- flags |= CMSE_NONSECURE;
- }
-
- return has_access_to_region(p, s, flags);
-}
-
void tfm_secure_api_error_handler(void)
{
ERROR_MSG("Security violation when calling secure API");
@@ -190,4 +59,3 @@
;
}
}
-
diff --git a/secure_fw/core/tfm_secure_api.h b/secure_fw/core/tfm_secure_api.h
index c626df1..68df628 100644
--- a/secure_fw/core/tfm_secure_api.h
+++ b/secure_fw/core/tfm_secure_api.h
@@ -91,44 +91,21 @@
int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
/**
- * \brief Check whether the current partition has read access to a memory range
+ * \brief Check whether a memory range is inside a memory region.
*
- * This function assumes, that the current MPU configuration is set for the
- * partition to be checked.
+ * \param[in] p The start address of the range to check
+ * \param[in] s The size of the range to check
+ * \param[in] region_start The start address of the region, which should
+ * contain the range
+ * \param[in] region_limit The end address of the region, which should contain
+ * the range
*
- * \param[in] p The start address of the range to check
- * \param[in] s The size of the range to check
- * \param[in] ns_caller Whether the current partition is a non-secure one
- * \param[in] privileged Privileged mode or unprivileged mode:
- * \ref TFM_PARTITION_UNPRIVILEGED_MODE
- * \ref TFM_PARTITION_PRIVILEGED_MODE
- *
- * \return TFM_SUCCESS if the partition has access to the memory range,
+ * \return TFM_SUCCESS if the region contains the range,
* TFM_ERROR_GENERIC otherwise.
*/
-enum tfm_status_e tfm_core_has_read_access_to_region(const void *p, size_t s,
- uint32_t ns_caller,
- uint32_t privileged);
-
-/**
- * \brief Check whether the current partition has write access to a memory range
- *
- * This function assumes, that the current MPU configuration is set for the
- * partition to be checked.
- *
- * \param[in] p The start address of the range to check
- * \param[in] s The size of the range to check
- * \param[in] ns_caller Whether the current partition is a non-secure one
- * \param[in] privileged Privileged mode or unprivileged mode:
- * \ref TFM_PARTITION_UNPRIVILEGED_MODE
- * \ref TFM_PARTITION_PRIVILEGED_MODE
- *
- * \return TFM_SUCCESS if the partition has access to the memory range,
- * TFM_ERROR_GENERIC otherwise.
- */
-enum tfm_status_e tfm_core_has_write_access_to_region(const void *p, size_t s,
- uint32_t ns_caller,
- uint32_t privileged);
+enum tfm_status_e check_address_range(const void *p, size_t s,
+ uintptr_t region_start,
+ uintptr_t region_limit);
void tfm_enable_irq(psa_signal_t irq_signal);
void tfm_disable_irq(psa_signal_t irq_signal);
diff --git a/secure_fw/spm/spm_api_ipc.c b/secure_fw/spm/spm_api_ipc.c
index 24fd179..b05ec81 100644
--- a/secure_fw/spm/spm_api_ipc.c
+++ b/secure_fw/spm/spm_api_ipc.c
@@ -17,6 +17,7 @@
#include "tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
+#include "tfm_core_mem_check.h"
#include "tfm_internal_defines.h"
#include "tfm_wait.h"
#include "tfm_message_queue.h"