feat(interrupts): allow interrupt to be enabled or disabled in runtime

This patch extends the paravirtualized interface introduced in earlier
patches to either enable or disable a secure physical interrupt.

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: I86250d8e4788feae4d2b9898567c640aa54b710f
diff --git a/inc/hf/interrupt_desc.h b/inc/hf/interrupt_desc.h
index 815816e..b97bfb0 100644
--- a/inc/hf/interrupt_desc.h
+++ b/inc/hf/interrupt_desc.h
@@ -58,6 +58,14 @@
 #define INT_SEC_STATE_S 1
 
 /**
+ * Legal values to enable or disable an interrupt through the
+ * `INT_RECONFIGURE_ENABLE` command using the `HF_INTERRUPT_RECONFIGURE`
+ * paravirtualized interface.
+ */
+#define INT_DISABLE 0
+#define INT_ENABLE 1
+
+/**
  * Attributes encoding in the manifest:
 
  * Field		Bit(s)
@@ -111,6 +119,7 @@
 	bool valid;
 	bool mpidr_valid;
 	uint64_t mpidr;
+	bool enabled;
 };
 
 /**
@@ -213,3 +222,9 @@
 {
 	int_desc->valid = valid;
 }
+
+static inline void interrupt_desc_set_enabled(
+	struct interrupt_descriptor *int_desc, bool enable)
+{
+	int_desc->enabled = enable;
+}
diff --git a/inc/hf/vm.h b/inc/hf/vm.h
index 3f06d38..9b7f40e 100644
--- a/inc/hf/vm.h
+++ b/inc/hf/vm.h
@@ -399,3 +399,5 @@
 	struct vm_locked vm_locked, uint32_t id, uint32_t target_mpidr);
 struct interrupt_descriptor *vm_interrupt_set_sec_state(
 	struct vm_locked vm_locked, uint32_t id, uint32_t sec_state);
+struct interrupt_descriptor *vm_interrupt_set_enable(struct vm_locked vm_locked,
+						     uint32_t id, bool enable);
diff --git a/inc/vmapi/hf/abi.h b/inc/vmapi/hf/abi.h
index 9a078d4..8e35ddf 100644
--- a/inc/vmapi/hf/abi.h
+++ b/inc/vmapi/hf/abi.h
@@ -29,5 +29,6 @@
 /* Possible commands that reconfigure an interrupt. */
 #define INT_RECONFIGURE_TARGET_PE 0
 #define INT_RECONFIGURE_SEC_STATE 1
+#define INT_RECONFIGURE_ENABLE 2
 
 /* clang-format on */
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index aca307b..a197256 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -2778,6 +2778,7 @@
  * partition:
  * - Change the target CPU of the interrupt.
  * - Change the security state of the interrupt.
+ * - Enable or disable the physical interrupt.
  */
 int64_t plat_ffa_interrupt_reconfigure(uint32_t int_id, uint32_t command,
 				       uint32_t value, struct vcpu *current)
@@ -2832,6 +2833,19 @@
 		}
 		int_desc = vm_interrupt_set_sec_state(vm_locked, int_id, value);
 		break;
+	case INT_RECONFIGURE_ENABLE:
+		/* Enable or disable the interrupt. */
+		if (value != INT_DISABLE && value != INT_ENABLE) {
+			dlog_verbose(
+				"Illegal value %x specified while "
+				"reconfiguring interrupt %x\n",
+				value, int_id);
+			goto out_unlock;
+		} else {
+			int_desc = vm_interrupt_set_enable(vm_locked, int_id,
+							   value == INT_ENABLE);
+		}
+		break;
 	default:
 		dlog_verbose("Interrupt reconfigure: Unsupported command %x\n",
 			     command);
diff --git a/src/load.c b/src/load.c
index 1c1794d..ae97a2d 100644
--- a/src/load.c
+++ b/src/load.c
@@ -151,6 +151,7 @@
 	}
 
 	interrupt_desc_set_valid(int_desc, true);
+	interrupt_desc_set_enabled(int_desc, true);
 }
 
 /**
@@ -184,6 +185,7 @@
 			interrupt = dev_region.interrupts[j];
 			infer_interrupt(interrupt, &int_desc);
 			vm_locked.vm->interrupt_desc[k] = int_desc;
+			assert(int_desc.enabled);
 
 			/*
 			 * Configure the physical interrupts allocated for this
diff --git a/src/vm.c b/src/vm.c
index ec1e374..8a91a2b 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1041,3 +1041,20 @@
 
 	return int_desc;
 }
+
+/**
+ * Enable or disable the specified interrupt id belonging to specified vm.
+ */
+struct interrupt_descriptor *vm_interrupt_set_enable(struct vm_locked vm_locked,
+						     uint32_t id, bool enable)
+{
+	struct interrupt_descriptor *int_desc;
+
+	int_desc = vm_find_interrupt_descriptor(vm_locked, id);
+
+	if (int_desc != NULL) {
+		interrupt_desc_set_enabled(int_desc, enable);
+	}
+
+	return int_desc;
+}