FF-A: SPMC direct messaging interface.

Adaptation of direct messaging interface to the SPMC.

Change-Id: Ic27d19908d2071be57483a76da61c7f948b86bdb
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/src/api.c b/src/api.c
index bdf60d3..a514bf6 100644
--- a/src/api.c
+++ b/src/api.c
@@ -123,6 +123,34 @@
 }
 
 /**
+ * Choose next vCPU to run to be the counterpart vCPU in the other
+ * world (run the normal world if currently running in the secure
+ * world). Set current vCPU state to the given vcpu_state parameter.
+ * Set FF-A return values to the target vCPU in the other world.
+ *
+ * Called in context of a direct message response from a secure
+ * partition to a VM.
+ */
+static struct vcpu *api_switch_to_other_world(struct vcpu *current,
+					      struct ffa_value other_world_ret,
+					      enum vcpu_state vcpu_state)
+{
+	struct vcpu *next = vcpu_get_other_world_counterpart(current);
+
+	CHECK(next != NULL);
+
+	/* Set the return value for the other world's VM. */
+	arch_regs_set_retval(&next->regs, other_world_ret);
+
+	/* Set the current vCPU state. */
+	sl_lock(&current->lock);
+	current->state = vcpu_state;
+	sl_unlock(&current->lock);
+
+	return next;
+}
+
+/**
  * Checks whether the given `to` VM's mailbox is currently busy, and optionally
  * registers the `from` VM to be notified when it becomes available.
  */
@@ -1601,26 +1629,15 @@
 					     struct vcpu **next)
 {
 	struct ffa_value ret = (struct ffa_value){.func = FFA_INTERRUPT_32};
-	ffa_vm_id_t current_vm_id = current->vm->id;
 	struct vm *receiver_vm;
 	struct vcpu *receiver_vcpu;
 	struct two_vcpu_locked vcpus_locked;
 
-	/* Only allow primary VM to send direct message requests. */
-	if (current_vm_id != HF_PRIMARY_VM_ID) {
+	if (!arch_other_world_is_direct_request_valid(current, sender_vm_id,
+						      receiver_vm_id)) {
 		return ffa_error(FFA_NOT_SUPPORTED);
 	}
 
-	/* Prevent sender_vm_id spoofing. */
-	if (current_vm_id != sender_vm_id) {
-		return ffa_error(FFA_INVALID_PARAMETERS);
-	}
-
-	/* Prevent a VM from sending messages to itself. */
-	if (current_vm_id == receiver_vm_id) {
-		return ffa_error(FFA_INVALID_PARAMETERS);
-	}
-
 	receiver_vm = vm_find(receiver_vm_id);
 	if (receiver_vm == NULL) {
 		return ffa_error(FFA_INVALID_PARAMETERS);
@@ -1696,7 +1713,7 @@
 	receiver_vcpu->cpu = current->cpu;
 	receiver_vcpu->state = VCPU_STATE_RUNNING;
 	receiver_vcpu->regs_available = false;
-	receiver_vcpu->direct_request_origin_vm_id = current_vm_id;
+	receiver_vcpu->direct_request_origin_vm_id = sender_vm_id;
 
 	arch_regs_set_retval(&receiver_vcpu->regs, (struct ffa_value){
 							   .func = args.func,
@@ -1735,61 +1752,67 @@
 					      struct vcpu *current,
 					      struct vcpu **next)
 {
-	ffa_vm_id_t current_vm_id = current->vm->id;
-	struct vcpu_locked vcpu_locked;
+	struct vcpu_locked current_locked;
 
-	/* Only allow secondary VMs to send direct message responses. */
-	if (current_vm_id == HF_PRIMARY_VM_ID) {
+	if (!arch_other_world_is_direct_response_valid(current, sender_vm_id,
+						       receiver_vm_id)) {
 		return ffa_error(FFA_NOT_SUPPORTED);
 	}
 
-	/* Prevent sender_vm_id spoofing. */
-	if (current_vm_id != sender_vm_id) {
-		return ffa_error(FFA_INVALID_PARAMETERS);
-	}
-
-	/* Prevent a VM from sending messages to itself. */
-	if (current_vm_id == receiver_vm_id) {
-		return ffa_error(FFA_INVALID_PARAMETERS);
-	}
-
-	vcpu_locked = vcpu_lock(current);
+	current_locked = vcpu_lock(current);
 
 	/*
 	 * Ensure the terminating FFA_MSG_SEND_DIRECT_REQ had a
 	 * defined originator.
 	 */
-	if (!is_ffa_direct_msg_request_ongoing(vcpu_locked)) {
+	if (!is_ffa_direct_msg_request_ongoing(current_locked)) {
 		/*
 		 * Sending direct response but direct request origin vCPU is
 		 * not set.
 		 */
-		vcpu_unlock(&vcpu_locked);
+		vcpu_unlock(&current_locked);
 		return ffa_error(FFA_DENIED);
 	}
 
 	if (current->direct_request_origin_vm_id != receiver_vm_id) {
-		vcpu_unlock(&vcpu_locked);
+		vcpu_unlock(&current_locked);
 		return ffa_error(FFA_DENIED);
 	}
 
 	/* Clear direct request origin for the caller. */
 	current->direct_request_origin_vm_id = HF_INVALID_VM_ID;
 
-	vcpu_unlock(&vcpu_locked);
+	vcpu_unlock(&current_locked);
 
-	*next = api_switch_to_primary(current,
-				      (struct ffa_value){
-					      .func = args.func,
-					      .arg1 = args.arg1,
-					      .arg2 = 0,
-					      .arg3 = args.arg3,
-					      .arg4 = args.arg4,
-					      .arg5 = args.arg5,
-					      .arg6 = args.arg6,
-					      .arg7 = args.arg7,
-				      },
-				      VCPU_STATE_BLOCKED_MAILBOX);
+	if (!vm_id_is_current_world(receiver_vm_id)) {
+		*next = api_switch_to_other_world(current,
+						  (struct ffa_value){
+							  .func = args.func,
+							  .arg1 = args.arg1,
+							  .arg2 = 0,
+							  .arg3 = args.arg3,
+							  .arg4 = args.arg4,
+							  .arg5 = args.arg5,
+							  .arg6 = args.arg6,
+							  .arg7 = args.arg7,
+						  },
+						  VCPU_STATE_BLOCKED_MAILBOX);
+	} else if (receiver_vm_id == HF_PRIMARY_VM_ID) {
+		*next = api_switch_to_primary(current,
+					      (struct ffa_value){
+						      .func = args.func,
+						      .arg1 = args.arg1,
+						      .arg2 = 0,
+						      .arg3 = args.arg3,
+						      .arg4 = args.arg4,
+						      .arg5 = args.arg5,
+						      .arg6 = args.arg6,
+						      .arg7 = args.arg7,
+					      },
+					      VCPU_STATE_BLOCKED_MAILBOX);
+	} else {
+		panic("Invalid direct message response invocation");
+	}
 
 	return (struct ffa_value){.func = FFA_INTERRUPT_32};
 }