summaryrefslogtreecommitdiff
path: root/src/arch/arm64/include/armv8
diff options
context:
space:
mode:
authorDavid Milosevic <David.Milosevic@9elements.com>2023-04-27 02:12:31 +0200
committerWerner Zeh <werner.zeh@siemens.com>2024-04-22 07:35:36 +0000
commit41ba11229a80eb19d97c8052aff1861478ee2486 (patch)
tree9b6f1803e5854e577a68959e679187e8e4c88c3c /src/arch/arm64/include/armv8
parent93cbbbfc7f32f62b1d20027541122c17e575ced6 (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.h3
-rw-r--r--src/arch/arm64/include/armv8/arch/lib_helpers.h51
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");