feat(psci): check that CPUs handled a pabandon
Up to now PSCI assumed that if a pabandon happened then the CPU driver
will have handled it. This patch adds a simple protocol to make sure
that this is indeed the case. The chosen method is with a return value
that is highly unlikely on cores that are unaware of pabandon (x0 will
be primed with 1 and if used should be overwritten with the value of
CPUPWRCTLR_EL1 which should have its last bit set to power off and its
top bits RES0; the ACK value is chosen to be the exact opposite). An
alternative method would have been to add a field in cpu_ops, however
that would have required more major refactoring across many cpus and
would have taken up more memory on older platforms, so it was not
chosen.
Change-Id: I5826c0e4802e104d295c4ecbd80b5f676d2cd871
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 04917ea..08e27ac 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -1196,7 +1196,7 @@
return (n_valid > 1U) ? 1 : 0;
}
-static void call_cpu_pwr_dwn(unsigned int power_level)
+static u_register_t call_cpu_pwr_dwn(unsigned int power_level)
{
struct cpu_ops *ops = get_cpu_data(cpu_ops_ptr);
@@ -1213,7 +1213,25 @@
static void prepare_cpu_pwr_dwn(unsigned int power_level)
{
- call_cpu_pwr_dwn(power_level);
+ /* ignore the return, all cpus should behave the same */
+ (void)call_cpu_pwr_dwn(power_level);
+}
+
+static void prepare_cpu_pwr_up(unsigned int power_level)
+{
+ /*
+ * Call the pwr_dwn cpu hook again, indicating that an abandon happened.
+ * The cpu driver is expected to clean up. We ask it to return
+ * PABANDON_ACK to indicate that it has handled this. This is a
+ * heuristic: the value has been chosen such that an unported CPU is
+ * extremely unlikely to return this value.
+ */
+ u_register_t ret = call_cpu_pwr_dwn(power_level);
+
+ /* unreachable on AArch32 so cast down to calm the compiler */
+ if (ret != (u_register_t) PABANDON_ACK) {
+ panic();
+ }
}
/*******************************************************************************
@@ -1321,10 +1339,9 @@
/*
* Begin unwinding. Everything can be shared with CPU_ON and co later,
* except the CPU specific bit. Cores that have hardware-assisted
- * coherency don't have much to do so just calling the hook again is
- * the simplest way to achieve this
+ * coherency should be able to handle this.
*/
- prepare_cpu_pwr_dwn(power_level);
+ prepare_cpu_pwr_up(power_level);
}
/*******************************************************************************