test(dir_msg): extend multiple uuids test

Extend test case `ffa_send_direct_message_req2_multiple_uuids`
to send a request to each of the target partition's UUIDs.

To enable this test, add parsing of `uuid` field to test service
manifest parsing.

Signed-off-by: Kathleen Capella <kathleen.capella@arm.com>
Change-Id: Ib6f3f86e5350143a624a555f5c0da98df4415ba8
diff --git a/test/hftest/service_common.c b/test/hftest/service_common.c
index 510fc77..214aefd 100644
--- a/test/hftest/service_common.c
+++ b/test/hftest/service_common.c
@@ -31,6 +31,23 @@
 	return &global_context;
 }
 
+static bool uint32list_has_next(const struct memiter *list)
+{
+	return memiter_size(list) > 0;
+}
+
+static void uint32list_get_next(struct memiter *list, uint32_t *out)
+{
+	uint64_t num;
+
+	CHECK(uint32list_has_next(list));
+	if (!fdt_parse_number(list, sizeof(uint32_t), &num)) {
+		return;
+	}
+
+	*out = (uint32_t)num;
+}
+
 noreturn void abort(void)
 {
 	HFTEST_LOG("Service contained failures.");
@@ -83,6 +100,10 @@
 	struct fdt_node ffa_node;
 	struct string mem_region_node_name = STRING_INIT("memory-regions");
 	struct string dev_region_node_name = STRING_INIT("device-regions");
+	struct memiter uuid;
+	uint32_t uuid_word = 0;
+	uint16_t j = 0;
+	uint16_t i = 0;
 	uint64_t number;
 
 	CHECK(ctx != NULL);
@@ -94,6 +115,30 @@
 				    &ctx->partition_manifest.load_addr));
 	EXPECT_TRUE(fdt_read_number(&root, "ffa-version", &number));
 
+	EXPECT_TRUE(fdt_read_property(&root, "uuid", &uuid));
+
+	/* Parse UUIDs and populate uuid count.*/
+	while (uint32list_has_next(&uuid) && j < PARTITION_MAX_UUIDS) {
+		while (uint32list_has_next(&uuid) && i < 4) {
+			uint32list_get_next(&uuid, &uuid_word);
+			ctx->partition_manifest.uuids[j].uuid[i] = uuid_word;
+			i++;
+		}
+
+		EXPECT_FALSE(
+			ffa_uuid_is_null(&ctx->partition_manifest.uuids[j]));
+
+		dlog_verbose("  UUID %#x-%x-%x-%x\n",
+			     ctx->partition_manifest.uuids[j].uuid[0],
+			     ctx->partition_manifest.uuids[j].uuid[1],
+			     ctx->partition_manifest.uuids[j].uuid[2],
+			     ctx->partition_manifest.uuids[j].uuid[3]);
+		j++;
+		i = 0;
+	}
+
+	ctx->partition_manifest.uuid_count = j;
+
 	ffa_node = root;
 
 	/* Look for the memory region node. */
diff --git a/test/vmapi/primary_with_secondaries/dir_msg.c b/test/vmapi/primary_with_secondaries/dir_msg.c
index 9d4a33e..972849b 100644
--- a/test/vmapi/primary_with_secondaries/dir_msg.c
+++ b/test/vmapi/primary_with_secondaries/dir_msg.c
@@ -688,10 +688,11 @@
 }
 
 /**
- * Send direct message via FFA_MSG_SEND_DIR_REQ2, verify that sent info is
- * echoed back.
+ * Send a direct message request via FFA_MSG_SEND_DIR_REQ2 to each of the target
+ * partition's UUIDs and  verify that sent info is echoed back.
  */
-TEST(direct_message, ffa_send_direct_message_req2_multiple_uuids)
+TEST_PRECONDITION(direct_message, ffa_send_direct_message_req2_multiple_uuids,
+		  service1_and_service2_are_secure)
 {
 	const uint64_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
 				0x88889999, 0x01010101, 0x23232323, 0x45454545,
@@ -703,7 +704,7 @@
 	struct ffa_uuid uuid = SERVICE2_UUID2;
 
 	SERVICE_SELECT(service2_info->vm_id,
-		       "ffa_direct_message_req2_resp_echo", mb.send);
+		       "ffa_direct_message_req2_resp_loop", mb.send);
 	ffa_run(service2_info->vm_id, 0);
 
 	res = ffa_msg_send_direct_req2(HF_PRIMARY_VM_ID, service2_info->vm_id,
@@ -726,6 +727,29 @@
 	EXPECT_EQ(res.extended_val.arg15, msg[11]);
 	EXPECT_EQ(res.extended_val.arg16, msg[12]);
 	EXPECT_EQ(res.extended_val.arg17, msg[13]);
+
+	uuid = SERVICE2;
+
+	res = ffa_msg_send_direct_req2(HF_PRIMARY_VM_ID, service2_info->vm_id,
+				       &uuid, (const uint64_t *)&msg,
+				       ARRAY_SIZE(msg));
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP2_64);
+
+	EXPECT_EQ(res.arg4, msg[0]);
+	EXPECT_EQ(res.arg5, msg[1]);
+	EXPECT_EQ(res.arg6, msg[2]);
+	EXPECT_EQ(res.arg7, msg[3]);
+	EXPECT_EQ(res.extended_val.arg8, msg[4]);
+	EXPECT_EQ(res.extended_val.arg9, msg[5]);
+	EXPECT_EQ(res.extended_val.arg10, msg[6]);
+	EXPECT_EQ(res.extended_val.arg11, msg[7]);
+	EXPECT_EQ(res.extended_val.arg12, msg[8]);
+	EXPECT_EQ(res.extended_val.arg13, msg[9]);
+	EXPECT_EQ(res.extended_val.arg14, msg[10]);
+	EXPECT_EQ(res.extended_val.arg15, msg[11]);
+	EXPECT_EQ(res.extended_val.arg16, msg[12]);
+	EXPECT_EQ(res.extended_val.arg17, msg[13]);
 }
 
 /**
diff --git a/test/vmapi/primary_with_secondaries/services/dir_msg.c b/test/vmapi/primary_with_secondaries/services/dir_msg.c
index 1807def..a433fe8 100644
--- a/test/vmapi/primary_with_secondaries/services/dir_msg.c
+++ b/test/vmapi/primary_with_secondaries/services/dir_msg.c
@@ -17,6 +17,46 @@
 
 #define MAX_RESP_REGS (MAX_MSG_SIZE / sizeof(uint64_t))
 
+static uint16_t get_uuid_count(struct hftest_context *ctx)
+{
+	if (ctx->is_ffa_manifest_parsed) {
+		return ctx->partition_manifest.uuid_count;
+	}
+
+	return 0;
+}
+
+static struct ffa_uuid *get_uuids(struct hftest_context *ctx)
+{
+	if (ctx->is_ffa_manifest_parsed) {
+		return (struct ffa_uuid *)&ctx->partition_manifest.uuids;
+	}
+
+	return NULL;
+}
+
+static bool is_uuid_in_list(uint16_t uuid_count, struct ffa_uuid target_uuid,
+			    struct ffa_uuid *uuid_list)
+{
+	uint16_t i;
+
+	/* Allow for nil uuid usage. */
+	if (ffa_uuid_is_null(&target_uuid)) {
+		return true;
+	}
+
+	for (i = 0; i < uuid_count; i++) {
+		if (ffa_uuid_is_null(&target_uuid)) {
+			break;
+		}
+		if (ffa_uuid_equal(&uuid_list[i], &target_uuid)) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
 TEST_SERVICE(ffa_direct_message_resp_echo)
 {
 	struct ffa_value args = ffa_msg_wait();
@@ -687,3 +727,44 @@
 	EXPECT_FFA_ERROR(res, FFA_DENIED);
 	ffa_yield();
 }
+
+/**
+ * Service traps execution in a loop, and expects to always wake up with a
+ * FFA_MSG_SEND_DIRECT_REQ2. Verify that target UUID was specified in the target
+ * partition's manifest before echoing message back to sender.
+ */
+TEST_SERVICE(ffa_direct_message_req2_resp_loop)
+{
+	struct hftest_context *ctx = hftest_get_context();
+	struct ffa_uuid *uuids = get_uuids(ctx);
+	uint16_t uuid_count = get_uuid_count(ctx);
+	struct ffa_value res;
+
+	if (!ctx->is_ffa_manifest_parsed) {
+		FAIL("Manifest not parsed");
+	}
+
+	res = ffa_msg_wait();
+
+	while (true) {
+		uint64_t msg[MAX_RESP_REGS];
+		struct ffa_uuid target_uuid;
+
+		EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_REQ2_64);
+
+		ffa_uuid_unpack_from_uint64(res.arg2, res.arg3, &target_uuid);
+
+		HFTEST_LOG("Target UUID: %X-%X-%X-%X", target_uuid.uuid[0],
+			   target_uuid.uuid[1], target_uuid.uuid[2],
+			   target_uuid.uuid[3]);
+
+		EXPECT_TRUE(is_uuid_in_list(uuid_count, target_uuid, uuids));
+
+		memcpy_s(&msg, sizeof(uint64_t) * MAX_RESP_REGS, &res.arg4,
+			 MAX_RESP_REGS * sizeof(uint64_t));
+
+		res = ffa_msg_send_direct_resp2(
+			ffa_receiver(res), ffa_sender(res),
+			(const uint64_t *)msg, MAX_RESP_REGS);
+	}
+}