feat(memory share): bypass multiple borrower check

FF-A v1.2 Alpha0, section 11.11.4.2 defines the behavior for bypassing
the multiple borrower check on FFA_MEMORY_RETRIEVE_REQ.

For this case, Hafnium will expect the borrower to specify only its
permissions.

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I9a3b088633ef218563e332e56874035462e98089
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index 238dabb..ebc5db7 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -17,8 +17,10 @@
 #include "hf/assert.h"
 #include "hf/check.h"
 #include "hf/dlog.h"
+#include "hf/ffa.h"
 #include "hf/ffa_internal.h"
 #include "hf/ffa_memory_internal.h"
+#include "hf/ffa_partition_manifest.h"
 #include "hf/mm.h"
 #include "hf/mpool.h"
 #include "hf/std.h"
@@ -2071,7 +2073,11 @@
  * specified by the lender.
  * In the `permissions` argument returns the permissions to set at S2 for the
  * caller to the FFA_MEMORY_RETRIEVE_REQ.
- * Returns FFA_SUCCESS if all specified permissions are valid.
+ * The function looks into the flag to bypass multiple borrower checks:
+ * - If not set returns FFA_SUCCESS if all specified permissions are valid.
+ * - If set returns FFA_SUCCESS if the descriptor contains the permissions
+ *   to the caller of FFA_MEM_RETRIEVE_REQ and they are valid. Other permissions
+ *   are ignored, if provided.
  */
 static struct ffa_value ffa_memory_retrieve_validate_memory_access_list(
 	struct ffa_memory_region *memory_region,
@@ -2079,14 +2085,28 @@
 	ffa_memory_access_permissions_t *permissions)
 {
 	uint32_t retrieve_receiver_index;
+	bool bypass_multi_receiver_check =
+		(retrieve_request->flags &
+		 FFA_MEMORY_REGION_FLAG_BYPASS_BORROWERS_CHECK) != 0U;
 
 	assert(permissions != NULL);
 
-	if (retrieve_request->receiver_count != memory_region->receiver_count) {
-		dlog_verbose(
-			"Retrieve request should contain same list of "
-			"borrowers, as specified by the lender.\n");
-		return ffa_error(FFA_INVALID_PARAMETERS);
+	if (!bypass_multi_receiver_check) {
+		if (retrieve_request->receiver_count !=
+		    memory_region->receiver_count) {
+			dlog_verbose(
+				"Retrieve request should contain same list of "
+				"borrowers, as specified by the lender.\n");
+			return ffa_error(FFA_INVALID_PARAMETERS);
+		}
+	} else {
+		if (retrieve_request->receiver_count != 1) {
+			dlog_verbose(
+				"Set bypass multiple borrower check, receiver "
+				"list must be sized 1 (%x)\n",
+				memory_region->receiver_count);
+			return ffa_error(FFA_INVALID_PARAMETERS);
+		}
 	}
 
 	retrieve_receiver_index = retrieve_request->receiver_count;
@@ -2104,6 +2124,13 @@
 			current_receiver->receiver_permissions.receiver;
 		bool found_to_id = current_receiver_id == to_vm_id;
 
+		if (bypass_multi_receiver_check && !found_to_id) {
+			dlog_verbose(
+				"Bypass multiple borrower check for id %x.\n",
+				current_receiver_id);
+			continue;
+		}
+
 		/*
 		 * Find the current receiver in the transaction descriptor from
 		 * sender.