SPM: Get "ns_caller" information from caller info

The "ns_caller" was passed to PSA API bodies as an argument.

This patch:
- Moves the non-secure caller check related codes into
  "tfm_spm_validate_caller()".
- Removes the arg "ns_caller" of PSA APIs, and changes to
  acquire "ns_caller" from the caller info.

Two cases for acquiring the "ns_caller":
- In multi-core topology, PSA API requests are processed via
  mailbox, which triggers pendSV. If PSA API is called from pendSV,
  caller is NS.
- Otherwise, caller security state is obtained from running
  partition load info.

Change-Id: I29d0a522fc4f50a258c9d12102ecdb5c35f4a5e1
Signed-off-by: Mingyang Sun <mingyang.sun@arm.com>
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.c b/secure_fw/spm/cmsis_psa/spm_ipc.c
index 5b6065c..42ef5a2 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.c
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.c
@@ -27,6 +27,7 @@
 #include "tfm_core_trustzone.h"
 #include "lists.h"
 #include "tfm_pools.h"
+#include "region.h"
 #include "psa_manifest/pid.h"
 #include "tfm/tfm_spm_services.h"
 #include "load/partition_defs.h"
@@ -44,6 +45,10 @@
 TFM_POOL_DECLARE(conn_handle_pool, sizeof(struct tfm_conn_handle_t),
                  TFM_CONN_HANDLE_MAX_NUM);
 
+/* The veneer section names come from the scatter file */
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
+
 void spm_interrupt_handler(struct partition_load_info_t *p_ldinf,
                            psa_signal_t signal,
                            uint32_t irq_line,
@@ -603,6 +608,21 @@
     return SPM_ERROR_MEMORY_CHECK;
 }
 
+bool tfm_spm_is_ns_caller(void)
+{
+#if defined(TFM_MULTI_CORE_TOPOLOGY) || defined(FORWARD_PROT_MSG)
+    /* Multi-core NS PSA API request is processed by pendSV. */
+    return (__get_active_exc_num() == EXC_NUM_PENDSV);
+#else
+    struct partition_t *partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_core_panic();
+    }
+
+    return (partition->p_ldinf->pid == TFM_SP_NON_SECURE_ID);
+#endif
+}
+
 uint32_t tfm_spm_init(void)
 {
     uint32_t i;
@@ -948,24 +968,47 @@
 }
 
 #if !defined(__ARM_ARCH_8_1M_MAIN__)
-void tfm_spm_validate_caller(struct partition_t *p_cur_sp, uint32_t *p_ctx,
-                             uint32_t exc_return, bool ns_caller)
+void tfm_spm_validate_caller(uint32_t *p_ctx, uint32_t exc_return)
 {
+    /*
+     * TODO: the reentrant detection mechanism needs to be changed when there
+     * is no boundaries.
+     */
     uintptr_t stacked_ctx_pos;
+    bool ns_caller = false;
+    struct partition_t *p_cur_sp = tfm_spm_get_running_partition();
+    uint32_t veneer_base =
+        (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
+    uint32_t veneer_limit =
+        (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
+
+    if (!p_cur_sp) {
+        tfm_core_panic();
+    }
+
+    /*
+     * The caller security attribute detection bases on LR of state context.
+     * However, if SP calls PSA APIs based on its customized SVC, the LR may be
+     * occupied by general purpose value while calling SVC.
+     * Check if caller comes from non-secure: return address (p_ctx[6]) belongs
+     * to veneer section, and the bit0 of LR (p_ctx[5]) is zero.
+     */
+    if (p_ctx[6] >= veneer_base && p_ctx[6] < veneer_limit &&
+        !(p_ctx[5] & TFM_VENEER_LR_BIT0_MASK)) {
+        ns_caller = true;
+    }
+
+    /* If called from ns, partition ID should be TFM_SP_NON_SECURE_ID. */
+    if ((ns_caller == true) !=
+        (p_cur_sp->p_ldinf->pid == TFM_SP_NON_SECURE_ID)) {
+            tfm_core_panic();
+    }
 
     if (ns_caller) {
         /*
          * The background IRQ can't be supported, since if SP is executing,
          * the preempted context of SP can be different with the one who
-         * preempts veneer.
-         */
-        if (p_cur_sp->p_ldinf->pid != TFM_SP_NON_SECURE_ID) {
-            tfm_core_panic();
-        }
-
-        /*
-         * It is non-secure caller, check if veneer stack contains
-         * multiple contexts.
+         * preempts veneer. Check if veneer stack contains multiple contexts.
          */
         stacked_ctx_pos = (uintptr_t)p_ctx +
                           sizeof(struct tfm_state_context_t) +
@@ -984,8 +1027,6 @@
         if (stacked_ctx_pos != p_cur_sp->sp_thread.stk_top) {
             tfm_core_panic();
         }
-    } else if (p_cur_sp->p_ldinf->pid <= 0) {
-        tfm_core_panic();
     }
 }
 #endif