feat(interrupts): modify interrupt properties in runtime

At present, the 'reconfigure interrupt' paravirtualized interface only
allows to change the sec state, and the target CPU of the interrupt.

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: Ie8780b6854314754ad948723d77c8dba68ae0c00
diff --git a/inc/hf/interrupt_desc.h b/inc/hf/interrupt_desc.h
index 0780dcc..815816e 100644
--- a/inc/hf/interrupt_desc.h
+++ b/inc/hf/interrupt_desc.h
@@ -50,6 +50,13 @@
 
 	bitmap->bitmap[index] &= ~(1U << shift);
 }
+
+/**
+ * Legal values to change the security state of an interrupt.
+ */
+#define INT_SEC_STATE_NS 0
+#define INT_SEC_STATE_S 1
+
 /**
  * Attributes encoding in the manifest:
 
diff --git a/inc/hf/vm.h b/inc/hf/vm.h
index 0ab4aaa..3f06d38 100644
--- a/inc/hf/vm.h
+++ b/inc/hf/vm.h
@@ -395,8 +395,6 @@
 		(UINT32_C(1) << VM_POWER_MANAGEMENT_CPU_OFF_SHIFT)) != 0;
 }
 
-struct interrupt_descriptor *vm_find_interrupt_descriptor(
-	struct vm_locked vm_locked, uint32_t id);
 struct interrupt_descriptor *vm_interrupt_set_target_mpidr(
 	struct vm_locked vm_locked, uint32_t id, uint32_t target_mpidr);
 struct interrupt_descriptor *vm_interrupt_set_sec_state(
diff --git a/inc/vmapi/hf/abi.h b/inc/vmapi/hf/abi.h
index dd9e698..9a078d4 100644
--- a/inc/vmapi/hf/abi.h
+++ b/inc/vmapi/hf/abi.h
@@ -26,4 +26,8 @@
 /* Custom FF-A-like calls returned from FFA_RUN. */
 #define HF_FFA_RUN_WAIT_FOR_INTERRUPT 0xff06
 
+/* Possible commands that reconfigure an interrupt. */
+#define INT_RECONFIGURE_TARGET_PE 0
+#define INT_RECONFIGURE_SEC_STATE 1
+
 /* clang-format on */
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 59bd11c..aca307b 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -2773,6 +2773,11 @@
 
 /**
  * Reconfigure the interrupt belonging to the current partition at runtime.
+ * At present, this paravirtualized interface only allows the following
+ * commands which signify what change is being requested by the current
+ * partition:
+ * - Change the target CPU of the interrupt.
+ * - Change the security state of the interrupt.
  */
 int64_t plat_ffa_interrupt_reconfigure(uint32_t int_id, uint32_t command,
 				       uint32_t value, struct vcpu *current)
@@ -2780,7 +2785,7 @@
 	struct vm *vm = current->vm;
 	struct vm_locked vm_locked;
 	int64_t ret = -1;
-	struct interrupt_descriptor *int_desc;
+	struct interrupt_descriptor *int_desc = NULL;
 
 	/*
 	 * Lock VM to protect interrupt descriptor from being modified
@@ -2788,9 +2793,52 @@
 	 */
 	vm_locked = vm_lock(vm);
 
-	/* Check if the interrupt belongs to the current SP. */
-	int_desc = vm_find_interrupt_descriptor(vm_locked, int_id);
+	switch (command) {
+	case INT_RECONFIGURE_TARGET_PE:
+		/* Here, value represents the target PE index. */
+		if (value >= MAX_CPUS) {
+			dlog_verbose(
+				"Illegal target PE index specified while "
+				"reconfiguring interrupt %x\n",
+				int_id);
+			goto out_unlock;
+		}
 
+		/*
+		 * An UP SP cannot reconfigure an interrupt to be targetted to
+		 * any other physical CPU except the one it is currently
+		 * running on.
+		 */
+		if ((vm->vcpu_count == 1) &&
+		    (value != cpu_index(current->cpu))) {
+			dlog_verbose(
+				"Illegal target PE index specified by current "
+				"UP SP\n");
+			goto out_unlock;
+		}
+
+		/* Configure the interrupt to be routed to a specific CPU. */
+		int_desc = vm_interrupt_set_target_mpidr(
+			vm_locked, int_id, cpu_find_index(value)->id);
+		break;
+	case INT_RECONFIGURE_SEC_STATE:
+		/* Specify the new security state of the interrupt. */
+		if (value != INT_SEC_STATE_NS && value != INT_SEC_STATE_S) {
+			dlog_verbose(
+				"Illegal value %x specified while "
+				"reconfiguring interrupt %x\n",
+				value, int_id);
+			goto out_unlock;
+		}
+		int_desc = vm_interrupt_set_sec_state(vm_locked, int_id, value);
+		break;
+	default:
+		dlog_verbose("Interrupt reconfigure: Unsupported command %x\n",
+			     command);
+		goto out_unlock;
+	}
+
+	/* Check if the interrupt belongs to the current SP. */
 	if (int_desc == NULL) {
 		dlog_verbose("Interrupt %x does not belong to current SP\n",
 			     int_id);
diff --git a/src/vm.c b/src/vm.c
index 1b7ae9d..ec1e374 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -988,7 +988,7 @@
  * Obtain the interrupt descriptor entry of the specified vm corresponding
  * to the specific interrupt id.
  */
-struct interrupt_descriptor *vm_find_interrupt_descriptor(
+static struct interrupt_descriptor *vm_find_interrupt_descriptor(
 	struct vm_locked vm_locked, uint32_t id)
 {
 	for (uint32_t i = 0; i < HF_NUM_INTIDS; i++) {