fix(interrupts): implicit secure interrupt completion signal
Per FF-A v1.1-Beta0 spec section 8.3, an SP can use multiple
mechanisms to signal completion of secure interrupt handling. SP
can invoke explicit FF-A ABIs, namely FFA_MSG_WAIT and FFA_RUN,
when in WAITING/BLOCKED state respectively, but has to perform
implicit signal completion mechanism by dropping the priority
of the virtual secure interrupt when SPMC signaled the virtual
interrupt in other execution context states such as RUNNING
and PREEMPTED.
This patch introduces a new variable that helps SPMC to keep a track
of such mechanism and perform appropriate bookkeeping.
It removes the existing limitation:
SPMC signals virtual interrupt to an SP in PREEMPTED state(such as
when processing a direct message request but got preempted by a
Self S-Int) and resumed the SP vCPU but SPMC temporarily held the
priority thereby not allowing secure physical interrupts to be
delivered to CPU interface till the SP sent a corresponding direct
message response. Ideally, SPMC should have considered the para-
virtualized de-activation(and priority drop) HVC call as an implicit
signal completion mechanism and relax the priority threshold.
Change-Id: I7fd16d4621a26839de1ce54b9a3535224a473051
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 6fe3179..c71894d 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -580,6 +580,14 @@
if (current->processing_secure_interrupt) {
CHECK(current->state == VCPU_STATE_WAITING);
+ /*
+ * This flag should not have been set by SPMC when it
+ * signaled the virtual interrupt to the SP while SP was
+ * in WAITING or BLOCKED states. Refer the embedded
+ * comment in vcpu.h file for further description.
+ */
+ assert(!current->implicit_completion_signal);
+
/* Secure interrupt pre-empted normal world. */
if (current->preempted_vcpu->vm->id ==
HF_OTHER_WORLD_ID) {
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index b067079..07f3266 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -758,6 +758,13 @@
CHECK(current->state == VCPU_STATE_BLOCKED);
CHECK(target_vcpu == current->preempted_vcpu);
+ /*
+ * This flag should not have been set by SPMC when it
+ * signaled the virtual interrupt to the SP while SP was
+ * in WAITING or BLOCKED states. Refer the embedded
+ * comment in vcpu.h file for further description.
+ */
+ assert(!current->implicit_completion_signal);
/* Restore interrupt priority mask. */
plat_interrupts_set_priority_mask(
@@ -822,6 +829,23 @@
current->secure_interrupt_deactivated = true;
}
+ if (current->implicit_completion_signal) {
+ /* There is no preempted vCPU to resume. */
+ assert(current->preempted_vcpu == NULL);
+
+ /* Restore interrupt priority mask. */
+ plat_interrupts_set_priority_mask(current->priority_mask);
+
+ /*
+ * Clear fields corresponding to secure interrupt
+ * handling.
+ */
+ current->processing_secure_interrupt = false;
+ current->secure_interrupt_deactivated = false;
+ current->current_sec_interrupt_id = 0;
+ current->implicit_completion_signal = false;
+ }
+
return 0;
}
@@ -927,6 +951,13 @@
CHECK(!target_vcpu->processing_secure_interrupt);
CHECK(vcpu_interrupt_irq_count_get(target_vcpu_locked) == 0);
+ /*
+ * SPMC has started handling a secure interrupt with a clean slate. This
+ * signal should be false unless there was a bug in source code. Hence,
+ * use assert rather than CHECK.
+ */
+ assert(!target_vcpu->implicit_completion_signal);
+
/* Inject this interrupt as a vIRQ to the target SP context. */
/* TODO: check api_interrupt_inject_locked return value. */
(void)api_interrupt_inject_locked(target_vcpu_locked, id, current,
@@ -958,6 +989,10 @@
break;
case VCPU_STATE_PREEMPTED:
/*
+ * The scenario in which vCPU of target SP is in PREEMPTED state
+ * due to a Self S-Int has been handled separately in
+ * plat_ffa_secure_interrupt() function.
+ *
* We do not resume a target vCPU that has been already
* pre-empted by an interrupt or waiting for an
* interrupt(WFI). We only pend the vIRQ for target SP
@@ -971,13 +1006,21 @@
*/
plat_interrupts_end_of_interrupt(id);
target_vcpu->secure_interrupt_deactivated = true;
+ /*
+ * Refer the embedded comment in vcpu.h file for description of
+ * this variable.
+ */
+ target_vcpu->implicit_completion_signal = true;
return;
case VCPU_STATE_BLOCKED_INTERRUPT:
/* WFI is no-op for SP. Fall through*/
default:
/*
- * vCPU of Target SP cannot be in RUNNING/OFF/ABORTED
- * state if it has to handle secure interrupt.
+ * vCPU of Target SP cannot be in OFF/ABORTED state if it has
+ * to handle secure interrupt.
+ * TODO: Refer Note 1. We do not support signaling virtual
+ * interrupt to a target vCPU that is in RUNNING state on
+ * another physical CPU.
*/
panic("Secure interrupt cannot be signaled to target "
"SP\n");
@@ -1016,14 +1059,19 @@
if (current == target_vcpu_locked.vcpu) {
/*
* A scenario where target vCPU is the current vCPU in secure
- * world.
+ * world. This is when a vCPU was preempted by a Self S-Int
+ * while it was in RUNNING state.
*/
dlog_verbose("Resume current vCPU\n");
*next = NULL;
/* We have already locked vCPU. */
current->state = VCPU_STATE_RUNNING;
-
+ /*
+ * Refer the embedded comment in vcpu.h file for description of
+ * this variable.
+ */
+ current->implicit_completion_signal = true;
/*
* In scenario where target vCPU is the current vCPU in
* secure world, there is no vCPU to resume when target