123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- /*
- * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <assert.h>
- #include <stdbool.h>
- #include <string.h>
- #include <platform_def.h>
- #include <arch.h>
- #include <arch_features.h>
- #include <arch_helpers.h>
- #include <common/bl_common.h>
- #include <context.h>
- #include <lib/el3_runtime/context_mgmt.h>
- #include <lib/extensions/amu.h>
- #include <lib/extensions/pmuv3.h>
- #include <lib/extensions/sys_reg_trace.h>
- #include <lib/extensions/trf.h>
- #include <lib/utils.h>
- /*******************************************************************************
- * Context management library initialisation routine. This library is used by
- * runtime services to share pointers to 'cpu_context' structures for the secure
- * 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
- * manages the cpu context used for entry from and exit to the non-secure state.
- * The Secure payload 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.
- ******************************************************************************/
- void cm_init(void)
- {
- /*
- * The context management library has only global data to initialize, but
- * that will be done when the BSS is zeroed out
- */
- }
- /*******************************************************************************
- * The following function initializes the cpu_context 'ctx' for
- * first use, and sets the 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
- * 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)
- {
- unsigned int security_state;
- uint32_t scr, sctlr;
- regs_t *reg_ctx;
- assert(ctx != NULL);
- security_state = GET_SECURITY_STATE(ep->h.attr);
- /* Clear any residual register values from the context */
- zeromem(ctx, sizeof(*ctx));
- reg_ctx = get_regs_ctx(ctx);
- /*
- * Base the context SCR on the current value, adjust for entry point
- * specific requirements
- */
- scr = read_scr();
- scr &= ~(SCR_NS_BIT | SCR_HCE_BIT);
- if (security_state != SECURE)
- scr |= SCR_NS_BIT;
- if (security_state != SECURE) {
- /*
- * Set up SCTLR for the Non-secure context.
- *
- * 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)
- *
- * Set remaining SCTLR fields to their architecturally defined
- * values. Some fields reset to an IMPLEMENTATION DEFINED value:
- *
- * SCTLR.TE: Set to zero so that exceptions to an Exception
- * Level executing at PL1 are taken to A32 state.
- *
- * SCTLR.V: Set to zero to select the normal exception vectors
- * with base address held in VBAR.
- */
- assert(((ep->spsr >> SPSR_E_SHIFT) & SPSR_E_MASK) ==
- (EP_GET_EE(ep->h.attr) >> EP_EE_SHIFT));
- sctlr = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0U;
- sctlr |= (SCTLR_RESET_VAL & ~(SCTLR_TE_BIT | SCTLR_V_BIT));
- write_ctx_reg(reg_ctx, CTX_NS_SCTLR, sctlr);
- }
- /*
- * The target exception level is based on the spsr mode requested. If
- * execution is requested to hyp mode, HVC is enabled via SCR.HCE.
- */
- if (GET_M32(ep->spsr) == MODE32_hyp)
- scr |= SCR_HCE_BIT;
- /*
- * Store the initialised values for SCTLR and SCR in the cpu_context.
- * The Hyp mode registers are not part of the saved context and are
- * set-up in cm_prepare_el3_exit().
- */
- write_ctx_reg(reg_ctx, CTX_SCR, scr);
- write_ctx_reg(reg_ctx, CTX_LR, ep->pc);
- write_ctx_reg(reg_ctx, CTX_SPSR, ep->spsr);
- /*
- * Store the r0-r3 value from the entrypoint into the context
- * Use memcpy as we are in control of the layout of the structures
- */
- memcpy((void *)reg_ctx, (void *)&ep->args, sizeof(aapcs32_params_t));
- }
- /*******************************************************************************
- * Enable architecture extensions on first entry to Non-secure world.
- * When EL2 is implemented but unused `el2_unused` is non-zero, otherwise
- * it is zero.
- ******************************************************************************/
- static void enable_extensions_nonsecure(bool el2_unused)
- {
- #if IMAGE_BL32
- if (is_feat_amu_supported()) {
- amu_enable(el2_unused);
- }
- if (is_feat_sys_reg_trace_supported()) {
- sys_reg_trace_enable();
- }
- if (is_feat_trf_supported()) {
- trf_enable();
- }
- /*
- * Also applies to PMU < v3. The PMU is only disabled for EL3 and Secure
- * state execution. This does not affect lower NS ELs.
- */
- pmuv3_disable_el3();
- #endif
- }
- /*******************************************************************************
- * The following function initializes the cpu_context for a CPU specified by
- * its `cpu_idx` for first use, and sets the initial entrypoint state as
- * specified by the entry_point_info structure.
- ******************************************************************************/
- void cm_init_context_by_index(unsigned int cpu_idx,
- const entry_point_info_t *ep)
- {
- cpu_context_t *ctx;
- ctx = cm_get_context_by_index(cpu_idx, GET_SECURITY_STATE(ep->h.attr));
- cm_setup_context(ctx, ep);
- }
- /*******************************************************************************
- * The following function initializes the cpu_context for the current CPU
- * for first use, and sets the initial entrypoint state as specified by the
- * entry_point_info structure.
- ******************************************************************************/
- void cm_init_my_context(const entry_point_info_t *ep)
- {
- cpu_context_t *ctx;
- ctx = cm_get_context(GET_SECURITY_STATE(ep->h.attr));
- cm_setup_context(ctx, ep);
- }
- /*******************************************************************************
- * Prepare the CPU system registers for first entry into secure or normal world
- *
- * If execution is requested to hyp mode, HSCTLR is initialized
- * If execution is requested to non-secure PL1, and the CPU supports
- * HYP mode then HYP mode is disabled by configuring all necessary HYP mode
- * registers.
- ******************************************************************************/
- void cm_prepare_el3_exit(uint32_t security_state)
- {
- uint32_t hsctlr, scr;
- cpu_context_t *ctx = cm_get_context(security_state);
- bool el2_unused = false;
- assert(ctx != NULL);
- if (security_state == NON_SECURE) {
- scr = read_ctx_reg(get_regs_ctx(ctx), CTX_SCR);
- if ((scr & SCR_HCE_BIT) != 0U) {
- /* Use SCTLR value to initialize HSCTLR */
- hsctlr = read_ctx_reg(get_regs_ctx(ctx),
- CTX_NS_SCTLR);
- hsctlr |= HSCTLR_RES1;
- /* Temporarily set the NS bit to access HSCTLR */
- write_scr(read_scr() | SCR_NS_BIT);
- /*
- * Make sure the write to SCR is complete so that
- * we can access HSCTLR
- */
- isb();
- write_hsctlr(hsctlr);
- isb();
- write_scr(read_scr() & ~SCR_NS_BIT);
- isb();
- } else if ((read_id_pfr1() &
- (ID_PFR1_VIRTEXT_MASK << ID_PFR1_VIRTEXT_SHIFT)) != 0U) {
- el2_unused = true;
- /*
- * Set the NS bit to access NS copies of certain banked
- * registers
- */
- write_scr(read_scr() | SCR_NS_BIT);
- isb();
- /*
- * Hyp / PL2 present but unused, need to disable safely.
- * HSCTLR can be ignored in this case.
- *
- * Set HCR to its architectural reset value so that
- * Non-secure operations do not trap to Hyp mode.
- */
- write_hcr(HCR_RESET_VAL);
- /*
- * Set HCPTR to its architectural reset value so that
- * Non-secure access from EL1 or EL0 to trace and to
- * Advanced SIMD and floating point functionality does
- * not trap to Hyp mode.
- */
- write_hcptr(HCPTR_RESET_VAL);
- /*
- * Initialise CNTHCTL. All fields are architecturally
- * UNKNOWN on reset and are set to zero except for
- * field(s) listed below.
- *
- * CNTHCTL.PL1PCEN: Disable traps to Hyp mode of
- * Non-secure EL0 and EL1 accessed to the physical
- * timer registers.
- *
- * CNTHCTL.PL1PCTEN: Disable traps to Hyp mode of
- * Non-secure EL0 and EL1 accessed to the physical
- * counter registers.
- */
- write_cnthctl(CNTHCTL_RESET_VAL |
- PL1PCEN_BIT | PL1PCTEN_BIT);
- /*
- * Initialise CNTVOFF to zero as it resets to an
- * IMPLEMENTATION DEFINED value.
- */
- write64_cntvoff(0);
- /*
- * Set VPIDR and VMPIDR to match MIDR_EL1 and MPIDR
- * respectively.
- */
- write_vpidr(read_midr());
- write_vmpidr(read_mpidr());
- /*
- * Initialise VTTBR, setting all fields rather than
- * relying on the hw. Some fields are architecturally
- * UNKNOWN at reset.
- *
- * VTTBR.VMID: Set to zero which is the architecturally
- * defined reset value. Even though EL1&0 stage 2
- * address translation is disabled, cache maintenance
- * operations depend on the VMID.
- *
- * VTTBR.BADDR: Set to zero as EL1&0 stage 2 address
- * translation is disabled.
- */
- write64_vttbr(VTTBR_RESET_VAL &
- ~((VTTBR_VMID_MASK << VTTBR_VMID_SHIFT)
- | (VTTBR_BADDR_MASK << VTTBR_BADDR_SHIFT)));
- /*
- * Initialise HDCR, setting all the fields rather than
- * relying on hw.
- *
- * HDCR.HPMN: Set to value of PMCR.N which is the
- * architecturally-defined reset value.
- *
- * HDCR.HLP: Set to one so that event counter
- * overflow, that is recorded in PMOVSCLR[0-30],
- * occurs on the increment that changes
- * PMEVCNTR<n>[63] from 1 to 0, when ARMv8.5-PMU is
- * implemented. This bit is RES0 in versions of the
- * architecture earlier than ARMv8.5, setting it to 1
- * doesn't have any effect on them.
- * This bit is Reserved, UNK/SBZP in ARMv7.
- *
- * HDCR.HPME: Set to zero to disable EL2 Event
- * counters.
- */
- #if (ARM_ARCH_MAJOR > 7)
- write_hdcr((HDCR_RESET_VAL | HDCR_HLP_BIT |
- ((read_pmcr() & PMCR_N_BITS) >>
- PMCR_N_SHIFT)) & ~HDCR_HPME_BIT);
- #else
- write_hdcr((HDCR_RESET_VAL |
- ((read_pmcr() & PMCR_N_BITS) >>
- PMCR_N_SHIFT)) & ~HDCR_HPME_BIT);
- #endif
- /*
- * Set HSTR to its architectural reset value so that
- * access to system registers in the cproc=1111
- * encoding space do not trap to Hyp mode.
- */
- write_hstr(HSTR_RESET_VAL);
- /*
- * Set CNTHP_CTL to its architectural reset value to
- * disable the EL2 physical timer and prevent timer
- * interrupts. Some fields are architecturally UNKNOWN
- * on reset and are set to zero.
- */
- write_cnthp_ctl(CNTHP_CTL_RESET_VAL);
- isb();
- write_scr(read_scr() & ~SCR_NS_BIT);
- isb();
- }
- enable_extensions_nonsecure(el2_unused);
- }
- }
- /*******************************************************************************
- * This function is used to exit to Non-secure world. It simply calls the
- * cm_prepare_el3_exit function for AArch32.
- ******************************************************************************/
- void cm_prepare_el3_exit_ns(void)
- {
- cm_prepare_el3_exit(NON_SECURE);
- }
|