Fully initialise essential control registers
This patch updates the el3_arch_init_common macro so that it fully
initialises essential control registers rather then relying on hardware
to set the reset values.
The context management functions are also updated to fully initialise
the appropriate control registers when initialising the non-secure and
secure context structures and when preparing to leave EL3 for a lower
EL.
This gives better alignement with the ARM ARM which states that software
must initialise RES0 and RES1 fields with 0 / 1.
This patch also corrects the following typos:
"NASCR definitions" -> "NSACR definitions"
Change-Id: Ia8940b8351dc27bc09e2138b011e249655041cfc
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 0104c4e..11ff163 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -71,70 +71,58 @@
zeromem(ctx, sizeof(*ctx));
/*
- * Base the context SCR on the current value, adjust for entry point
- * specific requirements and set trap bits from the IMF
- * TODO: provide the base/global SCR bits using another mechanism?
+ * SCR_EL3 was initialised during reset sequence in macro
+ * el3_arch_init_common. This code modifies the SCR_EL3 fields that
+ * affect the next EL.
+ *
+ * The following fields are initially set to zero and then updated to
+ * the required value depending on the state of the SPSR_EL3 and the
+ * Security state and entrypoint attributes of the next EL.
*/
scr_el3 = read_scr();
scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT |
SCR_ST_BIT | SCR_HCE_BIT);
-
+ /*
+ * SCR_NS: Set the security state of the next EL.
+ */
if (security_state != SECURE)
scr_el3 |= SCR_NS_BIT;
-
+ /*
+ * SCR_EL3.RW: Set the execution state, AArch32 or AArch64, for next
+ * Exception level as specified by SPSR.
+ */
if (GET_RW(ep->spsr) == MODE_RW_64)
scr_el3 |= SCR_RW_BIT;
-
+ /*
+ * SCR_EL3.ST: Traps Secure EL1 accesses to the Counter-timer Physical
+ * Secure timer registers to EL3, from AArch64 state only, if specified
+ * by the entrypoint attributes.
+ */
if (EP_GET_ST(ep->h.attr))
scr_el3 |= SCR_ST_BIT;
#ifndef HANDLE_EA_EL3_FIRST
- /* Explicitly stop to trap aborts from lower exception levels. */
+ /*
+ * SCR_EL3.EA: Do not route External Abort and SError Interrupt External
+ * to EL3 when executing at a lower EL. When executing at EL3, External
+ * Aborts are taken to EL3.
+ */
scr_el3 &= ~SCR_EA_BIT;
#endif
#ifdef IMAGE_BL31
/*
- * IRQ/FIQ bits only need setting if interrupt routing
- * model has been set up for BL31.
+ * SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ rounting as
+ * indicated by the interrupt routing model for BL31.
*/
scr_el3 |= get_scr_el3_from_routing_model(security_state);
#endif
/*
- * Set up SCTLR_ELx for the target exception level:
- * EE bit is taken from the entrypoint attributes
- * M, C and I bits must be zero (as required by PSCI specification)
- *
- * The target exception level is based on the spsr mode requested.
- * If execution is requested to EL2 or hyp mode, HVC is enabled
- * via SCR_EL3.HCE.
- *
- * Always compute the SCTLR_EL1 value and save in the cpu_context
- * - the EL2 registers are set up by cm_preapre_ns_entry() as they
- * are not part of the stored cpu_context
- *
- * TODO: In debug builds the spsr should be validated and checked
- * against the CPU support, security state, endianess and pc
+ * SCR_EL3.HCE: Enable HVC instructions if next execution state is
+ * AArch64 and next EL is EL2, or if next execution state is AArch32 and
+ * next mode is Hyp.
*/
- sctlr_elx = EP_GET_EE(ep->h.attr) ? SCTLR_EE_BIT : 0;
- if (GET_RW(ep->spsr) == MODE_RW_64)
- sctlr_elx |= SCTLR_EL1_RES1;
- else {
- sctlr_elx |= SCTLR_AARCH32_EL1_RES1;
- /*
- * If lower non-secure EL is AArch32, enable the CP15BEN, nTWI
- * & nTWI bits. This aligns with SCTLR initialization on
- * systems with an AArch32 EL3, where these bits
- * architecturally reset to 1.
- */
- if (security_state != SECURE)
- sctlr_elx |= SCTLR_CP15BEN_BIT | SCTLR_NTWI_BIT
- | SCTLR_NTWE_BIT;
- }
-
- write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx);
-
if ((GET_RW(ep->spsr) == MODE_RW_64
&& GET_EL(ep->spsr) == MODE_EL2)
|| (GET_RW(ep->spsr) != MODE_RW_64
@@ -142,6 +130,45 @@
scr_el3 |= SCR_HCE_BIT;
}
+ /*
+ * Initialise SCTLR_EL1 to the reset value corresponding to the target
+ * execution state setting all fields rather than relying of the hw.
+ * Some fields have architecturally UNKNOWN reset values and these are
+ * set to zero.
+ *
+ * SCTLR.EE: Endianness is taken from the entrypoint attributes.
+ *
+ * SCTLR.M, SCTLR.C and SCTLR.I: These fields must be zero (as
+ * required by PSCI specification)
+ */
+ sctlr_elx = EP_GET_EE(ep->h.attr) ? SCTLR_EE_BIT : 0;
+ if (GET_RW(ep->spsr) == MODE_RW_64)
+ sctlr_elx |= SCTLR_EL1_RES1;
+ else {
+ /*
+ * If the target execution state is AArch32 then the following
+ * fields need to be set.
+ *
+ * SCTRL_EL1.nTWE: Set to one so that EL0 execution of WFE
+ * instructions are not trapped to EL1.
+ *
+ * SCTLR_EL1.nTWI: Set to one so that EL0 execution of WFI
+ * instructions are not trapped to EL1.
+ *
+ * SCTLR_EL1.CP15BEN: Set to one to enable EL0 execution of the
+ * CP15DMB, CP15DSB, and CP15ISB instructions.
+ */
+ sctlr_elx |= SCTLR_AARCH32_EL1_RES1 | SCTLR_CP15BEN_BIT
+ | SCTLR_NTWI_BIT | SCTLR_NTWE_BIT;
+ }
+
+ /*
+ * 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
+ * are not part of the stored cpu_context.
+ */
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx);
+
/* 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);
@@ -191,7 +218,7 @@
******************************************************************************/
void cm_prepare_el3_exit(uint32_t security_state)
{
- uint32_t sctlr_elx, scr_el3, cptr_el2;
+ uint32_t sctlr_elx, scr_el3;
cpu_context_t *ctx = cm_get_context(security_state);
assert(ctx);
@@ -206,57 +233,141 @@
sctlr_elx |= SCTLR_EL2_RES1;
write_sctlr_el2(sctlr_elx);
} else if (EL_IMPLEMENTED(2)) {
- /* EL2 present but unused, need to disable safely */
-
- /* HCR_EL2 = 0, except RW bit set to match SCR_EL3 */
+ /*
+ * EL2 present but unused, need to disable safely.
+ * SCTLR_EL2 can be ignored in this case.
+ *
+ * Initialise all fields in HCR_EL2, except HCR_EL2.RW,
+ * to zero so that Non-secure operations do not trap to
+ * EL2.
+ *
+ * HCR_EL2.RW: Set this field to match SCR_EL3.RW
+ */
write_hcr_el2((scr_el3 & SCR_RW_BIT) ? HCR_RW_BIT : 0);
- /* SCTLR_EL2 : can be ignored when bypassing */
+ /*
+ * Initialise CPTR_EL2 setting all fields rather than
+ * relying on the hw. All fields have architecturally
+ * UNKNOWN reset values.
+ *
+ * CPTR_EL2.TCPAC: Set to zero so that Non-secure EL1
+ * accesses to the CPACR_EL1 or CPACR from both
+ * Execution states do not trap to EL2.
+ *
+ * CPTR_EL2.TTA: Set to zero so that Non-secure System
+ * register accesses to the trace registers from both
+ * Execution states do not trap to EL2.
+ *
+ * CPTR_EL2.TFP: Set to zero so that Non-secure accesses
+ * to SIMD and floating-point functionality from both
+ * Execution states do not trap to EL2.
+ */
+ write_cptr_el2(CPTR_EL2_RESET_VAL &
+ ~(CPTR_EL2_TCPAC_BIT | CPTR_EL2_TTA_BIT
+ | CPTR_EL2_TFP_BIT));
- /* CPTR_EL2 : disable all traps TCPAC, TTA, TFP */
- cptr_el2 = read_cptr_el2();
- cptr_el2 &= ~(TCPAC_BIT | TTA_BIT | TFP_BIT);
- write_cptr_el2(cptr_el2);
+ /*
+ * Initiliase CNTHCTL_EL2. All fields are
+ * architecturally UNKNOWN on reset and are set to zero
+ * except for field(s) listed below.
+ *
+ * CNTHCTL_EL2.EL1PCEN: Set to one to disable traps to
+ * Hyp mode of Non-secure EL0 and EL1 accesses to the
+ * physical timer registers.
+ *
+ * CNTHCTL_EL2.EL1PCTEN: Set to one to disable traps to
+ * Hyp mode of Non-secure EL0 and EL1 accesses to the
+ * physical counter registers.
+ */
+ write_cnthctl_el2(CNTHCTL_RESET_VAL |
+ EL1PCEN_BIT | EL1PCTEN_BIT);
- /* Enable EL1 access to timer */
- write_cnthctl_el2(EL1PCEN_BIT | EL1PCTEN_BIT);
-
- /* Reset CNTVOFF_EL2 */
+ /*
+ * Initialise CNTVOFF_EL2 to zero as it resets to an
+ * architecturally UNKNOWN value.
+ */
write_cntvoff_el2(0);
- /* Set VPIDR, VMPIDR to match MIDR, MPIDR */
+ /*
+ * Set VPIDR_EL2 and VMPIDR_EL2 to match MIDR_EL1 and
+ * MPIDR_EL1 respectively.
+ */
write_vpidr_el2(read_midr_el1());
write_vmpidr_el2(read_mpidr_el1());
/*
- * Reset VTTBR_EL2.
- * Needed because cache maintenance operations depend on
- * the VMID even when non-secure EL1&0 stage 2 address
- * translation are disabled.
+ * Initialise VTTBR_EL2. All fields are architecturally
+ * UNKNOWN on reset.
+ *
+ * VTTBR_EL2.VMID: Set to zero. Even though EL1&0 stage
+ * 2 address translation is disabled, cache maintenance
+ * operations depend on the VMID.
+ *
+ * VTTBR_EL2.BADDR: Set to zero as EL1&0 stage 2 address
+ * translation is disabled.
*/
- write_vttbr_el2(0);
+ write_vttbr_el2(VTTBR_RESET_VAL &
+ ~((VTTBR_VMID_MASK << VTTBR_VMID_SHIFT)
+ | (VTTBR_BADDR_MASK << VTTBR_BADDR_SHIFT)));
+
/*
- * Avoid unexpected debug traps in case where MDCR_EL2
- * is not completely reset by the hardware - set
- * MDCR_EL2.HPMN to PMCR_EL0.N and zero the remaining
- * bits.
- * MDCR_EL2.HPMN and PMCR_EL0.N fields are the same size
- * (5 bits) and HPMN is at offset zero within MDCR_EL2.
+ * Initialise MDCR_EL2, setting all fields rather than
+ * relying on hw. Some fields are architecturally
+ * UNKNOWN on reset.
+ *
+ * MDCR_EL2.TDRA: Set to zero so that Non-secure EL0 and
+ * EL1 System register accesses to the Debug ROM
+ * registers are not trapped to EL2.
+ *
+ * MDCR_EL2.TDOSA: Set to zero so that Non-secure EL1
+ * System register accesses to the powerdown debug
+ * registers are not trapped to EL2.
+ *
+ * MDCR_EL2.TDA: Set to zero so that System register
+ * accesses to the debug registers do not trap to EL2.
+ *
+ * MDCR_EL2.TDE: Set to zero so that debug exceptions
+ * are not routed to EL2.
+ *
+ * MDCR_EL2.HPME: Set to zero to disable EL2 Performance
+ * Monitors.
+ *
+ * MDCR_EL2.TPM: Set to zero so that Non-secure EL0 and
+ * EL1 accesses to all Performance Monitors registers
+ * are not trapped to EL2.
+ *
+ * MDCR_EL2.TPMCR: Set to zero so that Non-secure EL0
+ * and EL1 accesses to the PMCR_EL0 or PMCR are not
+ * trapped to EL2.
+ *
+ * MDCR_EL2.HPMN: Set to value of PMCR_EL0.N which is the
+ * architecturally-defined reset value.
*/
- write_mdcr_el2((read_pmcr_el0() & PMCR_EL0_N_BITS)
- >> PMCR_EL0_N_SHIFT);
+ write_mdcr_el2((MDCR_EL2_RESET_VAL |
+ ((read_pmcr_el0() & PMCR_EL0_N_BITS)
+ >> PMCR_EL0_N_SHIFT)) &
+ ~(MDCR_EL2_TDRA_BIT | MDCR_EL2_TDOSA_BIT
+ | MDCR_EL2_TDA_BIT | MDCR_EL2_TDE_BIT
+ | MDCR_EL2_HPME_BIT | MDCR_EL2_TPM_BIT
+ | MDCR_EL2_TPMCR_BIT));
/*
- * Avoid unexpected traps of non-secure access to
- * certain system registers at EL1 or lower where
- * HSTR_EL2 is not completely reset to zero by the
- * hardware - zero the entire register.
+ * Initialise HSTR_EL2. All fields are architecturally
+ * UNKNOWN on reset.
+ *
+ * HSTR_EL2.T<n>: Set all these fields to zero so that
+ * Non-secure EL0 or EL1 accesses to System registers
+ * do not trap to EL2.
*/
- write_hstr_el2(0);
+ write_hstr_el2(HSTR_EL2_RESET_VAL & ~(HSTR_EL2_T_MASK));
/*
- * Reset CNTHP_CTL_EL2 to disable the EL2 physical timer
- * and therefore prevent timer interrupts.
+ * Initialise CNTHP_CTL_EL2. All fields are
+ * architecturally UNKNOWN on reset.
+ *
+ * CNTHP_CTL_EL2:ENABLE: Set to zero to disable the EL2
+ * physical timer and prevent timer interrupts.
*/
- write_cnthp_ctl_el2(0);
+ write_cnthp_ctl_el2(CNTHP_CTL_RESET_VAL &
+ ~(CNTHP_CTL_ENABLE_BIT));
}
}