feat(interrupts): preferred managed exit signal

A SP optionally specifies if vIRQ is the preferred choice for
signaling Managed Exit in response to a non secure interrupt.

Moreover, SPMC enables the following virtual maintenenace interrupts
by default for each Secure Partition:
  > Managed Exit Interrupt
  > Notification Pending Interrupt

Change-Id: I17131b42ee6fae2896804e4f952d9a371f237cd5
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 4bab99c..abab7a4 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -492,3 +492,9 @@
 	(void)current;
 	(void)next;
 }
+
+void plat_ffa_enable_virtual_maintenance_interrupts(
+	struct vcpu_locked current_locked)
+{
+	(void)current_locked;
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index fc1548a..9629a61 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -998,3 +998,9 @@
 	(void)current;
 	(void)next;
 }
+
+void plat_ffa_enable_virtual_maintenance_interrupts(
+	struct vcpu_locked current_locked)
+{
+	(void)current_locked;
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index ef39ce4..c3de2d5 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -2040,3 +2040,38 @@
 	sl_unlock(&next->lock);
 	sl_unlock(&current->lock);
 }
+
+void plat_ffa_enable_virtual_maintenance_interrupts(
+	struct vcpu_locked current_locked)
+{
+	struct vcpu *current;
+	struct interrupts *interrupts;
+	struct vm *vm;
+
+	current = current_locked.vcpu;
+	interrupts = &current->interrupts;
+	vm = current->vm;
+
+	if (plat_ffa_vm_managed_exit_supported(vm)) {
+		vcpu_virt_interrupt_set_enabled(interrupts,
+						HF_MANAGED_EXIT_INTID);
+		/*
+		 * SPMC decides the interrupt type for Managed exit signal based
+		 * on the partition manifest.
+		 */
+		if (vm->me_signal_virq) {
+			vcpu_virt_interrupt_set_type(interrupts,
+						     HF_MANAGED_EXIT_INTID,
+						     INTERRUPT_TYPE_IRQ);
+		} else {
+			vcpu_virt_interrupt_set_type(interrupts,
+						     HF_MANAGED_EXIT_INTID,
+						     INTERRUPT_TYPE_FIQ);
+		}
+	}
+
+	if (vm->notifications.enabled) {
+		vcpu_virt_interrupt_set_enabled(interrupts,
+						HF_NOTIFICATION_PENDING_INTID);
+	}
+}
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index c41169b..0f45e3b 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -465,3 +465,9 @@
 	(void)current;
 	(void)next;
 }
+
+void plat_ffa_enable_virtual_maintenance_interrupts(
+	struct vcpu_locked current_locked)
+{
+	(void)current_locked;
+}
diff --git a/src/load.c b/src/load.c
index db4de88..d105f72 100644
--- a/src/load.c
+++ b/src/load.c
@@ -207,6 +207,9 @@
 		vm_locked.vm->ns_interrupts_action =
 			manifest_vm->partition.ns_interrupts_action;
 
+		vm_locked.vm->me_signal_virq =
+			manifest_vm->partition.me_signal_virq;
+
 		vm_locked.vm->notifications.enabled =
 			manifest_vm->partition.notification_support;
 
@@ -837,6 +840,10 @@
 	vcpu = vm_get_vcpu(vm, 0);
 
 	vcpu_locked = vcpu_lock(vcpu);
+
+	/* Enable virtual maintenance interrupts for Secure Partitions. */
+	plat_ffa_enable_virtual_maintenance_interrupts(vcpu_locked);
+
 	if (has_fdt) {
 		vcpu_secondary_reset_and_start(vcpu_locked, secondary_entry,
 					       pa_addr(fdt_addr));
diff --git a/src/manifest.c b/src/manifest.c
index b6c6e9a..90aefd7 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -910,6 +910,12 @@
 				"partition\n");
 			return MANIFEST_ILLEGAL_NS_ACTION;
 		}
+
+		TRY(read_bool(&root, "managed-exit-virq",
+			      &vm->partition.me_signal_virq));
+		if (vm->partition.me_signal_virq) {
+			dlog_verbose("  Managed Exit signaled through vIRQ\n");
+		}
 	}
 
 	TRY(read_bool(&root, "notification-support",