feat(interrupts): support for parsing interrupt ..

properties node from manifest and populating the interrupt descriptor
structure per VM.

Change-Id: I17f6dcd5d4af6eb37f1bb64770052fd6e8f23542
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/src/load.c b/src/load.c
index 0db27c5..14194ec 100644
--- a/src/load.c
+++ b/src/load.c
@@ -23,6 +23,7 @@
 #include "hf/memiter.h"
 #include "hf/mm.h"
 #include "hf/plat/console.h"
+#include "hf/plat/interrupts.h"
 #include "hf/plat/iommu.h"
 #include "hf/static_assert.h"
 #include "hf/std.h"
@@ -125,6 +126,25 @@
 	return true;
 }
 
+static void infer_interrupt(struct interrupt interrupt,
+			    struct interrupt_descriptor *int_desc)
+{
+	uint32_t attr = interrupt.attributes;
+
+	interrupt_desc_set_id(int_desc, interrupt.id);
+	interrupt_desc_set_priority(int_desc,
+				    (attr >> INT_DESC_PRIORITY_SHIFT) & 0xff);
+
+	/* Refer to the comments in interrupt_descriptor struct definition. */
+	interrupt_desc_set_type_config_sec_state(
+		int_desc,
+		(((attr >> INT_DESC_TYPE_SHIFT) & 0x3) << 2) |
+			(((attr >> INT_DESC_CONFIG_SHIFT) & 0x1) << 1) |
+			((attr >> INT_DESC_SEC_STATE_SHIFT) & 0x1));
+
+	interrupt_desc_set_valid(int_desc, true);
+}
+
 /**
  * Performs VM loading activities that are common between the primary and
  * secondaries.
@@ -134,9 +154,33 @@
 			const struct manifest_vm *manifest_vm,
 			struct mpool *ppool)
 {
+	struct device_region dev_region;
+	struct interrupt interrupt;
+	uint32_t k = 0;
+
 	vm_locked.vm->smc_whitelist = manifest_vm->smc_whitelist;
 	vm_locked.vm->uuid = manifest_vm->partition.uuid;
 
+	/* Populate the interrupt descriptor for current VM. */
+	for (uint8_t i = 0; i < SP_MAX_DEVICE_REGIONS; i++) {
+		dev_region = manifest_vm->partition.dev_regions[i];
+
+		CHECK(dev_region.interrupt_count <=
+		      SP_MAX_INTERRUPTS_PER_DEVICE);
+
+		for (uint8_t j = 0; j < dev_region.interrupt_count; j++) {
+			struct interrupt_descriptor int_desc;
+
+			interrupt = dev_region.interrupts[j];
+			infer_interrupt(interrupt, &int_desc);
+			vm_locked.vm->interrupt_desc[k] = int_desc;
+
+			k++;
+			CHECK(k <= VM_MANIFEST_MAX_INTERRUPTS);
+		}
+	}
+	dlog_verbose("VM has %d physical interrupts defined in manifest.\n", k);
+
 	if (manifest_vm->is_ffa_partition) {
 		struct ffa_value bitmap_create_res;
 
diff --git a/src/manifest.c b/src/manifest.c
index bd8c016..1d2d37a 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -430,7 +430,7 @@
 {
 	struct uint32list_iter list;
 	uint8_t i = 0;
-	uint8_t j = 0;
+	uint32_t j = 0;
 
 	dlog_verbose("  Partition Device Regions\n");
 
@@ -495,6 +495,8 @@
 				     dev_regions[i].interrupts[j].attributes);
 			j++;
 		}
+
+		dev_regions[i].interrupt_count = j;
 		if (j == 0) {
 			dlog_verbose("        Empty\n");
 		}
@@ -659,6 +661,7 @@
 	uint16_t ffa_version_minor;
 	enum manifest_return_code ret_code = MANIFEST_SUCCESS;
 	const char *error_string = "specified in manifest is unsupported";
+	uint32_t k = 0;
 
 	/* ensure that the SPM version is compatible */
 	ffa_version_major = (vm->partition.ffa_version & 0xffff0000) >>
@@ -710,6 +713,31 @@
 		ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
 	}
 
+	for (uint8_t i = 0; i < vm->partition.dev_region_count; i++) {
+		struct device_region dev_region;
+
+		dev_region = vm->partition.dev_regions[i];
+
+		if (dev_region.interrupt_count > SP_MAX_INTERRUPTS_PER_DEVICE) {
+			dlog_error(
+				"Interrupt count for device region exceeds "
+				"limit.\n");
+			ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
+			continue;
+		}
+
+		for (uint8_t j = 0; j < dev_region.interrupt_count; j++) {
+			k++;
+			if (k > VM_MANIFEST_MAX_INTERRUPTS) {
+				dlog_error(
+					"Interrupt count for VM exceeds "
+					"limit.\n");
+				ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
+				continue;
+			}
+		}
+	}
+
 	return ret_code;
 }