Core: Support isolation 2 memory check

In isolation level 2, the secure partition is divided
into two modes: privileged mode or unprivileged mode.
Add privileged setting check while performing memory
check.

Change-Id: I3a23df9aea34920f662a36e1389063d591b37119
Signed-off-by: Summer Qin <summer.qin@arm.com>
diff --git a/secure_fw/core/ipc/include/tfm_spm.h b/secure_fw/core/ipc/include/tfm_spm.h
index 62adf34..83c5172 100644
--- a/secure_fw/core/ipc/include/tfm_spm.h
+++ b/secure_fw/core/ipc/include/tfm_spm.h
@@ -71,6 +71,16 @@
  */
 uint32_t tfm_spm_partition_get_running_partition_id_ext(void);
 
+/**
+ * \brief                   Get the current partition mode.
+ *
+ * \param[in] partition_idx                 Index of current partition
+ *
+ * \retval TFM_PARTITION_PRIVILEGED_MODE    Privileged mode
+ * \retval TFM_PARTITION_UNPRIVILEGED_MODE  Unprivileged mode
+ */
+uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_idx);
+
 /******************** Service handle management functions ********************/
 
 /**
@@ -275,20 +285,24 @@
                                      uint32_t minor_version);
 
 /**
- * \brief                   Check the memory reference is valid.
+ * \brief                      Check the memory reference is valid.
  *
- * \param[in] buffer        Pointer of memory reference
- * \param[in] len           Length of memory reference in bytes
- * \param[in] ns_caller     From non-secure caller
- * \param[in] access        Type of access specified by the
- *                          \ref tfm_memory_access_e
+ * \param[in] buffer           Pointer of memory reference
+ * \param[in] len              Length of memory reference in bytes
+ * \param[in] ns_caller        From non-secure caller
+ * \param[in] access           Type of access specified by the
+ *                             \ref tfm_memory_access_e
+ * \param[in] privileged       Privileged mode or unprivileged mode:
+ *                             \ref TFM_PARTITION_UNPRIVILEGED_MODE
+ *                             \ref TFM_PARTITION_PRIVILEGED_MODE
  *
- * \retval IPC_SUCCESS      Success
- * \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
- * \retval IPC_ERROR_MEMORY_CHECK Check failed
+ * \retval IPC_SUCCESS               Success
+ * \retval IPC_ERROR_BAD_PARAMETERS  Bad parameters input
+ * \retval IPC_ERROR_MEMORY_CHECK    Check failed
  */
 int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller,
-                         enum tfm_memory_access_e access);
+                         enum tfm_memory_access_e access,
+                         uint32_t privileged);
 
 /* This function should be called before schedule function */
 void tfm_spm_init(void);
diff --git a/secure_fw/core/ipc/tfm_spm.c b/secure_fw/core/ipc/tfm_spm.c
index 50aa249..1ecc1a4 100644
--- a/secure_fw/core/ipc/tfm_spm.c
+++ b/secure_fw/core/ipc/tfm_spm.c
@@ -455,9 +455,9 @@
                     partition_priority;
 }
 
-/* FixMe: This is only valid for TFM LVL 1 now */
 int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller,
-                         enum tfm_memory_access_e access)
+                         enum tfm_memory_access_e access,
+                         uint32_t privileged)
 {
     int32_t err;
 
@@ -475,9 +475,11 @@
     }
 
     if (access == TFM_MEMORY_ACCESS_RW) {
-        err = tfm_core_has_write_access_to_region(buffer, len, ns_caller);
+        err = tfm_core_has_write_access_to_region(buffer, len, ns_caller,
+                                                  privileged);
     } else {
-        err = tfm_core_has_read_access_to_region(buffer, len, ns_caller);
+        err = tfm_core_has_read_access_to_region(buffer, len, ns_caller,
+                                                 privileged);
     }
     if (err == TFM_SUCCESS) {
         return IPC_SUCCESS;
@@ -486,6 +488,15 @@
     return IPC_ERROR_MEMORY_CHECK;
 }
 
+uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_idx)
+{
+    if (tfm_spm_partition_get_flags(partition_idx) & SPM_PART_FLAG_PSA_ROT) {
+        return TFM_PARTITION_PRIVILEGED_MODE;
+    } else {
+        return TFM_PARTITION_UNPRIVILEGED_MODE;
+    }
+}
+
 /********************** SPM functions for thread mode ************************/
 
 void tfm_spm_init(void)
diff --git a/secure_fw/core/ipc/tfm_svcalls.c b/secure_fw/core/ipc/tfm_svcalls.c
index 29f9130..49b009f 100644
--- a/secure_fw/core/ipc/tfm_svcalls.c
+++ b/secure_fw/core/ipc/tfm_svcalls.c
@@ -21,6 +21,7 @@
 #include "tfm_api.h"
 #include "tfm_secure_api.h"
 #include "tfm_memory_utils.h"
+#include "spm_api.h"
 
 #define PSA_TIMEOUT_MASK        PSA_BLOCK
 
@@ -116,9 +117,18 @@
     struct tfm_spm_service_t *service;
     struct tfm_msg_body_t *msg;
     int i;
+    struct tfm_spm_ipc_partition_t *partition = NULL;
+    uint32_t privileged;
 
     TFM_ASSERT(args != NULL);
     handle = (psa_handle_t)args[0];
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_panic();
+    }
+    privileged = tfm_spm_partition_get_privileged_mode(partition->index);
+
     if (!ns_caller) {
         inptr = (psa_invec *)args[1];
         in_num = (size_t)args[2];
@@ -153,11 +163,11 @@
          * memory reference for buffer is invalid or not readable.
          */
         if (tfm_memory_check((void *)args[1], sizeof(uint32_t),
-            ns_caller, TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
+            ns_caller, TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
             tfm_panic();
         }
         if (tfm_memory_check((void *)args[2], sizeof(uint32_t),
-            ns_caller, TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
+            ns_caller, TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
             tfm_panic();
         }
 
@@ -185,7 +195,7 @@
      * readable.
      */
     if (tfm_memory_check((void *)inptr, in_num * sizeof(psa_invec),
-        ns_caller, TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
+        ns_caller, TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
         tfm_panic();
     }
     /*
@@ -194,7 +204,7 @@
      * the wrap output vector is invalid or not read-write.
      */
     if (tfm_memory_check((void *)outptr, out_num * sizeof(psa_outvec),
-        ns_caller, TFM_MEMORY_ACCESS_RW) != IPC_SUCCESS) {
+        ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
         tfm_panic();
     }
 
@@ -211,7 +221,7 @@
      */
     for (i = 0; i < in_num; i++) {
         if (tfm_memory_check((void *)invecs[i].base, invecs[i].len,
-            ns_caller, TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
+            ns_caller, TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
             tfm_panic();
         }
     }
@@ -221,7 +231,7 @@
      */
     for (i = 0; i < out_num; i++) {
         if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
-            ns_caller, TFM_MEMORY_ACCESS_RW) != IPC_SUCCESS) {
+            ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
             tfm_panic();
         }
     }
@@ -363,6 +373,7 @@
     struct tfm_spm_service_t *service = NULL;
     struct tfm_msg_body_t *tmp_msg = NULL;
     struct tfm_spm_ipc_partition_t *partition = NULL;
+    uint32_t privileged;
 
     TFM_ASSERT(args != NULL);
     signal = (psa_signal_t)args[0];
@@ -376,17 +387,18 @@
         tfm_panic();
     }
 
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_panic();
+    }
+    privileged = tfm_spm_partition_get_privileged_mode(partition->index);
+
     /*
      * Write the message to the service buffer. It is a fatal error if the
      * input msg pointer is not a valid memory reference or not read-write.
      */
     if (tfm_memory_check((void *)msg, sizeof(psa_msg_t),
-        false, TFM_MEMORY_ACCESS_RW) != IPC_SUCCESS) {
-        tfm_panic();
-    }
-
-    partition = tfm_spm_get_running_partition();
-    if (!partition) {
+        false, TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
         tfm_panic();
     }
 
@@ -499,6 +511,8 @@
     size_t num_bytes;
     size_t bytes;
     struct tfm_msg_body_t *msg = NULL;
+    uint32_t privileged;
+    struct tfm_spm_ipc_partition_t *partition = NULL;
 
     TFM_ASSERT(args != NULL);
     msg_handle = (psa_handle_t)args[0];
@@ -512,6 +526,9 @@
         tfm_panic();
     }
 
+    partition = msg->service->partition;
+    privileged = tfm_spm_partition_get_privileged_mode(partition->index);
+
     /*
      * It is a fatal error if message handle does not refer to a PSA_IPC_CALL
      * message
@@ -538,7 +555,7 @@
      * if the memory reference for buffer is invalid or not read-write.
      */
     if (tfm_memory_check(buffer, num_bytes, false,
-        TFM_MEMORY_ACCESS_RW) != IPC_SUCCESS) {
+        TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
         tfm_panic();
     }
 
@@ -650,6 +667,8 @@
     void *buffer = NULL;
     size_t num_bytes;
     struct tfm_msg_body_t *msg = NULL;
+    uint32_t privileged;
+    struct tfm_spm_ipc_partition_t *partition = NULL;
 
     TFM_ASSERT(args != NULL);
     msg_handle = (psa_handle_t)args[0];
@@ -663,6 +682,9 @@
         tfm_panic();
     }
 
+    partition = msg->service->partition;
+    privileged = tfm_spm_partition_get_privileged_mode(partition->index);
+
     /*
      * It is a fatal error if message handle does not refer to a PSA_IPC_CALL
      * message
@@ -693,7 +715,7 @@
      * if the memory reference for buffer is invalid or not readable.
      */
     if (tfm_memory_check(buffer, num_bytes, false,
-        TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
+        TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
         tfm_panic();
     }
 
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index c2c89b2..4687342 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -204,9 +204,14 @@
 }
 
 int32_t tfm_core_has_read_access_to_region(const void *p, size_t s,
-                                           uint32_t ns_caller)
+                                           uint32_t ns_caller,
+                                           uint32_t privileged)
 {
-    int flags = CMSE_MPU_UNPRIV|CMSE_MPU_READ;
+    int flags = CMSE_MPU_READ;
+
+    if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
+        flags |= CMSE_MPU_UNPRIV;
+    }
 
     if (ns_caller) {
         flags |= CMSE_NONSECURE;
@@ -216,9 +221,14 @@
 }
 
 int32_t tfm_core_has_write_access_to_region(void *p, size_t s,
-                                            uint32_t ns_caller)
+                                            uint32_t ns_caller,
+                                            uint32_t privileged)
 {
-    int flags = CMSE_MPU_UNPRIV|CMSE_MPU_READWRITE;
+    int flags = CMSE_MPU_READWRITE;
+
+    if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
+        flags |= CMSE_MPU_UNPRIV;
+    }
 
     if (ns_caller) {
         flags |= CMSE_NONSECURE;
@@ -264,8 +274,8 @@
     if (in_len > 0) {
         if ((in_vec == NULL) ||
             (tfm_core_has_write_access_to_region(in_vec,
-                                        sizeof(psa_invec)*in_len,
-                                        desc_ptr->ns_caller) != TFM_SUCCESS)) {
+                            sizeof(psa_invec)*in_len, desc_ptr->ns_caller,
+                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
             return TFM_ERROR_INVALID_PARAMETER;
         }
     } else {
@@ -276,8 +286,8 @@
     if (out_len > 0) {
         if ((out_vec == NULL) ||
             (tfm_core_has_write_access_to_region(out_vec,
-                                        sizeof(psa_outvec)*out_len,
-                                        desc_ptr->ns_caller) != TFM_SUCCESS)) {
+                            sizeof(psa_outvec)*out_len, desc_ptr->ns_caller,
+                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
             return TFM_ERROR_INVALID_PARAMETER;
         }
     } else {
@@ -293,8 +303,8 @@
         if (in_vec[i].len > 0) {
             if ((in_vec[i].base == NULL) ||
                 (tfm_core_has_read_access_to_region(in_vec[i].base,
-                                        in_vec[i].len,
-                                        desc_ptr->ns_caller) != TFM_SUCCESS)) {
+                            in_vec[i].len, desc_ptr->ns_caller,
+                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
                 return TFM_ERROR_INVALID_PARAMETER;
             }
         }
@@ -303,8 +313,8 @@
         if (out_vec[i].len > 0) {
             if ((out_vec[i].base == NULL) ||
                 (tfm_core_has_write_access_to_region(out_vec[i].base,
-                                        out_vec[i].len,
-                                        desc_ptr->ns_caller) != TFM_SUCCESS)) {
+                            out_vec[i].len, desc_ptr->ns_caller,
+                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
                 return TFM_ERROR_INVALID_PARAMETER;
             }
         }
diff --git a/secure_fw/core/tfm_secure_api.h b/secure_fw/core/tfm_secure_api.h
index 88392a9..23bcd40 100644
--- a/secure_fw/core/tfm_secure_api.h
+++ b/secure_fw/core/tfm_secure_api.h
@@ -96,15 +96,19 @@
  * 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] 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.
  */
 int32_t tfm_core_has_read_access_to_region(const void *p, size_t s,
-                                           uint32_t ns_caller);
+                                           uint32_t ns_caller,
+                                           uint32_t privileged);
 
 /**
  * \brief Check whether the current partition has write access to a memory range
@@ -112,15 +116,19 @@
  * 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] 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.
  */
 int32_t tfm_core_has_write_access_to_region(void *p, size_t s,
-                                            uint32_t ns_caller);
+                                            uint32_t ns_caller,
+                                            uint32_t privileged);
 
 #define TFM_CORE_IOVEC_SFN_REQUEST(id, fn, a, b, c, d) \
         return tfm_core_partition_request(id, fn, TFM_SFN_API_IOVEC, \
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index 67accd5..87cc4e2 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -15,6 +15,10 @@
 
 #define SPM_INVALID_PARTITION_IDX     (~0U)
 
+/* Privileged definitions for partition thread mode */
+#define TFM_PARTITION_PRIVILEGED_MODE   1
+#define TFM_PARTITION_UNPRIVILEGED_MODE 0
+
 enum spm_err_t {
     SPM_ERR_OK = 0,
     SPM_ERR_PARTITION_DB_NOT_INIT,