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/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(