refactor(context mgmt): refactor the cm_setup_context function
This patch splits the function 'cm_setup_context' into four functions to make it more readable and easier to maintain. The function is split into the following functions based on the security state of the context. - setup_context_common - performs common initializations - setup_secure_context - performs Secure state specific initializations - setup_realm_context - performs Realm state specific initializations - setup_ns_context - performs Non-secure state specific initializations Signed-off-by: Zelalem Aweke <zelalem.aweke@arm.com> Change-Id: Ie14a1c2fc6586087e7aa36537cf9064c80802f8f
This commit is contained in:
parent
7f41bcc76d
commit
2bbad1d126
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -31,54 +31,133 @@
|
||||||
|
|
||||||
static void manage_extensions_secure(cpu_context_t *ctx);
|
static void manage_extensions_secure(cpu_context_t *ctx);
|
||||||
|
|
||||||
/*******************************************************************************
|
/******************************************************************************
|
||||||
* Context management library initialisation routine. This library is used by
|
* This function performs initializations that are specific to SECURE state
|
||||||
* runtime services to share pointers to 'cpu_context' structures for the secure
|
* and updates the cpu context specified by 'ctx'.
|
||||||
* and non-secure states. Management of the structures and their associated
|
*****************************************************************************/
|
||||||
* memory is not done by the context management library e.g. the PSCI service
|
static void setup_secure_context(cpu_context_t *ctx, const struct entry_point_info *ep)
|
||||||
* manages the cpu context used for entry from and exit to the non-secure state.
|
|
||||||
* The Secure payload dispatcher service manages the context(s) corresponding to
|
|
||||||
* the secure state. It also uses this library to get access to the non-secure
|
|
||||||
* state cpu context pointers.
|
|
||||||
* Lastly, this library provides the api to make SP_EL3 point to the cpu context
|
|
||||||
* which will used for programming an entry into a lower EL. The same context
|
|
||||||
* will used to save state upon exception entry from that EL.
|
|
||||||
******************************************************************************/
|
|
||||||
void __init cm_init(void)
|
|
||||||
{
|
{
|
||||||
|
u_register_t scr_el3;
|
||||||
|
el3_state_t *state;
|
||||||
|
|
||||||
|
state = get_el3state_ctx(ctx);
|
||||||
|
scr_el3 = read_ctx_reg(state, CTX_SCR_EL3);
|
||||||
|
|
||||||
|
#if defined(IMAGE_BL31) && !defined(SPD_spmd)
|
||||||
/*
|
/*
|
||||||
* The context management library has only global data to intialize, but
|
* SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ routing as
|
||||||
* that will be done when the BSS is zeroed out
|
* indicated by the interrupt routing model for BL31.
|
||||||
*/
|
*/
|
||||||
|
scr_el3 |= get_scr_el3_from_routing_model(SECURE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !CTX_INCLUDE_MTE_REGS || ENABLE_ASSERTIONS
|
||||||
|
/* Get Memory Tagging Extension support level */
|
||||||
|
unsigned int mte = get_armv8_5_mte_support();
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Allow access to Allocation Tags when CTX_INCLUDE_MTE_REGS
|
||||||
|
* is set, or when MTE is only implemented at EL0.
|
||||||
|
*/
|
||||||
|
#if CTX_INCLUDE_MTE_REGS
|
||||||
|
assert((mte == MTE_IMPLEMENTED_ELX) || (mte == MTE_IMPLEMENTED_ASY));
|
||||||
|
scr_el3 |= SCR_ATA_BIT;
|
||||||
|
#else
|
||||||
|
if (mte == MTE_IMPLEMENTED_EL0) {
|
||||||
|
scr_el3 |= SCR_ATA_BIT;
|
||||||
|
}
|
||||||
|
#endif /* CTX_INCLUDE_MTE_REGS */
|
||||||
|
|
||||||
|
/* Enable S-EL2 if the next EL is EL2 and S-EL2 is present */
|
||||||
|
if ((GET_EL(ep->spsr) == MODE_EL2) && is_armv8_4_sel2_present()) {
|
||||||
|
if (GET_RW(ep->spsr) != MODE_RW_64) {
|
||||||
|
ERROR("S-EL2 can not be used in AArch32\n.");
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
scr_el3 |= SCR_EEL2_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
|
||||||
|
|
||||||
|
manage_extensions_secure(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_RME
|
||||||
|
/******************************************************************************
|
||||||
|
* This function performs initializations that are specific to REALM state
|
||||||
|
* and updates the cpu context specified by 'ctx'.
|
||||||
|
*****************************************************************************/
|
||||||
|
static void setup_realm_context(cpu_context_t *ctx, const struct entry_point_info *ep)
|
||||||
|
{
|
||||||
|
u_register_t scr_el3;
|
||||||
|
el3_state_t *state;
|
||||||
|
|
||||||
|
state = get_el3state_ctx(ctx);
|
||||||
|
scr_el3 = read_ctx_reg(state, CTX_SCR_EL3);
|
||||||
|
|
||||||
|
scr_el3 |= SCR_NS_BIT | SCR_NSE_BIT | SCR_EnSCXT_BIT;
|
||||||
|
|
||||||
|
write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
|
||||||
|
}
|
||||||
|
#endif /* ENABLE_RME */
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This function performs initializations that are specific to NON-SECURE state
|
||||||
|
* and updates the cpu context specified by 'ctx'.
|
||||||
|
*****************************************************************************/
|
||||||
|
static void setup_ns_context(cpu_context_t *ctx, const struct entry_point_info *ep)
|
||||||
|
{
|
||||||
|
u_register_t scr_el3;
|
||||||
|
el3_state_t *state;
|
||||||
|
|
||||||
|
state = get_el3state_ctx(ctx);
|
||||||
|
scr_el3 = read_ctx_reg(state, CTX_SCR_EL3);
|
||||||
|
|
||||||
|
/* SCR_NS: Set the NS bit */
|
||||||
|
scr_el3 |= SCR_NS_BIT;
|
||||||
|
|
||||||
|
#if !CTX_INCLUDE_PAUTH_REGS
|
||||||
|
/*
|
||||||
|
* If the pointer authentication registers aren't saved during world
|
||||||
|
* switches the value of the registers can be leaked from the Secure to
|
||||||
|
* the Non-secure world. To prevent this, rather than enabling pointer
|
||||||
|
* authentication everywhere, we only enable it in the Non-secure world.
|
||||||
|
*
|
||||||
|
* If the Secure world wants to use pointer authentication,
|
||||||
|
* CTX_INCLUDE_PAUTH_REGS must be set to 1.
|
||||||
|
*/
|
||||||
|
scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
|
||||||
|
#endif /* !CTX_INCLUDE_PAUTH_REGS */
|
||||||
|
|
||||||
|
/* Allow access to Allocation Tags when MTE is implemented. */
|
||||||
|
scr_el3 |= SCR_ATA_BIT;
|
||||||
|
|
||||||
|
#ifdef IMAGE_BL31
|
||||||
|
/*
|
||||||
|
* SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ routing as
|
||||||
|
* indicated by the interrupt routing model for BL31.
|
||||||
|
*/
|
||||||
|
scr_el3 |= get_scr_el3_from_routing_model(NON_SECURE);
|
||||||
|
#endif
|
||||||
|
write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* The following function initializes the cpu_context 'ctx' for
|
* The following function performs initialization of the cpu_context 'ctx'
|
||||||
* first use, and sets the initial entrypoint state as specified by the
|
* for first use that is common to all security states, and sets the
|
||||||
* entry_point_info structure.
|
* initial entrypoint state as specified by the entry_point_info structure.
|
||||||
*
|
|
||||||
* The security state to initialize is determined by the SECURE attribute
|
|
||||||
* of the entry_point_info.
|
|
||||||
*
|
*
|
||||||
* The EE and ST attributes are used to configure the endianness and secure
|
* The EE and ST attributes are used to configure the endianness and secure
|
||||||
* timer availability for the new execution context.
|
* timer availability for the new execution context.
|
||||||
*
|
|
||||||
* To prepare the register state for entry call cm_prepare_el3_exit() and
|
|
||||||
* el3_exit(). For Secure-EL1 cm_prepare_el3_exit() is equivalent to
|
|
||||||
* cm_el1_sysregs_context_restore().
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
|
static void setup_context_common(cpu_context_t *ctx, const entry_point_info_t *ep)
|
||||||
{
|
{
|
||||||
unsigned int security_state;
|
|
||||||
u_register_t scr_el3;
|
u_register_t scr_el3;
|
||||||
el3_state_t *state;
|
el3_state_t *state;
|
||||||
gp_regs_t *gp_regs;
|
gp_regs_t *gp_regs;
|
||||||
u_register_t sctlr_elx, actlr_elx;
|
u_register_t sctlr_elx, actlr_elx;
|
||||||
|
|
||||||
assert(ctx != NULL);
|
|
||||||
|
|
||||||
security_state = GET_SECURITY_STATE(ep->h.attr);
|
|
||||||
|
|
||||||
/* Clear any residual register values from the context */
|
/* Clear any residual register values from the context */
|
||||||
zeromem(ctx, sizeof(*ctx));
|
zeromem(ctx, sizeof(*ctx));
|
||||||
|
|
||||||
|
@ -93,26 +172,7 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
|
||||||
*/
|
*/
|
||||||
scr_el3 = read_scr();
|
scr_el3 = read_scr();
|
||||||
scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT |
|
scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT |
|
||||||
SCR_ST_BIT | SCR_HCE_BIT);
|
SCR_ST_BIT | SCR_HCE_BIT | SCR_NSE_BIT);
|
||||||
|
|
||||||
#if ENABLE_RME
|
|
||||||
/* When RME support is enabled, clear the NSE bit as well. */
|
|
||||||
scr_el3 &= ~SCR_NSE_BIT;
|
|
||||||
#endif /* ENABLE_RME */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SCR_NS: Set the security state of the next EL.
|
|
||||||
*/
|
|
||||||
if (security_state == NON_SECURE) {
|
|
||||||
scr_el3 |= SCR_NS_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ENABLE_RME
|
|
||||||
/* Check for realm state if RME support enabled. */
|
|
||||||
if (security_state == REALM) {
|
|
||||||
scr_el3 |= SCR_NS_BIT | SCR_NSE_BIT | SCR_EnSCXT_BIT;
|
|
||||||
}
|
|
||||||
#endif /* ENABLE_RME */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SCR_EL3.RW: Set the execution state, AArch32 or AArch64, for next
|
* SCR_EL3.RW: Set the execution state, AArch32 or AArch64, for next
|
||||||
|
@ -121,6 +181,7 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
|
||||||
if (GET_RW(ep->spsr) == MODE_RW_64) {
|
if (GET_RW(ep->spsr) == MODE_RW_64) {
|
||||||
scr_el3 |= SCR_RW_BIT;
|
scr_el3 |= SCR_RW_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SCR_EL3.ST: Traps Secure EL1 accesses to the Counter-timer Physical
|
* SCR_EL3.ST: Traps Secure EL1 accesses to the Counter-timer Physical
|
||||||
* Secure timer registers to EL3, from AArch64 state only, if specified
|
* Secure timer registers to EL3, from AArch64 state only, if specified
|
||||||
|
@ -149,8 +210,8 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
|
||||||
#if !HANDLE_EA_EL3_FIRST
|
#if !HANDLE_EA_EL3_FIRST
|
||||||
/*
|
/*
|
||||||
* SCR_EL3.EA: Do not route External Abort and SError Interrupt External
|
* 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
|
* to EL3 when executing at a lower EL. When executing at EL3, External
|
||||||
* Aborts are taken to EL3.
|
* Aborts are taken to EL3.
|
||||||
*/
|
*/
|
||||||
scr_el3 &= ~SCR_EA_BIT;
|
scr_el3 &= ~SCR_EA_BIT;
|
||||||
#endif
|
#endif
|
||||||
|
@ -160,68 +221,11 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
|
||||||
scr_el3 |= SCR_FIEN_BIT;
|
scr_el3 |= SCR_FIEN_BIT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !CTX_INCLUDE_PAUTH_REGS
|
|
||||||
/*
|
/*
|
||||||
* If the pointer authentication registers aren't saved during world
|
* CPTR_EL3 was initialized out of reset, copy that value to the
|
||||||
* switches the value of the registers can be leaked from the Secure to
|
* context register.
|
||||||
* the Non-secure world. To prevent this, rather than enabling pointer
|
|
||||||
* authentication everywhere, we only enable it in the Non-secure world.
|
|
||||||
*
|
|
||||||
* If the Secure world wants to use pointer authentication,
|
|
||||||
* CTX_INCLUDE_PAUTH_REGS must be set to 1.
|
|
||||||
*/
|
*/
|
||||||
if (security_state == NON_SECURE) {
|
|
||||||
scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
|
|
||||||
}
|
|
||||||
#endif /* !CTX_INCLUDE_PAUTH_REGS */
|
|
||||||
|
|
||||||
#if !CTX_INCLUDE_MTE_REGS || ENABLE_ASSERTIONS
|
|
||||||
/* Get Memory Tagging Extension support level */
|
|
||||||
unsigned int mte = get_armv8_5_mte_support();
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* Enable MTE support. Support is enabled unilaterally for the normal
|
|
||||||
* world, and only for the secure world when CTX_INCLUDE_MTE_REGS is
|
|
||||||
* set.
|
|
||||||
*/
|
|
||||||
#if CTX_INCLUDE_MTE_REGS
|
|
||||||
assert((mte == MTE_IMPLEMENTED_ELX) || (mte == MTE_IMPLEMENTED_ASY));
|
|
||||||
scr_el3 |= SCR_ATA_BIT;
|
|
||||||
#else
|
|
||||||
/*
|
|
||||||
* When MTE is only implemented at EL0, it can be enabled
|
|
||||||
* across both worlds as no MTE registers are used.
|
|
||||||
*/
|
|
||||||
if ((mte == MTE_IMPLEMENTED_EL0) ||
|
|
||||||
/*
|
|
||||||
* When MTE is implemented at all ELs, it can be only enabled
|
|
||||||
* in Non-Secure world without register saving.
|
|
||||||
*/
|
|
||||||
(((mte == MTE_IMPLEMENTED_ELX) || (mte == MTE_IMPLEMENTED_ASY)) &&
|
|
||||||
(security_state == NON_SECURE))) {
|
|
||||||
scr_el3 |= SCR_ATA_BIT;
|
|
||||||
}
|
|
||||||
#endif /* CTX_INCLUDE_MTE_REGS */
|
|
||||||
|
|
||||||
#ifdef IMAGE_BL31
|
|
||||||
/*
|
|
||||||
* SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ routing as
|
|
||||||
* indicated by the interrupt routing model for BL31.
|
|
||||||
*
|
|
||||||
* TODO: The interrupt routing model code is not updated for REALM
|
|
||||||
* state. Use the default values of IRQ = FIQ = 0 for REALM security
|
|
||||||
* state for now.
|
|
||||||
*/
|
|
||||||
if (security_state != REALM) {
|
|
||||||
scr_el3 |= get_scr_el3_from_routing_model(security_state);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Save the initialized value of CPTR_EL3 register */
|
|
||||||
write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, read_cptr_el3());
|
write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, read_cptr_el3());
|
||||||
if (security_state == SECURE) {
|
|
||||||
manage_extensions_secure(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SCR_EL3.HCE: Enable HVC instructions if next execution state is
|
* SCR_EL3.HCE: Enable HVC instructions if next execution state is
|
||||||
|
@ -249,16 +253,6 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable S-EL2 if the next EL is EL2 and security state is secure */
|
|
||||||
if ((security_state == SECURE) && (GET_EL(ep->spsr) == MODE_EL2)) {
|
|
||||||
if (GET_RW(ep->spsr) != MODE_RW_64) {
|
|
||||||
ERROR("S-EL2 can not be used in AArch32.");
|
|
||||||
panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
scr_el3 |= SCR_EEL2_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FEAT_AMUv1p1 virtual offset registers are only accessible from EL3
|
* FEAT_AMUv1p1 virtual offset registers are only accessible from EL3
|
||||||
* and EL2, when clear, this bit traps accesses from EL2 so we set it
|
* and EL2, when clear, this bit traps accesses from EL2 so we set it
|
||||||
|
@ -361,6 +355,66 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
|
||||||
memcpy(gp_regs, (void *)&ep->args, sizeof(aapcs64_params_t));
|
memcpy(gp_regs, (void *)&ep->args, sizeof(aapcs64_params_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Context management library initialization routine. This library is used by
|
||||||
|
* runtime services to share pointers to 'cpu_context' structures for secure
|
||||||
|
* non-secure and realm states. Management of the structures and their associated
|
||||||
|
* memory is not done by the context management library e.g. the PSCI service
|
||||||
|
* manages the cpu context used for entry from and exit to the non-secure state.
|
||||||
|
* The Secure payload dispatcher service manages the context(s) corresponding to
|
||||||
|
* the secure state. It also uses this library to get access to the non-secure
|
||||||
|
* state cpu context pointers.
|
||||||
|
* Lastly, this library provides the API to make SP_EL3 point to the cpu context
|
||||||
|
* which will be used for programming an entry into a lower EL. The same context
|
||||||
|
* will be used to save state upon exception entry from that EL.
|
||||||
|
******************************************************************************/
|
||||||
|
void __init cm_init(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The context management library has only global data to intialize, but
|
||||||
|
* that will be done when the BSS is zeroed out.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* This is the high-level function used to initialize the cpu_context 'ctx' for
|
||||||
|
* first use. It performs initializations that are common to all security states
|
||||||
|
* and initializations specific to the security state specified in 'ep'
|
||||||
|
******************************************************************************/
|
||||||
|
void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
|
||||||
|
{
|
||||||
|
unsigned int security_state;
|
||||||
|
|
||||||
|
assert(ctx != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform initializations that are common
|
||||||
|
* to all security states
|
||||||
|
*/
|
||||||
|
setup_context_common(ctx, ep);
|
||||||
|
|
||||||
|
security_state = GET_SECURITY_STATE(ep->h.attr);
|
||||||
|
|
||||||
|
/* Perform security state specific initializations */
|
||||||
|
switch (security_state) {
|
||||||
|
case SECURE:
|
||||||
|
setup_secure_context(ctx, ep);
|
||||||
|
break;
|
||||||
|
#if ENABLE_RME
|
||||||
|
case REALM:
|
||||||
|
setup_realm_context(ctx, ep);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case NON_SECURE:
|
||||||
|
setup_ns_context(ctx, ep);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid security state\n");
|
||||||
|
panic();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Enable architecture extensions on first entry to Non-secure world.
|
* Enable architecture extensions on first entry to Non-secure world.
|
||||||
* When EL2 is implemented but unused `el2_unused` is non-zero, otherwise
|
* When EL2 is implemented but unused `el2_unused` is non-zero, otherwise
|
||||||
|
|
Loading…
Reference in New Issue