SPM: Refinements on de-privileged FLIH implementation

There is the possibility that an interrupt preempts scheduler.
This may cause the execution contexts - CURRENT_THREAD, isolation
boundaries and PSP/PSPLIM - out-of-sync with each other.

This patch is to solve this issue.

- The EXC_RETURN payload is statically constructed instead of save
  on MSP, PSPLIM substitutes it.
- Add critical section around boundaries update and CURRENT_THREAD
  update in do_schedule. This makes boundaries and CURRENT_THREAD
  always match.
- Add critical section when manipulating stack contexts in
  PendSV_Handler
- Push PSP and PSPLIM on MSP for restoring context, EXC_RETURN payload
  is not pushed as it's statically defined now
- Address of FLIH function context is decided by checking if current
  PSP belongs to the IRQ owner

Change-Id: I0b6996c98e90c5025676c5299024dd4084c8c79c
Signed-off-by: Kevin Peng <kevin.peng@arm.com>
diff --git a/secure_fw/spm/ffm/interrupt.c b/secure_fw/spm/ffm/interrupt.c
index 87c0751..920554c 100644
--- a/secure_fw/spm/ffm/interrupt.c
+++ b/secure_fw/spm/ffm/interrupt.c
@@ -8,6 +8,7 @@
 #include "interrupt.h"
 
 #include "bitops.h"
+#include "current.h"
 #include "tfm_arch.h"
 #include "tfm_hal_interrupt.h"
 #include "tfm_hal_isolation.h"
@@ -19,7 +20,7 @@
 __attribute__((naked))
 static psa_flih_result_t tfm_flih_deprivileged_handling(void *p_pt,
                                                         uintptr_t fn_flih,
-                                                        void *p_context_ctrl)
+                                                        void *curr_component)
 {
     __ASM volatile("SVC %0           \n"
                    "BX LR            \n"
@@ -53,7 +54,7 @@
                                       uintptr_t flih_func)
 {
     struct partition_t *p_curr_sp;
-    uintptr_t sp_limit, stack;
+    uintptr_t sp_base, sp_limit, curr_stack, ctx_stack;
     struct context_ctrl_t flih_ctx_ctrl;
 
     /* Come too early before runtime setup, should not happen. */
@@ -61,32 +62,35 @@
         tfm_core_panic();
     }
 
-    p_curr_sp = GET_CTX_OWNER(CURRENT_THREAD->p_context_ctrl);
-    sp_limit =
-           ((struct context_ctrl_t *)p_owner_sp->thrd.p_context_ctrl)->sp_limit;
+    p_curr_sp = GET_CURRENT_COMPONENT();
+    sp_base  = LOAD_ALLOCED_STACK_ADDR(p_owner_sp->p_ldinf)
+                                              + p_owner_sp->p_ldinf->stack_size;
+    sp_limit = LOAD_ALLOCED_STACK_ADDR(p_owner_sp->p_ldinf);
 
-    if (p_owner_sp == p_curr_sp) {
-        stack = (uintptr_t)__get_PSP();
+    curr_stack = (uintptr_t)__get_PSP();
+    if (curr_stack < sp_base && curr_stack > sp_limit) {
+        /* The IRQ Partition's stack is being used */
+        ctx_stack = curr_stack;
     } else {
-        stack = ((struct context_ctrl_t *)p_owner_sp->thrd.p_context_ctrl)->sp;
-
-        if (p_owner_sp->p_boundaries != p_curr_sp->p_boundaries) {
-            tfm_hal_update_boundaries(p_owner_sp->p_ldinf,
-                                      p_owner_sp->p_boundaries);
-        }
-
-        /*
-         * CURRENT_THREAD->p_context_ctrl is the svc_args[2] on MSP, safe to
-         * update it. It is only used to track the owner of the thread data,
-         * i.e. the partition that has been interrupted.
-         */
-        THRD_UPDATE_CUR_CTXCTRL(&(p_owner_sp->ctx_ctrl));
+        ctx_stack =
+                 ((struct context_ctrl_t *)p_owner_sp->thrd.p_context_ctrl)->sp;
     }
 
+    if (p_owner_sp->p_boundaries != p_curr_sp->p_boundaries) {
+        tfm_hal_update_boundaries(p_owner_sp->p_ldinf,
+                                  p_owner_sp->p_boundaries);
+    }
+
+    /*
+     * The CURRENT_COMPONENT has been stored on MSP by the SVC call, safe to
+     * update it.
+     */
+    SET_CURRENT_COMPONENT(p_owner_sp);
+
     tfm_arch_init_context(&flih_ctx_ctrl,
                           flih_func, NULL,
                           (uintptr_t)tfm_flih_func_return,
-                          sp_limit, stack);
+                          sp_limit, ctx_stack);
 
     (void)tfm_arch_refresh_hardware_context(&flih_ctx_ctrl);
 
@@ -99,25 +103,24 @@
 {
     struct partition_t *p_prev_sp, *p_owner_sp;
 
-    p_prev_sp = GET_CTX_OWNER(p_ctx_flih_ret->state_ctx.r2);
-    p_owner_sp = GET_CTX_OWNER(CURRENT_THREAD->p_context_ctrl);
+    p_prev_sp = (struct partition_t *)(p_ctx_flih_ret->state_ctx.r2);
+    p_owner_sp = GET_CURRENT_COMPONENT();
 
     if (p_owner_sp->p_boundaries != p_prev_sp->p_boundaries) {
         tfm_hal_update_boundaries(p_prev_sp->p_ldinf,
                                   p_prev_sp->p_boundaries);
     }
 
-    /* Restore context pointer */
-    THRD_UPDATE_CUR_CTXCTRL(p_ctx_flih_ret->state_ctx.r2);
+    /* Restore current component */
+    SET_CURRENT_COMPONENT(p_prev_sp);
 
-    tfm_arch_set_psplim(
-        ((struct context_ctrl_t *)CURRENT_THREAD->p_context_ctrl)->sp_limit);
+    tfm_arch_set_psplim(p_ctx_flih_ret->psplim);
     __set_PSP(p_ctx_flih_ret->psp);
 
     /* Set FLIH result to the ISR */
     p_ctx_flih_ret->state_ctx.r0 = (uint32_t)result;
 
-    return p_ctx_flih_ret->exc_ret;
+    return EXC_RETURN_HANDLER_S_MSP;
 }
 
 void spm_handle_interrupt(void *p_pt, struct irq_load_info_t *p_ildi)
@@ -148,7 +151,7 @@
             flih_result = tfm_flih_deprivileged_handling(
                                                 p_part,
                                                 (uintptr_t)p_ildi->flih_func,
-                                                CURRENT_THREAD->p_context_ctrl);
+                                                GET_CURRENT_COMPONENT());
         }
     }