feat(memory share): memcpy_trapped to copy retrieve resp

Use the function memcpy_trapped to copy the retrieve response
message to the Partition's RX buffer.
The SPMC might handle retrieve requests from the NWd, and their
RX buffer may have been assigned to realm PAS.
In such case, the SPMC would fault and `memcpy_trapped` would
return error. From this point the SPMC could recover its state
and return FFA_ERROR to the invoker partition.

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: Ib5fbe8a7baa18d38135678afb5abba0633f0e0d6
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index 8b550b9..2db0e8a 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -8,8 +8,7 @@
 
 #include "hf/ffa_memory.h"
 
-#include <stdint.h>
-
+#include "hf/arch/memcpy_trapped.h"
 #include "hf/arch/mm.h"
 #include "hf/arch/other_world.h"
 #include "hf/arch/plat/ffa.h"
@@ -3281,17 +3280,36 @@
 	/*
 	 * Prepare the memory region descriptor for the retrieve response.
 	 * Provide the pointer to the receiver tracked in the share state
-	 * strucutures.
+	 * structures.
+	 * At this point the retrieve request descriptor from the partition
+	 * has been processed. The `retrieve_request` is expected to be in
+	 * a region that is handled by the SPMC/Hyp. Reuse the same buffer to
+	 * prepare the retrieve response before copying it to the RX buffer of
+	 * the caller.
 	 */
 	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, permissions, receiver, 1,
-		memory_access_desc_size, composite->page_count,
-		composite->constituent_count, share_state->fragments[0],
+		retrieve_request, to_locked.vm->ffa_version, HF_MAILBOX_SIZE,
+		memory_region->sender, attributes, 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));
 
+	/*
+	 * Copy the message from the buffer into the partition's mailbox.
+	 * The operation might fail unexpectedly due to change in PAS address
+	 * space, or improper values to the sizes of the structures.
+	 */
+	if (!memcpy_trapped(to_locked.vm->mailbox.recv, HF_MAILBOX_SIZE,
+			    retrieve_request, fragment_length)) {
+		dlog_error(
+			"%s: aborted the copy of response to RX buffer of "
+			"%x.\n",
+			__func__, to_locked.vm->id);
+		return ffa_error(FFA_ABORTED);
+	}
+
 	if (is_retrieve_complete) {
 		ffa_memory_retrieve_complete(share_states, share_state,
 					     page_pool);
@@ -3368,10 +3386,13 @@
 
 	receiver = ffa_memory_region_get_receiver(memory_region, 0);
 
+	/*
+	 * At this point the `retrieve_request` is expected to be in a section
+	 * managed by the hypervisor.
+	 */
 	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,
+		retrieve_request, to_locked.vm->ffa_version, HF_MAILBOX_SIZE,
+		memory_region->sender, attributes, memory_region->flags, handle,
 		receiver->receiver_permissions.permissions, receiver,
 		memory_region->receiver_count, memory_access_desc_size,
 		composite->page_count, composite->constituent_count,
@@ -3379,6 +3400,20 @@
 		share_state->fragment_constituent_counts[0], &total_length,
 		&fragment_length));
 
+	/*
+	 * Copy the message from the buffer into the hypervisor's mailbox.
+	 * The operation might fail unexpectedly due to change in PAS, or
+	 * improper values for the sizes of the structures.
+	 */
+	if (!memcpy_trapped(to_locked.vm->mailbox.recv, HF_MAILBOX_SIZE,
+			    retrieve_request, fragment_length)) {
+		dlog_error(
+			"%s: aborted the copy of response to RX buffer of "
+			"%x.\n",
+			__func__, to_locked.vm->id);
+		return ffa_error(FFA_ABORTED);
+	}
+
 	return ffa_memory_retrieve_resp(total_length, fragment_length);
 }