diff options
author | David Milosevic <David.Milosevic@9elements.com> | 2023-04-27 02:12:31 +0200 |
---|---|---|
committer | Werner Zeh <werner.zeh@siemens.com> | 2024-04-22 07:35:36 +0000 |
commit | 41ba11229a80eb19d97c8052aff1861478ee2486 (patch) | |
tree | 9b6f1803e5854e577a68959e679187e8e4c88c3c /src/arch/arm64/include/armv8 | |
parent | 93cbbbfc7f32f62b1d20027541122c17e575ced6 (diff) |
arch/arm64: Add EL1/EL2/EL3 support for arm64
Currently, arch/arm64 requires coreboot to run on EL3 due
to EL3 register access. This might be an issue when, for example,
one boots into TF-A first and drops into EL2 for coreboot afterwards.
This patch aims at making arch/arm64 more versatile by removing the
current EL3 constraint and allowing arm64 coreboot to run on EL1,
EL2 and EL3.
The strategy here, is to add a Kconfig option (ARM64_CURRENT_EL) which
lets us specify coreboot's EL upon entry. Based on that, we access the
appropriate ELx registers. So, for example, when running coreboot on
EL1, we would not access vbar_el3 or vbar_el2 but instead vbar_el1.
This way, we don't generate faults when accessing higher-EL registers.
Currently only tested on the qemu-aarch64 target. Exceptions were
tested by enabling FATAL_ASSERTS.
Signed-off-by: David Milosevic <David.Milosevic@9elements.com>
Change-Id: Iae1c57f0846c8d0585384f7e54102a837e701e7e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/74798
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: ron minnich <rminnich@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'src/arch/arm64/include/armv8')
-rw-r--r-- | src/arch/arm64/include/armv8/arch/cache.h | 3 | ||||
-rw-r--r-- | src/arch/arm64/include/armv8/arch/lib_helpers.h | 51 |
2 files changed, 52 insertions, 2 deletions
diff --git a/src/arch/arm64/include/armv8/arch/cache.h b/src/arch/arm64/include/armv8/arch/cache.h index 3a72d40c7a..5097196308 100644 --- a/src/arch/arm64/include/armv8/arch/cache.h +++ b/src/arch/arm64/include/armv8/arch/cache.h @@ -55,7 +55,8 @@ unsigned int dcache_line_bytes(void); static inline void tlb_invalidate_all(void) { /* TLBIALL includes dTLB and iTLB on systems that have them. */ - tlbiall_el3(); + + tlbiall(); dsb(); isb(); } diff --git a/src/arch/arm64/include/armv8/arch/lib_helpers.h b/src/arch/arm64/include/armv8/arch/lib_helpers.h index ff3459a91e..cb6c2abb3d 100644 --- a/src/arch/arm64/include/armv8/arch/lib_helpers.h +++ b/src/arch/arm64/include/armv8/arch/lib_helpers.h @@ -113,10 +113,49 @@ : : "r" (value) : "memory"); \ } +/* + * In order to allow easy access to current EL's registers, + * we export following two functions for each EL register, that + * was passed to the MAKE_REGISTER_ACCESSORS_CURRENT_EL macro. Doing + * that, eliminates, or at least hides, repetitive branching on the + * current EL across the arm64 codebase. + * + * MAKE_REGISTER_ACCESSORS_CURRENT_EL was hooked into MAKE_REGISTER_ACCESSORS_EL123, + * in order to automatically generate current_el accessors only for registers which + * exist on EL1, EL2 and EL3. + * + * Note, that we don't handle EL0 here, as most of the defined registers do not + * have an EL0 variant (see MAKE_REGISTER_ACCESSORS_EL123). + * + * Important: + * - target register should be specified without the '_elx' suffix + * - only registers which exist in EL1, EL2 and EL3 should be passed + * to the MAKE_REGISTER_ACCESSORS_CURRENT_EL macro + */ +#define MAKE_REGISTER_ACCESSORS_CURRENT_EL(reg) \ + static inline uint64_t raw_read_##reg(void) \ + { \ + if (CONFIG_ARM64_CURRENT_EL == EL1) \ + return raw_read_##reg##_el1(); \ + else if (CONFIG_ARM64_CURRENT_EL == EL2) \ + return raw_read_##reg##_el2(); \ + return raw_read_##reg##_el3(); \ + } \ + static inline void raw_write_##reg(uint64_t value) \ + { \ + if (CONFIG_ARM64_CURRENT_EL == EL1) \ + raw_write_##reg##_el1(value); \ + else if (CONFIG_ARM64_CURRENT_EL == EL2) \ + raw_write_##reg##_el2(value); \ + else \ + raw_write_##reg##_el3(value); \ + } + #define MAKE_REGISTER_ACCESSORS_EL123(reg) \ MAKE_REGISTER_ACCESSORS(reg##_el1) \ MAKE_REGISTER_ACCESSORS(reg##_el2) \ - MAKE_REGISTER_ACCESSORS(reg##_el3) + MAKE_REGISTER_ACCESSORS(reg##_el3) \ + MAKE_REGISTER_ACCESSORS_CURRENT_EL(reg) /* Architectural register accessors */ MAKE_REGISTER_ACCESSORS_EL123(actlr) @@ -318,6 +357,16 @@ static inline void tlbiall_el3(void) __asm__ __volatile__("tlbi alle3\n\t" : : : "memory"); } +static inline void tlbiall(void) +{ + if (CONFIG_ARM64_CURRENT_EL == EL1) + tlbiall_el1(); + else if (CONFIG_ARM64_CURRENT_EL == EL2) + tlbiall_el2(); + else + tlbiall_el3(); +} + static inline void tlbiallis_el1(void) { __asm__ __volatile__("tlbi alle1is\n\t" : : : "memory"); |