Factor out parts of api_spci_msg_send to helper functions.
Bug: 132429380
Change-Id: I39394ae1d8795e47b10d1c9c75dfaa55556c8bc7
diff --git a/src/api.c b/src/api.c
index 9ee5c5c..e583a31 100644
--- a/src/api.c
+++ b/src/api.c
@@ -841,6 +841,72 @@
}
/**
+ * Checks whether the given `to` VM's mailbox is currently busy, and optionally
+ * registers the `from` VM to be notified when it becomes available.
+ */
+static bool msg_receiver_busy(struct vm_locked to, struct vm_locked from,
+ bool notify)
+{
+ if (to.vm->mailbox.state != MAILBOX_STATE_EMPTY ||
+ to.vm->mailbox.recv == NULL) {
+ /*
+ * Fail if the receiver isn't currently ready to receive data,
+ * setting up for notification if requested.
+ */
+ if (notify) {
+ struct wait_entry *entry =
+ &from.vm->wait_entries[to.vm->id];
+
+ /* Append waiter only if it's not there yet. */
+ if (list_empty(&entry->wait_links)) {
+ list_append(&to.vm->mailbox.waiter_list,
+ &entry->wait_links);
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Notifies the `to` VM about the message currently in its mailbox, possibly
+ * with the help of the primary VM.
+ */
+static void deliver_msg(struct vm_locked to, struct vm_locked from,
+ uint32_t size, struct vcpu *current, struct vcpu **next)
+{
+ struct hf_vcpu_run_return primary_ret = {
+ .code = HF_VCPU_RUN_MESSAGE,
+ };
+
+ primary_ret.message.vm_id = to.vm->id;
+
+ /* Messages for the primary VM are delivered directly. */
+ if (to.vm->id == HF_PRIMARY_VM_ID) {
+ /*
+ * Only tell the primary VM the size if the message is for it,
+ * to avoid leaking data about messages for other VMs.
+ */
+ primary_ret.message.size = size;
+
+ to.vm->mailbox.state = MAILBOX_STATE_READ;
+ *next = api_switch_to_primary(current, primary_ret,
+ VCPU_STATE_READY);
+ return;
+ }
+
+ to.vm->mailbox.state = MAILBOX_STATE_RECEIVED;
+
+ /* Return to the primary VM directly or with a switch. */
+ if (from.vm->id != HF_PRIMARY_VM_ID) {
+ *next = api_switch_to_primary(current, primary_ret,
+ VCPU_STATE_READY);
+ }
+}
+
+/**
* Copies data from the sender's send buffer to the recipient's receive buffer
* and notifies the recipient.
*
@@ -857,9 +923,6 @@
struct two_vm_locked vm_to_from_lock;
- struct hf_vcpu_run_return primary_ret = {
- .code = HF_VCPU_RUN_MESSAGE,
- };
const void *from_msg;
struct spci_value ret;
@@ -911,23 +974,8 @@
*/
vm_to_from_lock = vm_lock_both(to, from);
- if (to->mailbox.state != MAILBOX_STATE_EMPTY ||
- to->mailbox.recv == NULL) {
- /*
- * Fail if the receiver isn't currently ready to receive data,
- * setting up for notification if requested.
- */
- if (notify) {
- struct wait_entry *entry =
- &from->wait_entries[receiver_vm_id];
-
- /* Append waiter only if it's not there yet. */
- if (list_empty(&entry->wait_links)) {
- list_append(&to->mailbox.waiter_list,
- &entry->wait_links);
- }
- }
-
+ if (msg_receiver_busy(vm_to_from_lock.vm1, vm_to_from_lock.vm2,
+ notify)) {
ret = spci_error(SPCI_BUSY);
goto out;
}
@@ -989,29 +1037,8 @@
ret = (struct spci_value){.func = SPCI_SUCCESS_32};
}
- primary_ret.message.vm_id = to->id;
-
- /* Messages for the primary VM are delivered directly. */
- if (to->id == HF_PRIMARY_VM_ID) {
- /*
- * Only tell the primary VM the size if the message is for it,
- * to avoid leaking data about messages for other VMs.
- */
- primary_ret.message.size = size;
-
- to->mailbox.state = MAILBOX_STATE_READ;
- *next = api_switch_to_primary(current, primary_ret,
- VCPU_STATE_READY);
- goto out;
- }
-
- to->mailbox.state = MAILBOX_STATE_RECEIVED;
-
- /* Return to the primary VM directly or with a switch. */
- if (from->id != HF_PRIMARY_VM_ID) {
- *next = api_switch_to_primary(current, primary_ret,
- VCPU_STATE_READY);
- }
+ deliver_msg(vm_to_from_lock.vm1, vm_to_from_lock.vm2, size, current,
+ next);
out:
vm_unlock(&vm_to_from_lock.vm1);
@@ -1402,7 +1429,7 @@
return ret;
}
-/** TODO: Move function to spci_architectted_message.c. */
+/** TODO: Move function to spci_architected_message.c. */
/**
* Shares memory from the calling VM with another. The memory can be shared in
* different modes.