Init and save / restore of PMCR_EL0 / PMCR
Currently TF does not initialise the PMCR_EL0 register in
the secure context or save/restore the register.
In particular, the DP field may not be set to one to prohibit
cycle counting in the secure state, even though event counting
generally is prohibited via the default setting of MDCR_EL3.SMPE
to 0.
This patch initialises PMCR_EL0.DP to one in the secure state
to prohibit cycle counting and also initialises other fields
that have an architectually UNKNOWN reset value.
Additionally, PMCR_EL0 is added to the list of registers that are
saved and restored during a world switch.
Similar changes are made for PMCR for the AArch32 execution state.
NOTE: secure world code at lower ELs that assume other values in PMCR_EL0
will be impacted.
Change-Id: Iae40e8c0a196d74053accf97063ebc257b4d2f3a
Signed-off-by: David Cunado <david.cunado@arm.com>
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 3d26056..21e86de 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -58,7 +58,7 @@
static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t *ep)
{
unsigned int security_state;
- uint32_t scr_el3;
+ uint32_t scr_el3, pmcr_el0;
el3_state_t *state;
gp_regs_t *gp_regs;
unsigned long sctlr_elx;
@@ -164,11 +164,35 @@
/*
* Store the initialised SCTLR_EL1 value in the cpu_context - SCTLR_EL2
- * and other EL2 resgisters are set up by cm_preapre_ns_entry() as they
+ * and other EL2 registers are set up by cm_preapre_ns_entry() as they
* are not part of the stored cpu_context.
*/
write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx);
+ if (security_state == SECURE) {
+ /*
+ * Initialise PMCR_EL0 for secure context only, setting all
+ * fields rather than relying on hw. Some fields are
+ * architecturally UNKNOWN on reset.
+ *
+ * PMCR_EL0.LC: Set to one so that cycle counter overflow, that
+ * is recorded in PMOVSCLR_EL0[31], occurs on the increment
+ * that changes PMCCNTR_EL0[63] from 1 to 0.
+ *
+ * PMCR_EL0.DP: Set to one so that the cycle counter,
+ * PMCCNTR_EL0 does not count when event counting is prohibited.
+ *
+ * PMCR_EL0.X: Set to zero to disable export of events.
+ *
+ * PMCR_EL0.D: Set to zero so that, when enabled, PMCCNTR_EL0
+ * counts on every clock cycle.
+ */
+ pmcr_el0 = ((PMCR_EL0_RESET_VAL | PMCR_EL0_LC_BIT
+ | PMCR_EL0_DP_BIT)
+ & ~(PMCR_EL0_X_BIT | PMCR_EL0_D_BIT));
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_PMCR_EL0, pmcr_el0);
+ }
+
/* Populate EL3 state so that we've the right context before doing ERET */
state = get_el3state_ctx(ctx);
write_ctx_reg(state, CTX_SCR_EL3, scr_el3);