SPM: Tidying FF-A Memory Sharing tests

Moving code about memory sharing tests to comply with recent changes:
- Placed helper functions that can be used by TFTF and Cactus in files
spm_common.c/h.
- Removed 'ffa_memory_sharing_test' and added its body to handler of
test command CACTUS_MEM_SEND_CMD.

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I58af9b475730d171306581741becbb0665e1859d
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index 17587b3..064b5a3 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -364,16 +364,6 @@
 	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);
-
 static inline ffa_vm_id_t ffa_dir_msg_dest(smc_ret_values val) {
 	return (ffa_vm_id_t)val.ret1 & U(0xFFFF);
 }
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index b090002..74a2b27 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -82,4 +82,30 @@
 
 unsigned int get_ffa_feature_test_target(const struct ffa_features_test **test_target);
 
+/**
+ * Helper to conduct a memory retrieve. This is to be called by the receiver
+ * of a memory share operation.
+ */
+bool memory_retrieve(struct mailbox_buffers *mb,
+		     struct ffa_memory_region **retrieved, uint64_t handle,
+		     ffa_vm_id_t sender, ffa_vm_id_t receiver,
+		     uint32_t mem_func);
+
+/**
+ * Helper to conduct a memory relinquish. The caller is usually the receiver,
+ * after it being done with the memory shared, identified by the 'handle'.
+ */
+bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
+		       ffa_vm_id_t id);
+
+ffa_memory_handle_t memory_send(
+	struct ffa_memory_region *memory_region, uint32_t mem_func,
+	uint32_t fragment_length, uint32_t total_length);
+
+ffa_memory_handle_t 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);
+
 #endif /* SPM_COMMON_H */
diff --git a/spm/cactus/cactus_ffa_tests.c b/spm/cactus/cactus_ffa_tests.c
index 8d34e37..c1ba783 100644
--- a/spm/cactus/cactus_ffa_tests.c
+++ b/spm/cactus/cactus_ffa_tests.c
@@ -14,7 +14,6 @@
 #include <spm_common.h>
 
 #include <lib/libc/string.h>
-#include <lib/xlat_tables/xlat_tables_v2.h>
 
 /* FFA version test helpers */
 #define FFA_MAJOR 1U
@@ -163,166 +162,6 @@
 	announce_test_end(test_ffa_version);
 }
 
-bool ffa_memory_retrieve_test(struct mailbox_buffers *mb,
-			 struct ffa_memory_region **retrieved,
-			 uint64_t handle, ffa_vm_id_t sender,
-			 ffa_vm_id_t receiver, uint32_t mem_func)
-{
-	smc_ret_values ret;
-	uint32_t fragment_size;
-	uint32_t total_size;
-	uint32_t descriptor_size;
-
-	if (retrieved == NULL || mb == NULL) {
-		ERROR("Invalid parameters!\n");
-		return false;
-	}
-
-	/*
-	 * TODO: Revise shareability attribute in function call
-	 * below.
-	 * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
-	 */
-	descriptor_size = ffa_memory_retrieve_request_init(
-	    mb->send, handle, sender, receiver, 0, 0,
-	    FFA_DATA_ACCESS_RW,
-	    FFA_INSTRUCTION_ACCESS_NX,
-	    FFA_MEMORY_NORMAL_MEM,
-	    FFA_MEMORY_CACHE_WRITE_BACK,
-	    FFA_MEMORY_OUTER_SHAREABLE);
-
-	ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
-
-	if (ffa_func_id(ret) != FFA_MEM_RETRIEVE_RESP) {
-		ERROR("Couldn't retrieve the memory page. Error: %lx\n",
-		      ret.ret2);
-		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.
-	 * This is a simple test with only one segment. As such, upon
-	 * successful ffa_mem_retrieve_req, total_size must be equal to
-	 * fragment_size.
-	 */
-	total_size = ret.ret1;
-	fragment_size = ret.ret2;
-
-	if (total_size != fragment_size) {
-		ERROR("Only expect one memory segment to be sent!\n");
-		return false;
-	}
-
-	if (fragment_size > PAGE_SIZE) {
-		ERROR("Fragment should be smaller than RX buffer!\n");
-		return false;
-	}
-
-	*retrieved = (struct ffa_memory_region *)mb->recv;
-
-	if ((*retrieved)->receiver_count > MAX_MEM_SHARE_RECIPIENTS) {
-		VERBOSE("SPMC memory sharing operations support max of %u "
-			"receivers!\n", MAX_MEM_SHARE_RECIPIENTS);
-		return false;
-	}
-
-	VERBOSE("Memory Retrieved!\n");
-
-	return true;
-}
-
-bool ffa_memory_relinquish_test(struct ffa_mem_relinquish *m,
-			   uint64_t handle,
-			   ffa_vm_id_t id)
-{
-	smc_ret_values ret;
-
-	ffa_mem_relinquish_init(m, handle, 0, id);
-	ret = ffa_mem_relinquish();
-	if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
-		ERROR("%s failed to relinquish memory! error: %x\n",
-		      __func__, ffa_error_code(ret));
-		return false;
-	}
-
-	VERBOSE("Memory Relinquished!\n");
-	return true;
-}
-
-void ffa_memory_management_test(struct mailbox_buffers *mb, ffa_vm_id_t vm_id,
-				ffa_vm_id_t sender, uint32_t mem_func,
-				uint64_t handle)
-{
-	const char *test_ffa = "Memory Management";
-	struct ffa_memory_region *m;
-	struct ffa_composite_memory_region *composite;
-	int ret;
-	unsigned int mem_attrs;
-	uint32_t *ptr;
-
-	announce_test_section_start(test_ffa);
-
-	expect(ffa_memory_retrieve_test(
-				mb, &m, handle, sender, vm_id, mem_func),
-		true);
-
-	composite = ffa_memory_region_get_composite(m, 0);
-
-	VERBOSE("Address: %p; page_count: %x %x\n",
-		composite->constituents[0].address,
-		composite->constituents[0].page_count, PAGE_SIZE);
-
-	/* This test is only concerned with RW permissions. */
-	expect(ffa_get_data_access_attr(
-			m->receivers[0].receiver_permissions.permissions),
-		FFA_DATA_ACCESS_RW);
-
-	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,
-			(uint64_t)composite->constituents[0].address,
-			composite->constituents[0].page_count * PAGE_SIZE,
-			mem_attrs);
-	expect(ret, 0);
-
-	VERBOSE("Memory has been mapped\n");
-
-	ptr = (uint32_t *) composite->constituents[0].address;
-
-	/* Write mem_func to retrieved memory region for validation purposes. */
-	VERBOSE("Writing: %x\n", mem_func);
-	for (unsigned int i = 0U; i < 5U; i++)
-		ptr[i] = mem_func;
-
-	/*
-	 * A FFA_MEM_DONATE changes the ownership of the page, as such no
-	 * relinquish is needed.
-	 */
-	if (mem_func != FFA_MEM_DONATE_SMC32) {
-		ret = mmap_remove_dynamic_region(
-			(uint64_t)composite->constituents[0].address,
-			composite->constituents[0].page_count * PAGE_SIZE);
-		expect(ret, 0);
-
-		expect(ffa_memory_relinquish_test(
-			   (struct ffa_mem_relinquish *)mb->send,
-			   m->handle, vm_id),
-		       true);
-	}
-
-	expect(ffa_func_id(ffa_rx_release()), FFA_SUCCESS_SMC32);
-
-	announce_test_section_end(test_ffa);
-}
-
 void ffa_tests(struct mailbox_buffers *mb)
 {
 	const char *test_ffa = "FFA Interfaces";
diff --git a/spm/cactus/cactus_tests.h b/spm/cactus/cactus_tests.h
index c0c235e..1039ba5 100644
--- a/spm/cactus/cactus_tests.h
+++ b/spm/cactus/cactus_tests.h
@@ -13,19 +13,6 @@
  * Test functions
  */
 
-/*
- * Alter SIMD vectors to check saving of the context while switching between
- * the normal world and the secure world.
- */
-void fill_simd_vectors(void);
-
-/*
- * Test to FFA interfaces.
- */
-void ffa_memory_management_test(struct mailbox_buffers *mb, ffa_vm_id_t vm_id,
-				ffa_vm_id_t sender, uint32_t mem_func,
-				uint64_t handle);
-
 void ffa_tests(struct mailbox_buffers *mb);
 
 /*
diff --git a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
index 63c3d13..82cdac3 100644
--- a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
+++ b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
@@ -4,25 +4,101 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include "cactus_def.h"
+#include <cactus_def.h>
 #include "cactus_test_cmds.h"
 #include "cactus_tests.h"
 #include <ffa_helpers.h>
 #include <sp_helpers.h>
 #include <xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
 
 /* Memory section to be used for memory share operations */
 static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
 
 CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
 {
-	ffa_memory_management_test(
-		mb, ffa_dir_msg_dest(*args), ffa_dir_msg_source(*args),
-		cactus_req_mem_send_get_mem_func(*args),
-		cactus_mem_send_get_handle(*args));
+	struct ffa_memory_region *m;
+	struct ffa_composite_memory_region *composite;
+	int ret;
+	unsigned int mem_attrs;
+	uint32_t *ptr;
+	ffa_vm_id_t source = ffa_dir_msg_source(*args);
+	ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
+	uint32_t mem_func = cactus_req_mem_send_get_mem_func(*args);
+	uint64_t handle = cactus_mem_send_get_handle(*args);
 
-	return cactus_success_resp(ffa_dir_msg_dest(*args),
-				   ffa_dir_msg_source(*args), 0);
+	expect(memory_retrieve(mb, &m, handle, source, vm_id, mem_func), true);
+
+	composite = ffa_memory_region_get_composite(m, 0);
+
+	VERBOSE("Address: %p; page_count: %x %x\n",
+		composite->constituents[0].address,
+		composite->constituents[0].page_count, PAGE_SIZE);
+
+	/* This test is only concerned with RW permissions. */
+	if (ffa_get_data_access_attr(
+			m->receivers[0].receiver_permissions.permissions) !=
+		FFA_DATA_ACCESS_RW) {
+		ERROR("Permissions not expected!\n");
+		return cactus_error_resp(vm_id, source, CACTUS_ERROR_TEST);
+	}
+
+	mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
+
+	if (!IS_SP_ID(source)) {
+		mem_attrs |= MT_NS;
+	}
+
+	ret = mmap_add_dynamic_region(
+			(uint64_t)composite->constituents[0].address,
+			(uint64_t)composite->constituents[0].address,
+			composite->constituents[0].page_count * PAGE_SIZE,
+			mem_attrs);
+
+	if (ret != 0) {
+		ERROR("Failed first mmap_add_dynamic_region!\n");
+		return cactus_error_resp(vm_id, source, CACTUS_ERROR_TEST);
+	}
+
+	VERBOSE("Memory has been mapped\n");
+
+	ptr = (uint32_t *) composite->constituents[0].address;
+
+	/* Write mem_func to retrieved memory region for validation purposes. */
+	VERBOSE("Writing: %x\n", mem_func);
+	for (unsigned int i = 0U; i < 5U; i++)
+		ptr[i] = mem_func;
+
+	/*
+	 * A FFA_MEM_DONATE changes the ownership of the page, as such no
+	 * relinquish is needed.
+	 */
+	if (mem_func != FFA_MEM_DONATE_SMC32) {
+		ret = mmap_remove_dynamic_region(
+			(uint64_t)composite->constituents[0].address,
+			composite->constituents[0].page_count * PAGE_SIZE);
+
+		if (ret != 0) {
+			ERROR("Failed first mmap_add_dynamic_region!\n");
+			return cactus_error_resp(vm_id, source,
+						 CACTUS_ERROR_TEST);
+		}
+
+		if (!memory_relinquish((struct ffa_mem_relinquish *)mb->send,
+					m->handle, vm_id)) {
+			return cactus_error_resp(vm_id, source,
+						 CACTUS_ERROR_TEST);
+		}
+	}
+
+	if (ffa_func_id(ffa_rx_release()) != FFA_SUCCESS_SMC32) {
+		ERROR("Failed to release buffer!\n");
+		return cactus_error_resp(vm_id, source,
+					 CACTUS_ERROR_FFA_CALL);
+	}
+
+	return cactus_success_resp(vm_id,
+				   source, 0);
 }
 
 CACTUS_CMD_HANDLER(req_mem_send_cmd, CACTUS_REQ_MEM_SEND_CMD)
@@ -44,7 +120,7 @@
 	const uint32_t constituents_count = (sizeof(constituents) /
 					     sizeof(constituents[0]));
 
-	handle = ffa_memory_init_and_send(
+	handle = memory_init_and_send(
 		(struct ffa_memory_region *)mb->send, PAGE_SIZE,
 		vm_id, receiver, constituents,
 		constituents_count, mem_func);
@@ -52,7 +128,11 @@
 	/*
 	 * If returned an invalid handle, we should break the test.
 	 */
-	expect(handle != FFA_MEMORY_HANDLE_INVALID, true);
+	if (handle == FFA_MEMORY_HANDLE_INVALID) {
+		ERROR("Received an invalid FF-A memory Handle!\n");
+		return cactus_error_resp(vm_id, source,
+					 CACTUS_ERROR_TEST);
+	}
 
 	ffa_ret = cactus_mem_send_cmd(vm_id, receiver, mem_func, handle);
 
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index f3da55f..9567deb 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -268,91 +268,6 @@
 	       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 (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
-		ERROR("Failed to send memory to %x, error: %x.\n",
-				      receiver, ffa_error_code(ret));
-		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.
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index cc3ed5d..541ec92 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -4,8 +4,10 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <debug.h>
 #include <ffa_endpoints.h>
 #include <spm_common.h>
+#include <xlat_tables_v2.h>
 
 #define __STR(x) #x
 #define STR(x) __STR(x)
@@ -146,3 +148,176 @@
 	return sizeof(ffa_feature_test_target) /
 	       sizeof(struct ffa_features_test);
 }
+
+bool memory_retrieve(struct mailbox_buffers *mb,
+		     struct ffa_memory_region **retrieved, uint64_t handle,
+		     ffa_vm_id_t sender, ffa_vm_id_t receiver,
+		     uint32_t mem_func)
+{
+	smc_ret_values ret;
+	uint32_t fragment_size;
+	uint32_t total_size;
+	uint32_t descriptor_size;
+
+	if (retrieved == NULL || mb == NULL) {
+		ERROR("Invalid parameters!\n");
+		return false;
+	}
+
+	/*
+	 * TODO: Revise shareability attribute in function call
+	 * below.
+	 * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
+	 */
+	descriptor_size = ffa_memory_retrieve_request_init(
+	    mb->send, handle, sender, receiver, 0, 0,
+	    FFA_DATA_ACCESS_RW,
+	    FFA_INSTRUCTION_ACCESS_NX,
+	    FFA_MEMORY_NORMAL_MEM,
+	    FFA_MEMORY_CACHE_WRITE_BACK,
+	    FFA_MEMORY_OUTER_SHAREABLE);
+
+	ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
+
+	if (ffa_func_id(ret) != FFA_MEM_RETRIEVE_RESP) {
+		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.
+	 * This is a simple test with only one segment. As such, upon
+	 * successful ffa_mem_retrieve_req, total_size must be equal to
+	 * fragment_size.
+	 */
+	total_size = ret.ret1;
+	fragment_size = ret.ret2;
+
+	if (total_size != fragment_size) {
+		ERROR("Only expect one memory segment to be sent!\n");
+		return false;
+	}
+
+	if (fragment_size > PAGE_SIZE) {
+		ERROR("Fragment should be smaller than RX buffer!\n");
+		return false;
+	}
+
+	*retrieved = (struct ffa_memory_region *)mb->recv;
+
+	if ((*retrieved)->receiver_count > MAX_MEM_SHARE_RECIPIENTS) {
+		VERBOSE("SPMC memory sharing operations support max of %u "
+			"receivers!\n", MAX_MEM_SHARE_RECIPIENTS);
+		return false;
+	}
+
+	VERBOSE("Memory Retrieved!\n");
+
+	return true;
+}
+
+bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
+		       ffa_vm_id_t id)
+{
+	smc_ret_values ret;
+
+	ffa_mem_relinquish_init(m, handle, 0, id);
+	ret = ffa_mem_relinquish();
+	if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+		ERROR("%s failed to relinquish memory! error: %x\n",
+		      __func__, ffa_error_code(ret));
+		return false;
+	}
+
+	VERBOSE("Memory Relinquished!\n");
+	return true;
+}
+
+/**
+ * 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 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 (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+		ERROR("Failed to send memory to %x, error: %x.\n",
+				      receiver, ffa_error_code(ret));
+		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 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 memory_send(memory_region, mem_func, fragment_length,
+			       total_length);
+}
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 67ffb53..61b6edd 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
@@ -63,7 +63,7 @@
 	const uint32_t constituents_count = sizeof(constituents) /
 			sizeof(struct ffa_memory_region_constituent);
 
-	handle = ffa_memory_init_and_send((struct ffa_memory_region *)mb.send,
+	handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
 					MAILBOX_SIZE, SENDER, RECEIVER,
 					constituents, constituents_count,
 					mem_func);