feat(tsp): enable test cases for EL3 SPMC

Introduce initial test cases to the TSP which are
designed to be exercised by the FF-A Test Driver
in the Normal World. These have been designed to
test basic functionality of the EL3 SPMC.

These tests currently ensure the following functionality:
  - Partition discovery.
  - Direct messaging.
  - Communication with a Logical SP.
  - Memory Sharing and Lending ABIs
  - Sharing of contiguous and non-contiguous memory regions.
  - Memory region descriptors spread of over multiple
    invocations.

Signed-off-by: Marc Bonnici <marc.bonnici@arm.com>
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
Change-Id: Iaee4180aa18d6b7ac7b53685c6589f0ab306e876
diff --git a/bl32/tsp/ffa_helpers.c b/bl32/tsp/ffa_helpers.c
index 296957e..3639c22 100644
--- a/bl32/tsp/ffa_helpers.c
+++ b/bl32/tsp/ffa_helpers.c
@@ -9,6 +9,48 @@
 #include <services/ffa_svc.h>
 #include "tsp_private.h"
 
+/*******************************************************************************
+ * Wrapper function to send a direct request.
+ ******************************************************************************/
+smc_args_t ffa_msg_send_direct_req(ffa_endpoint_id16_t sender,
+				   ffa_endpoint_id16_t receiver,
+				   uint32_t arg3,
+				   uint32_t arg4,
+				   uint32_t arg5,
+				   uint32_t arg6,
+				   uint32_t arg7)
+{
+	uint32_t src_dst_ids = (sender << FFA_DIRECT_MSG_SOURCE_SHIFT) |
+			       (receiver << FFA_DIRECT_MSG_DESTINATION_SHIFT);
+
+
+	/* Send Direct Request. */
+	return smc_helper(FFA_MSG_SEND_DIRECT_REQ_SMC64, src_dst_ids,
+			0, arg3, arg4, arg5, arg6, arg7);
+}
+
+/*******************************************************************************
+ * Wrapper function to send a direct response.
+ ******************************************************************************/
+smc_args_t *ffa_msg_send_direct_resp(ffa_endpoint_id16_t sender,
+				     ffa_endpoint_id16_t receiver,
+				     uint32_t arg3,
+				     uint32_t arg4,
+				     uint32_t arg5,
+				     uint32_t arg6,
+				     uint32_t arg7)
+{
+	uint32_t src_dst_ids = (sender << FFA_DIRECT_MSG_SOURCE_SHIFT) |
+			       (receiver << FFA_DIRECT_MSG_DESTINATION_SHIFT);
+
+	return set_smc_args(FFA_MSG_SEND_DIRECT_RESP_SMC64, src_dst_ids,
+			    0, arg3, arg4, arg5, arg6, arg7);
+}
+
+/*******************************************************************************
+ * Memory Management Helpers.
+ ******************************************************************************/
+
 /**
  * Initialises the header of the given `ffa_mtd`, not including the
  * composite memory region offset.
@@ -49,7 +91,7 @@
  *
  * Returns the size of the descriptor written.
  */
-uint32_t ffa_memory_retrieve_request_init(
+static uint32_t ffa_memory_retrieve_request_init(
 	struct ffa_mtd *memory_region, uint64_t handle,
 	ffa_endpoint_id16_t sender, ffa_endpoint_id16_t *receivers, uint32_t receiver_count,
 	uint64_t tag, ffa_mtd_flag32_t flags,
@@ -98,6 +140,89 @@
 		       0, 0, 0, 0);
 }
 
+bool memory_retrieve(struct mailbox *mb,
+			    struct ffa_mtd **retrieved,
+			    uint64_t handle, ffa_endpoint_id16_t sender,
+			    ffa_endpoint_id16_t *receivers, uint32_t receiver_count,
+			    ffa_mtd_flag32_t flags, uint32_t *frag_length,
+			    uint32_t *total_length)
+{
+	smc_args_t ret;
+	uint32_t descriptor_size;
+	struct ffa_mtd *memory_region = (struct ffa_mtd *)mb->tx_buffer;
+
+	if (retrieved == NULL || mb == NULL) {
+		ERROR("Invalid parameters!\n");
+		return false;
+	}
+
+	/* Clear TX buffer. */
+	memset(memory_region, 0, PAGE_SIZE);
+
+	/* Clear local buffer. */
+	memset(mem_region_buffer, 0, REGION_BUF_SIZE);
+
+	descriptor_size = ffa_memory_retrieve_request_init(
+	    memory_region, handle, sender, receivers, receiver_count, 0, flags,
+	    FFA_MEM_PERM_RW | FFA_MEM_PERM_NX,
+	    FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB |
+	    FFA_MEM_ATTR_INNER_SHAREABLE);
+
+	ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
+
+	if (ffa_func_id(ret) == FFA_ERROR) {
+		ERROR("Couldn't retrieve the memory page. Error: %x\n",
+		      ffa_error_code(ret));
+		return false;
+	}
+
+	/*
+	 * Following total_size and fragment_size are useful to keep track
+	 * of the state of transaction. When the sum of all fragment_size of all
+	 * fragments is equal to total_size, the memory transaction has been
+	 * completed.
+	 */
+	*total_length = ret._regs[1];
+	*frag_length = ret._regs[2];
+
+	/* Validate frag_length is less than total_length and mailbox size. */
+	if (*frag_length == 0U || *total_length == 0U ||
+	    *frag_length > *total_length || *frag_length > (mb->rxtx_page_count * PAGE_SIZE)) {
+		ERROR("Invalid parameters!\n");
+		return false;
+	}
+
+	/* Copy response to local buffer. */
+	memcpy(mem_region_buffer, mb->rx_buffer, *frag_length);
+
+	if (ffa_rx_release()) {
+		ERROR("Failed to release buffer!\n");
+		return false;
+	}
+
+	*retrieved = (struct ffa_mtd *) mem_region_buffer;
+
+	if ((*retrieved)->emad_count > MAX_MEM_SHARE_RECIPIENTS) {
+		VERBOSE("SPMC memory sharing supports max of %u receivers!\n",
+			MAX_MEM_SHARE_RECIPIENTS);
+		return false;
+	}
+
+	/*
+	 * We are sharing memory from the normal world therefore validate the NS
+	 * bit was set by the SPMC.
+	 */
+	if (((*retrieved)->memory_region_attributes & FFA_MEM_ATTR_NS_BIT) == 0U) {
+		ERROR("SPMC has not set the NS bit! 0x%x\n",
+		      (*retrieved)->memory_region_attributes);
+		return false;
+	}
+
+	VERBOSE("Memory Descriptor Retrieved!\n");
+
+	return true;
+}
+
 /* Relinquish the memory region. */
 bool memory_relinquish(struct ffa_mem_relinquish_descriptor *m, uint64_t handle,
 		       ffa_endpoint_id16_t id)