Merge changes from topic "sp_to_sp_mem_share"

* changes:
  Cactus: cmd for mem share tests
  TFTF: tests to request SP-to-SP memory share
  cactus: test SP-to-SP memory share operations
  cactus: add command to request memory sharing between SPs
  TFTF: Refactor FF-A memory sharing tests
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index ed3302f..b8928d4 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -397,6 +397,16 @@
 	enum ffa_memory_shareability shareability, uint32_t *total_length,
 	uint32_t *fragment_length);
 
+ffa_memory_handle_t ffa_memory_send(
+	struct ffa_memory_region *memory_region, uint32_t mem_func,
+	uint32_t fragment_length, uint32_t total_length);
+
+ffa_memory_handle_t ffa_memory_init_and_send(
+	struct ffa_memory_region *memory_region, size_t memory_region_max_size,
+	ffa_vm_id_t sender, ffa_vm_id_t receiver,
+	const struct ffa_memory_region_constituent* constituents,
+	uint32_t constituents_count, uint32_t mem_func);
+
 bool check_spmc_execution_level(void);
 smc_ret_values ffa_msg_send_direct_req(uint32_t source_id, uint32_t dest_id, uint32_t message);
 smc_ret_values ffa_msg_send_direct_req64(uint32_t source_id, uint32_t dest_id, uint64_t message);
diff --git a/spm/cactus/cactus_ffa_tests.c b/spm/cactus/cactus_ffa_tests.c
index 07aaaca..5863456 100644
--- a/spm/cactus/cactus_ffa_tests.c
+++ b/spm/cactus/cactus_ffa_tests.c
@@ -307,7 +307,11 @@
 			m->receivers[0].receiver_permissions.permissions),
 		FFA_DATA_ACCESS_RW);
 
-	mem_attrs = MT_RW_DATA | MT_NS | MT_EXECUTE_NEVER;
+	mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
+
+	if (!IS_SP_ID(sender)) {
+		mem_attrs |= MT_NS;
+	}
 
 	ret = mmap_add_dynamic_region(
 			(uint64_t)composite->constituents[0].address,
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index da7e913..de1e555 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -30,6 +30,9 @@
 extern const char build_message[];
 extern const char version_string[];
 
+/* Memory section to be used for memory share operations */
+static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
+
 /*
  *
  * Message loop function
@@ -46,7 +49,6 @@
 	ffa_vm_id_t destination;
 	uint64_t cactus_cmd;
 
-
 	/*
 	* This initial wait call is necessary to inform SPMD that
 	* SP initialization has completed. It blocks until receiving
@@ -85,12 +87,10 @@
 		cactus_cmd = CACTUS_GET_CMD(ffa_ret);
 
 		switch (cactus_cmd) {
-		case FFA_MEM_SHARE_SMC32:
-		case FFA_MEM_LEND_SMC32:
-		case FFA_MEM_DONATE_SMC32:
+		case CACTUS_MEM_SEND_CMD:
 			ffa_memory_management_test(
 					mb, vm_id, source,
-					CACTUS_GET_CMD(ffa_ret),
+					CACTUS_MEM_SEND_GET_FUNC(ffa_ret),
 					CACTUS_MEM_SEND_GET_HANDLE(ffa_ret));
 
 			/*
@@ -99,7 +99,91 @@
 			 */
 			ffa_ret = CACTUS_SUCCESS_RESP(vm_id, source);
 			break;
+		case CACTUS_REQ_MEM_SEND_CMD:
+		{
+			uint32_t mem_func =
+				CACTUS_REQ_MEM_SEND_GET_MEM_FUNC(ffa_ret);
+			ffa_vm_id_t receiver =
+				CACTUS_REQ_MEM_SEND_GET_RECEIVER(ffa_ret);
+			ffa_memory_handle_t handle;
 
+			VERBOSE("%x requested to send memory to %x (func: %x)\n",
+				source, receiver, mem_func);
+
+			const struct ffa_memory_region_constituent
+							constituents[] = {
+				{(void *)share_page, 1, 0}
+			};
+
+			const uint32_t constituents_count = (
+				sizeof(constituents) /
+				sizeof(constituents[0])
+			);
+
+			handle = ffa_memory_init_and_send(
+				(struct ffa_memory_region *)mb->send, PAGE_SIZE,
+				vm_id, receiver, constituents,
+				constituents_count, mem_func);
+
+			/*
+			 * If returned an invalid handle, we should break the
+			 * test.
+			 */
+			expect(handle != FFA_MEMORY_HANDLE_INVALID, true);
+
+			ffa_ret = CACTUS_MEM_SEND_CMD_SEND(vm_id, receiver,
+							   mem_func, handle);
+
+			if (ffa_ret.ret0 != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
+				ERROR("Failed to send message. error: %lx\n",
+					ffa_ret.ret2);
+				ffa_ret = CACTUS_ERROR_RESP(vm_id, source);
+				break;
+			}
+
+			/* If anything went bad on the receiver's end. */
+			if (CACTUS_IS_ERROR_RESP(ffa_ret)) {
+				ERROR("Received error from receiver!\n");
+				ffa_ret = CACTUS_ERROR_RESP(vm_id, source);
+				break;
+			}
+
+			if (mem_func != FFA_MEM_DONATE_SMC32) {
+				/*
+				 * Do a memory reclaim only if the mem_func
+				 * regards to memory share or lend operations,
+				 * as with a donate the owner is permanently
+				 * given up access to the memory region.
+				 */
+				if (ffa_mem_reclaim(handle, 0)
+							.ret0 == FFA_ERROR) {
+					ERROR("Failed to reclaim memory!\n");
+					ffa_ret = CACTUS_ERROR_RESP(vm_id,
+								    source);
+					break;
+				}
+
+				/**
+				 * Read Content that has been written to memory
+				 * to validate access to memory segment has been
+				 * reestablished, and receiver made use of
+				 * memory region.
+				 */
+				#if (LOG_LEVEL >= LOG_LEVEL_VERBOSE)
+					uint32_t *ptr =
+						(uint32_t *)constituents
+								->address;
+					VERBOSE("Memory contents after receiver"
+						" SP's use:\n");
+					for (unsigned int i = 0U; i < 5U; i++)
+						VERBOSE("      %u: %x\n", i,
+									ptr[i]);
+				#endif
+			}
+
+			ffa_ret = CACTUS_SUCCESS_RESP(vm_id, source);
+		}
+		break;
 		case CACTUS_ECHO_CMD:
 		{
 			uint64_t echo_val = CACTUS_ECHO_GET_VAL(ffa_ret);
diff --git a/spm/cactus/cactus_test_cmds.h b/spm/cactus/cactus_test_cmds.h
index 3e16e57..7555b8b 100644
--- a/spm/cactus/cactus_test_cmds.h
+++ b/spm/cactus/cactus_test_cmds.h
@@ -96,22 +96,45 @@
 /**
  * Command to notify cactus of a memory management operation. The cmd value
  * should be the memory management smc function id.
+ *
+ * The id is the hex representation of the string "mem"
  */
-#define CACTUS_MEM_SEND_CMD(source, dest, mem_func, handle) 		\
-		CACTUS_SEND_CMD(source, dest, mem_func, handle, 0, 0, 0)
+#define CACTUS_MEM_SEND_CMD U(0x6d656d)
 
-#define CACTUS_MEM_SEND_GET_HANDLE(smc_ret) smc_ret.ret4
+#define CACTUS_MEM_SEND_CMD_SEND(source, dest, mem_func, handle) 	\
+		CACTUS_SEND_CMD(source, dest, CACTUS_MEM_SEND_CMD, 	\
+				mem_func, handle, 0, 0)
+
+#define CACTUS_MEM_SEND_GET_FUNC(smc_ret) smc_ret.ret4
+
+#define CACTUS_MEM_SEND_GET_HANDLE(smc_ret) smc_ret.ret5
+
+/**
+ * Command to request a memory management operation. The 'mem_func' argument
+ * identifies the operation that is to be performend, and 'receiver' is the id
+ * of the partition to receive the memory region.
+ *
+ * The command id is the hex representation of the string "memory".
+ */
+#define CACTUS_REQ_MEM_SEND_CMD U(0x6d656d6f7279)
+
+#define CACTUS_REQ_MEM_SEND_SEND_CMD(source, dest, mem_func, receiver)	\
+	CACTUS_SEND_CMD(source, dest, CACTUS_REQ_MEM_SEND_CMD, mem_func, \
+			receiver, 0, 0)
+
+#define CACTUS_REQ_MEM_SEND_GET_MEM_FUNC(smc_ret) smc_ret.ret4
+#define CACTUS_REQ_MEM_SEND_GET_RECEIVER(smc_ret) smc_ret.ret5
 
 /**
  * Template for responses to CACTUS commands.
  */
-#define CACTUS_RESPONSE(source, dest, response) 			\
+#define CACTUS_RESPONSE(source, dest, response) 				\
 		ffa_msg_send_direct_resp(source, dest, response)
 
-#define CACTUS_SUCCESS_RESP(source, dest) 				\
+#define CACTUS_SUCCESS_RESP(source, dest) 					\
 		CACTUS_RESPONSE(source, dest, CACTUS_SUCCESS)
 
-#define CACTUS_ERROR_RESP(source, dest) 				\
+#define CACTUS_ERROR_RESP(source, dest) 					\
 		CACTUS_RESPONSE(source, dest, CACTUS_ERROR)
 
 #define CACTUS_GET_RESPONSE(smc_ret) smc_ret.ret3
@@ -119,4 +142,7 @@
 #define CACTUS_IS_SUCCESS_RESP(smc_ret)					\
 		(CACTUS_GET_RESPONSE(smc_ret) == CACTUS_SUCCESS)
 
+#define CACTUS_IS_ERROR_RESP(smc_ret)						\
+		(CACTUS_GET_RESPONSE(smc_ret) == CACTUS_ERROR)
+
 #endif
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 8ee4ebc..1b79018 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -310,6 +310,92 @@
 	       memory_region->receiver_count * sizeof(struct ffa_memory_access);
 }
 
+/**
+ * Helper to call memory send function whose func id is passed as a parameter.
+ * Returns a valid handle in case of successful operation or
+ * FFA_MEMORY_HANDLE_INVALID if something goes wrong.
+ *
+ * TODO: Do memory send with 'ffa_memory_region' taking multiple segments
+ */
+ffa_memory_handle_t ffa_memory_send(
+	struct ffa_memory_region *memory_region, uint32_t mem_func,
+	uint32_t fragment_length, uint32_t total_length)
+{
+	smc_ret_values ret;
+	ffa_vm_id_t receiver =
+		memory_region->receivers[0].receiver_permissions.receiver;
+
+	if (fragment_length != total_length) {
+		ERROR("For now, fragment_length and total_length need to be"
+		      " equal");
+		return FFA_MEMORY_HANDLE_INVALID;
+	}
+
+	switch (mem_func) {
+	case FFA_MEM_SHARE_SMC32:
+		ret = ffa_mem_share(total_length, fragment_length);
+		break;
+	case FFA_MEM_LEND_SMC32:
+		ret = ffa_mem_lend(total_length, fragment_length);
+		break;
+	case FFA_MEM_DONATE_SMC32:
+		ret = ffa_mem_donate(total_length, fragment_length);
+		break;
+	default:
+		ERROR("TFTF - Invalid func id %x!\n", mem_func);
+		return FFA_MEMORY_HANDLE_INVALID;
+	}
+
+	if (ret.ret0 != FFA_SUCCESS_SMC32) {
+		ERROR("Failed to send memory to %x, error: %lx.\n",
+				      receiver, ret.ret2);
+		return FFA_MEMORY_HANDLE_INVALID;
+	}
+
+	return ffa_mem_success_handle(ret);
+;
+}
+
+/**
+ * Helper that initializes and sends a memory region. The memory region's
+ * configuration is statically defined and is implementation specific. However,
+ * doing it in this file for simplicity and for testing purposes.
+ */
+ffa_memory_handle_t ffa_memory_init_and_send(
+	struct ffa_memory_region *memory_region, size_t memory_region_max_size,
+	ffa_vm_id_t sender, ffa_vm_id_t receiver,
+	const struct ffa_memory_region_constituent *constituents,
+	uint32_t constituents_count, uint32_t mem_func)
+{
+	uint32_t remaining_constituent_count;
+	uint32_t total_length;
+	uint32_t fragment_length;
+
+	enum ffa_data_access data_access = (mem_func == FFA_MEM_DONATE_SMC32) ?
+						FFA_DATA_ACCESS_NOT_SPECIFIED :
+						FFA_DATA_ACCESS_RW;
+
+	remaining_constituent_count = ffa_memory_region_init(
+		memory_region, memory_region_max_size, sender, receiver, constituents,
+		constituents_count, 0, 0, data_access,
+		FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+		FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+		FFA_MEMORY_INNER_SHAREABLE, &total_length, &fragment_length
+	);
+
+	/*
+	 * For simplicity of the test, and at least for the time being,
+	 * the following condition needs to be true.
+	 */
+	if (remaining_constituent_count != 0U) {
+		ERROR("Remaining constituent should be 0\n");
+		return FFA_MEMORY_HANDLE_INVALID;
+	}
+
+	return ffa_memory_send(memory_region, mem_func, fragment_length,
+			       total_length);
+}
+
 /*
  * FFA Version ABI helper.
  * Version fields:
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
index fded199..61f1aaa 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
@@ -17,46 +17,44 @@
 #define SENDER HYP_ID
 #define RECEIVER SP_ID(1)
 
-/* Memory section to be sent over mem management ABIs */
+static const struct ffa_uuid expected_sp_uuids[] = {
+		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+	};
+
+/* Memory section to be used for memory share operations */
 static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
 
+/**
+ * Tests that it is possible to share memory with SWd from NWd.
+ * After calling the respective memory send API, it will expect a reply from
+ * cactus SP, at which point it will reclaim access to the memory region and
+ * check the memory region has been used by receiver SP.
+ *
+ * Accessing memory before a memory reclaim operation should only be possible
+ * in the context of a memory share operation.
+ * According to the FF-A spec, the owner is temporarily relinquishing
+ * access to the memory region on a memory lend operation, and on a
+ * memory donate operation the access is relinquished permanently.
+ * SPMC is positioned in S-EL2, and doesn't control stage-1 mapping for
+ * EL2. Therefore, it is impossible to enforce the expected access
+ * policy for a donate and lend operations within the SPMC.
+ * Current SPMC implementation is under the assumption of trust that
+ * Hypervisor (sitting in EL2) would relinquish access from EL1/EL0
+ * FF-A endpoint at relevant moment.
+ */
 static test_result_t test_memory_send_sp(uint32_t mem_func)
 {
 	smc_ret_values ret;
-	uint32_t remaining_constituent_count;
-	uint32_t total_length;
-	uint32_t fragment_length;
-	uint32_t sent_length;
 	ffa_memory_handle_t handle;
 	uint32_t *ptr;
 	struct mailbox_buffers mb;
-	const uint32_t primary_uuid[] = PRIMARY_UUID;
 
-	/**********************************************************************
-	 * Verify that FFA is there and that it has the correct version.
+	/***********************************************************************
+	 * Check if SPMC has ffa_version and expected FFA endpoints are deployed.
 	 **********************************************************************/
-	SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+	CHECK_HAFNIUM_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
 
-	/**********************************************************************
-	 * If OPTEE is SPMC skip this test.
-	 **********************************************************************/
-	if (check_spmc_execution_level()) {
-		VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
-		return TEST_RESULT_SKIPPED;
-	}
-
-	if (!get_tftf_mailbox(&mb)) {
-		ERROR("Mailbox not configured!\n This test relies on"
-		      " test suite \"FF-A RXTX Mapping\" to map/configure"
-		      " RXTX buffers\n");
-		return TEST_RESULT_FAIL;
-	}
-
-
-	/**********************************************************************
-	 * Verify that cactus primary SP is deployed in the system.
-	 **********************************************************************/
-	SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(mb, primary_uuid);
+	GET_TFTF_MAILBOX(mb);
 
 	struct ffa_memory_region_constituent constituents[] = {
 						{(void *)share_page, 1, 0}
@@ -65,68 +63,21 @@
 	const uint32_t constituents_count = sizeof(constituents) /
 			sizeof(struct ffa_memory_region_constituent);
 
-	enum ffa_data_access data_access = (mem_func == FFA_MEM_DONATE_SMC32) ?
-						FFA_DATA_ACCESS_NOT_SPECIFIED :
-						FFA_DATA_ACCESS_RW;
+	handle = ffa_memory_init_and_send((struct ffa_memory_region *)mb.send,
+					MAILBOX_SIZE, SENDER, RECEIVER,
+					constituents, constituents_count,
+					mem_func);
 
-	/*
-	 * TODO: Revise shareability attribute in function call
-	 * below.
-	 * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
-	 */
-	remaining_constituent_count = ffa_memory_region_init(
-		mb.send, MAILBOX_SIZE, SENDER, RECEIVER, constituents,
-		constituents_count, 0, 0,
-		data_access,
-		FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
-		FFA_MEMORY_NORMAL_MEM,
-		FFA_MEMORY_CACHE_WRITE_BACK,
-		FFA_MEMORY_OUTER_SHAREABLE,
-		&total_length,
-		&fragment_length
-	);
-
-	switch (mem_func) {
-	case FFA_MEM_SHARE_SMC32:
-		ret = ffa_mem_share(total_length, fragment_length);
-		break;
-	case FFA_MEM_LEND_SMC32:
-		ret = ffa_mem_lend(total_length, fragment_length);
-		break;
-	case FFA_MEM_DONATE_SMC32:
-		ret = ffa_mem_donate(total_length, fragment_length);
-		break;
-	default:
-		NOTICE("TFTF - Invalid func id!\n");
+	if (handle == FFA_MEMORY_HANDLE_INVALID) {
 		return TEST_RESULT_FAIL;
 	}
 
-	sent_length = fragment_length;
-
-	if (ret.ret0 != FFA_SUCCESS_SMC32) {
-		tftf_testcase_printf("Failed to send memory to SP %x.\n",
-				      RECEIVER);
-		return TEST_RESULT_FAIL;
-	}
-
-	if (sent_length != total_length) {
-		tftf_testcase_printf("Sent and Total lengths must be equal!\n");
-		return TEST_RESULT_FAIL;
-	}
-
-	if (remaining_constituent_count != 0) {
-		tftf_testcase_printf("Remaining constituent should be 0\n");
-		return TEST_RESULT_FAIL;
-	}
-
-	handle = ffa_mem_success_handle(ret);
-
 	VERBOSE("TFTF - Handle: %llx\nTFTF - Address: %p\n",
 					handle, constituents[0].address);
 
 	ptr = (uint32_t *)constituents[0].address;
 
-	ret = CACTUS_MEM_SEND_CMD(SENDER, RECEIVER, mem_func, handle);
+	ret = CACTUS_MEM_SEND_CMD_SEND(SENDER, RECEIVER, mem_func, handle);
 
 	if (ret.ret0 != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
 		ERROR("Failed to send message. error: %lx\n",
@@ -135,7 +86,7 @@
 	}
 
 	if (CACTUS_GET_RESPONSE(ret) != CACTUS_SUCCESS) {
-		tftf_testcase_printf("Failed memory send operation!\n");
+		ERROR("Failed memory send operation!\n");
 		return TEST_RESULT_FAIL;
 	}
 
@@ -174,3 +125,51 @@
 {
 	return test_memory_send_sp(FFA_MEM_DONATE_SMC32);
 }
+
+/*
+ * Test requests a memory send operation between cactus SPs.
+ * Cactus SP should reply to TFTF on whether the test succeeded or not.
+ */
+static test_result_t test_req_mem_send_sp_to_sp(uint32_t mem_func,
+						ffa_vm_id_t sender_sp,
+						ffa_vm_id_t receiver_sp)
+{
+	smc_ret_values ret;
+
+	/***********************************************************************
+	 * Check if SPMC's ffa_version and presence of expected FF-A endpoints.
+	 **********************************************************************/
+	CHECK_HAFNIUM_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+	ret = CACTUS_REQ_MEM_SEND_SEND_CMD(HYP_ID, sender_sp, mem_func,
+					   receiver_sp);
+
+	if (ret.ret0 != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
+		ERROR("Failed to send message. error: %lx\n", ret.ret2);
+		return TEST_RESULT_FAIL;
+	}
+
+	if (CACTUS_IS_ERROR_RESP(ret)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+test_result_t test_req_mem_share_sp_to_sp(void)
+{
+	return test_req_mem_send_sp_to_sp(FFA_MEM_SHARE_SMC32, SP_ID(3),
+					  SP_ID(2));
+}
+
+test_result_t test_req_mem_lend_sp_to_sp(void)
+{
+	return test_req_mem_send_sp_to_sp(FFA_MEM_LEND_SMC32, SP_ID(2),
+					  SP_ID(1));
+}
+
+test_result_t test_req_mem_donate_sp_to_sp(void)
+{
+	return test_req_mem_send_sp_to_sp(FFA_MEM_DONATE_SMC32, SP_ID(1),
+					  SP_ID(3));
+}
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 14be8ca..2637acd 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -46,12 +46,18 @@
 
   <testsuite name="FF-A Memory Sharing"
              description="Test FF-A Memory Sharing ABIs" >
-  <testcase name="Lend Memory to Secure World"
-              function="test_mem_lend_sp" />
-  <testcase name="Share Memory with Secure World"
-              function="test_mem_share_sp" />
-  <testcase name="Donate Memory to Secure World"
-              function="test_mem_donate_sp"/>
+     <testcase name="Lend Memory to Secure World"
+               function="test_mem_lend_sp" />
+     <testcase name="Share Memory with Secure World"
+               function="test_mem_share_sp" />
+     <testcase name="Donate Memory to Secure World"
+               function="test_mem_donate_sp"/>
+     <testcase name="Request Share Memory SP-to-SP"
+               function="test_req_mem_share_sp_to_sp" />
+     <testcase name="Request Lend Memory SP-to-SP"
+               function="test_req_mem_lend_sp_to_sp" />
+     <testcase name="Request Donate Memory SP-to-SP"
+               function="test_req_mem_donate_sp_to_sp" />
   </testsuite>
 
   <testsuite name="FF-A features"