| /* |
| * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com> |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_ARCH_ARM64_LIB_HELPERS_H_ |
| #define ZEPHYR_INCLUDE_ARCH_ARM64_LIB_HELPERS_H_ |
| |
| #ifndef _ASMLANGUAGE |
| |
| #include <arch/arm64/cpu.h> |
| #include <stdint.h> |
| |
| /* All the macros need a memory clobber */ |
| |
| #define read_sysreg(reg) \ |
| ({ \ |
| uint64_t val; \ |
| __asm__ volatile ("mrs %0, " STRINGIFY(reg) \ |
| : "=r" (val) :: "memory"); \ |
| val; \ |
| }) |
| |
| #define write_sysreg(val, reg) \ |
| ({ \ |
| __asm__ volatile ("msr " STRINGIFY(reg) ", %0" \ |
| :: "r" (val) : "memory"); \ |
| }) |
| |
| #define zero_sysreg(reg) \ |
| ({ \ |
| __asm__ volatile ("msr " STRINGIFY(reg) ", xzr" \ |
| ::: "memory"); \ |
| }) |
| |
| #define MAKE_REG_HELPER(reg) \ |
| static ALWAYS_INLINE uint64_t read_##reg(void) \ |
| { \ |
| return read_sysreg(reg); \ |
| } \ |
| static ALWAYS_INLINE void write_##reg(uint64_t val) \ |
| { \ |
| write_sysreg(val, reg); \ |
| } \ |
| static ALWAYS_INLINE void zero_##reg(void) \ |
| { \ |
| zero_sysreg(reg); \ |
| } |
| |
| #define MAKE_REG_HELPER_EL123(reg) \ |
| MAKE_REG_HELPER(reg##_el1) \ |
| MAKE_REG_HELPER(reg##_el2) \ |
| MAKE_REG_HELPER(reg##_el3) |
| |
| MAKE_REG_HELPER(cntfrq_el0); |
| MAKE_REG_HELPER(cnthctl_el2); |
| MAKE_REG_HELPER(cnthp_ctl_el2); |
| MAKE_REG_HELPER(cntv_ctl_el0) |
| MAKE_REG_HELPER(cntv_cval_el0) |
| MAKE_REG_HELPER(cntvct_el0); |
| MAKE_REG_HELPER(cntvoff_el2); |
| MAKE_REG_HELPER(currentel); |
| MAKE_REG_HELPER(daif) |
| MAKE_REG_HELPER(hcr_el2); |
| MAKE_REG_HELPER(id_aa64pfr0_el1); |
| MAKE_REG_HELPER(id_aa64mmfr0_el1); |
| MAKE_REG_HELPER(scr_el3); |
| MAKE_REG_HELPER(tpidrro_el0); |
| MAKE_REG_HELPER(clidr_el1); |
| MAKE_REG_HELPER(csselr_el1); |
| MAKE_REG_HELPER(ccsidr_el1); |
| MAKE_REG_HELPER(vmpidr_el2); |
| MAKE_REG_HELPER(mpidr_el1); |
| |
| MAKE_REG_HELPER_EL123(actlr) |
| MAKE_REG_HELPER_EL123(cpacr) |
| MAKE_REG_HELPER_EL123(cptr) |
| MAKE_REG_HELPER_EL123(elr) |
| MAKE_REG_HELPER_EL123(esr) |
| MAKE_REG_HELPER_EL123(far) |
| MAKE_REG_HELPER_EL123(mair) |
| MAKE_REG_HELPER_EL123(sctlr) |
| MAKE_REG_HELPER_EL123(spsr) |
| MAKE_REG_HELPER_EL123(tcr) |
| MAKE_REG_HELPER_EL123(ttbr0) |
| MAKE_REG_HELPER_EL123(vbar) |
| |
| #if defined(CONFIG_ARM_MPU) |
| /* Armv8-R aarch64 mpu registers */ |
| #define mpuir_el1 S3_0_c0_c0_4 |
| #define prselr_el1 S3_0_c6_c2_1 |
| #define prbar_el1 S3_0_c6_c8_0 |
| #define prlar_el1 S3_0_c6_c8_1 |
| |
| MAKE_REG_HELPER(mpuir_el1); |
| MAKE_REG_HELPER(prselr_el1); |
| MAKE_REG_HELPER(prbar_el1); |
| MAKE_REG_HELPER(prlar_el1); |
| #endif |
| |
| static ALWAYS_INLINE void enable_debug_exceptions(void) |
| { |
| __asm__ volatile ("msr DAIFClr, %0" |
| :: "i" (DAIFCLR_DBG_BIT) : "memory"); |
| } |
| |
| static ALWAYS_INLINE void disable_debug_exceptions(void) |
| { |
| __asm__ volatile ("msr DAIFSet, %0" |
| :: "i" (DAIFSET_DBG_BIT) : "memory"); |
| } |
| |
| static ALWAYS_INLINE void enable_serror_exceptions(void) |
| { |
| __asm__ volatile ("msr DAIFClr, %0" |
| :: "i" (DAIFCLR_ABT_BIT) : "memory"); |
| } |
| |
| static ALWAYS_INLINE void disable_serror_exceptions(void) |
| { |
| __asm__ volatile ("msr DAIFSet, %0" |
| :: "i" (DAIFSET_ABT_BIT) : "memory"); |
| } |
| |
| static ALWAYS_INLINE void enable_irq(void) |
| { |
| __asm__ volatile ("msr DAIFClr, %0" |
| :: "i" (DAIFCLR_IRQ_BIT) : "memory"); |
| } |
| |
| static ALWAYS_INLINE void disable_irq(void) |
| { |
| __asm__ volatile ("msr DAIFSet, %0" |
| :: "i" (DAIFSET_IRQ_BIT) : "memory"); |
| } |
| |
| static ALWAYS_INLINE void enable_fiq(void) |
| { |
| __asm__ volatile ("msr DAIFClr, %0" |
| :: "i" (DAIFCLR_FIQ_BIT) : "memory"); |
| } |
| |
| static ALWAYS_INLINE void disable_fiq(void) |
| { |
| __asm__ volatile ("msr DAIFSet, %0" |
| :: "i" (DAIFSET_FIQ_BIT) : "memory"); |
| } |
| |
| #define sev() __asm__ volatile("sev" : : : "memory") |
| #define wfe() __asm__ volatile("wfe" : : : "memory") |
| #define wfi() __asm__ volatile("wfi" : : : "memory") |
| |
| #define dsb() __asm__ volatile ("dsb sy" ::: "memory") |
| #define dmb() __asm__ volatile ("dmb sy" ::: "memory") |
| #define isb() __asm__ volatile ("isb" ::: "memory") |
| |
| /* Zephyr needs these as well */ |
| #define __ISB() isb() |
| #define __DMB() dmb() |
| #define __DSB() dsb() |
| |
| static inline bool is_el_implemented(unsigned int el) |
| { |
| unsigned int shift; |
| |
| if (el > 3) { |
| return false; |
| } |
| |
| shift = ID_AA64PFR0_EL1_SHIFT * el; |
| |
| return (((read_id_aa64pfr0_el1() >> shift) & ID_AA64PFR0_ELX_MASK) != 0U); |
| } |
| |
| static inline bool is_el_highest_implemented(void) |
| { |
| uint32_t el_highest; |
| uint32_t curr_el; |
| |
| el_highest = read_id_aa64pfr0_el1() & 0xFFFF; |
| el_highest = (31U - __builtin_clz(el_highest)) / 4; |
| |
| curr_el = GET_EL(read_currentel()); |
| |
| if (curr_el < el_highest) |
| return false; |
| |
| return true; |
| } |
| |
| static inline bool is_el2_sec_supported(void) |
| { |
| return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_SEL2_SHIFT) & |
| ID_AA64PFR0_SEL2_MASK) != 0U); |
| } |
| |
| static inline bool is_in_secure_state(void) |
| { |
| /* We cannot read SCR_EL3 from EL2 or EL1 */ |
| return !IS_ENABLED(CONFIG_ARMV8_A_NS); |
| } |
| |
| #endif /* !_ASMLANGUAGE */ |
| |
| #endif /* ZEPHYR_INCLUDE_ARCH_ARM64_LIB_HELPERS_H_ */ |