Implement minimal PSCI for secondary VMs to manage their vCPUs.
Bug: 132422393
Change-Id: I44643ec9eec722dfe0332b7ffefadcdd8dd98985
diff --git a/src/cpu.c b/src/cpu.c
index e35b1ec..affba4a 100644
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -209,27 +209,62 @@
}
/**
- * Starts a vCPU of a secondary VM.
+ * Check whether the given vcpu_state is an off state, for the purpose of
+ * turning vCPUs on and off. Note that aborted still counts as on in this
+ * context.
*/
-void vcpu_secondary_reset_and_start(struct vcpu *vcpu, ipaddr_t entry,
+bool vcpu_is_off(struct vcpu_locked vcpu)
+{
+ switch (vcpu.vcpu->state) {
+ case VCPU_STATE_OFF:
+ return true;
+ case VCPU_STATE_READY:
+ case VCPU_STATE_RUNNING:
+ case VCPU_STATE_BLOCKED_MAILBOX:
+ case VCPU_STATE_BLOCKED_INTERRUPT:
+ case VCPU_STATE_ABORTED:
+ /*
+ * Aborted still counts as ON for the purposes of PSCI,
+ * because according to the PSCI specification (section
+ * 5.7.1) a core is only considered to be off if it has
+ * been turned off with a CPU_OFF call or hasn't yet
+ * been turned on with a CPU_ON call.
+ */
+ return false;
+ }
+}
+
+/**
+ * Starts a vCPU of a secondary VM.
+ *
+ * Returns true if the secondary was reset and started, or false if it was
+ * already on and so nothing was done.
+ */
+bool vcpu_secondary_reset_and_start(struct vcpu *vcpu, ipaddr_t entry,
uintreg_t arg)
{
struct vcpu_locked vcpu_locked;
struct vm *vm = vcpu->vm;
+ bool vcpu_was_off;
assert(vm->id != HF_PRIMARY_VM_ID);
vcpu_locked = vcpu_lock(vcpu);
- /*
- * Set vCPU registers to a clean state ready for boot. As this is a
- * secondary which can migrate between pCPUs, the ID of the vCPU is
- * defined as the index and does not match the ID of the pCPU it is
- * running on.
- */
- arch_regs_reset(&vcpu->regs, false, vm->id, vcpu_index(vcpu),
- vm->ptable.root);
- vcpu_on(vcpu_locked, entry, arg);
+ vcpu_was_off = vcpu_is_off(vcpu_locked);
+ if (vcpu_was_off) {
+ /*
+ * Set vCPU registers to a clean state ready for boot. As this
+ * is a secondary which can migrate between pCPUs, the ID of the
+ * vCPU is defined as the index and does not match the ID of the
+ * pCPU it is running on.
+ */
+ arch_regs_reset(&vcpu->regs, false, vm->id, vcpu_index(vcpu),
+ vm->ptable.root);
+ vcpu_on(vcpu_locked, entry, arg);
+ }
vcpu_unlock(&vcpu_locked);
+
+ return vcpu_was_off;
}
/**