Add support for notifying VMs when mailboxes become writable.

This allows VMs to know when they can retry sending messages to another
VM after an attempt fails because the recipient's mailbox is not
available.

Change-Id: Ib20159f7ecf81544e40149edcd663876c58851c7
diff --git a/inc/vmapi/hf/abi.h b/inc/vmapi/hf/abi.h
index 6f43360..451de41 100644
--- a/inc/vmapi/hf/abi.h
+++ b/inc/vmapi/hf/abi.h
@@ -64,6 +64,13 @@
 	 * `hf_vcpu_run` on it again.
 	 */
 	HF_VCPU_RUN_SLEEP,
+
+	/**
+	 * The vCPU has made the mailbox writable and there are pending waiters.
+	 * The scheduler MUST call hf_mailbox_waiter_get() repeatedly and notify
+	 * all waiters by injecting an HF_MAILBOX_WRITABLE_INTID interrupt.
+	 */
+	HF_VCPU_RUN_NOTIFY_WAITERS,
 };
 
 struct hf_vcpu_run_return {
diff --git a/inc/vmapi/hf/call.h b/inc/vmapi/hf/call.h
index 3922f7a..8014f8c 100644
--- a/inc/vmapi/hf/call.h
+++ b/inc/vmapi/hf/call.h
@@ -23,18 +23,20 @@
 /* clang-format off */
 
 /* TODO: Define constants below according to spec. */
-#define HF_VM_GET_ID        0xff00
-#define HF_VM_GET_COUNT     0xff01
-#define HF_VCPU_GET_COUNT   0xff02
-#define HF_VCPU_RUN         0xff03
-#define HF_VCPU_YIELD       0xff04
-#define HF_VM_CONFIGURE     0xff05
-#define HF_MAILBOX_SEND     0xff06
-#define HF_MAILBOX_RECEIVE  0xff07
-#define HF_MAILBOX_CLEAR    0xff08
-#define HF_INTERRUPT_ENABLE 0xff09
-#define HF_INTERRUPT_GET    0xff0a
-#define HF_INTERRUPT_INJECT 0xff0b
+#define HF_VM_GET_ID            0xff00
+#define HF_VM_GET_COUNT         0xff01
+#define HF_VCPU_GET_COUNT       0xff02
+#define HF_VCPU_RUN             0xff03
+#define HF_VCPU_YIELD           0xff04
+#define HF_VM_CONFIGURE         0xff05
+#define HF_MAILBOX_SEND         0xff06
+#define HF_MAILBOX_RECEIVE      0xff07
+#define HF_MAILBOX_CLEAR        0xff08
+#define HF_MAILBOX_WRITABLE_GET 0xff09
+#define HF_MAILBOX_WAITER_GET   0xff0a
+#define HF_INTERRUPT_ENABLE     0xff0b
+#define HF_INTERRUPT_GET        0xff0c
+#define HF_INTERRUPT_INJECT     0xff0d
 
 /** The amount of data that can be sent to a mailbox. */
 #define HF_MAILBOX_SIZE 4096
@@ -95,7 +97,11 @@
  * Configures the pages to send/receive data through. The pages must not be
  * shared.
  *
- * Returns 0 on success or -1 or failure.
+ * Returns:
+ *  - -1 on failure.
+ *  - 0 on success if no further action is needed.
+ *  - 1 if it was called by the primary VM and the primary VM now needs to wake
+ *    up or kick waiters.
  */
 static inline int64_t hf_vm_configure(hf_ipaddr_t send, hf_ipaddr_t recv)
 {
@@ -137,8 +143,12 @@
 /**
  * Clears the caller's mailbox so a new message can be received.
  *
- * Returns 0 on success, or -1 if the mailbox hasn't been read or is already
- * empty.
+ * Returns:
+ *  - -1 on failure, if the mailbox hasn't been read or is already empty.
+ *  - 0 on success if no further action is needed.
+ *  - 1 if it was called by the primary VM and the primary VM now needs to wake
+ *    up or kick waiters. Waiters should be retrieved by calling
+ *    hf_mailbox_waiter_get.
  */
 static inline int64_t hf_mailbox_clear(void)
 {
@@ -146,6 +156,34 @@
 }
 
 /**
+ * Retrieves the next VM whose mailbox became writable. For a VM to be notified
+ * by this function, the caller must have called api_mailbox_send before with
+ * the notify argument set to true, and this call must have failed because the
+ * mailbox was not available.
+ *
+ * It should be called repeatedly to retreive a list of VMs.
+ *
+ * Returns -1 if no VM became writable, or the id of the VM whose mailbox
+ * became writable.
+ */
+static inline int64_t hf_mailbox_writable_get(void)
+{
+	return hf_call(HF_MAILBOX_WRITABLE_GET, 0, 0, 0);
+}
+
+/**
+ * Retrieves the next VM waiting to be notified that the mailbox of the
+ * specified VM became writable. Only primary VMs are allowed to call this.
+ *
+ * Returns -1 if there are no waiters, or the VM id of the next waiter
+ * otherwise.
+ */
+static inline int64_t hf_mailbox_waiter_get(uint32_t vm_id)
+{
+	return hf_call(HF_MAILBOX_WAITER_GET, vm_id, 0, 0);
+}
+
+/**
  * Enables or disables a given interrupt ID.
  *
  * Returns 0 on success, or -1 if the intid is invalid.
diff --git a/inc/vmapi/hf/types.h b/inc/vmapi/hf/types.h
index 697a990..f0b39d9 100644
--- a/inc/vmapi/hf/types.h
+++ b/inc/vmapi/hf/types.h
@@ -45,3 +45,9 @@
 
 /** Interrupt ID returned when there is no interrupt pending. */
 #define HF_INVALID_INTID 0xffffffff
+
+/** Interrupt ID indicating the mailbox is readable. */
+#define HF_MAILBOX_READBLE_INTID 1
+
+/** Interrupt ID indicating a mailbox is writable. */
+#define HF_MAILBOX_WRITABLE_INTID 2