fix(memory share): hypervisor retrieve request

Hypervisor retrieve request was not producing the correct
response according to FF-A v1.2.
As well, the sanity checks present in the handling of the
retrieve request were not considering the hypervisor
retrieve request scenario. The checks are now skipped for
such case.

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I5d6d05f138f709cf8d9c833fbaf26c12a598d003
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index 7fb7d61..8641d5b 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -25,6 +25,7 @@
 #include "hf/mpool.h"
 #include "hf/std.h"
 #include "hf/vm.h"
+#include "hf/vm_ids.h"
 
 #include "vmapi/hf/ffa_v1_0.h"
 
@@ -2133,10 +2134,10 @@
 	void *response, uint32_t ffa_version, size_t response_max_size,
 	ffa_id_t sender, ffa_memory_attributes_t attributes,
 	ffa_memory_region_flags_t flags, ffa_memory_handle_t handle,
-	ffa_id_t receiver_id, uint32_t memory_access_desc_size,
 	ffa_memory_access_permissions_t permissions,
-	struct ffa_memory_access_impdef receiver_impdef_val,
-	uint32_t page_count, uint32_t total_constituent_count,
+	struct ffa_memory_access *receivers, size_t receiver_count,
+	uint32_t memory_access_desc_size, uint32_t page_count,
+	uint32_t total_constituent_count,
 	const struct ffa_memory_region_constituent constituents[],
 	uint32_t fragment_constituent_count, uint32_t *total_length,
 	uint32_t *fragment_length)
@@ -2145,7 +2146,6 @@
 	uint32_t i;
 	uint32_t composite_offset;
 	uint32_t constituents_offset;
-	uint32_t receiver_count;
 
 	assert(response != NULL);
 
@@ -2154,22 +2154,30 @@
 			(struct ffa_memory_region_v1_0 *)response;
 		struct ffa_memory_access_v1_0 *receiver;
 
-		ffa_memory_region_init_header_v1_0(
-			retrieve_response, sender, attributes, flags, handle, 0,
-			RECEIVERS_COUNT_IN_RETRIEVE_RESP);
+		ffa_memory_region_init_header_v1_0(retrieve_response, sender,
+						   attributes, flags, handle, 0,
+						   receiver_count);
 
 		receiver = (struct ffa_memory_access_v1_0 *)
 				   retrieve_response->receivers;
 		receiver_count = retrieve_response->receiver_count;
 
-		/*
-		 * Initialized here as in memory retrieve responses we currently
-		 * expect one borrower to be specified.
-		 */
-		ffa_memory_access_init_v1_0(
-			receiver, receiver_id,
-			ffa_get_data_access_attr(permissions),
-			ffa_get_instruction_access_attr(permissions), flags);
+		for (uint32_t i = 0; i < receiver_count; i++) {
+			ffa_id_t receiver_id =
+				receivers[i].receiver_permissions.receiver;
+			ffa_memory_receiver_flags_t recv_flags =
+				receivers[i].receiver_permissions.flags;
+
+			/*
+			 * Initialized here as in memory retrieve responses we
+			 * currently expect one borrower to be specified.
+			 */
+			ffa_memory_access_init_v1_0(
+				receiver, receiver_id,
+				ffa_get_data_access_attr(permissions),
+				ffa_get_instruction_access_attr(permissions),
+				recv_flags);
+		}
 
 		composite_offset =
 			sizeof(struct ffa_memory_region_v1_0) +
@@ -2181,13 +2189,11 @@
 	} else {
 		struct ffa_memory_region *retrieve_response =
 			(struct ffa_memory_region *)response;
-		struct ffa_memory_access *receiver;
+		struct ffa_memory_access *retrieve_response_receivers;
 
-		ffa_memory_region_init_header(retrieve_response, sender,
-					      attributes, flags, handle, 0, 1,
-					      memory_access_desc_size);
-
-		receiver_count = retrieve_response->receiver_count;
+		ffa_memory_region_init_header(
+			retrieve_response, sender, attributes, flags, handle, 0,
+			receiver_count, memory_access_desc_size);
 
 		/*
 		 * Note that `sizeof(struct_ffa_memory_region)` and
@@ -2202,19 +2208,22 @@
 			(uint32_t)(receiver_count *
 				   retrieve_response->memory_access_desc_size);
 
-		receiver = ffa_memory_region_get_receiver(retrieve_response, 0);
-		assert(receiver != NULL);
+		retrieve_response_receivers =
+			ffa_memory_region_get_receiver(retrieve_response, 0);
+		assert(retrieve_response_receivers != NULL);
 
 		/*
 		 * Initialized here as in memory retrieve responses we currently
 		 * expect one borrower to be specified.
 		 */
-		ffa_memory_access_init(
-			receiver, receiver_id,
-			ffa_get_data_access_attr(permissions),
-			ffa_get_instruction_access_attr(permissions), flags,
-			&receiver_impdef_val);
-		receiver->composite_memory_region_offset = composite_offset;
+		memcpy_s(retrieve_response_receivers,
+			 sizeof(struct ffa_memory_access) * receiver_count,
+			 receivers,
+			 sizeof(struct ffa_memory_access) * receiver_count);
+
+		retrieve_response_receivers->composite_memory_region_offset =
+			composite_offset;
+
 		composite_memory_region =
 			ffa_memory_region_get_composite(retrieve_response, 0);
 	}
@@ -2406,8 +2415,8 @@
 static struct ffa_value ffa_memory_retrieve_validate_memory_access_list(
 	struct ffa_memory_region *memory_region,
 	struct ffa_memory_region *retrieve_request, ffa_id_t to_vm_id,
-	ffa_memory_access_permissions_t *permissions, uint32_t func_id,
-	struct ffa_memory_access_impdef *to_impdef_val)
+	ffa_memory_access_permissions_t *permissions,
+	struct ffa_memory_access **receiver_ret, uint32_t func_id)
 {
 	uint32_t retrieve_receiver_index;
 	bool bypass_multi_receiver_check =
@@ -2416,8 +2425,11 @@
 	const uint32_t region_receiver_count = memory_region->receiver_count;
 	struct ffa_value ret;
 
+	assert(receiver_ret != NULL);
 	assert(permissions != NULL);
 
+	*permissions = 0;
+
 	if (!bypass_multi_receiver_check) {
 		if (retrieve_request->receiver_count != region_receiver_count) {
 			dlog_verbose(
@@ -2437,9 +2449,6 @@
 
 	retrieve_receiver_index = retrieve_request->receiver_count;
 
-	/* Should be populated with the permissions of the retriever. */
-	*permissions = 0;
-
 	for (uint32_t i = 0U; i < retrieve_request->receiver_count; i++) {
 		ffa_memory_access_permissions_t sent_permissions;
 		struct ffa_memory_access *retrieve_request_receiver =
@@ -2451,6 +2460,10 @@
 		ffa_id_t current_receiver_id =
 			retrieve_request_receiver->receiver_permissions
 				.receiver;
+		struct ffa_memory_access *receiver;
+		uint32_t mem_region_receiver_index;
+		bool permissions_RO;
+		bool clear_memory_flags;
 		bool found_to_id = current_receiver_id == to_vm_id;
 
 		if (bypass_multi_receiver_check && !found_to_id) {
@@ -2474,7 +2487,7 @@
 		 * Find the current receiver in the transaction descriptor from
 		 * sender.
 		 */
-		uint32_t mem_region_receiver_index =
+		mem_region_receiver_index =
 			ffa_memory_region_get_receiver_index(
 				memory_region, current_receiver_id);
 
@@ -2485,15 +2498,16 @@
 			return ffa_error(FFA_DENIED);
 		}
 
-		struct ffa_memory_access *receiver =
-			ffa_memory_region_get_receiver(
-				memory_region, mem_region_receiver_index);
+		receiver = ffa_memory_region_get_receiver(
+			memory_region, mem_region_receiver_index);
 		assert(receiver != NULL);
 
 		sent_permissions = receiver->receiver_permissions.permissions;
 
 		if (found_to_id) {
 			retrieve_receiver_index = i;
+
+			*receiver_ret = receiver;
 		}
 
 		/*
@@ -2508,19 +2522,21 @@
 			ffa_get_instruction_access_attr(requested_permissions),
 			found_to_id ? permissions : NULL,
 			region_receiver_count > 1);
+
 		if (ret.func != FFA_SUCCESS_32) {
 			return ret;
 		}
 
+		permissions_RO = (ffa_get_data_access_attr(*permissions) ==
+				  FFA_DATA_ACCESS_RO);
+		clear_memory_flags = (retrieve_request->flags &
+				      FFA_MEMORY_REGION_FLAG_CLEAR) != 0U;
+
 		/*
-		 * Can't request PM to clear memory if only provided with RO
-		 * permissions.
+		 * Can't request PM to clear memory if only provided
+		 * with RO permissions.
 		 */
-		if (found_to_id &&
-		    (ffa_get_data_access_attr(*permissions) ==
-		     FFA_DATA_ACCESS_RO) &&
-		    (retrieve_request->flags & FFA_MEMORY_REGION_FLAG_CLEAR) !=
-			    0U) {
+		if (found_to_id && permissions_RO && clear_memory_flags) {
 			dlog_verbose(
 				"Receiver has RO permissions can not request "
 				"clear.\n");
@@ -2537,10 +2553,6 @@
 		    ffa_version_from_memory_access_desc_size(
 			    retrieve_request->memory_access_desc_size) >=
 			    MAKE_FFA_VERSION(1, 2)) {
-			if (found_to_id) {
-				*to_impdef_val =
-					retrieve_request_receiver->impdef;
-			}
 			if (receiver->impdef.val[0] !=
 				    retrieve_request_receiver->impdef.val[0] ||
 			    receiver->impdef.val[1] !=
@@ -2819,11 +2831,10 @@
 	ffa_id_t receiver_id = to_locked.vm->id;
 	bool is_retrieve_complete = false;
 	ffa_memory_attributes_t attributes;
-	struct ffa_memory_access_impdef receiver_impdef_val;
 	const uint64_t memory_access_desc_size =
 		retrieve_request->memory_access_desc_size;
 	uint32_t receiver_index;
-
+	struct ffa_memory_access *receiver;
 	ffa_memory_handle_t handle = retrieve_request->handle;
 
 	struct ffa_memory_region *memory_region = share_state->memory_region;
@@ -2863,8 +2874,7 @@
 	 */
 	ret = ffa_memory_retrieve_validate_memory_access_list(
 		memory_region, retrieve_request, receiver_id, &permissions,
-		share_state->share_func, &receiver_impdef_val);
-
+		&receiver, share_state->share_func);
 	if (ret.func != FFA_SUCCESS_32) {
 		return ret;
 	}
@@ -2899,7 +2909,6 @@
 	 * Copy response to RX buffer of caller and deliver the message.
 	 * This must be done before the share_state is (possibly) freed.
 	 */
-	/* TODO: combine attributes from sender and request. */
 	composite = ffa_memory_region_get_composite(memory_region, 0);
 
 	/*
@@ -2917,13 +2926,20 @@
 	attributes = plat_ffa_memory_security_mode(
 		memory_region->attributes, share_state->sender_orig_mode);
 
+	/* Provide the permissions that had been provided. */
+	receiver->receiver_permissions.permissions = permissions;
+
+	/*
+	 * Prepare the memory region descriptor for the retrieve response.
+	 * Provide the pointer to the receiver tracked in the share state
+	 * strucutures.
+	 */
 	CHECK(ffa_retrieved_memory_region_init(
 		to_locked.vm->mailbox.recv, to_locked.vm->ffa_version,
 		HF_MAILBOX_SIZE, memory_region->sender, attributes,
-		memory_region->flags, handle, receiver_id,
-		memory_access_desc_size, permissions, receiver_impdef_val,
-		composite->page_count, composite->constituent_count,
-		share_state->fragments[0],
+		memory_region->flags, handle, permissions, receiver, 1,
+		memory_access_desc_size, composite->page_count,
+		composite->constituent_count, share_state->fragments[0],
 		share_state->fragment_constituent_counts[0], &total_length,
 		&fragment_length));
 
@@ -2943,18 +2959,16 @@
 	struct ffa_composite_memory_region *composite;
 	uint32_t total_length;
 	uint32_t fragment_length;
-	ffa_id_t receiver_id = to_locked.vm->id;
 	ffa_memory_attributes_t attributes;
 	uint64_t memory_access_desc_size;
 	struct ffa_memory_region *memory_region;
-
+	struct ffa_memory_access *receiver;
 	ffa_memory_handle_t handle = retrieve_request->handle;
 
-	/** TODO: include in the hypervisor retrieve response. */
-	struct ffa_memory_access_impdef receiver_impdef_val = {{0, 0}};
-
 	memory_region = share_state->memory_region;
 
+	assert(to_locked.vm->id == HF_HYPERVISOR_VM_ID);
+
 	switch (to_locked.vm->ffa_version) {
 	case MAKE_FFA_VERSION(1, 2):
 		memory_access_desc_size = sizeof(struct ffa_memory_access);
@@ -3002,11 +3016,15 @@
 	 */
 	attributes = plat_ffa_memory_security_mode(
 		memory_region->attributes, share_state->sender_orig_mode);
+
+	receiver = ffa_memory_region_get_receiver(memory_region, 0);
+
 	CHECK(ffa_retrieved_memory_region_init(
 		to_locked.vm->mailbox.recv, to_locked.vm->ffa_version,
 		HF_MAILBOX_SIZE, memory_region->sender, attributes,
-		memory_region->flags, handle, receiver_id,
-		memory_access_desc_size, 0, receiver_impdef_val,
+		memory_region->flags, handle,
+		receiver->receiver_permissions.permissions, receiver,
+		memory_region->receiver_count, memory_access_desc_size,
 		composite->page_count, composite->constituent_count,
 		share_state->fragments[0],
 		share_state->fragment_constituent_counts[0], &total_length,