feat(manifest): check interrupt IDs are unique

Add a checks to prevent two endpoints from declaring the same
interrupt ID resource for a device peripheral.

Also add macros used to access the bitmask that tracks
interrupts.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I5074e8d4209588a6c8f62ee06e0eb05b20cac387
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index beaf883..6d4fda8 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -27,6 +27,10 @@
 using ::testing::IsEmpty;
 using ::testing::NotNull;
 
+using struct_manifest = struct manifest;
+
+constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 32;
+
 template <typename T>
 void exec(const char *program, const char *args[], const T &stdin,
 	  std::vector<char> *stdout)
@@ -308,29 +312,102 @@
 	std::stringstream dts_;
 };
 
-static enum manifest_return_code manifest_from_vec(struct manifest *m,
-						   const std::vector<char> &vec)
+class manifest : public ::testing::Test
 {
-	struct memiter it;
+	void SetUp() override
+	{
+		test_heap = std::make_unique<uint8_t[]>(TEST_HEAP_SIZE);
+		mpool_init(&ppool, MM_PPOOL_ENTRY_SIZE);
+		mpool_add_chunk(&ppool, test_heap.get(), TEST_HEAP_SIZE);
+	}
+
+	std::unique_ptr<uint8_t[]> test_heap;
+
+       protected:
 	struct mpool ppool;
-	struct mm_stage1_locked mm_stage1_locked;
 
-	memiter_init(&it, vec.data(), vec.size());
-	return manifest_init(mm_stage1_locked, m, &it, &ppool);
-}
+       public:
+	/**
+	 * Class for programatically building a Partition package.
+	 */
+	class Partition_package
+	{
+	       public:
+		__attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
+		__attribute__((
+			aligned(PAGE_SIZE))) char manifest_dtb[PAGE_SIZE] = {};
+		__attribute__((aligned(PAGE_SIZE))) char img[PAGE_SIZE] = {};
 
-TEST(manifest, no_hypervisor_node)
+		Partition_package(const std::vector<char> &vec)
+		{
+			// Initialise header field
+			spkg.magic = SP_PKG_HEADER_MAGIC;
+			spkg.version = SP_PKG_HEADER_VERSION_2;
+			spkg.pm_offset = PAGE_SIZE;
+			spkg.pm_size = vec.size();
+			spkg.img_offset = 2 * PAGE_SIZE;
+			spkg.img_size = ARRAY_SIZE(img);
+
+			// Copy dtb into package
+			std::copy(vec.begin(), vec.end(), manifest_dtb);
+		}
+	};
+
+	enum manifest_return_code manifest_from_vec(
+		struct_manifest *m, const std::vector<char> &vec)
+	{
+		struct memiter it;
+		struct mm_stage1_locked mm_stage1_locked;
+		enum manifest_return_code ret;
+
+		memiter_init(&it, vec.data(), vec.size());
+		ret = manifest_init(mm_stage1_locked, m, &it, &ppool);
+
+		manifest_deinit(&ppool);
+		return ret;
+	}
+
+	enum manifest_return_code ffa_manifest_from_vec(
+		struct_manifest *m, const std::vector<char> &vec)
+	{
+		struct memiter it;
+		struct mm_stage1_locked mm_stage1_locked;
+		enum manifest_return_code ret;
+
+		Partition_package spkg(vec);
+
+		/* clang-format off */
+		std::vector<char> core_dtb = ManifestDtBuilder()
+			.StartChild("hypervisor")
+				.Compatible()
+				.StartChild("vm1")
+					.DebugName("primary_vm")
+					.FfaPartition()
+					.LoadAddress((uint64_t)&spkg)
+				.EndChild()
+			.EndChild()
+			.Build();
+		/* clang-format on */
+		memiter_init(&it, core_dtb.data(), core_dtb.size());
+		ret = manifest_init(mm_stage1_locked, m, &it, &ppool);
+
+		manifest_deinit(&ppool);
+		return ret;
+	}
+};
+
+TEST_F(manifest, no_hypervisor_node)
 {
-	struct manifest m;
+	struct_manifest m;
 	std::vector<char> dtb = ManifestDtBuilder().Build();
 
 	ASSERT_EQ(manifest_from_vec(&m, dtb),
 		  MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
 }
 
-TEST(manifest, no_compatible_property)
+TEST_F(manifest, no_compatible_property)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char> dtb = ManifestDtBuilder()
@@ -342,9 +419,9 @@
 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
 }
 
-TEST(manifest, not_compatible)
+TEST_F(manifest, not_compatible)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char> dtb = ManifestDtBuilder()
@@ -357,9 +434,9 @@
 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
 }
 
-TEST(manifest, compatible_one_of_many)
+TEST_F(manifest, compatible_one_of_many)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char> dtb = ManifestDtBuilder()
@@ -375,9 +452,9 @@
 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
 }
 
-TEST(manifest, no_vm_nodes)
+TEST_F(manifest, no_vm_nodes)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char> dtb = ManifestDtBuilder()
@@ -409,9 +486,9 @@
 	/* clang-format on */
 }
 
-TEST(manifest, long_string)
+TEST_F(manifest, long_string)
 {
-	struct manifest m;
+	struct_manifest m;
 	std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
 	std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
 
@@ -420,9 +497,9 @@
 		  MANIFEST_ERROR_STRING_TOO_LONG);
 }
 
-TEST(manifest, reserved_vm_id)
+TEST_F(manifest, reserved_vm_id)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char> dtb = ManifestDtBuilder()
@@ -464,9 +541,9 @@
 	/* clang-format on */
 }
 
-TEST(manifest, vcpu_count_limit)
+TEST_F(manifest, vcpu_count_limit)
 {
-	struct manifest m;
+	struct_manifest m;
 	std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
 	std::vector<char> dtb_first_invalid =
 		gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
@@ -479,9 +556,9 @@
 		  MANIFEST_ERROR_INTEGER_OVERFLOW);
 }
 
-TEST(manifest, no_ramdisk_primary)
+TEST_F(manifest, no_ramdisk_primary)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char> dtb = ManifestDtBuilder()
@@ -500,9 +577,9 @@
 	ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
 }
 
-TEST(manifest, no_boot_address_primary)
+TEST_F(manifest, no_boot_address_primary)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char> dtb = ManifestDtBuilder()
@@ -521,9 +598,9 @@
 	ASSERT_EQ(m.vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
 }
 
-TEST(manifest, boot_address_primary)
+TEST_F(manifest, boot_address_primary)
 {
-	struct manifest m;
+	struct_manifest m;
 	const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
 
 	/* clang-format off */
@@ -560,9 +637,9 @@
 	/* clang-format on */
 }
 
-TEST(manifest, malformed_booleans)
+TEST_F(manifest, malformed_booleans)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
 	std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
@@ -579,9 +656,9 @@
 		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
 }
 
-TEST(manifest, valid)
+TEST_F(manifest, valid)
 {
-	struct manifest m;
+	struct_manifest m;
 	struct manifest_vm *vm;
 
 	/* clang-format off */
@@ -646,59 +723,9 @@
 	ASSERT_FALSE(vm->smc_whitelist.permissive);
 }
 
-/**
- * Class for programatically building a Partition package.
- */
-class Partition_package
+TEST_F(manifest, ffa_not_compatible)
 {
-       public:
-	__attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
-	__attribute__((aligned(PAGE_SIZE))) char manifest_dtb[PAGE_SIZE] = {};
-	__attribute__((aligned(PAGE_SIZE))) char img[PAGE_SIZE] = {};
-
-	Partition_package(const std::vector<char> &vec)
-	{
-		// Initialise header field
-		spkg.magic = SP_PKG_HEADER_MAGIC;
-		spkg.version = SP_PKG_HEADER_VERSION_2;
-		spkg.pm_offset = PAGE_SIZE;
-		spkg.pm_size = vec.size();
-		spkg.img_offset = 2 * PAGE_SIZE;
-		spkg.img_size = ARRAY_SIZE(img);
-
-		// Copy dtb into package
-		std::copy(vec.begin(), vec.end(), manifest_dtb);
-	}
-};
-
-static enum manifest_return_code ffa_manifest_from_vec(
-	struct manifest *m, const std::vector<char> &vec)
-{
-	struct memiter it;
-	struct mpool ppool;
-	struct mm_stage1_locked mm_stage1_locked;
-
-	Partition_package spkg(vec);
-
-	/* clang-format off */
-	std::vector<char> core_dtb = ManifestDtBuilder()
-		.StartChild("hypervisor")
-			.Compatible()
-			.StartChild("vm1")
-				.DebugName("primary_vm")
-				.FfaPartition()
-				.LoadAddress((uint64_t)&spkg)
-			.EndChild()
-		.EndChild()
-		.Build();
-	/* clang-format on */
-	memiter_init(&it, core_dtb.data(), core_dtb.size());
-	return manifest_init(mm_stage1_locked, m, &it, &ppool);
-}
-
-TEST(manifest, ffa_not_compatible)
-{
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char>  dtb = ManifestDtBuilder()
@@ -718,9 +745,9 @@
 		  MANIFEST_ERROR_NOT_COMPATIBLE);
 }
 
-TEST(manifest, ffa_missing_property)
+TEST_F(manifest, ffa_missing_property)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char>  dtb = ManifestDtBuilder()
@@ -733,13 +760,13 @@
 		  MANIFEST_ERROR_PROPERTY_NOT_FOUND);
 }
 
-TEST(manifest, ffa_validate_sanity_check)
+TEST_F(manifest, ffa_validate_sanity_check)
 {
 	/*
 	 * TODO: write test excluding all optional fields of the manifest, in
 	 * accordance with specification.
 	 */
-	struct manifest m;
+	struct_manifest m;
 
 	/* Incompatible version */
 	/* clang-format off */
@@ -832,9 +859,9 @@
 		  MANIFEST_ERROR_NOT_COMPATIBLE);
 }
 
-TEST(manifest, ffa_validate_rxtx_info)
+TEST_F(manifest, ffa_validate_rxtx_info)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* Not Compatible */
 	/* clang-format off */
@@ -861,9 +888,9 @@
 		  MANIFEST_ERROR_PROPERTY_NOT_FOUND);
 }
 
-TEST(manifest, ffa_validate_mem_regions)
+TEST_F(manifest, ffa_validate_mem_regions)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* Not Compatible */
 	/* clang-format off */
@@ -936,9 +963,9 @@
 		  MANIFEST_ERROR_RXTX_SIZE_MISMATCH);
 }
 
-TEST(manifest, ffa_validate_dev_regions)
+TEST_F(manifest, ffa_validate_dev_regions)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* Not Compatible */
 	/* clang-format off */
@@ -1000,9 +1027,10 @@
 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
 		  MANIFEST_ERROR_MALFORMED_INTEGER_LIST);
 }
-TEST(manifest, ffa_invalid_memory_region_attributes)
+
+TEST_F(manifest, ffa_invalid_memory_region_attributes)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char>  dtb = ManifestDtBuilder()
@@ -1042,9 +1070,9 @@
 		  MANIFEST_ERROR_INVALID_MEM_PERM);
 }
 
-TEST(manifest, ffa_invalid_device_region_attributes)
+TEST_F(manifest, ffa_invalid_device_region_attributes)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char>  dtb = ManifestDtBuilder()
@@ -1096,9 +1124,9 @@
 		  MANIFEST_ERROR_INVALID_MEM_PERM);
 }
 
-TEST(manifest, ffa_valid)
+TEST_F(manifest, ffa_valid)
 {
-	struct manifest m;
+	struct_manifest m;
 
 	/* clang-format off */
 	std::vector<char>  dtb = ManifestDtBuilder()