arm-trusted-firmware/include/lib/aarch64/arch_helpers.h
David Cunado 3e61b2b543 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>
2017-10-13 09:48:48 +01:00

359 lines
11 KiB
C

/*
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __ARCH_HELPERS_H__
#define __ARCH_HELPERS_H__
#include <arch.h> /* for additional register definitions */
#include <cdefs.h> /* For __dead2 */
#include <stdint.h>
#include <sys/types.h>
/**********************************************************************
* Macros which create inline functions to read or write CPU system
* registers
*********************************************************************/
#define _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \
static inline uint64_t read_ ## _name(void) \
{ \
uint64_t v; \
__asm__ volatile ("mrs %0, " #_reg_name : "=r" (v)); \
return v; \
}
#define _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) \
static inline void write_ ## _name(uint64_t v) \
{ \
__asm__ volatile ("msr " #_reg_name ", %0" : : "r" (v)); \
}
#define _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _reg_name) \
static inline void write_ ## _name(const uint64_t v) \
{ \
__asm__ volatile ("msr " #_reg_name ", %0" : : "i" (v)); \
}
/* Define read function for system register */
#define DEFINE_SYSREG_READ_FUNC(_name) \
_DEFINE_SYSREG_READ_FUNC(_name, _name)
/* Define read & write function for system register */
#define DEFINE_SYSREG_RW_FUNCS(_name) \
_DEFINE_SYSREG_READ_FUNC(_name, _name) \
_DEFINE_SYSREG_WRITE_FUNC(_name, _name)
/* Define read & write function for renamed system register */
#define DEFINE_RENAME_SYSREG_RW_FUNCS(_name, _reg_name) \
_DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \
_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
/* Define read function for renamed system register */
#define DEFINE_RENAME_SYSREG_READ_FUNC(_name, _reg_name) \
_DEFINE_SYSREG_READ_FUNC(_name, _reg_name)
/* Define write function for renamed system register */
#define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name) \
_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
/* Define write function for special system registers */
#define DEFINE_SYSREG_WRITE_CONST_FUNC(_name) \
_DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _name)
/**********************************************************************
* Macros to create inline functions for system instructions
*********************************************************************/
/* Define function for simple system instruction */
#define DEFINE_SYSOP_FUNC(_op) \
static inline void _op(void) \
{ \
__asm__ (#_op); \
}
/* Define function for system instruction with type specifier */
#define DEFINE_SYSOP_TYPE_FUNC(_op, _type) \
static inline void _op ## _type(void) \
{ \
__asm__ (#_op " " #_type); \
}
/* Define function for system instruction with register parameter */
#define DEFINE_SYSOP_TYPE_PARAM_FUNC(_op, _type) \
static inline void _op ## _type(uint64_t v) \
{ \
__asm__ (#_op " " #_type ", %0" : : "r" (v)); \
}
/*******************************************************************************
* TLB maintenance accessor prototypes
******************************************************************************/
#if ERRATA_A57_813419
/*
* Define function for TLBI instruction with type specifier that implements
* the workaround for errata 813419 of Cortex-A57.
*/
#define DEFINE_TLBIOP_ERRATA_A57_813419_TYPE_FUNC(_type)\
static inline void tlbi ## _type(void) \
{ \
__asm__("tlbi " #_type "\n" \
"dsb ish\n" \
"tlbi " #_type); \
}
/*
* Define function for TLBI instruction with register parameter that implements
* the workaround for errata 813419 of Cortex-A57.
*/
#define DEFINE_TLBIOP_ERRATA_A57_813419_TYPE_PARAM_FUNC(_type) \
static inline void tlbi ## _type(uint64_t v) \
{ \
__asm__("tlbi " #_type ", %0\n" \
"dsb ish\n" \
"tlbi " #_type ", %0" : : "r" (v)); \
}
#endif /* ERRATA_A57_813419 */
DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1)
DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1is)
DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2)
DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2is)
#if ERRATA_A57_813419
DEFINE_TLBIOP_ERRATA_A57_813419_TYPE_FUNC(alle3)
DEFINE_TLBIOP_ERRATA_A57_813419_TYPE_FUNC(alle3is)
#else
DEFINE_SYSOP_TYPE_FUNC(tlbi, alle3)
DEFINE_SYSOP_TYPE_FUNC(tlbi, alle3is)
#endif
DEFINE_SYSOP_TYPE_FUNC(tlbi, vmalle1)
DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaae1is)
DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaale1is)
DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vae2is)
DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vale2is)
#if ERRATA_A57_813419
DEFINE_TLBIOP_ERRATA_A57_813419_TYPE_PARAM_FUNC(vae3is)
DEFINE_TLBIOP_ERRATA_A57_813419_TYPE_PARAM_FUNC(vale3is)
#else
DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vae3is)
DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vale3is)
#endif
/*******************************************************************************
* Cache maintenance accessor prototypes
******************************************************************************/
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, isw)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cisw)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, csw)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cvac)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, ivac)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, civac)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cvau)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, zva)
/*******************************************************************************
* Address translation accessor prototypes
******************************************************************************/
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1r)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1w)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0r)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0w)
void flush_dcache_range(uintptr_t addr, size_t size);
void clean_dcache_range(uintptr_t addr, size_t size);
void inv_dcache_range(uintptr_t addr, size_t size);
void dcsw_op_louis(u_register_t op_type);
void dcsw_op_all(u_register_t op_type);
void disable_mmu_el3(void);
void disable_mmu_icache_el3(void);
/*******************************************************************************
* Misc. accessor prototypes
******************************************************************************/
DEFINE_SYSREG_WRITE_CONST_FUNC(daifset)
DEFINE_SYSREG_WRITE_CONST_FUNC(daifclr)
DEFINE_SYSREG_READ_FUNC(par_el1)
DEFINE_SYSREG_READ_FUNC(id_pfr1_el1)
DEFINE_SYSREG_READ_FUNC(id_aa64pfr0_el1)
DEFINE_SYSREG_READ_FUNC(id_aa64dfr0_el1)
DEFINE_SYSREG_READ_FUNC(CurrentEl)
DEFINE_SYSREG_RW_FUNCS(daif)
DEFINE_SYSREG_RW_FUNCS(spsr_el1)
DEFINE_SYSREG_RW_FUNCS(spsr_el2)
DEFINE_SYSREG_RW_FUNCS(spsr_el3)
DEFINE_SYSREG_RW_FUNCS(elr_el1)
DEFINE_SYSREG_RW_FUNCS(elr_el2)
DEFINE_SYSREG_RW_FUNCS(elr_el3)
DEFINE_SYSOP_FUNC(wfi)
DEFINE_SYSOP_FUNC(wfe)
DEFINE_SYSOP_FUNC(sev)
DEFINE_SYSOP_TYPE_FUNC(dsb, sy)
DEFINE_SYSOP_TYPE_FUNC(dmb, sy)
DEFINE_SYSOP_TYPE_FUNC(dmb, st)
DEFINE_SYSOP_TYPE_FUNC(dmb, ld)
DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
DEFINE_SYSOP_FUNC(isb)
uint32_t get_afflvl_shift(uint32_t);
uint32_t mpidr_mask_lower_afflvls(uint64_t, uint32_t);
void __dead2 eret(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, uint64_t x5, uint64_t x6, uint64_t x7);
void __dead2 smc(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, uint64_t x5, uint64_t x6, uint64_t x7);
/*******************************************************************************
* System register accessor prototypes
******************************************************************************/
DEFINE_SYSREG_READ_FUNC(midr_el1)
DEFINE_SYSREG_READ_FUNC(mpidr_el1)
DEFINE_SYSREG_READ_FUNC(id_aa64mmfr0_el1)
DEFINE_SYSREG_RW_FUNCS(scr_el3)
DEFINE_SYSREG_RW_FUNCS(hcr_el2)
DEFINE_SYSREG_RW_FUNCS(vbar_el1)
DEFINE_SYSREG_RW_FUNCS(vbar_el2)
DEFINE_SYSREG_RW_FUNCS(vbar_el3)
DEFINE_SYSREG_RW_FUNCS(sctlr_el1)
DEFINE_SYSREG_RW_FUNCS(sctlr_el2)
DEFINE_SYSREG_RW_FUNCS(sctlr_el3)
DEFINE_SYSREG_RW_FUNCS(actlr_el1)
DEFINE_SYSREG_RW_FUNCS(actlr_el2)
DEFINE_SYSREG_RW_FUNCS(actlr_el3)
DEFINE_SYSREG_RW_FUNCS(esr_el1)
DEFINE_SYSREG_RW_FUNCS(esr_el2)
DEFINE_SYSREG_RW_FUNCS(esr_el3)
DEFINE_SYSREG_RW_FUNCS(afsr0_el1)
DEFINE_SYSREG_RW_FUNCS(afsr0_el2)
DEFINE_SYSREG_RW_FUNCS(afsr0_el3)
DEFINE_SYSREG_RW_FUNCS(afsr1_el1)
DEFINE_SYSREG_RW_FUNCS(afsr1_el2)
DEFINE_SYSREG_RW_FUNCS(afsr1_el3)
DEFINE_SYSREG_RW_FUNCS(far_el1)
DEFINE_SYSREG_RW_FUNCS(far_el2)
DEFINE_SYSREG_RW_FUNCS(far_el3)
DEFINE_SYSREG_RW_FUNCS(mair_el1)
DEFINE_SYSREG_RW_FUNCS(mair_el2)
DEFINE_SYSREG_RW_FUNCS(mair_el3)
DEFINE_SYSREG_RW_FUNCS(amair_el1)
DEFINE_SYSREG_RW_FUNCS(amair_el2)
DEFINE_SYSREG_RW_FUNCS(amair_el3)
DEFINE_SYSREG_READ_FUNC(rvbar_el1)
DEFINE_SYSREG_READ_FUNC(rvbar_el2)
DEFINE_SYSREG_READ_FUNC(rvbar_el3)
DEFINE_SYSREG_RW_FUNCS(rmr_el1)
DEFINE_SYSREG_RW_FUNCS(rmr_el2)
DEFINE_SYSREG_RW_FUNCS(rmr_el3)
DEFINE_SYSREG_RW_FUNCS(tcr_el1)
DEFINE_SYSREG_RW_FUNCS(tcr_el2)
DEFINE_SYSREG_RW_FUNCS(tcr_el3)
DEFINE_SYSREG_RW_FUNCS(ttbr0_el1)
DEFINE_SYSREG_RW_FUNCS(ttbr0_el2)
DEFINE_SYSREG_RW_FUNCS(ttbr0_el3)
DEFINE_SYSREG_RW_FUNCS(ttbr1_el1)
DEFINE_SYSREG_RW_FUNCS(vttbr_el2)
DEFINE_SYSREG_RW_FUNCS(cptr_el2)
DEFINE_SYSREG_RW_FUNCS(cptr_el3)
DEFINE_SYSREG_RW_FUNCS(cpacr_el1)
DEFINE_SYSREG_RW_FUNCS(cntfrq_el0)
DEFINE_SYSREG_RW_FUNCS(cntps_ctl_el1)
DEFINE_SYSREG_RW_FUNCS(cntps_tval_el1)
DEFINE_SYSREG_RW_FUNCS(cntps_cval_el1)
DEFINE_SYSREG_READ_FUNC(cntpct_el0)
DEFINE_SYSREG_RW_FUNCS(cnthctl_el2)
DEFINE_SYSREG_RW_FUNCS(tpidr_el3)
DEFINE_SYSREG_RW_FUNCS(cntvoff_el2)
DEFINE_SYSREG_RW_FUNCS(vpidr_el2)
DEFINE_SYSREG_RW_FUNCS(vmpidr_el2)
DEFINE_SYSREG_RW_FUNCS(cntp_ctl_el0)
DEFINE_SYSREG_READ_FUNC(isr_el1)
DEFINE_SYSREG_READ_FUNC(ctr_el0)
DEFINE_SYSREG_RW_FUNCS(mdcr_el2)
DEFINE_SYSREG_RW_FUNCS(hstr_el2)
DEFINE_SYSREG_RW_FUNCS(cnthp_ctl_el2)
DEFINE_SYSREG_RW_FUNCS(pmcr_el0)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir1_el1, ICC_HPPIR1_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1)
#define IS_IN_EL(x) \
(GET_EL(read_CurrentEl()) == MODE_EL##x)
#define IS_IN_EL1() IS_IN_EL(1)
#define IS_IN_EL3() IS_IN_EL(3)
/*
* Check if an EL is implemented from AA64PFR0 register fields. 'el' argument
* must be one of 1, 2 or 3.
*/
#define EL_IMPLEMENTED(el) \
((read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL##el##_SHIFT) \
& ID_AA64PFR0_ELX_MASK)
/* Previously defined accesor functions with incomplete register names */
#define read_current_el() read_CurrentEl()
#define dsb() dsbsy()
#define read_midr() read_midr_el1()
#define read_mpidr() read_mpidr_el1()
#define read_scr() read_scr_el3()
#define write_scr(_v) write_scr_el3(_v)
#define read_hcr() read_hcr_el2()
#define write_hcr(_v) write_hcr_el2(_v)
#define read_cpacr() read_cpacr_el1()
#define write_cpacr(_v) write_cpacr_el1(_v)
#endif /* __ARCH_HELPERS_H__ */