FF-A: secondary EC cold boot
When the SPMC boots, all Secure Partitions are initialized
on their primary Execution Context. A Secure Partition calls
FFA_SECONDARY_EP_REGISTER at virtual FF-A instance from
its first EC passing the entry point address for secondary
ECs. A secondary EC is first resumed either upon invocation
of PSCI_CPU_ON from the NWd to which a SP is registered
(currently the first SP) or by ffa_run invocation.
Change-Id: Ic6050af16d4081ca31729744995fbb999b170e11
Signed-off-by: Max Shvetsov <maksims.svecovs@arm.com>
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/src/api.c b/src/api.c
index 75a06b7..fdb395f 100644
--- a/src/api.c
+++ b/src/api.c
@@ -545,6 +545,8 @@
static bool api_vcpu_prepare_run(const struct vcpu *current, struct vcpu *vcpu,
struct ffa_value *run_ret)
{
+ struct vcpu_locked vcpu_locked;
+ struct vm_locked vm_locked;
bool need_vm_lock;
bool ret;
@@ -556,14 +558,24 @@
* dependencies in the common run case meaning the sensitive context
* switch performance is consistent.
*/
- sl_lock(&vcpu->lock);
+ vcpu_locked = vcpu_lock(vcpu);
+
+#if SECURE_WORLD == 1
+
+ if (vcpu_secondary_reset_and_start(vcpu_locked, vcpu->vm->secondary_ep,
+ 0)) {
+ dlog_verbose("%s secondary cold boot vmid %#x vcpu id %#x\n",
+ __func__, vcpu->vm->id, current->cpu->id);
+ }
+
+#endif
/* The VM needs to be locked to deliver mailbox messages. */
need_vm_lock = vcpu->state == VCPU_STATE_BLOCKED_MAILBOX;
if (need_vm_lock) {
- sl_unlock(&vcpu->lock);
- sl_lock(&vcpu->vm->lock);
- sl_lock(&vcpu->lock);
+ vcpu_unlock(&vcpu_locked);
+ vm_locked = vm_lock(vcpu->vm);
+ vcpu_locked = vcpu_lock(vcpu);
}
/*
@@ -671,9 +683,9 @@
ret = true;
out:
- sl_unlock(&vcpu->lock);
+ vcpu_unlock(&vcpu_locked);
if (need_vm_lock) {
- sl_unlock(&vcpu->vm->lock);
+ vm_unlock(&vm_locked);
}
return ret;
@@ -2278,3 +2290,15 @@
return ret;
}
+
+struct ffa_value api_ffa_secondary_ep_register(ipaddr_t entry_point,
+ struct vcpu *current)
+{
+ struct vm_locked vm_locked;
+
+ vm_locked = vm_lock(current->vm);
+ vm_locked.vm->secondary_ep = entry_point;
+ vm_unlock(&vm_locked);
+
+ return (struct ffa_value){.func = FFA_SUCCESS_32};
+}
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 1552e17..f7851d9 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -470,6 +470,10 @@
ffa_msg_send_sender(*args),
ffa_msg_send_receiver(*args), *args, current, next);
return true;
+ case FFA_SECONDARY_EP_REGISTER_32:
+ *args = api_ffa_secondary_ep_register(ipa_init(args->arg1),
+ current);
+ return true;
}
return false;
diff --git a/src/arch/aarch64/hypervisor/psci_handler.c b/src/arch/aarch64/hypervisor/psci_handler.c
index 825ec9f..358c827 100644
--- a/src/arch/aarch64/hypervisor/psci_handler.c
+++ b/src/arch/aarch64/hypervisor/psci_handler.c
@@ -317,6 +317,8 @@
vcpu_id_to_index(target_cpu);
struct vm *vm = vcpu->vm;
struct vcpu *target_vcpu;
+ struct vcpu_locked vcpu_locked;
+ bool vcpu_was_off;
if (target_vcpu_index >= vm->vcpu_count) {
*ret = PSCI_ERROR_INVALID_PARAMETERS;
@@ -324,9 +326,12 @@
}
target_vcpu = vm_get_vcpu(vm, target_vcpu_index);
+ vcpu_locked = vcpu_lock(target_vcpu);
+ vcpu_was_off = vcpu_secondary_reset_and_start(
+ vcpu_locked, entry_point_address, context_id);
+ vcpu_unlock(&vcpu_locked);
- if (vcpu_secondary_reset_and_start(
- target_vcpu, entry_point_address, context_id)) {
+ if (vcpu_was_off) {
/*
* Tell the scheduler that it can start running the new
* vCPU now.
diff --git a/src/load.c b/src/load.c
index 7accc65..d31b67a 100644
--- a/src/load.c
+++ b/src/load.c
@@ -365,6 +365,7 @@
{
struct vm *vm;
struct vm_locked vm_locked;
+ struct vcpu_locked vcpu_locked;
struct vcpu *vcpu;
ipaddr_t secondary_entry;
bool ret;
@@ -561,8 +562,9 @@
vcpu = vm_get_vcpu(vm, 0);
+ vcpu_locked = vcpu_lock(vcpu);
if (has_fdt) {
- vcpu_secondary_reset_and_start(vcpu, secondary_entry,
+ vcpu_secondary_reset_and_start(vcpu_locked, secondary_entry,
pa_addr(fdt_addr));
} else {
/*
@@ -570,9 +572,12 @@
* passed in register x0, which is what
* vcpu_secondary_reset_and_start does in this case.
*/
- vcpu_secondary_reset_and_start(vcpu, secondary_entry, mem_size);
+ vcpu_secondary_reset_and_start(vcpu_locked, secondary_entry,
+ mem_size);
}
+ vcpu_unlock(&vcpu_locked);
+
ret = true;
out:
diff --git a/src/vcpu.c b/src/vcpu.c
index 7fd2e75..b3b3f5a 100644
--- a/src/vcpu.c
+++ b/src/vcpu.c
@@ -114,16 +114,14 @@
* 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)
+bool vcpu_secondary_reset_and_start(struct vcpu_locked vcpu_locked,
+ ipaddr_t entry, uintreg_t arg)
{
- struct vcpu_locked vcpu_locked;
- struct vm *vm = vcpu->vm;
+ struct vm *vm = vcpu_locked.vcpu->vm;
bool vcpu_was_off;
CHECK(vm->id != HF_PRIMARY_VM_ID);
- vcpu_locked = vcpu_lock(vcpu);
vcpu_was_off = vcpu_is_off(vcpu_locked);
if (vcpu_was_off) {
/*
@@ -132,10 +130,9 @@
* vCPU is defined as the index and does not match the ID of the
* pCPU it is running on.
*/
- arch_regs_reset(vcpu);
+ arch_regs_reset(vcpu_locked.vcpu);
vcpu_on(vcpu_locked, entry, arg);
}
- vcpu_unlock(&vcpu_locked);
return vcpu_was_off;
}
@@ -186,7 +183,7 @@
void vcpu_reset(struct vcpu *vcpu)
{
- arch_cpu_init(vcpu->cpu, ipa_init(0));
+ arch_cpu_init(vcpu->cpu, vcpu->vm->secondary_ep);
/* Reset the registers to give a clean start for vCPU. */
arch_regs_reset(vcpu);