Core: Add non-secure thread entry

The non-secure thread entry is used to replace the idle thread.
It takes over the main init process, and jump to the non-secure
world at last.
- Set the non-secure thread entry with the lowest priority.
- Delete the idle thread which is unused anymore.
- Refine tfm_pendsv_do_schedule() function, does not need to handle
  the idle thread.

Change-Id: Id2b04647db26b92c61f5f63fb0ac0f814a55aab4
Signed-off-by: Edison Ai <edison.ai@arm.com>
diff --git a/platform/ext/target/mps2/an521/spm_hal.c b/platform/ext/target/mps2/an521/spm_hal.c
index d7a3bb0..9b05a75 100644
--- a/platform/ext/target/mps2/an521/spm_hal.c
+++ b/platform/ext/target/mps2/an521/spm_hal.c
@@ -48,12 +48,17 @@
 #define MPU_REGION_VENEERS           0
 #define MPU_REGION_TFM_UNPRIV_CODE   1
 #define MPU_REGION_TFM_UNPRIV_DATA   2
-#define MPU_REGION_NS_DATA           3
 #define PARTITION_REGION_RO          4
 #define PARTITION_REGION_RW_STACK    5
 #define PARTITION_REGION_PERIPH      6
 #define PARTITION_REGION_SHARE       7
 
+#if TFM_LVL == 2
+#define MPU_REGION_NS_STACK          3
+#elif TFM_LVL == 3
+#define MPU_REGION_NS_DATA           3
+#endif
+
 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
 REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
@@ -65,6 +70,8 @@
 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
+REGION_DECLARE(Image$$, ARM_LIB_STACK, $$ZI$$Base);
+REGION_DECLARE(Image$$, ARM_LIB_STACK, $$ZI$$Limit);
 #endif
 
 static enum spm_err_t tfm_spm_mpu_init(void)
@@ -113,6 +120,7 @@
         return SPM_ERR_INVALID_CONFIG;
     }
 
+#if TFM_LVL == 3
     /* TFM Core unprivileged non-secure data region */
     region_cfg.region_nr = MPU_REGION_NS_DATA;
     region_cfg.region_base = NS_DATA_START;
@@ -124,8 +132,22 @@
     if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
         return SPM_ERR_INVALID_CONFIG;
     }
+#endif
 
 #if TFM_LVL == 2
+    /* NSPM PSP */
+    region_cfg.region_nr = MPU_REGION_NS_STACK;
+    region_cfg.region_base =
+        (uint32_t)&REGION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Base);
+    region_cfg.region_limit =
+        (uint32_t)&REGION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Limit);
+    region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+    region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+    region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+    if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
+        return SPM_ERR_INVALID_CONFIG;
+    }
+
     /* RO region */
     region_cfg.region_nr = PARTITION_REGION_RO;
     region_cfg.region_base =
diff --git a/secure_fw/core/ipc/tfm_spm.c b/secure_fw/core/ipc/tfm_spm.c
index 54b7d04..4181616 100644
--- a/secure_fw/core/ipc/tfm_spm.c
+++ b/secure_fw/core/ipc/tfm_spm.c
@@ -524,10 +524,10 @@
     for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
         part = &g_spm_partition_db.partitions[i];
         tfm_spm_hal_configure_default_isolation(part->platform_data);
+        g_spm_ipc_partition[i].index = i;
         if ((tfm_spm_partition_get_flags(i) & SPM_PART_FLAG_IPC) == 0) {
             continue;
         }
-        g_spm_ipc_partition[i].index = i;
         g_spm_ipc_partition[i].id = tfm_spm_partition_get_partition_id(i);
 
         tfm_event_init(&g_spm_ipc_partition[i].signal_evnt);
diff --git a/secure_fw/core/ipc/tfm_thread.c b/secure_fw/core/ipc/tfm_thread.c
index 0ea94b8..b349732 100644
--- a/secure_fw/core/ipc/tfm_thread.c
+++ b/secure_fw/core/ipc/tfm_thread.c
@@ -126,42 +126,9 @@
     update_running_head(&RUNN_HEAD, pth);
 }
 
-/*
- * TEMP WORKAROUND: The caller function who called thread module init needs to
- * be returned. The caller is not a thread. Create a dummy IDLE thread to
- * collect caller context; and schedule back to the caller with this context
- * after all other real threads blocked.
- *
- * This WORKAROUND needs to be removed after IPC NSPM takes place.
- */
-#define DUMMY_IDLE_TAG       0xDEEDDEED
-static uint8_t idle_stack[32] __attribute__((aligned(8)));
-static struct tfm_thrd_ctx idle_thread;
-static struct tfm_thrd_ctx *init_idle_thread(struct tfm_thrd_ctx *pth)
-{
-    /*
-     * IDLE thread is a thread with the lowest priority.
-     * It gets scheduled after all other higher priority threads get blocked.
-     * The entry of IDLE thread is a dummy and has no mean.
-     */
-    tfm_thrd_init(pth, (tfm_thrd_func_t)DUMMY_IDLE_TAG, NULL,
-                  (uint8_t *)&idle_stack[32], (uint8_t *)idle_stack);
-    tfm_thrd_priority(pth, THRD_PRIOR_LOWEST);
-    tfm_thrd_start(pth);
-    return pth;
-}
-
 /* Scheduling won't happen immediately but after the exception returns */
 void tfm_thrd_activate_schedule(void)
 {
-    /*
-     * The current thread can be NULL only when initializing. Create the IDLE
-     * thread and set it as the current thread to collect caller context.
-     */
-    if (CURR_THRD == NULL) {
-        CURR_THRD = init_idle_thread(&idle_thread);
-    }
-
     tfm_trigger_pendsv();
 }
 
diff --git a/secure_fw/core/tfm_core.c b/secure_fw/core/tfm_core.c
index 27411d4..1c53071 100644
--- a/secure_fw/core/tfm_core.c
+++ b/secure_fw/core/tfm_core.c
@@ -207,6 +207,13 @@
     tfm_spm_partition_set_state(TFM_SP_CORE_ID, SPM_PARTITION_STATE_CLOSED);
     tfm_spm_partition_set_state(TFM_SP_NON_SECURE_ID,
                                 SPM_PARTITION_STATE_RUNNING);
+
+#ifdef TFM_CORE_DEBUG
+    /* Jumps to non-secure code */
+    LOG_MSG("Jumping to non-secure code...");
+#endif
+
+    jump_to_ns_code();
 #else
     /*
      * Prioritise secure exceptions to avoid NS being able to pre-empt
@@ -215,11 +222,4 @@
     tfm_core_set_secure_exception_priorities();
     tfm_spm_init();
 #endif
-
-#ifdef TFM_CORE_DEBUG
-    /* Jumps to non-secure code */
-    LOG_MSG("Jumping to non-secure code...");
-#endif
-
-    jump_to_ns_code();
 }
diff --git a/secure_fw/core/tfm_nspm.c b/secure_fw/core/tfm_nspm.c
index 3188e28..3db30c2 100644
--- a/secure_fw/core/tfm_nspm.c
+++ b/secure_fw/core/tfm_nspm.c
@@ -6,8 +6,13 @@
  */
 
 #include <stdio.h>
+#include <stdbool.h>
 #include "secure_utilities.h"
 #include "tfm_api.h"
+#if TFM_PSA_API
+#include "tfm_utils.h"
+#include "tfm_internal.h"
+#endif
 
 #ifndef TFM_MAX_NS_THREAD_COUNT
 #define TFM_MAX_NS_THREAD_COUNT 8
@@ -300,3 +305,20 @@
     return TFM_SUCCESS;
 }
 #endif
+
+#ifdef TFM_PSA_API
+__attribute__((section("SFN")))
+psa_status_t tfm_nspm_thread_entry(void)
+{
+#ifdef TFM_CORE_DEBUG
+    /* Jumps to non-secure code */
+    LOG_MSG("Jumping to non-secure code...");
+#endif
+
+    jump_to_ns_code();
+
+    /* Should not run here */
+    TFM_ASSERT(false);
+    return PSA_SUCCESS;
+}
+#endif
diff --git a/secure_fw/core/tfm_nspm.h b/secure_fw/core/tfm_nspm.h
index b485462..572c734 100644
--- a/secure_fw/core/tfm_nspm.h
+++ b/secure_fw/core/tfm_nspm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -23,4 +23,15 @@
  */
 int32_t tfm_nspm_get_current_client_id(void);
 
+#ifdef TFM_PSA_API
+/**
+ * \brief NSPM thread main entry function
+ *
+ * \return  PSA_SUCCESS indicates failed.
+ *
+ * Note: This function should not return back.
+ */
+psa_status_t tfm_nspm_thread_entry(void);
+#endif
+
 #endif /* __TFM_NSPM_H__ */
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index a1ee127..05d6c8d 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -110,7 +110,14 @@
     part_ptr = &(g_spm_partition_db.partitions[
             g_spm_partition_db.partition_count]);
     part_ptr->static_data.partition_id = TFM_SP_NON_SECURE_ID;
+#if TFM_PSA_API
+    part_ptr->static_data.partition_flags = SPM_PART_FLAG_APP_ROT |
+                                            SPM_PART_FLAG_IPC;
+    part_ptr->static_data.partition_priority = TFM_PRIORITY_LOW;
+    part_ptr->static_data.partition_init = tfm_nspm_thread_entry;
+#else
     part_ptr->static_data.partition_flags = 0;
+#endif
 
 #if TFM_LVL != 1
     part_ptr->memory_data.stack_bottom = psp_stack_bottom;