Dualcpu: Add NS mailbox functions to handle reply in IRQ handler

Add tfm_ns_mailbox_fetch_reply_msg_isr() to fetch the handle of the
first replied mailbox message from NSPE mailbox queue in platform
inter-processor communication interrupt handler.
NS OS can get the handle of the waiting caller task by calling
tfm_ns_mailbox_get_msg_owner() and wake-up the caller task
according to the handle value.

Change-Id: Id86e0b23819cf8963831006fd037142d9efb4d9f
Signed-off-by: David Hu <david.hu@arm.com>
diff --git a/interface/include/tfm_mailbox.h b/interface/include/tfm_mailbox.h
index bb23b7a..76759aa 100644
--- a/interface/include/tfm_mailbox.h
+++ b/interface/include/tfm_mailbox.h
@@ -15,6 +15,7 @@
 #ifndef __TFM_MAILBOX_H__
 #define __TFM_MAILBOX_H__
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <stddef.h>
 #include "psa/client.h"
@@ -108,9 +109,13 @@
 struct ns_mailbox_slot_t {
     struct mailbox_msg_t   msg;
     struct mailbox_reply_t reply;
-    const void             *owner;     /* Handle of the owner task of this
-                                        * slot
-                                        */
+    const void             *owner;          /* Handle of the owner task of this
+                                             * slot
+                                             */
+    bool                   is_woken;        /* Indicate that owner task has been
+                                             * or should be woken up, after the
+                                             * replied is received.
+                                             */
 };
 
 typedef uint32_t   mailbox_queue_status_t;
diff --git a/interface/include/tfm_ns_mailbox.h b/interface/include/tfm_ns_mailbox.h
index 3340735..49c4ca6 100644
--- a/interface/include/tfm_ns_mailbox.h
+++ b/interface/include/tfm_ns_mailbox.h
@@ -88,6 +88,32 @@
 #endif
 
 /**
+ * \brief Fetch the handle to the first replied mailbox message in the NSPE
+ *        mailbox queue.
+ *        This function is intended to be called inside platform specific
+ *        notification IRQ handler.
+ *
+ * \note The replied status of the fetched mailbox message will be cleaned after
+ *       the message is fetched. When this function is called again, it fetches
+ *       the next replied mailbox message from the NSPE mailbox queue.
+ *
+ * \return Return the handle to the first replied mailbox message in the
+ *         queue.
+ *         Return \ref MAILBOX_MSG_NULL_HANDLE if no mailbox message is replied.
+ */
+mailbox_msg_handle_t tfm_ns_mailbox_fetch_reply_msg_isr(void);
+
+/**
+ * \brief Return the handle of owner task of a mailbox message according to the
+ *        \ref mailbox_msg_handle_t
+ *
+ * \param[in] handle            The handle of mailbox message.
+ *
+ * \return Return the handle value of the owner task.
+ */
+const void *tfm_ns_mailbox_get_msg_owner(mailbox_msg_handle_t handle);
+
+/**
  * \brief Platform specific NSPE mailbox initialization.
  *        Invoked by \ref tfm_ns_mailbox_init().
  *
diff --git a/interface/src/tfm_ns_mailbox.c b/interface/src/tfm_ns_mailbox.c
index 9ab3004..98193e8 100644
--- a/interface/src/tfm_ns_mailbox.c
+++ b/interface/src/tfm_ns_mailbox.c
@@ -64,6 +64,13 @@
     }
 }
 
+static inline void set_queue_slot_woken(uint8_t idx)
+{
+    if (idx < NUM_MAILBOX_QUEUE_SLOT) {
+        mailbox_queue_ptr->queue[idx].is_woken = true;
+    }
+}
+
 static uint8_t acquire_empty_slot(const struct ns_mailbox_queue_t *queue)
 {
     uint8_t idx;
@@ -170,8 +177,13 @@
     set_msg_owner(idx, NULL);
 
     tfm_ns_mailbox_hal_enter_critical();
-    set_queue_slot_empty(idx);
     clear_queue_slot_replied(idx);
+    clear_queue_slot_woken(idx);
+    /*
+     * Make sure that the empty flag is set after all the other status flags are
+     * re-initialized.
+     */
+    set_queue_slot_empty(idx);
     tfm_ns_mailbox_hal_exit_critical();
 
     return MAILBOX_SUCCESS;
@@ -207,6 +219,56 @@
     return false;
 }
 
+mailbox_msg_handle_t tfm_ns_mailbox_fetch_reply_msg_isr(void)
+{
+    uint8_t idx;
+    mailbox_msg_handle_t handle;
+    mailbox_queue_status_t replied_status;
+
+    if (!mailbox_queue_ptr) {
+        return MAILBOX_MSG_NULL_HANDLE;
+    }
+
+    tfm_ns_mailbox_hal_enter_critical_isr();
+    replied_status = mailbox_queue_ptr->replied_slots;
+    tfm_ns_mailbox_hal_exit_critical_isr();
+
+    if (!replied_status) {
+        return MAILBOX_MSG_NULL_HANDLE;
+    }
+
+    for (idx = 0; idx < NUM_MAILBOX_QUEUE_SLOT; idx++) {
+        /* Find the first replied message in queue */
+        if (replied_status & (0x1UL << idx)) {
+            tfm_ns_mailbox_hal_enter_critical_isr();
+            clear_queue_slot_replied(idx);
+            set_queue_slot_woken(idx);
+            tfm_ns_mailbox_hal_exit_critical_isr();
+
+            if (get_mailbox_msg_handle(idx, &handle) == MAILBOX_SUCCESS) {
+                return handle;
+            }
+       }
+    }
+
+    return MAILBOX_MSG_NULL_HANDLE;
+}
+
+const void *tfm_ns_mailbox_get_msg_owner(mailbox_msg_handle_t handle)
+{
+    uint8_t idx;
+
+    if (get_mailbox_msg_idx(handle, &idx) != MAILBOX_SUCCESS) {
+        return NULL;
+    }
+
+    if (idx < NUM_MAILBOX_QUEUE_SLOT) {
+        return mailbox_queue_ptr->queue[idx].owner;
+    }
+
+    return NULL;
+}
+
 int32_t tfm_ns_mailbox_init(struct ns_mailbox_queue_t *queue)
 {
     int32_t ret;