fix(memory share): checks to allow VM to SP memory share

Fix check made to the memory region structure on memory share operation
to permit calls from the other world.

With the update:
- Hypervisor is allowed to forward the call to the SPMC and sender be a
VM.
- SPMC is allowed to handle call forwarded from the Hypervisor.
- Number of borrowers still limited to one if call to the other
world. This is temporary.
- Lender VM can now specify an FF-A ID belonging to an SP.

Change-Id: I5f740316a8f3d0e2749b8ac68e78c0d482634f8f
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index eb09499..705db71 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2851,13 +2851,6 @@
 	}
 	memcpy_s(memory_region, MM_PPOOL_ENTRY_SIZE, from_msg, fragment_length);
 
-	/* The sender must match the caller. */
-	if (memory_region->sender != from->id) {
-		dlog_verbose("Memory region sender doesn't match caller.\n");
-		ret = ffa_error(FFA_DENIED);
-		goto out;
-	}
-
 	if (!api_memory_region_check_flags(memory_region, share_func)) {
 		dlog_verbose(
 			"Memory region reserved arguments must be zero.\n");
@@ -2923,8 +2916,9 @@
 
 	/* Allow for one memory region to be shared to the TEE. */
 	if (targets_other_world) {
-		assert(memory_region->receiver_count == 1 &&
-		       to->id == HF_TEE_VM_ID);
+		assert(memory_region->receiver_count == 1);
+		to = vm_find(HF_OTHER_WORLD_ID);
+
 		/*
 		 * The 'to' VM lock is only needed in the case that it is the
 		 * TEE VM.
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index 5826cb2..240b230 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -1393,10 +1393,13 @@
 	enum ffa_instruction_access instruction_access;
 	struct ffa_value ret;
 
-	/* The sender must match the message sender. */
-	if (memory_region->sender != from_locked.vm->id) {
-		dlog_verbose("Invalid sender %d.\n", memory_region->sender);
-		return ffa_error(FFA_INVALID_PARAMETERS);
+	/* The sender must match the caller. */
+	if ((!vm_id_is_current_world(from_locked.vm->id) &&
+	     vm_id_is_current_world(memory_region->sender)) ||
+	    (vm_id_is_current_world(from_locked.vm->id) &&
+	     memory_region->sender != from_locked.vm->id)) {
+		dlog_verbose("Invalid memory sender ID.\n");
+		return ffa_error(FFA_DENIED);
 	}
 
 	/*
@@ -1701,6 +1704,22 @@
 }
 
 /**
+ * Checks if there is at least one receiver from the other world.
+ */
+static bool memory_region_receivers_from_other_world(
+	struct ffa_memory_region *memory_region)
+{
+	for (uint32_t i = 0; i < memory_region->receiver_count; i++) {
+		ffa_vm_id_t receiver = memory_region->receivers[i]
+					       .receiver_permissions.receiver;
+		if (!vm_id_is_current_world(receiver)) {
+			return true;
+		}
+	}
+	return false;
+}
+
+/**
  * Validates a call to donate, lend or share memory to a non-TEE VM and then
  * updates the stage-2 page tables. Specifically, check if the message length
  * and number of memory region constituents match, and if the transition is
@@ -1971,8 +1990,7 @@
 	}
 	memory_region = share_state->memory_region;
 
-	if (memory_region->receivers[0].receiver_permissions.receiver ==
-	    HF_TEE_VM_ID) {
+	if (memory_region_receivers_from_other_world(memory_region)) {
 		dlog_error(
 			"Got hypervisor-allocated handle for memory send to "
 			"TEE. This should never happen, and indicates a bug in "
@@ -2042,8 +2060,7 @@
 	}
 	memory_region = share_state->memory_region;
 
-	if (memory_region->receivers[0].receiver_permissions.receiver !=
-	    HF_TEE_VM_ID) {
+	if (!memory_region_receivers_from_other_world(memory_region)) {
 		dlog_error(
 			"Got SPM-allocated handle for memory send to non-TEE "
 			"VM. This should never happen, and indicates a bug.\n");