feat: add support for newly added lifecycle states of a vCPU
Please refer to section 7 of the FF-A v1.3 ALP2 specification for
details of newly added lifecycle states. The changes in this patch
help partition manager to support the use case of managing lifecycle
of a secure partition from its creation to deletion.
Change-Id: I78d52b33e0eb3a7ea93dd65e85dbc37fcaa384a9
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/src/api.c b/src/api.c
index 806edd7..aff2efa 100644
--- a/src/api.c
+++ b/src/api.c
@@ -1262,7 +1262,8 @@
* until this has finished, so count this state as still running for the
* purposes of this check.
*/
- if (vcpu->state == VCPU_STATE_RUNNING || !vcpu->regs_available) {
+ if (vcpu->state == VCPU_STATE_RUNNING ||
+ vcpu->state == VCPU_STATE_STARTING || !vcpu->regs_available) {
/*
* vCPU is running on another pCPU.
*
@@ -1276,39 +1277,56 @@
}
if (atomic_load_explicit(&vcpu->vm->aborting, memory_order_relaxed)) {
- if (vcpu->state != VCPU_STATE_ABORTED) {
+ if (vcpu->state != VCPU_STATE_NULL &&
+ vcpu->state != VCPU_STATE_STOPPED &&
+ vcpu->state != VCPU_STATE_ABORTED) {
dlog_verbose("VM %#x was aborted, cannot run vCPU %u\n",
vcpu->vm->id, vcpu_index(vcpu));
vcpu->state = VCPU_STATE_ABORTED;
}
- *run_ret = ffa_error(FFA_ABORTED);
- ret = false;
- goto out;
}
switch (vcpu->state) {
+ case VCPU_STATE_ABORTED:
+ if (vcpu->vm->lifecycle_support) {
+ *run_ret = ffa_error(FFA_BUSY);
+ } else {
+ *run_ret = ffa_error(FFA_ABORTED);
+ }
+ ret = false;
+ goto out;
+ case VCPU_STATE_NULL:
+ *run_ret = ffa_error(FFA_INVALID_PARAMETERS);
+ ret = false;
+ goto out;
+ case VCPU_STATE_STOPPED:
+ case VCPU_STATE_STARTING:
+ *run_ret = ffa_error(FFA_BUSY);
+ [[fallthrough]];
case VCPU_STATE_RUNNING:
case VCPU_STATE_OFF:
- case VCPU_STATE_ABORTED:
+ ret = false;
+ goto out;
+
+ case VCPU_STATE_CREATED:
+ /*
+ * An initial FFA_RUN is necessary for vCPUs of secondary VMs
+ * to reach the message wait loop. Note that vCPU(s) of Secure
+ * Partitions don't need it.
+ */
+ if (ffa_is_vm_id(vcpu->vm->id)) {
+ assert(vcpu->rt_model == RTM_SP_INIT);
+ vcpu->rt_model = RTM_NONE;
+
+ vcpu_was_init_state = true;
+ vcpu->state = VCPU_STATE_STARTING;
+ break;
+ }
+ *run_ret = ffa_error(FFA_BUSY);
ret = false;
goto out;
case VCPU_STATE_WAITING:
- /*
- * An initial FFA_RUN is necessary for SP's secondary vCPUs to
- * reach the message wait loop.
- */
- if (vcpu->rt_model == RTM_SP_INIT) {
- /*
- * TODO: this should be removed, but omitting it makes
- * normal world arch gicv3 tests failing.
- */
- vcpu->rt_model = RTM_NONE;
-
- vcpu_was_init_state = true;
- break;
- }
-
assert(need_vm_lock == true);
if (!vm_locked.vm->el0_partition) {
ffa_interrupts_inject_notification_pending_interrupt(
@@ -1358,7 +1376,8 @@
goto out;
case VCPU_STATE_BLOCKED:
- /* A blocked vCPU is run unconditionally. Fall through. */
+ /* A blocked vCPU is run unconditionally. */
+ [[fallthrough]];
case VCPU_STATE_PREEMPTED:
/* Check NPI is to be injected here. */
if (need_vm_lock) {
@@ -2944,27 +2963,39 @@
if (atomic_load_explicit(&receiver_vcpu->vm->aborting,
memory_order_relaxed)) {
- if (receiver_vcpu->state != VCPU_STATE_ABORTED) {
+ if (receiver_vcpu->state != VCPU_STATE_NULL &&
+ receiver_vcpu->state != VCPU_STATE_ABORTED &&
+ receiver_vcpu->state != VCPU_STATE_STOPPED) {
dlog_verbose(
"Receiver VM %#x aborted, cannot run vCPU %u\n",
receiver_vcpu->vm->id,
vcpu_index(receiver_vcpu));
receiver_vcpu->state = VCPU_STATE_ABORTED;
}
-
- ret = ffa_error(FFA_ABORTED);
- goto out;
}
switch (receiver_vcpu->state) {
+ case VCPU_STATE_ABORTED:
+ if (receiver_vcpu->vm->lifecycle_support) {
+ ret = ffa_error(FFA_BUSY);
+ } else {
+ ret = ffa_error(FFA_ABORTED);
+ }
+ goto out;
case VCPU_STATE_OFF:
case VCPU_STATE_RUNNING:
- case VCPU_STATE_ABORTED:
+ case VCPU_STATE_STARTING:
+ case VCPU_STATE_CREATED:
case VCPU_STATE_BLOCKED_INTERRUPT:
case VCPU_STATE_BLOCKED:
case VCPU_STATE_PREEMPTED:
+ case VCPU_STATE_STOPPED:
+ case VCPU_STATE_STOPPING:
ret = ffa_error(FFA_BUSY);
goto out;
+ case VCPU_STATE_NULL:
+ ret = ffa_error(FFA_INVALID_PARAMETERS);
+ goto out;
case VCPU_STATE_WAITING:
/*
* We expect target vCPU to be in WAITING state after either