feat(uuids): add support for multiple UUIDs per partition

Add manifest parsing, population of load-time data structures,
and manifest unit tests needed for supporting usage of multiple
UUIDs per partition.

This patch does not add support to ffa_partition_info_get
for discovery of multiple UUIDs/partition. That will be
addressed in a subsequent patch and for now, only the first
UUID for a partition is reported in the partition info
descriptors.

Signed-off-by: Kathleen Capella <kathleen.capella@arm.com>
Change-Id: I23f6c21dfab2c24cb4a3f7e664616b7bd183b88d
diff --git a/src/api.c b/src/api.c
index 0e97c09..547b3f8 100644
--- a/src/api.c
+++ b/src/api.c
@@ -516,7 +516,8 @@
 	for (ffa_vm_count_t index = 0; index < vm_get_count(); ++index) {
 		struct vm *vm = vm_find_index(index);
 
-		if (uuid_is_null || ffa_uuid_equal(uuid, &vm->uuid)) {
+		/*TODO fix logic to search through all uuids */
+		if (uuid_is_null || ffa_uuid_equal(uuid, &vm->uuids[0])) {
 			uint16_t array_index = vm_count;
 
 			++vm_count;
@@ -535,7 +536,7 @@
 			partitions[array_index].properties |=
 				FFA_PARTITION_AARCH64_EXEC;
 			if (uuid_is_null) {
-				partitions[array_index].uuid = vm->uuid;
+				partitions[array_index].uuid = vm->uuids[0];
 			}
 		}
 	}
@@ -2584,11 +2585,24 @@
 					       struct ffa_value args)
 {
 	struct ffa_uuid target_uuid;
+	uint16_t i;
 
 	ffa_uuid_unpack_from_uint64(args.arg2, args.arg3, &target_uuid);
 
-	return (ffa_uuid_is_null(&target_uuid) ||
-		ffa_uuid_equal(&target_uuid, &receiver_vm->uuid));
+	/* Allow for use of Nil UUID. */
+	if (ffa_uuid_is_null(&target_uuid)) {
+		return true;
+	}
+
+	for (i = 0; i < PARTITION_MAX_UUIDS; i++) {
+		if (ffa_uuid_is_null(&receiver_vm->uuids[i])) {
+			break;
+		}
+		if (ffa_uuid_equal(&target_uuid, &receiver_vm->uuids[i])) {
+			return true;
+		}
+	}
+	return false;
 }
 
 /**
diff --git a/src/load.c b/src/load.c
index 1453219..59c3f1c 100644
--- a/src/load.c
+++ b/src/load.c
@@ -168,10 +168,20 @@
 	uint32_t k = 0;
 
 	vm_locked.vm->smc_whitelist = manifest_vm->smc_whitelist;
-	vm_locked.vm->uuid = manifest_vm->partition.uuid;
 	vm_locked.vm->power_management =
 		manifest_vm->partition.power_management;
 
+	/* Populate array of UUIDs. */
+	for (uint16_t i = 0; i < PARTITION_MAX_UUIDS; i++) {
+		struct ffa_uuid current_uuid = manifest_vm->partition.uuids[i];
+
+		if (ffa_uuid_is_null(&current_uuid)) {
+			break;
+		}
+
+		vm_locked.vm->uuids[i] = current_uuid;
+	}
+
 	/* Populate the interrupt descriptor for current VM. */
 	for (uint16_t i = 0; i < PARTITION_MAX_DEVICE_REGIONS; i++) {
 		dev_region = manifest_vm->partition.dev_regions[i];
diff --git a/src/manifest.c b/src/manifest.c
index 6be414a..5fbd87c 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -1000,6 +1000,7 @@
 	struct fdt_node *boot_info_node, const struct boot_params *boot_params)
 {
 	unsigned int i = 0;
+	unsigned int j = 0;
 	struct uint32list_iter uuid;
 	uint32_t uuid_word;
 	struct fdt_node root;
@@ -1021,14 +1022,27 @@
 
 	TRY(read_uint32list(&root, "uuid", &uuid));
 
-	while (uint32list_has_next(&uuid) && i < 4) {
-		TRY(uint32list_get_next(&uuid, &uuid_word));
-		vm->partition.uuid.uuid[i] = uuid_word;
-		i++;
+	while (uint32list_has_next(&uuid) && j < PARTITION_MAX_UUIDS) {
+		while (uint32list_has_next(&uuid) && i < 4) {
+			TRY(uint32list_get_next(&uuid, &uuid_word));
+			vm->partition.uuids[j].uuid[i] = uuid_word;
+			i++;
+		}
+
+		if (ffa_uuid_is_null(&vm->partition.uuids[j])) {
+			return MANIFEST_ERROR_UUID_ALL_ZEROS;
+		}
+		dlog_verbose("  UUID %#x-%x-%x-%x\n",
+			     vm->partition.uuids[j].uuid[0],
+			     vm->partition.uuids[j].uuid[1],
+			     vm->partition.uuids[j].uuid[2],
+			     vm->partition.uuids[j].uuid[3]);
+		j++;
+		i = 0;
 	}
-	dlog_verbose("UUID %#x-%x-%x-%x\n", vm->partition.uuid.uuid[0],
-		     vm->partition.uuid.uuid[1], vm->partition.uuid.uuid[2],
-		     vm->partition.uuid.uuid[3]);
+
+	vm->partition.uuid_count = j;
+	dlog_verbose("  Number of UUIDs %u\n", vm->partition.uuid_count);
 
 	TRY(read_uint32(&root, "ffa-version", &vm->partition.ffa_version));
 	dlog_verbose("  Expected FF-A version %u.%u\n",
@@ -1275,7 +1289,7 @@
 	manifest_address = va_add(va_init(load_address), header.pm_offset);
 	if (!fdt_init_from_ptr(&sp_fdt, ptr_from_va(manifest_address),
 			       header.pm_size)) {
-		dlog_error("FDT failed validation.\n");
+		dlog_error("manifest.c: FDT failed validation.\n");
 		goto out;
 	}
 
@@ -1514,6 +1528,8 @@
 	case MANIFEST_ERROR_INVALID_BOOT_ORDER:
 		return "Boot order should be a unique value less than "
 		       "default largest value";
+	case MANIFEST_ERROR_UUID_ALL_ZEROS:
+		return "UUID should not be NIL";
 	}
 
 	panic("Unexpected manifest return code.");
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 1adaa0e..427922d 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -1680,7 +1680,7 @@
 	vm = &m->vm[0];
 	ASSERT_EQ(vm->partition.ffa_version, 0x10000);
 	ASSERT_THAT(
-		std::span(vm->partition.uuid.uuid, 4),
+		std::span(vm->partition.uuids[0].uuid, 4),
 		ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb));
 	ASSERT_EQ(vm->partition.execution_ctx_count, 1);
 	ASSERT_EQ(vm->partition.run_time_el, S_EL1);
@@ -1860,4 +1860,69 @@
 	ASSERT_EQ(manifest_init(mm_stage1_locked, &m, &it, &params, &ppool),
 		  MANIFEST_ERROR_INVALID_BOOT_ORDER);
 }
+TEST_F(manifest, ffa_valid_multiple_uuids)
+{
+	struct manifest_vm *vm;
+	struct_manifest *m;
+
+	/* clang-format off */
+	std::vector<char>  dtb = ManifestDtBuilder()
+		.Compatible({ "arm,ffa-manifest-1.0" })
+		.Property("ffa-version", "<0x10002>")
+		.Property("uuid",
+			 "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>,\
+			  <0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1daaa>")
+		.Property("execution-ctx-count", "<1>")
+		.Property("exception-level", "<2>")
+		.Property("execution-state", "<0>")
+		.Property("entrypoint-offset", "<0x00002000>")
+		.Property("xlat-granule", "<0>")
+		.Property("boot-order", "<0>")
+		.Property("messaging-method", "<4>")
+		.Property("ns-interrupts-action", "<1>")
+		.Build();
+	/* clang-format on */
+	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
+
+	vm = &m->vm[0];
+	ASSERT_EQ(vm->partition.ffa_version, 0x10002);
+	ASSERT_THAT(
+		std::span(vm->partition.uuids[0].uuid, 4),
+		ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb));
+	ASSERT_THAT(
+		std::span(vm->partition.uuids[1].uuid, 4),
+		ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1daaa));
+	ASSERT_EQ(vm->partition.uuid_count, 2);
+	ASSERT_EQ(vm->partition.execution_ctx_count, 1);
+	ASSERT_EQ(vm->partition.run_time_el, S_EL1);
+	ASSERT_EQ(vm->partition.execution_state, AARCH64);
+	ASSERT_EQ(vm->partition.ep_offset, 0x00002000);
+	ASSERT_EQ(vm->partition.xlat_granule, PAGE_4KB);
+	ASSERT_EQ(vm->partition.boot_order, 0);
+	ASSERT_EQ(vm->partition.messaging_method, FFA_PARTITION_INDIRECT_MSG);
+	ASSERT_EQ(vm->partition.ns_interrupts_action, NS_ACTION_ME);
+}
+TEST_F(manifest, ffa_uuid_all_zeros)
+{
+	struct_manifest *m;
+
+	/* clang-format off */
+	std::vector<char>  dtb = ManifestDtBuilder()
+		.Compatible({ "arm,ffa-manifest-1.0" })
+		.Property("ffa-version", "<0x10002>")
+		.Property("uuid",
+			 "<0x0 0x0 0x0 0x0>, <0x0 0x0 0x0 0x0>")
+		.Property("execution-ctx-count", "<1>")
+		.Property("exception-level", "<2>")
+		.Property("execution-state", "<0>")
+		.Property("entrypoint-offset", "<0x00002000>")
+		.Property("xlat-granule", "<0>")
+		.Property("boot-order", "<0>")
+		.Property("messaging-method", "<4>")
+		.Property("ns-interrupts-action", "<1>")
+		.Build();
+	/* clang-format on */
+	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
+		  MANIFEST_ERROR_UUID_ALL_ZEROS);
+}
 } /* namespace */