refactor(interrupts): changes based on updated guidance
In anticipation of updated guidance for interrupt management based
on FF-A v1.1 EAC0 specification, changes are made to add helper
utilities to distinguish handling secure interrupt triggered while
executing in normal world vs secure world.
Moreover, a legacy design constraint has been removed. SPMC now
changes the state of the target SP to RUNNING upon resuming it
for handling a secure virtual interrupt.
Change-Id: I4de5ec8c92e55238be9f43a8ea99bda39b0f9c8d
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/inc/hf/arch/plat/ffa.h b/inc/hf/arch/plat/ffa.h
index dce8f6c..d176afd 100644
--- a/inc/hf/arch/plat/ffa.h
+++ b/inc/hf/arch/plat/ffa.h
@@ -261,9 +261,9 @@
int64_t plat_ffa_interrupt_deactivate(uint32_t pint_id, uint32_t vint_id,
struct vcpu *current);
-void plat_ffa_secure_interrupt(struct vcpu *current, struct vcpu **next);
-struct ffa_value plat_ffa_delegate_ffa_interrupt(struct vcpu *current,
- struct vcpu **next);
+struct ffa_value plat_ffa_handle_secure_interrupt(struct vcpu *current,
+ struct vcpu **next,
+ bool from_normal_world);
struct ffa_value plat_ffa_normal_world_resume(struct vcpu *current,
struct vcpu **next);
struct ffa_value plat_ffa_preempted_vcpu_resume(struct vcpu *current,
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 0d46b66..68a1777 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -635,7 +635,7 @@
*args = api_ffa_notification_info_get(current);
return true;
case FFA_INTERRUPT_32:
- *args = plat_ffa_delegate_ffa_interrupt(current, next);
+ *args = plat_ffa_handle_secure_interrupt(current, next, true);
return true;
case FFA_CONSOLE_LOG_32:
case FFA_CONSOLE_LOG_64:
@@ -985,7 +985,7 @@
#if SECURE_WORLD == 1
struct vcpu *next = NULL;
- plat_ffa_secure_interrupt(current(), &next);
+ plat_ffa_handle_secure_interrupt(current(), &next, false);
/*
* Since we are in interrupt context, set the bit for the
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index ed19602..8b6a9a7 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -376,11 +376,13 @@
return true;
}
-struct ffa_value plat_ffa_delegate_ffa_interrupt(struct vcpu *current,
- struct vcpu **next)
+struct ffa_value plat_ffa_handle_secure_interrupt(struct vcpu *current,
+ struct vcpu **next,
+ bool from_normal_world)
{
(void)current;
(void)next;
+ (void)from_normal_world;
/*
* SPMD uses FFA_INTERRUPT ABI to convey secure interrupt to SPMC.
* Execution not expected to reach here.
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 7f0666b..5cf2d6a 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -774,11 +774,13 @@
return true;
}
-struct ffa_value plat_ffa_delegate_ffa_interrupt(struct vcpu *current,
- struct vcpu **next)
+struct ffa_value plat_ffa_handle_secure_interrupt(struct vcpu *current,
+ struct vcpu **next,
+ bool from_normal_world)
{
(void)current;
(void)next;
+ (void)from_normal_world;
/*
* SPMD uses FFA_INTERRUPT ABI to convey secure interrupt to
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 4efeb9a..fea68f8 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -866,7 +866,7 @@
goto out;
}
- if ((current->vm->id & HF_VM_ID_WORLD_MASK) != 0) {
+ if (vm_id_is_current_world(current->vm->id)) {
/*
* Refer FF-A v1.1 Beta0 section 8.3.
* SPMC treats the first invocation of FFA_RUN as interrupt
@@ -875,13 +875,6 @@
* to resume the vCPU of preempted SP through this FFA_RUN.
*/
if (current->processing_secure_interrupt) {
- /*
- * Refer FF-A v1.1 Beta0 section 8.3 Rule 2. FFA_RUN
- * ABI is used for secure interrupt signal completion by
- * SP if it was in BLOCKED state.
- */
- CHECK(current->state == VCPU_STATE_BLOCKED);
-
CHECK(target_vcpu == current->preempted_vcpu);
/*
* This flag should not have been set by SPMC when it
@@ -1043,23 +1036,7 @@
}
/**
- * TODO: As of now, we did not implement support for checking legal state
- * transitions defined under the partition runtime models defined in the
- * FF-A v1.1-Beta0 spec.
- * Moreover, support for scheduling models has not been implemented. However,
- * the current implementation loosely maps to the following valid actions for
- * a S-EL1 Partition as described in Table 8.14 of FF-A v1.1 Beta0 spec with
- * the exception that Other S-Int are unconditionally queued during secure
- * interrupt handling.
- * Refer Table 8.5 for detailed description of actions.
-
- Runtime Model NS-Int Self S-Int Other S-Int
- --------------------------------------------------------------------------
- Message Processing Signalable with ME Signalable Signalable
- Interrupt Handling Queued Queued Queued
- --------------------------------------------------------------------------
-
- * Note 1: TODO: The current design makes the assumption that the target vCPU
+ * TODO: The current design makes the assumption that the target vCPU
* of a secure interrupt is pinned to the same physical CPU on which the
* secure interrupt triggered. The target vCPU has to be resumed on the current
* CPU in order for it to service the virtual interrupt. This design limitation
@@ -1120,8 +1097,12 @@
return target_vcpu_locked;
}
-static void plat_ffa_signal_secure_interrupt(
- struct vcpu_locked target_vcpu_locked, uint32_t id, struct vcpu **next)
+/**
+ * Helper for secure interrupt signaling for a S-EL1 SP.
+ */
+static void plat_ffa_signal_secure_interrupt_sel1(
+ struct vcpu *current, struct vcpu_locked target_vcpu_locked,
+ uint32_t id, struct vcpu **next, bool from_normal_world)
{
struct vcpu *target_vcpu = target_vcpu_locked.vcpu;
struct ffa_value args = {
@@ -1133,33 +1114,48 @@
* vCPU cannot be resumed, SPMC resumes current vCPU.
*/
*next = target_vcpu;
+ (void)current;
+ /* Secure interrupt signaling and queuing for S-EL1 SP. */
switch (target_vcpu->state) {
case VCPU_STATE_WAITING:
- /* FF-A v1.1 Beta0 section 7.4 bullet 1 and Table 8.2 case 1. */
+ /* FF-A v1.1 EAC0 Table 8.2 case 1. */
args.arg1 = id;
break;
case VCPU_STATE_BLOCKED:
+ if (from_normal_world) {
+ /*
+ * TODO: Current design has the following limitation.
+ * All endpoints with multiple execution contexts have
+ * their contexts pinned to corresponding PEs.
+ * Assuming no UP migratable execution contexts, under
+ * the current design, the target vCPU cannot be in
+ * BLOCKED state.
+ */
+ panic("Target vCPU cannot be in blocked state\n");
+ }
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
- * and continue to resume current vCPU.
+ * pre-empted by an interrupt. Make the vIRQ pending for target
+ * SP(i.e., queue the interrupt) and continue to resume current
+ * vCPU. Refer to section 8.3.2.1 bullet 3 in the FF-A v1.1
+ * EAC0 spec.
+ *
+ * The scenario in which vCPU of target SP is in
+ * PREEMPTED state due to a Self S-Int has been handled
+ * separately in the function
+ * plat_ffa_handle_secure_interrupt_secure_world().
*/
*next = NULL;
-
/*
* De-activate the interrupt. If not, it could trigger again
* after resuming current vCPU.
*/
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.
@@ -1167,33 +1163,26 @@
target_vcpu->implicit_completion_signal = true;
return;
case VCPU_STATE_BLOCKED_INTERRUPT:
- /* WFI is no-op for SP. Fall through*/
+ /* WFI is no-op for SP. Fall through. */
default:
/*
* 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.
+ * TODO: 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");
+ panic("Secure interrupt cannot be signaled to target SP\n");
break;
}
- CHECK((*next)->regs_available);
- arch_regs_set_retval(&((*next)->regs), args);
-
- /*
- * Strictly speaking, we are about to resume target vCPU which means it
- * should move to RUNNING state. But, we do not modify the state as per
- * rules defined in section 7.4 of FF-A v1.1 Beta0 spec. This is because
- * we associate the state of vCPU with the mechanism used for interrupt
- * completion.
- */
+ CHECK(target_vcpu->regs_available);
+ arch_regs_set_retval(&target_vcpu->regs, args);
/* Mark the registers as unavailable now. */
- (*next)->regs_available = false;
+ target_vcpu->regs_available = false;
+
+ /* We are about to resume target vCPU. */
+ target_vcpu->state = VCPU_STATE_RUNNING;
}
/**
@@ -1201,22 +1190,23 @@
* controller and inject the corresponding virtual interrupt to the target vCPU
* for handling.
*/
-void plat_ffa_secure_interrupt(struct vcpu *current, struct vcpu **next)
+static struct ffa_value plat_ffa_handle_secure_interrupt_secure_world(
+ struct vcpu *current, struct vcpu **next)
{
struct vcpu_locked target_vcpu_locked;
+ struct ffa_value ffa_ret = ffa_error(FFA_NOT_SUPPORTED);
uint32_t id;
- /* Secure interrupt triggered while execution is in SWD. */
+ /* Secure interrupt triggered while execution is in SWd. */
CHECK((current->vm->id & HF_VM_ID_WORLD_MASK) != 0);
target_vcpu_locked = plat_ffa_secure_interrupt_prepare(current, &id);
if (current == target_vcpu_locked.vcpu) {
/*
* A scenario where target vCPU is the current vCPU in secure
- * world. This is when a vCPU was preempted by a Self S-Int
+ * world. This is when a vCPU gets 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. */
@@ -1233,7 +1223,8 @@
*/
target_vcpu_locked.vcpu->preempted_vcpu = NULL;
} else {
- plat_ffa_signal_secure_interrupt(target_vcpu_locked, id, next);
+ plat_ffa_signal_secure_interrupt_sel1(
+ current, target_vcpu_locked, id, next, false);
/*
* In the scenario where target SP cannot be resumed for
* processing interrupt, resume the current vCPU.
@@ -1248,6 +1239,8 @@
target_vcpu_locked.vcpu->processing_secure_interrupt = true;
target_vcpu_locked.vcpu->current_sec_interrupt_id = id;
vcpu_unlock(&target_vcpu_locked);
+
+ return ffa_ret;
}
/**
@@ -1255,8 +1248,8 @@
* the interrupt to SPMC through FFA_INTERRUPT_32 ABI synchronously using eret
* conduit.
*/
-struct ffa_value plat_ffa_delegate_ffa_interrupt(struct vcpu *current,
- struct vcpu **next)
+static struct ffa_value plat_ffa_handle_secure_interrupt_from_normal_world(
+ struct vcpu *current, struct vcpu **next)
{
struct ffa_value ffa_ret = ffa_error(FFA_NOT_SUPPORTED);
uint32_t id;
@@ -1271,7 +1264,8 @@
}
target_vcpu_locked = plat_ffa_secure_interrupt_prepare(current, &id);
- plat_ffa_signal_secure_interrupt(target_vcpu_locked, id, next);
+ plat_ffa_signal_secure_interrupt_sel1(current, target_vcpu_locked, id,
+ next, true);
/*
* current refers to other world. target must be a vCPU in the secure
@@ -1297,6 +1291,17 @@
return ffa_ret;
}
+struct ffa_value plat_ffa_handle_secure_interrupt(struct vcpu *current,
+ struct vcpu **next,
+ bool from_normal_world)
+{
+ if (from_normal_world) {
+ return plat_ffa_handle_secure_interrupt_from_normal_world(
+ current, next);
+ }
+ return plat_ffa_handle_secure_interrupt_secure_world(current, next);
+}
+
/**
* Switches the physical CPU back to the corresponding vCPU of the normal world.
*
@@ -1324,6 +1329,7 @@
/* Clear fields corresponding to secure interrupt handling. */
current->preempted_vcpu = NULL;
current->current_sec_interrupt_id = 0;
+ current->state = VCPU_STATE_WAITING;
vcpu_unlock(¤t_locked);
/* Restore interrupt priority mask. */
@@ -1370,6 +1376,7 @@
/* Clear fields corresponding to secure interrupt handling. */
current->preempted_vcpu = NULL;
current->current_sec_interrupt_id = 0;
+ current->state = VCPU_STATE_WAITING;
target_vcpu->state = VCPU_STATE_RUNNING;
@@ -1596,8 +1603,6 @@
/* Refer FF-A v1.1 Beta0 section 7.4 bullet 2. */
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