Non-secure interrupt handling with managed exit
This patch implements the scenario when non-secure interrupt occurs
while executing a Secure Partition at S-EL1.
A non-secure interrupt traps as FIQ at S-EL2.
If the SP supports managed exit:
1. The SPMC decreases the current core priority mask register to
prevent other interrupts triggering while the managed exit
operation is on-going.
2. The SPMC injects a "managed exit" virtual interrupt to the current
SP and resumes it.
3. The SP traps to its interrupt handler (IRQ or FIQ depending on
the interrupt enable call), it performs its housekeeping and returns
with FFA_MSG_SEND_DIRECT_RESP.
4. The SPMC on receiving FFA_MSG_SEND_DIRECT_RESP, increases the
current core priority mask register and forwards the direct message
response to the "other world".
5. The SPMD transfers control back to non-secure world for handling of
the non-secure interrupt. The SP driver can schedule again the SP
by another direct message request.
If the SP does not support managed exit:
1. The SP is pre-empted and its live context saved.
2. The SPMC switches to "other world" with FFA_INTERRUPT.
3. the SPMD forwards FFA_INTERRUPT to the normal world.
4. The normal world handles the non-secure interrupt.
5. The SP driver has the possiblity to schedule again
the SP by ffa_run.
Change-Id: I7858e5ad49225d2c26e6d4c31f8f4d007d6a7d07
Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 32c58f2..cd98722 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -20,6 +20,7 @@
#include "hf/ffa.h"
#include "hf/ffa_internal.h"
#include "hf/panic.h"
+#include "hf/plat/interrupts.h"
#include "hf/vm.h"
#include "vmapi/hf/call.h"
@@ -882,6 +883,47 @@
struct vcpu *fiq_lower(void)
{
+#if SECURE_WORLD == 1
+ struct vcpu_locked current_locked;
+ struct vcpu *current_vcpu = current();
+ int ret;
+
+ if (current_vcpu->vm->supports_managed_exit) {
+ /* Mask all interrupts */
+ plat_interrupts_set_priority_mask(0x0);
+
+ current_locked = vcpu_lock(current_vcpu);
+ ret = api_interrupt_inject_locked(current_locked,
+ HF_MANAGED_EXIT_INTID,
+ current_vcpu, NULL);
+ if (ret != 0) {
+ panic("Failed to inject managed exit interrupt\n");
+ }
+
+ /* Entering managed exit sequence. */
+ current_vcpu->processing_managed_exit = true;
+
+ vcpu_unlock(¤t_locked);
+
+ /*
+ * Since we are in interrupt context, set the bit for the
+ * current vCPU directly in the register.
+ */
+ vcpu_update_virtual_interrupts(NULL);
+
+ /* Resume current vCPU. */
+ return NULL;
+ }
+
+ /*
+ * SP does not support managed exit. It is pre-empted and execution
+ * handed back to the normal world through the FFA_INTERRUPT ABI.
+ * The SP can be resumed later by ffa_run. The call to irq_lower
+ * and api_preempt is equivalent to calling api_switch_to_other_world
+ * for current vCPU passing FFA_INTERRUPT_32.
+ */
+#endif
+
return irq_lower();
}