feat(psci): remove cpu context init by index
Currently, the calling core (meaning the core which received the call to
CPU_ON or the powerdown path of CPU_SUSPEND on the same core) is in
charge of initialising the context for the waking core (the warmboot
entrypoint for both). This is convenient because the calling core can
write the context while in coherency and the waking core will only need
the context after its entered coherency. This avoids any cache
maintenance and makes communication simple.
However, this has 3 main problems:
a) asymmetric feature support is problematic - the calling core has no
way of knowing the feature set of the waking core. If the two
diverge, the architectural feature discovery via ID registers breaks
down. We've thus far "fixed" this on a case by case basis which
doesn't scale and introduces redundancy.
b) powerdown abandon (pabandon) introduces a contradiction - the calling
core has to initialise the context for when the core wakes up, but
should the core not powerdown it needs its old context intact. The only
way to work around this is by keeping two copies of context which
incurs a runtime and memory overhead.
c) cm_prepare_el3_exit[_ns]() doesn't have access to the entrypoint but needs
it to make initialisation decisions. We can infer some of this from
registers that have already been written but this is awkwardly
limiting for what we can do. This also necessitates the split from
the context initialisation.
We can solve all three by a making a core be in full ownership of its
own context. The calling core then only writes entrypoint information
and nothing else. The waking core then initialises its own context as it
sees fit with full knowledge of the whole picture.
The only tricky bit is cache coherency - the waking core has to be able
to coherently observe its new entrypoint. Calling cores will write to
the shared region with coherent caches on. If we make sure to read the
context only after the waking core has entered coherency, then we can
avoid cache operations and let hardware handle everything.
We can skip the spsr check for FEAT_TCR2 as it doesn't make a
difference. We can also skip enabling it twice from generic code.
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
Change-Id: I86e7fe8b698191fc3b469e5ced1fd010f8754b0e
diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c
index f690e49..39d4482 100644
--- a/lib/psci/psci_suspend.c
+++ b/lib/psci/psci_suspend.c
@@ -45,7 +45,6 @@
static void psci_suspend_to_pwrdown_start(unsigned int idx,
unsigned int end_pwrlvl,
unsigned int max_off_lvl,
- const entry_point_info_t *ep,
const psci_power_state_t *state_info)
{
PUBLISH_EVENT_ARG(psci_suspend_pwrdown_start, &idx);
@@ -85,12 +84,6 @@
if (psci_plat_pm_ops->pwr_domain_suspend_pwrdown_early != NULL)
psci_plat_pm_ops->pwr_domain_suspend_pwrdown_early(state_info);
#endif
-
- /*
- * Store the re-entry information for the non-secure world.
- */
- cm_init_my_context(ep);
-
/*
* Arch. management. Initiate power down sequence.
*/
@@ -116,7 +109,6 @@
* not possible to undo any of the actions taken beyond that point.
******************************************************************************/
int psci_cpu_suspend_start(unsigned int idx,
- const entry_point_info_t *ep,
unsigned int end_pwrlvl,
psci_power_state_t *state_info,
unsigned int is_power_down_state)
@@ -124,10 +116,6 @@
int rc = PSCI_E_SUCCESS;
unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
unsigned int max_off_lvl = 0;
-#if FEAT_PABANDON
- cpu_context_t *ctx = cm_get_context(NON_SECURE);
- cpu_context_t old_ctx;
-#endif
/*
* This function must only be called on platforms where the
@@ -205,26 +193,9 @@
#if !CTX_INCLUDE_EL2_REGS
cm_el1_sysregs_context_save(NON_SECURE);
#endif
- /*
- * when the core wakes it expects its context to already be in
- * place so we must overwrite it before powerdown. But if
- * powerdown never happens we want the old context. Save it in
- * case we wake up. EL2/El1 will not be touched by PSCI so don't
- * copy */
- memcpy(&ctx->gpregs_ctx, &old_ctx.gpregs_ctx, sizeof(gp_regs_t));
- memcpy(&ctx->el3state_ctx, &old_ctx.el3state_ctx, sizeof(el3_state_t));
-#if DYNAMIC_WORKAROUND_CVE_2018_3639
- memcpy(&ctx->cve_2018_3639_ctx, &old_ctx.cve_2018_3639_ctx, sizeof(cve_2018_3639_t));
-#endif
-#if ERRATA_SPECULATIVE_AT
- memcpy(&ctx->errata_speculative_at_ctx, &old_ctx.errata_speculative_at_ctx, sizeof(errata_speculative_at_t));
-#endif
-#if CTX_INCLUDE_PAUTH_REGS
- memcpy(&ctx->pauth_ctx, &old_ctx.pauth_ctx, sizeof(pauth_t));
-#endif
#endif
max_off_lvl = psci_find_max_off_lvl(state_info);
- psci_suspend_to_pwrdown_start(idx, end_pwrlvl, end_pwrlvl, ep, state_info);
+ psci_suspend_to_pwrdown_start(idx, end_pwrlvl, end_pwrlvl, state_info);
}
/*
@@ -301,18 +272,6 @@
#if FEAT_PABANDON
psci_cpu_suspend_to_powerdown_finish(idx, max_off_lvl, state_info);
- /* we overwrote context ourselves, put it back */
- memcpy(&ctx->gpregs_ctx, &old_ctx.gpregs_ctx, sizeof(gp_regs_t));
- memcpy(&ctx->el3state_ctx, &old_ctx.el3state_ctx, sizeof(el3_state_t));
-#if DYNAMIC_WORKAROUND_CVE_2018_3639
- memcpy(&ctx->cve_2018_3639_ctx, &old_ctx.cve_2018_3639_ctx, sizeof(cve_2018_3639_t));
-#endif
-#if ERRATA_SPECULATIVE_AT
- memcpy(&ctx->errata_speculative_at_ctx, &old_ctx.errata_speculative_at_ctx, sizeof(errata_speculative_at_t));
-#endif
-#if CTX_INCLUDE_PAUTH_REGS
- memcpy(&ctx->pauth_ctx, &old_ctx.pauth_ctx, sizeof(pauth_t));
-#endif
#if !CTX_INCLUDE_EL2_REGS
cm_el1_sysregs_context_restore(NON_SECURE);
#endif