fix(ff-a): harden ffa_secondary_ep_register abi
Add more verbose comments with references to the specification for the
FFA_SECONDARY_EP_REGISTER ABI implementation.
Add FFA_FEATURES response to FFA_SECONDARY_EP_REGISTER ABI
for the SPMC case.
Add check whether ABI is called in context of Hypervisor or SPMC.
Reject the call in the former case.
Reject the FFA_SECONDARY_EP_REGISTER call for UP partitions.
Reject the FFA_SECONDARY_EP_REGISTER call after partition has
initialized.
Change-Id: I3ce723fc6cdde6f27709b664abfe2c7929e9d9b2
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/inc/hf/arch/plat/ffa.h b/inc/hf/arch/plat/ffa.h
index f4f916a..fb830e4 100644
--- a/inc/hf/arch/plat/ffa.h
+++ b/inc/hf/arch/plat/ffa.h
@@ -250,3 +250,9 @@
size_t fdt_allocated_size,
const struct manifest_vm *manifest_vm,
struct mpool *ppool);
+
+/**
+ * Returns true if the FFA_SECONDARY_EP_REGISTER interface is supported at
+ * the virtual FF-A instance.
+ */
+bool plat_ffa_is_secondary_ep_register_supported(void);
diff --git a/src/api.c b/src/api.c
index c80b701..9cd7971 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2812,16 +2812,50 @@
return ret;
}
+/**
+ * Register an entry point for a vCPU in warm boot cases.
+ * DEN0077A FF-A v1.1 Beta0 section 18.3.2.1 FFA_SECONDARY_EP_REGISTER.
+ */
struct ffa_value api_ffa_secondary_ep_register(ipaddr_t entry_point,
struct vcpu *current)
{
struct vm_locked vm_locked;
+ struct ffa_value ret = ffa_error(FFA_DENIED);
+ /*
+ * Reject if interface is not supported at this FF-A instance
+ * (DEN0077A FF-A v1.1 Beta0 Table 18.29) or the VM is UP.
+ */
+ if (!plat_ffa_is_secondary_ep_register_supported() ||
+ current->vm->vcpu_count == 1) {
+ return ffa_error(FFA_NOT_SUPPORTED);
+ }
+
+ /*
+ * No further check is made on the address validity
+ * (FF-A v1.1 Beta0 Table 18.29) as the VM boundaries are not known
+ * from the VM or vCPU structure.
+ * DEN0077A FF-A v1.1 Beta0 section 18.3.2.1.1:
+ * For each SP [...] the Framework assumes that the same entry point
+ * address is used for initializing any execution context during a
+ * secondary cold boot.
+ * If this function is invoked multiple times, then the entry point
+ * address specified in the last valid invocation must be used by the
+ * callee.
+ */
vm_locked = vm_lock(current->vm);
+ if (vm_locked.vm->initialized) {
+ goto out;
+ }
+
vm_locked.vm->secondary_ep = entry_point;
+
+ ret = (struct ffa_value){.func = FFA_SUCCESS_32};
+
+out:
vm_unlock(&vm_locked);
- return (struct ffa_value){.func = FFA_SUCCESS_32};
+ return ret;
}
struct ffa_value api_ffa_notification_bitmap_create(ffa_vm_id_t vm_id,
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 94a0c5b..5eac56d 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -650,6 +650,12 @@
current, next);
return true;
case FFA_SECONDARY_EP_REGISTER_64:
+ /*
+ * DEN0077A FF-A v1.1 Beta0 section 18.3.2.1.1
+ * The callee must return NOT_SUPPORTED if this function is
+ * invoked by a caller that implements version v1.0 of
+ * the Framework.
+ */
*args = api_ffa_secondary_ep_register(ipa_init(args->arg1),
current);
return true;
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 6cd28f2..f8dccfd 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -717,3 +717,12 @@
CHECK(mm_unmap(stage1_locked, fdt_addr,
pa_add(fdt_addr, fdt_allocated_size), ppool) == true);
}
+
+/**
+ * Returns FFA_ERROR as FFA_SECONDARY_EP_REGISTER is not supported at the
+ * non-secure FF-A instances.
+ */
+bool plat_ffa_is_secondary_ep_register_supported(void)
+{
+ return false;
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 2ffaa25..891ec0e 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -113,6 +113,9 @@
switch (function_feature_id) {
#if (MAKE_FFA_VERSION(1, 1) <= FFA_VERSION_COMPILED)
+ case FFA_SECONDARY_EP_REGISTER_64:
+ ret = (struct ffa_value){.func = FFA_SUCCESS_32};
+ break;
case FFA_FEATURE_MEI:
ret = api_ffa_feature_success(HF_MANAGED_EXIT_INTID);
break;
@@ -1317,3 +1320,12 @@
/* should never be called in SPMC */
CHECK(false);
}
+
+/**
+ * Returns FFA_SUCCESS as FFA_SECONDARY_EP_REGISTER is supported at the
+ * secure virtual FF-A instance.
+ */
+bool plat_ffa_is_secondary_ep_register_supported(void)
+{
+ return true;
+}
diff --git a/src/arch/aarch64/plat/psci/spmc.c b/src/arch/aarch64/plat/psci/spmc.c
index b92e48f..8395ab0 100644
--- a/src/arch/aarch64/plat/psci/spmc.c
+++ b/src/arch/aarch64/plat/psci/spmc.c
@@ -30,7 +30,11 @@
{
struct ffa_value res;
- /* Register SPMC secondary cold boot entry point */
+ /*
+ * DEN0077A FF-A v1.1 Beta0 section 18.3.2.1.1
+ * Register the SPMC secondary cold boot entry point at the secure
+ * physical FF-A instance (to the SPMD).
+ */
res = smc_ffa_call(
(struct ffa_value){.func = FFA_SECONDARY_EP_REGISTER_64,
.arg1 = (uintreg_t)&cpu_entry});
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 916aea8..9300963 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -328,3 +328,8 @@
(void)partitions;
(void)ret_count;
}
+
+bool plat_ffa_is_secondary_ep_register_supported(void)
+{
+ return false;
+}