@ -71,77 +71,104 @@ static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t
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 .
* 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 .
*/
if ( ( GET_RW ( ep - > spsr ) = = MODE_RW_64
& & GET_EL ( ep - > spsr ) = = MODE_EL2 )
| | ( GET_RW ( ep - > spsr ) ! = MODE_RW_64
& & GET_M32 ( ep - > spsr ) = = MODE32_hyp ) ) {
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 .
*
* 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
* SCTLR . EE : Endianness is taken from the entrypoint attributes .
*
* TODO : In debug builds the spsr should be validated and checked
* against the CPU support , security state , endianess and pc
* 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 {
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 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 .
*/
if ( security_state ! = SECURE )
sctlr_elx | = SCTLR_CP15BEN_BIT | SCTLR_NTWI_BIT
| SCTLR_NTWE_BIT ;
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 ) ;
if ( ( GET_RW ( ep - > spsr ) = = MODE_RW_64
& & GET_EL ( ep - > spsr ) = = MODE_EL2 )
| | ( GET_RW ( ep - > spsr ) ! = MODE_RW_64
& & GET_M32 ( ep - > spsr ) = = MODE32_hyp ) ) {
scr_el3 | = SCR_HCE_BIT ;
}
/* 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_init_my_context(const entry_point_info_t *ep)
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 @@ void cm_prepare_el3_exit(uint32_t security_state)
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 */
/* 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 ) ;
/*
* 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 ) ) ;
/* Enable EL1 access to timer */
write_cnthctl_el2 ( EL1PCEN_BIT | EL1PCTEN_BIT ) ;
/*
* 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 ) ;
/* 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 ) ) ;
}
}