blob: 84f6b4bb84ca29f9bff2e6ec92f3cd1313952c64 [file] [log] [blame]
From dbc1a218e9837e39cd50dd3c19f603f29a08ddba Mon Sep 17 00:00:00 2001
From: Peter Hoyes <Peter.Hoyes@arm.com>
Date: Wed, 14 Jul 2021 12:44:27 +0100
Subject: [PATCH 4/9] armv8: ARMV8_SWITCH_TO_EL1 improvements
Convert CONFIG_ARMV8_SWITCH_TO_EL1 to a Kconfig variable.
Add support for switching to EL1 to bootefi.
Add the environment variable armv8_switch_to_el1 to allow configuring
whether to switch to EL1 at runtime. This overrides the compile-time
option.
Issue-Id: SCM-3728
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Peter Hoyes <Peter.Hoyes@arm.com>
Change-Id: If98478148d6d8d1f732acac5439276700614815f
---
arch/arm/cpu/armv8/Kconfig | 8 +++++++
arch/arm/cpu/armv8/exception_level.c | 21 ++++++++++++++--
arch/arm/lib/bootm.c | 36 ++++++++++++++++------------
configs/vexpress_aemv8r_defconfig | 1 +
4 files changed, 49 insertions(+), 17 deletions(-)
diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig
index 031faa909c..110adf63b3 100644
--- a/arch/arm/cpu/armv8/Kconfig
+++ b/arch/arm/cpu/armv8/Kconfig
@@ -191,4 +191,12 @@ config ARMV8_EA_EL3_FIRST
Exception handling at all exception levels for External Abort and
SError interrupt exception are taken in EL3.
+config ARMV8_SWITCH_TO_EL1
+ bool "Switch to EL1 before booting the operating system"
+ default n
+ help
+ Switch to EL1 before booting the operating system, if for example the
+ operating system does not support booting at EL2, or you wish to prevent
+ any hypervisors from running. Supported for bootm, booti and bootefi.
+
endif
diff --git a/arch/arm/cpu/armv8/exception_level.c b/arch/arm/cpu/armv8/exception_level.c
index b11936548f..4aad1550f4 100644
--- a/arch/arm/cpu/armv8/exception_level.c
+++ b/arch/arm/cpu/armv8/exception_level.c
@@ -40,19 +40,36 @@ static void entry_non_secure(struct jmp_buf_data *non_secure_jmp)
* trusted firmware being one embodiment). The operating system shall be
* started at exception level EL2. So here we check the exception level
* and switch it if necessary.
+ *
+ * If armv8_switch_to_el1 (config or env var) is enabled, also switch to EL1
+ * before booting the operating system.
*/
void switch_to_non_secure_mode(void)
{
struct jmp_buf_data non_secure_jmp;
/* On AArch64 we need to make sure we call our payload in < EL3 */
- if (current_el() == 3) {
+
+ int switch_to_el1 = env_get_yesno("armv8_switch_to_el1");
+#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+ if (switch_to_el1 == -1) {
+ switch_to_el1 = 1;
+ }
+#endif
+
+ if (current_el() > 2) {
if (setjmp(&non_secure_jmp))
return;
dcache_disable(); /* flush cache before switch to EL2 */
-
/* Move into EL2 and keep running there */
armv8_switch_to_el2((uintptr_t)&non_secure_jmp, 0, 0, 0,
(uintptr_t)entry_non_secure, ES_TO_AARCH64);
+ } else if (switch_to_el1 == 1 && current_el() > 1) {
+ if (setjmp(&non_secure_jmp))
+ return;
+ dcache_disable(); /* flush cache before switch to EL1 */
+ /* Move into EL1 and keep running there */
+ armv8_switch_to_el1((uintptr_t)&non_secure_jmp, 0, 0, 0,
+ (uintptr_t)entry_non_secure, ES_TO_AARCH64);
}
}
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index a59a5e6c0e..e2cf2e6ec4 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -272,7 +272,6 @@ __weak void update_os_arch_secondary_cores(uint8_t os_arch)
{
}
-#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
static void switch_to_el1(void)
{
if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
@@ -287,7 +286,6 @@ static void switch_to_el1(void)
ES_TO_AARCH64);
}
#endif
-#endif
/* Subcommand: GO */
static void boot_jump_linux(bootm_headers_t *images, int flag)
@@ -314,21 +312,29 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
update_os_arch_secondary_cores(images->os.arch);
+ int armv8_switch_to_el1 = env_get_yesno("armv8_switch_to_el1");
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
- armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
- (u64)switch_to_el1, ES_TO_AARCH64);
-#else
- if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
- (images->os.arch == IH_ARCH_ARM))
- armv8_switch_to_el2(0, (u64)gd->bd->bi_arch_number,
- (u64)images->ft_addr, 0,
- (u64)images->ep,
- ES_TO_AARCH32);
- else
- armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
- images->ep,
- ES_TO_AARCH64);
+ if (armv8_switch_to_el1 == -1) {
+ armv8_switch_to_el1 = 1;
+ }
#endif
+ if (armv8_switch_to_el1 == 1) {
+ armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
+ (u64)switch_to_el1, ES_TO_AARCH64);
+ } else {
+ if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
+ (images->os.arch == IH_ARCH_ARM))
+ armv8_switch_to_el2(0,
+ (u64)gd->bd->bi_arch_number,
+ (u64)images->ft_addr, 0,
+ (u64)images->ep,
+ ES_TO_AARCH32);
+ else
+ armv8_switch_to_el2((u64)images->ft_addr,
+ 0, 0, 0,
+ images->ep,
+ ES_TO_AARCH64);
+ }
}
#else
unsigned long machid = gd->bd->bi_arch_number;
diff --git a/configs/vexpress_aemv8r_defconfig b/configs/vexpress_aemv8r_defconfig
index 1d5b7411f0..35e5e8a5e1 100644
--- a/configs/vexpress_aemv8r_defconfig
+++ b/configs/vexpress_aemv8r_defconfig
@@ -14,3 +14,4 @@ CONFIG_SYS_PROMPT="VExpress64# "
# CONFIG_MMC is not set
CONFIG_VIRTIO_MMIO=y
CONFIG_ARMV8_EXCEPTION_VECTORS=n
+CONFIG_ARMV8_SWITCH_TO_EL1=y
--
2.25.1