test(memory sharing): force fragmented ff-a v1.0

Force a fragmented memory share operation, using FF-A v1.0 memory
transaction descriptors.

Change-Id: I1a06ec58601c82135a534a0a29ec6e5677a17744
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/test/inc/test/vmapi/ffa.h b/test/inc/test/vmapi/ffa.h
index 5b18aa2..8c01f72 100644
--- a/test/inc/test/vmapi/ffa.h
+++ b/test/inc/test/vmapi/ffa.h
@@ -102,6 +102,12 @@
 	uint32_t tag, ffa_memory_region_flags_t flags,
 	enum ffa_memory_type type, enum ffa_memory_cacheability cacheability,
 	enum ffa_memory_shareability shareability, ffa_vm_id_t recipient);
+void send_fragmented_memory_region(
+	struct ffa_value *send_ret, void *tx_buffer,
+	struct ffa_memory_region_constituent constituents[],
+	uint32_t constituent_count, uint32_t remaining_constituent_count,
+	uint32_t sent_length, uint32_t total_length,
+	ffa_memory_handle_t *handle, uint64_t allocator_mask);
 ffa_vm_id_t retrieve_memory_from_message(
 	void *recv_buf, void *send_buf, ffa_memory_handle_t *handle,
 	struct ffa_memory_region *memory_region_ret,
diff --git a/test/vmapi/common/ffa.c b/test/vmapi/common/ffa.c
index a134d20..ee3f23b 100644
--- a/test/vmapi/common/ffa.c
+++ b/test/vmapi/common/ffa.c
@@ -99,7 +99,7 @@
 	EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
 }
 
-static void send_fragmented_memory_region(
+void send_fragmented_memory_region(
 	struct ffa_value *send_ret, void *tx_buffer,
 	struct ffa_memory_region_constituent constituents[],
 	uint32_t constituent_count, uint32_t remaining_constituent_count,
diff --git a/test/vmapi/primary_with_secondaries/memory_sharing.c b/test/vmapi/primary_with_secondaries/memory_sharing.c
index 4d619a2..04d9795 100644
--- a/test/vmapi/primary_with_secondaries/memory_sharing.c
+++ b/test/vmapi/primary_with_secondaries/memory_sharing.c
@@ -3291,3 +3291,89 @@
 
 	EXPECT_EQ(ffa_run(service1_info->vm_id, 0).func, FFA_YIELD_32);
 }
+
+TEST(memory_sharing, force_fragmented_ffa_v1_0)
+{
+	struct ffa_value ret;
+	struct mailbox_buffers mb = set_up_mailbox();
+	uint32_t msg_size;
+	ffa_memory_handle_t handle;
+	struct ffa_memory_access receiver;
+	struct ffa_memory_region_constituent constituents[] = {
+		{.address = (uint64_t)pages, .page_count = 2},
+		{.address = (uint64_t)pages + PAGE_SIZE * 3, .page_count = 1},
+	};
+	uint32_t remaining_constituent_count;
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+	struct ffa_partition_msg *retrieve_message = mb.send;
+	uint32_t fragment_length;
+	uint32_t total_length;
+	uint64_t allocator_mask;
+	uint8_t *ptr = pages;
+
+	/* Set current version to FF-A v1.0. */
+	EXPECT_NE(ffa_version(MAKE_FFA_VERSION(1, 0)), FFA_ERROR_32);
+
+	SERVICE_SELECT(service1_info->vm_id, "retrieve_ffa_v1_0", mb.send);
+
+	ffa_memory_access_init_permissions(
+		&receiver, service1_info->vm_id, FFA_DATA_ACCESS_RW,
+		FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED, 0);
+
+	/* Initialize memory sharing test according to v1.0. */
+	remaining_constituent_count = ffa_memory_region_init_v1_0(
+		(struct ffa_memory_region_v1_0 *)mb.send, HF_MAILBOX_SIZE,
+		hf_vm_get_id(), &receiver, 1, constituents,
+		ARRAY_SIZE(constituents), 0, 0, FFA_MEMORY_NORMAL_MEM,
+		FFA_MEMORY_CACHE_WRITE_BACK, FFA_MEMORY_INNER_SHAREABLE,
+		&total_length, &fragment_length);
+
+	EXPECT_EQ(remaining_constituent_count, 0);
+	EXPECT_EQ(total_length, fragment_length);
+
+	/* Don't include the last constituent in the first fragment. */
+	fragment_length -= sizeof(struct ffa_memory_region_constituent);
+	remaining_constituent_count = 1;
+
+	ret = ffa_mem_share(total_length, fragment_length);
+	EXPECT_EQ(ret.func, FFA_MEM_FRAG_RX_32);
+	handle = ffa_frag_handle(ret);
+	EXPECT_NE(handle, FFA_MEMORY_HANDLE_INVALID);
+
+	allocator_mask =
+		(IS_SP_ID(hf_vm_get_id()) || IS_SP_ID(service1_info->vm_id))
+			? FFA_MEMORY_HANDLE_ALLOCATOR_SPMC
+			: FFA_MEMORY_HANDLE_ALLOCATOR_HYPERVISOR;
+
+	send_fragmented_memory_region(
+		&ret, mb.send, constituents, ARRAY_SIZE(constituents),
+		remaining_constituent_count, fragment_length, total_length,
+		&handle, allocator_mask);
+
+	msg_size = ffa_memory_retrieve_request_init_v1_0(
+		(struct ffa_memory_region_v1_0 *)retrieve_message->payload,
+		handle, hf_vm_get_id(), &receiver, 1, 0,
+		FFA_MEMORY_REGION_TRANSACTION_TYPE_SHARE, FFA_MEMORY_NORMAL_MEM,
+		FFA_MEMORY_CACHE_WRITE_BACK, FFA_MEMORY_INNER_SHAREABLE);
+	ffa_rxtx_header_init(hf_vm_get_id(), service1_info->vm_id, msg_size,
+			     &retrieve_message->header);
+	EXPECT_LE(msg_size, HF_MAILBOX_SIZE);
+	EXPECT_EQ(ffa_msg_send2(0).func, FFA_SUCCESS_32);
+
+	/* Run service1 to retrieve memory. */
+	EXPECT_EQ(ffa_run(service1_info->vm_id, 0).func, FFA_YIELD_32);
+
+	/* Initialise the memory before giving it. */
+	for (uint32_t i = 0; i < PAGE_SIZE; i++) {
+		ptr[i] = i;
+	}
+
+	/* Run service1 to access memory. */
+	EXPECT_EQ(ffa_run(service1_info->vm_id, 0).func, FFA_YIELD_32);
+
+	/* Validate service1 access to the memory. */
+	for (uint32_t i = 0; i < PAGE_SIZE; i++) {
+		uint8_t val = i + 1;
+		ASSERT_EQ(ptr[i], val);
+	}
+}
diff --git a/test/vmapi/primary_with_secondaries/services/memory.c b/test/vmapi/primary_with_secondaries/services/memory.c
index dd6c14c..022bd6a 100644
--- a/test/vmapi/primary_with_secondaries/services/memory.c
+++ b/test/vmapi/primary_with_secondaries/services/memory.c
@@ -938,12 +938,17 @@
 	void *recv_buf = SERVICE_RECV_BUFFER();
 	void *send_buf = SERVICE_SEND_BUFFER();
 	struct ffa_memory_region_v1_0 *memory_region =
-		(struct ffa_memory_region_v1_0 *)recv_buf;
+		(struct ffa_memory_region_v1_0 *)retrieve_buffer;
 	struct ffa_composite_memory_region *composite;
 	ffa_vm_id_t own_id = hf_vm_get_id();
 	const struct ffa_partition_msg *retrv_message =
 		(struct ffa_partition_msg *)recv_buf;
 	struct ffa_value ret;
+	uint32_t fragment_length;
+	uint32_t total_length;
+	uint32_t memory_region_max_size = HF_MAILBOX_SIZE;
+	uint32_t fragment_offset;
+	ffa_memory_handle_t handle;
 
 	/* Set Version to v1.0. */
 	ffa_version(MAKE_FFA_VERSION(1, 0));
@@ -964,9 +969,39 @@
 
 	ret = ffa_mem_retrieve_req(msg_size, msg_size);
 	EXPECT_EQ(ret.func, FFA_MEM_RETRIEVE_RESP_32);
+	fragment_length = ret.arg2;
+	total_length = ret.arg1;
 
+	memcpy_s(memory_region, memory_region_max_size, recv_buf,
+		 fragment_length);
+
+	handle = memory_region->handle;
+
+	/* Copy first fragment. */
+	ASSERT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
+
+	fragment_offset = fragment_length;
+
+	while (fragment_offset < total_length) {
+		ret = ffa_mem_frag_rx(handle, fragment_offset);
+		EXPECT_EQ(ret.func, FFA_MEM_FRAG_TX_32);
+		EXPECT_EQ(ffa_frag_handle(ret), handle);
+		fragment_length = ret.arg3;
+		EXPECT_GT(fragment_length, 0);
+		ASSERT_LE(fragment_offset + fragment_length,
+			  memory_region_max_size);
+		/* Copy received fragment. */
+		memcpy_s((uint8_t *)memory_region + fragment_offset,
+			 memory_region_max_size - fragment_offset, recv_buf,
+			 fragment_length);
+		fragment_offset += fragment_length;
+		ASSERT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
+	}
+
+	/* Retrieved all the fragments. */
 	ffa_yield();
 
+	/* Point to the whole copied structure. */
 	composite = ffa_memory_region_get_composite_v1_0(memory_region, 0);
 
 	update_mm_security_state(composite, arch_mm_extra_attributes_from_vm(