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)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+    uint32_t scratch_limit =
+        (uint32_t)&REGION_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)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
-    uint32_t scratch_limit =
-        (uint32_t)&REGION_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"