SPM: Add First-Level Interrupt Handling implementation

Change-Id: I5cc6d63f9864c5ea35e7a5236a736799d727855e
Signed-off-by: Kevin Peng <kevin.peng@arm.com>
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
index fc41394..c63e3cc 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
@@ -8,6 +8,7 @@
 #include <inttypes.h>
 #include "tfm_hal_device_header.h"
 #include "tfm_arch.h"
+#include "svc_num.h"
 #include "exception_info.h"
 
 #if !defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_7M__) && \
@@ -86,18 +87,60 @@
 }
 
 #if defined(__ICCARM__)
-uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t exc_return,
+                              uint32_t *psp);
 #pragma required = tfm_core_svc_handler
 #endif
 
 __attribute__((naked)) void SVC_Handler(void)
 {
     __ASM volatile(
+#if !defined(__ICCARM__)
+    ".syntax unified                        \n"
+#endif
     "MRS     r0, MSP                        \n"
-    "MRS     r1, PSP                        \n"
-    "MOV     r2, lr                         \n"
+    "MOV     r1, lr                         \n"
+    "MRS     r2, PSP                        \n"
+    "SUB     sp, #8                         \n" /* For FLIH PID and signal */
+    "PUSH    {r1, r2}                       \n" /* Orig_exc_return, PSP */
     "BL      tfm_core_svc_handler           \n"
-    "BX      r0                             \n"
+    "MOV     lr, r0                         \n"
+    "LDR     r1, [sp]                       \n" /* Original EXC_RETURN */
+    "MOVS    r2, #8                         \n"
+    "ANDS    r0, r2                         \n" /* Mode bit */
+    "ANDS    r1, r2                         \n"
+    "SUBS    r0, r1                         \n" /* Compare EXC_RETURN values */
+    "BGT     to_flih_func                   \n"
+    "BLT     from_flih_func                 \n"
+    "ADD     sp, #16                        \n"
+    "BX      lr                             \n"
+    "to_flih_func:                          \n"
+    "PUSH    {r4-r7}                        \n"
+    "MOV     r4, r8                         \n"
+    "MOV     r5, r9                         \n"
+    "MOV     r6, r10                        \n"
+    "MOV     r7, r11                        \n"
+    "PUSH    {r4-r7}                        \n"
+    "LDR     r4, =0xFEF5EDA5                \n" /* clear r4-r11 */
+    "MOV     r5, r4                         \n"
+    "MOV     r6, r4                         \n"
+    "MOV     r7, r4                         \n"
+    "MOV     r8, r4                         \n"
+    "MOV     r9, r4                         \n"
+    "MOV     r10, r4                        \n"
+    "MOV     r11, r4                        \n"
+    "PUSH    {r4, r5}                       \n" /* Seal stack before EXC_RET */
+    "BX      lr                             \n"
+    "from_flih_func:                        \n"
+    "ADD     sp, #24                        \n"
+    "POP     {r4-r7}                        \n"
+    "MOV     r8, r4                         \n"
+    "MOV     r9, r5                         \n"
+    "MOV     r10, r6                        \n"
+    "MOV     r11, r7                        \n"
+    "POP     {r4-r7}                        \n"
+    "ADD     sp, #16                        \n"
+    "BX      lr                             \n"
     );
 }
 
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
index 66d50d8..015ae73 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
@@ -118,18 +118,60 @@
 }
 
 #if defined(__ICCARM__)
-uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t exc_return,
+                              uint32_t *psp);
 #pragma required = tfm_core_svc_handler
 #endif
 
 __attribute__((naked)) void SVC_Handler(void)
 {
     __ASM volatile(
+#if !defined(__ICCARM__)
+    ".syntax unified                        \n"
+#endif
     "MRS     r0, MSP                        \n"
-    "MRS     r1, PSP                        \n"
-    "MOV     r2, lr                         \n"
+    "MOV     r1, lr                         \n"
+    "MRS     r2, PSP                        \n"
+    "SUB     sp, #8                         \n" /* For FLIH PID and signal */
+    "PUSH    {r1, r2}                       \n" /* Orig_exc_return, PSP */
     "BL      tfm_core_svc_handler           \n"
-    "BX      r0                             \n"
+    "MOV     lr, r0                         \n"
+    "LDR     r1, [sp]                       \n" /* Original EXC_RETURN */
+    "MOVS    r2, #8                         \n"
+    "ANDS    r0, r2                         \n" /* Mode bit */
+    "ANDS    r1, r2                         \n"
+    "SUBS    r0, r1                         \n" /* Compare EXC_RETURN values */
+    "BGT     to_flih_func                   \n"
+    "BLT     from_flih_func                 \n"
+    "ADD     sp, #16                        \n"
+    "BX      lr                             \n"
+    "to_flih_func:                          \n"
+    "PUSH    {r4-r7}                        \n"
+    "MOV     r4, r8                         \n"
+    "MOV     r5, r9                         \n"
+    "MOV     r6, r10                        \n"
+    "MOV     r7, r11                        \n"
+    "PUSH    {r4-r7}                        \n"
+    "LDR     r4, =0xFEF5EDA5                \n" /* clear r4-r11 */
+    "MOV     r5, r4                         \n"
+    "MOV     r6, r4                         \n"
+    "MOV     r7, r4                         \n"
+    "MOV     r8, r4                         \n"
+    "MOV     r9, r4                         \n"
+    "MOV     r10, r4                        \n"
+    "MOV     r11, r4                        \n"
+    "PUSH    {r4, r5}                       \n" /* Seal stack before EXC_RET */
+    "BX      lr                             \n"
+    "from_flih_func:                        \n"
+    "ADD     sp, #24                        \n"
+    "POP     {r4-r7}                        \n"
+    "MOV     r8, r4                         \n"
+    "MOV     r9, r5                         \n"
+    "MOV     r10, r6                        \n"
+    "MOV     r11, r7                        \n"
+    "POP     {r4-r7}                        \n"
+    "ADD     sp, #16                        \n"
+    "BX      lr                             \n"
     );
 }
 
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
index b96c8cc..33fda0c 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
@@ -97,7 +97,8 @@
 }
 
 #if defined(__ICCARM__)
-uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t exc_return,
+                              uint32_t *psp);
 #pragma required = tfm_core_svc_handler
 #endif
 
@@ -105,10 +106,37 @@
 {
     __ASM volatile(
     "MRS     r0, MSP                        \n"
-    "MRS     r1, PSP                        \n"
-    "MOV     r2, lr                         \n"
-    "BL      tfm_core_svc_handler           \n"
-    "BX      r0                             \n"
+    "MOV     r1, lr                         \n"
+    "MRS     r2, PSP                        \n"
+    "SUB     sp, #8                         \n" /* For FLIH PID and signal */
+    "PUSH    {r1, r2}                       \n" /* Orig_exc_return, PSP */
+    "BL      tfm_core_svc_handler           \n" /* New EXC_RET returned */
+    "MOV     lr, r0                         \n"
+    "LDR     r1, [sp]                       \n" /* Original EXC_RETURN */
+    "AND     r0, #8                         \n" /* Mode bit */
+    "AND     r1, #8                         \n"
+    "SUBS    r0, r1                         \n" /* Compare EXC_RETURN values */
+    "BGT     to_flih_func                   \n"
+    "BLT     from_flih_func                 \n"
+    "ADD     sp, #16                        \n"
+    "BX      lr                             \n"
+    "to_flih_func:                          \n"
+    "PUSH    {r4-r11}                       \n"
+    "LDR     r4, =0xFEF5EDA5                \n" /* clear r4-r11 */
+    "MOV     r5, r4                         \n"
+    "MOV     r6, r4                         \n"
+    "MOV     r7, r4                         \n"
+    "MOV     r8, r4                         \n"
+    "MOV     r9, r4                         \n"
+    "MOV     r10, r4                        \n"
+    "MOV     r11, r4                        \n"
+    "PUSH    {r4, r5}                       \n" /* Seal stack before EXC_RET */
+    "BX      lr                             \n"
+    "from_flih_func:                        \n"
+    "ADD     sp, #24                        \n"
+    "POP     {r4-r11}                       \n"
+    "ADD     sp, #16                        \n"
+    "BX      lr                             \n"
     );
 }
 
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.c b/secure_fw/spm/cmsis_psa/spm_ipc.c
index 384aa36..2db3dce 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.c
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.c
@@ -45,8 +45,10 @@
 TFM_POOL_DECLARE(conn_handle_pool, sizeof(struct tfm_conn_handle_t),
                  TFM_CONN_HANDLE_MAX_NUM);
 
-void tfm_set_irq_signal(uint32_t partition_id, psa_signal_t signal,
-                        uint32_t irq_line);
+void spm_interrupt_handler(struct partition_load_info_t *p_ldinf,
+                           psa_signal_t signal,
+                           uint32_t irq_line,
+                           psa_flih_func flih_func);
 
 #include "tfm_secure_irq_handlers_ipc.inc"
 
@@ -323,7 +325,7 @@
  * \retval "Not NULL"       Target partition context pointer,
  *                          \ref partition_t structures
  */
-static struct partition_t *tfm_spm_get_partition_by_id(int32_t partition_id)
+struct partition_t *tfm_spm_get_partition_by_id(int32_t partition_id)
 {
     struct partition_t *p_part;
 
@@ -876,25 +878,53 @@
     }
 }
 
-/**
- * \brief Sets signal to partition for Second-Level Interrupt Handling mode IRQ
- *
- * \param[in] partition_id      The ID of the partition which handles this IRQ
- * \param[in] signal            The signal associated with this IRQ
- * \param[in] irq_line          The number of the IRQ line
- *
- * \retval void                 Success.
- * \retval "Does not return"    Partition ID is invalid
- */
-void tfm_set_irq_signal(uint32_t partition_id, psa_signal_t signal,
-                        uint32_t irq_line)
+__attribute__((naked))
+static void tfm_flih_deprivileged_handling(uint32_t p_ldinf,
+                                           psa_flih_func flih_func,
+                                           psa_signal_t signal)
 {
-    __disable_irq();
+    __ASM volatile("SVC %0           \n"
+                   "BX LR            \n"
+                   : : "I" (TFM_SVC_PREPARE_DEPRIV_FLIH));
+}
 
-    tfm_spm_hal_disable_irq(irq_line);
-    notify_with_signal(partition_id, signal);
+void spm_interrupt_handler(struct partition_load_info_t *p_ldinf,
+                           psa_signal_t signal,
+                           uint32_t irq_line,
+                           psa_flih_func flih_func)
+{
+    uint32_t pid;
+    psa_flih_result_t flih_result;
 
-    __enable_irq();
+    pid = p_ldinf->pid;
+
+    if (flih_func == NULL) {
+        /* SLIH Model Handling */
+        __disable_irq();
+        tfm_spm_hal_disable_irq(irq_line);
+        notify_with_signal(pid, signal);
+        __enable_irq();
+        return;
+    }
+
+    /* FLIH Model Handling */
+    if (tfm_spm_partition_get_privileged_mode(p_ldinf->flags) ==
+                                                TFM_PARTITION_PRIVILEGED_MODE) {
+        flih_result = flih_func();
+        if (flih_result == PSA_FLIH_SIGNAL) {
+            __disable_irq();
+            notify_with_signal(pid, signal);
+            __enable_irq();
+        } else if (flih_result != PSA_FLIH_NO_SIGNAL) {
+            /*
+             * Nothing needed to do for PSA_FLIH_NO_SIGNAL
+             * But if the flih_result is invalid, should panic.
+             */
+            tfm_core_panic();
+        }
+    } else {
+        tfm_flih_deprivileged_handling((uint32_t)p_ldinf, flih_func, signal);
+    }
 }
 
 struct irq_load_info_t *get_irq_info_for_signal(
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.h b/secure_fw/spm/cmsis_psa/spm_ipc.h
index d8fd3c7..43b836b 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.h
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.h
@@ -211,6 +211,18 @@
 struct tfm_msg_body_t *tfm_spm_get_msg_by_signal(struct partition_t *partition,
                                                  psa_signal_t signal);
 
+
+/**
+ * \brief                   Get partition by Partition ID.
+ *
+ * \param[in] partition_id  The Partition ID of the partition to get
+ *
+ * \retval NULL             Failed
+ * \retval "Not NULL"       Return the parttion context pointer
+ *                          \ref partition_t structures
+ */
+struct partition_t *tfm_spm_get_partition_by_id(int32_t partition_id);
+
 /**
  * \brief                   Get current running partition context.
  *
diff --git a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
index e02753a..7ca5cfc 100644
--- a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
+++ b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
@@ -6,11 +6,13 @@
  */
 
 #include <string.h>
+#include "load/partition_defs.h"
 #include "region.h"
 #include "spm_ipc.h"
 #include "tfm_api.h"
 #include "tfm_arch.h"
 #include "tfm_core_trustzone.h"
+#include "tfm_core_utils.h"
 #include "tfm_svcalls.h"
 #include "utilities.h"
 #include "svc_num.h"
@@ -30,6 +32,13 @@
                                      uint32_t *ctx, uint32_t lr);
 #endif
 
+struct tfm_svc_flih_ctx_t {
+    uint32_t exc_ret;                      /* EXC_RETURN payload at SVC entry */
+    uint32_t psp;                          /* PSP value at SVC entry */
+    const struct partition_load_info_t *p_ldinf;/* Load info of IRQ Partition */
+    uint32_t signal;                       /* The IRQ signal */
+};
+
 static int32_t SVC_Handler_IPC(uint8_t svc_num, uint32_t *ctx,
                                uint32_t lr)
 {
@@ -128,10 +137,115 @@
     return PSA_SUCCESS;
 }
 
-uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return)
+extern void tfm_flih_func_return(psa_flih_result_t result);
+
+/*
+ * Prepare execution context for deprivileged FLIH functions
+ * svc_args: IRQ owner Partition load info, flih_func, signal
+ */
+uint32_t tfm_flih_prepare_depriv_flih(uintptr_t ctx, uint32_t *svc_args)
+{
+    struct tfm_core_thread_t *irq_sp_thread;
+    struct partition_t *irq_sp, *curr_sp;
+    struct tfm_state_context_t *p_stat_ctx;
+    struct tfm_svc_flih_ctx_t *flih_ctx;
+
+    irq_sp = tfm_spm_get_partition_by_id(
+                            ((struct partition_load_info_t *)svc_args[0])->pid);
+
+    if (!irq_sp) {
+        tfm_core_panic();
+    }
+    irq_sp_thread = &irq_sp->sp_thread;
+
+    curr_sp = TO_CONTAINER(tfm_core_thrd_get_curr(),
+                           struct partition_t,
+                           sp_thread);
+
+    flih_ctx = (struct tfm_svc_flih_ctx_t *)ctx;
+    flih_ctx->signal = svc_args[2];
+    flih_ctx->p_ldinf = curr_sp->p_ldinf;
+
+    if (curr_sp == irq_sp) {
+        /*
+         * Either the Partition Thread or FLIH Function within the same
+         * Partition was preempted.
+         */
+        p_stat_ctx = (struct tfm_state_context_t *)flih_ctx->psp;
+    } else {
+        p_stat_ctx = (struct tfm_state_context_t *)irq_sp_thread->arch_ctx.sp;
+        tfm_core_thrd_set_curr(irq_sp_thread);
+        tfm_set_up_isolation_boundary(irq_sp);
+        tfm_arch_set_psplim(irq_sp_thread->stk_btm);
+    }
+
+    p_stat_ctx--;
+    if ((uintptr_t)p_stat_ctx < irq_sp_thread->stk_btm) {
+        tfm_core_panic();
+    }
+    spm_memset(p_stat_ctx, 0, sizeof(struct tfm_state_context_t));
+
+    p_stat_ctx->ra = (uint32_t)svc_args[1];
+    p_stat_ctx->lr = (uint32_t)tfm_flih_func_return;
+    p_stat_ctx->xpsr = XPSR_T32;
+
+    __set_PSP((uint32_t)p_stat_ctx);
+
+    return EXC_RETURN_THREAD_S_PSP;
+}
+
+/* Go back to ISR from FLIH functions */
+uint32_t tfm_flih_return_to_isr(uintptr_t ctx, psa_flih_result_t result)
+{
+    struct partition_t *curr_sp, *prev_sp;
+    struct tfm_svc_flih_ctx_t *flih_ctx;
+    uint32_t msp_top =
+                (uint32_t)&REGION_NAME(Image$$, ARM_LIB_STACK_MSP, $$ZI$$Limit);
+
+    /* Skip one tfm_svc_flih_ctx_t + 8 words (R4- R11) + seals (2 words) */
+    flih_ctx = (struct tfm_svc_flih_ctx_t *)
+              (ctx + sizeof(struct tfm_svc_flih_ctx_t) + 10 * sizeof(uint32_t));
+    if ((uint32_t)flih_ctx > msp_top - TFM_STACK_SEALED_SIZE) {
+        tfm_core_panic();
+    }
+
+    curr_sp = TO_CONTAINER(tfm_core_thrd_get_curr(),
+                           struct partition_t,
+                           sp_thread);
+
+    prev_sp = tfm_spm_get_partition_by_id(flih_ctx->p_ldinf->pid);
+    if (!prev_sp) {
+        tfm_core_panic();
+    }
+
+    if (curr_sp != prev_sp) {
+        tfm_set_up_isolation_boundary(prev_sp);
+        tfm_core_thrd_set_curr(&(prev_sp->sp_thread));
+        tfm_arch_set_psplim(prev_sp->sp_thread.stk_btm);
+    }
+
+    __set_PSP(flih_ctx->psp);
+
+    if (result == PSA_FLIH_SIGNAL) {
+        notify_with_signal(curr_sp->p_ldinf->pid, flih_ctx->signal);
+    } else if (result != PSA_FLIH_NO_SIGNAL) {
+        /*
+         * Nothing needed to do for PSA_FLIH_NO_SIGNAL
+         * But if the flih_result is invalid, should panic.
+         */
+        tfm_core_panic();
+    }
+
+    return flih_ctx->exc_ret;
+}
+
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t exc_return,
+                              uint32_t *psp)
 {
     uint8_t svc_number = TFM_SVC_PSA_FRAMEWORK_VERSION;
     uint32_t *svc_args = msp;
+    uintptr_t flih_ctx =
+                 (uintptr_t)((uint32_t)msp - sizeof(struct tfm_svc_flih_ctx_t));
 
     if ((exc_return & EXC_RETURN_MODE) && (exc_return & EXC_RETURN_SPSEL)) {
         /* Use PSP when both EXC_RETURN.MODE and EXC_RETURN.SPSEL are set */
@@ -171,6 +285,12 @@
     case TFM_SVC_GET_BOOT_DATA:
         tfm_core_get_boot_data_handler(svc_args);
         break;
+    case TFM_SVC_PREPARE_DEPRIV_FLIH:
+        exc_return = tfm_flih_prepare_depriv_flih(flih_ctx, svc_args);
+        break;
+    case TFM_SVC_FLIH_FUNC_RETURN:
+        exc_return = tfm_flih_return_to_isr(flih_ctx, svc_args[0]);
+        break;
     default:
         if (((uint32_t)&REGION_NAME(Image$$, ARM_LIB_STACK_MSP, $$ZI$$Limit)
                                      - (uint32_t)msp) > TFM_STACK_SEALED_SIZE) {
diff --git a/secure_fw/spm/cmsis_psa/tfm_secure_irq_handlers_ipc.inc.template b/secure_fw/spm/cmsis_psa/tfm_secure_irq_handlers_ipc.inc.template
index f5faa43..d7b9fde 100644
--- a/secure_fw/spm/cmsis_psa/tfm_secure_irq_handlers_ipc.inc.template
+++ b/secure_fw/spm/cmsis_psa/tfm_secure_irq_handlers_ipc.inc.template
@@ -14,6 +14,7 @@
 #ifdef {{partition.attr.conditional}}
         {% endif %}
 #include "{{partition.header_file}}"
+extern struct partition_{{partition.manifest.name|lower}}_load_info_t {{partition.manifest.name|lower}}_load;
         {% for irq in partition.manifest.irqs %}
             {% set irq_data = namespace() %}
             {% if partition.manifest.psa_framework_version == 1.0 %}
@@ -31,15 +32,15 @@
 {
             {% if irq.source %}
                 {% if partition.manifest.psa_framework_version == 1.1 and irq.handling == "FLIH" %}
-#error "FLIH is not supported yet!"
+                    {% set irq_data.flih =  irq.name|lower + "_flih" %}
                 {% else %}
-    tfm_set_irq_signal({{partition.manifest.name}}, {{irq_data.signal}}, {{irq.source}});
+                    {% set irq_data.flih =  "NULL" %}
                 {% endif %}
+    spm_interrupt_handler((struct partition_load_info_t *)&{{partition.manifest.name|lower}}_load, {{irq_data.signal}}, {{irq.source}}, {{irq_data.flih}});
             {% else %}
 #error "Interrupt source isn't provided for 'irqs' in partition {{partition.manifest.name}}"
             {% endif %}
 }
-
         {% endfor %}
         {% if partition.attr.conditional %}
 #endif /* {{partition.attr.conditional}} */
diff --git a/secure_fw/spm/cmsis_psa/tfm_svcalls.h b/secure_fw/spm/cmsis_psa/tfm_svcalls.h
index d3b374f..5d7f964 100644
--- a/secure_fw/spm/cmsis_psa/tfm_svcalls.h
+++ b/secure_fw/spm/cmsis_psa/tfm_svcalls.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -13,11 +13,12 @@
  * \brief The C source of SVCall handlers
  *
  * \param[in] msp               MSP at SVCall entry.
- * \param[in] psp               PSP at SVCall entry.
  * \param[in] exc_return        EXC_RETURN value of the SVC.
- *
+ * \param[in] psp               PSP at SVCall entry.
+
  * \returns                     EXC_RETURN value indicates where to return.
  */
-uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t exc_return,
+                              uint32_t *psp);
 
 #endif
diff --git a/secure_fw/spm/cmsis_psa/tfm_thread.c b/secure_fw/spm/cmsis_psa/tfm_thread.c
index 43a128a..ef371a1 100644
--- a/secure_fw/spm/cmsis_psa/tfm_thread.c
+++ b/secure_fw/spm/cmsis_psa/tfm_thread.c
@@ -44,6 +44,15 @@
     return CURR_THRD;
 }
 
+void tfm_core_thrd_set_curr(struct tfm_core_thread_t *pth)
+{
+    if (!pth) {
+        tfm_core_panic();
+    }
+
+    CURR_THRD = pth;
+}
+
 /* Insert a new thread into list by descending priority (Highest at head) */
 static void insert_by_prior(struct tfm_core_thread_t **head,
                             struct tfm_core_thread_t *node)
@@ -73,6 +82,7 @@
     pth->param = param;
     pth->stk_btm = stk_btm;
     pth->stk_top = stk_top;
+    pth->flih_ctx = stk_top;
 }
 
 uint32_t tfm_core_thrd_start(struct tfm_core_thread_t *pth)
@@ -155,6 +165,8 @@
     spm_memcpy(&prev->arch_ctx, p_actx, sizeof(*p_actx));
     spm_memcpy(p_actx, &next->arch_ctx, sizeof(next->arch_ctx));
 
+    prev->flih_ctx = prev->arch_ctx.sp;
+
     /* Update current thread indicator */
     CURR_THRD = next;
 }
diff --git a/secure_fw/spm/cmsis_psa/tfm_thread.h b/secure_fw/spm/cmsis_psa/tfm_thread.h
index 3841f94..76a274f 100644
--- a/secure_fw/spm/cmsis_psa/tfm_thread.h
+++ b/secure_fw/spm/cmsis_psa/tfm_thread.h
@@ -45,6 +45,7 @@
     void            *param;             /* entry parameter              */
     uintptr_t       stk_btm;            /* stack bottom (lower address) */
     uintptr_t       stk_top;            /* stack top    (higher address)*/
+    uintptr_t       flih_ctx;           /* FLIH context pointer         */
     uint32_t        prior;              /* priority                     */
     uint32_t        state;              /* state                        */
 
@@ -175,6 +176,18 @@
 struct tfm_core_thread_t *tfm_core_thrd_get_curr(void);
 
 /*
+ * Set the current running thread
+ * Note:
+ *  This API is intended to update the current thread in FLIH handling.
+ *  So that in nested FLIH interrupts, the handler knows which isolation
+ *  boundary was preempted.
+ *  Although the CURR_THRD is updated, it does not mean the running Partition
+ *  thread is changed. It could also be the FLIH function which runs with the
+ *  same isolation boundary of the CURR_THRD.
+ */
+void tfm_core_thrd_set_curr(struct tfm_core_thread_t *pth);
+
+/*
  * Get next thread to run in list.
  *
  * Return :
diff --git a/secure_fw/spm/include/interface/svc_num.h b/secure_fw/spm/include/interface/svc_num.h
index 955d7bf..7a3c3c5 100644
--- a/secure_fw/spm/include/interface/svc_num.h
+++ b/secure_fw/spm/include/interface/svc_num.h
@@ -42,6 +42,7 @@
 #define TFM_SVC_SPM_REQUEST             (0x40)
 #define TFM_SVC_GET_BOOT_DATA           (0x41)
 #define TFM_SVC_SPM_INIT                (0x42)
+#define TFM_SVC_FLIH_FUNC_RETURN        (0x43)
 #define TFM_SVC_THREAD_NUMBER_END       (0x7F)
 #if (TFM_SPM_LOG_LEVEL > TFM_SPM_LOG_LEVEL_SILENCE)
 #define TFM_SVC_OUTPUT_UNPRIV_STRING    (TFM_SVC_THREAD_NUMBER_END)
@@ -50,5 +51,6 @@
 #define TFM_SVC_HANDLER_NUMBER_START    (0x80)
 
 /********************* SVC for interrupt handling *****************************/
+#define TFM_SVC_PREPARE_DEPRIV_FLIH     (0x80)
 
 #endif /* __SVC_NUM_H__ */
diff --git a/secure_fw/spm/include/spm_partition_defs.h b/secure_fw/spm/include/spm_partition_defs.h
index c811cb6..252f99c 100644
--- a/secure_fw/spm/include/spm_partition_defs.h
+++ b/secure_fw/spm/include/spm_partition_defs.h
@@ -31,6 +31,7 @@
 #define TFM_SP_CORE_ID (1)
 
 #include "psa_manifest/pid.h"
+#include "psa/service.h"
 
 /* This limit is only used to define the size of the database reserved for
  * partitions. There's no requirement that it match the number of partitions
@@ -39,5 +40,6 @@
 #define SPM_MAX_PARTITIONS (TFM_MAX_USER_PARTITIONS + TFM_INTERNAL_PARTITIONS)
 
 typedef void(*sp_entry_point)(void);
+typedef psa_flih_result_t (*psa_flih_func)(void);
 
 #endif /* __SPM_PARTITION_DEFS_H__ */