[U-Boot] [PATCH v4 0/5] efi_loader: ARM: add support for ARMV7_NONSEC=y

This series makes it possible to run EFI applications in non-secure mode. It allows me to run OpenBSD on the Technexion PICO-PI-IMX7 and Banana Pi boards using the PSCI implementation provided by U-Boot.
The second version avoids using r3 to pass the original stack pointer. For some reason that register gets clobbered on the Banana Pi. Instead this version just migrates SP_svc to SP_hyp.
The third version avoids saving r3 on the stack and fixes an include guard as suggested by Alexander Graf.
This fourth version enables ARMV7_LPAE if HYP mode is supported sych that we enable the MMU and caches in HYP mode. It also makes sure we don't attempt to enter non-secure mode twice if we execute a 2nd EFI payload.
Mark Kettenis (5): ARM: HYP/non-sec: migrate stack efi_loader: ARM: run EFI payloads non-secure efi_loader: ARM: don't attempt to enter non-secure mode twice ARM: HYP/non-sec: enable ARMV7_LPAE if HYP mode is supported Revert "efi_loader: no support for ARMV7_NONSEC=y"
arch/arm/cpu/armv7/Kconfig | 2 +- arch/arm/cpu/armv7/nonsec_virt.S | 2 ++ cmd/bootefi.c | 36 ++++++++++++++++++++++++++++++++++++ doc/README.uefi | 2 -- lib/efi_loader/Kconfig | 2 -- 5 files changed, 39 insertions(+), 5 deletions(-)

The current code that switches into HYP mode doesn't bother to set up a stack for HYP mode. This doesn't work for EFI applications as they expect a usable stack. Fix this by migrating the stack pointer from SP_svc to SP_hyp while in Monitor mode. This restores the stack pointer when we drop into HYP mode.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- arch/arm/cpu/armv7/nonsec_virt.S | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S index 56bdba1d38..1773fae205 100644 --- a/arch/arm/cpu/armv7/nonsec_virt.S +++ b/arch/arm/cpu/armv7/nonsec_virt.S @@ -80,6 +80,8 @@ _secure_monitor: #ifdef CONFIG_ARMV7_VIRT orreq r5, r5, #0x100 @ allow HVC instruction moveq r6, #HYP_MODE @ Enter the kernel as HYP + mrseq r3, sp_svc + msreq sp_hyp, r3 @ migrate SP #endif
mcr p15, 0, r5, c1, c1, 0 @ write SCR (with NS bit set)

The current code that switches into HYP mode doesn't bother to set up a stack for HYP mode. This doesn't work for EFI applications as they expect a usable stack. Fix this by migrating the stack pointer from SP_svc to SP_hyp while in Monitor mode. This restores the stack pointer when we drop into HYP mode.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
Thanks, applied to efi-next
Alex

If desired (and possible) switch into HYP mode or non-secure SVC mode before calling the entry point of an EFI application. This allows U-Boot to provide a usable PSCI implementation and makes it possible to boot kernels into hypervisor mode using an EFI bootloader.
Based on diffs from Heinrich Schuchardt and Alexander Graf.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- cmd/bootefi.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 707d159bac..12a6b84ce6 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -20,6 +20,11 @@ #include <asm-generic/unaligned.h> #include <linux/linkage.h>
+#ifdef CONFIG_ARMV7_NONSEC +#include <asm/armv7.h> +#include <asm/secure.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
#define OBJ_LIST_NOT_INITIALIZED 1 @@ -189,6 +194,18 @@ static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)( } #endif
+#ifdef CONFIG_ARMV7_NONSEC +static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)( + efi_handle_t image_handle, struct efi_system_table *st), + efi_handle_t image_handle, struct efi_system_table *st) +{ + /* Enable caches again */ + dcache_enable(); + + return efi_do_enter(image_handle, st, entry); +} +#endif + /* Carve out DT reserved memory ranges */ static efi_status_t efi_carve_out_dt_rsv(void *fdt) { @@ -338,6 +355,21 @@ static efi_status_t do_bootefi_exec(void *efi, } #endif
+#ifdef CONFIG_ARMV7_NONSEC + if (armv7_boot_nonsec()) { + dcache_disable(); /* flush cache before switch to HYP */ + + armv7_init_nonsec(); + secure_ram_addr(_do_nonsec_entry)(efi_run_in_hyp, + (uintptr_t)entry, + (uintptr_t)loaded_image_info_obj.handle, + (uintptr_t)&systab); + + /* Should never reach here, efi exits with longjmp */ + while (1) { } + } +#endif + ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry);
exit:

If desired (and possible) switch into HYP mode or non-secure SVC mode before calling the entry point of an EFI application. This allows U-Boot to provide a usable PSCI implementation and makes it possible to boot kernels into hypervisor mode using an EFI bootloader.
Based on diffs from Heinrich Schuchardt and Alexander Graf.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
Thanks, applied to efi-next
Alex

Multiple EFI binaries may be executed in sequence. So if we already are in non-secure mode after running the first one we should skip the switching code since it no longer works once we're non-secure.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- cmd/bootefi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 12a6b84ce6..12081cee46 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -195,6 +195,8 @@ static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)( #endif
#ifdef CONFIG_ARMV7_NONSEC +static bool is_nonsec; + static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)( efi_handle_t image_handle, struct efi_system_table *st), efi_handle_t image_handle, struct efi_system_table *st) @@ -202,6 +204,8 @@ static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)( /* Enable caches again */ dcache_enable();
+ is_nonsec = true; + return efi_do_enter(image_handle, st, entry); } #endif @@ -356,7 +360,7 @@ static efi_status_t do_bootefi_exec(void *efi, #endif
#ifdef CONFIG_ARMV7_NONSEC - if (armv7_boot_nonsec()) { + if (armv7_boot_nonsec() && !is_nonsec) { dcache_disable(); /* flush cache before switch to HYP */
armv7_init_nonsec();

Multiple EFI binaries may be executed in sequence. So if we already are in non-secure mode after running the first one we should skip the switching code since it no longer works once we're non-secure.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
Thanks, applied to efi-next
Alex

ARMV7_LPAE is required in order to enable the MMU in HYP mode. And we really want to enable the MMU in HYP mode such that we can enable the the caches. Otherwise U-Boot code (such as the EFI implementation) that runs in HYP mode will run at a snils pace.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- arch/arm/cpu/armv7/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/Kconfig b/arch/arm/cpu/armv7/Kconfig index 37a0be932e..73d57a2aae 100644 --- a/arch/arm/cpu/armv7/Kconfig +++ b/arch/arm/cpu/armv7/Kconfig @@ -53,7 +53,7 @@ config ARMV7_PSCI_NR_CPUS config ARMV7_LPAE bool "Use LPAE page table format" if EXPERT depends on CPU_V7A - default n + default y if ARMV7_VIRT ---help--- Say Y here to use the long descriptor page table format. This is required if U-Boot runs in HYP mode.

ARMV7_LPAE is required in order to enable the MMU in HYP mode. And we really want to enable the MMU in HYP mode such that we can enable the the caches. Otherwise U-Boot code (such as the EFI implementation) that runs in HYP mode will run at a snils pace.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
Thanks, applied to efi-next
Alex

This reverts commit c524997acb3d322e1bbd36c06ad02ef589705e7c.
Booting ARMv7 in non-secure mode using bootefi works now.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- doc/README.uefi | 2 -- lib/efi_loader/Kconfig | 2 -- 2 files changed, 4 deletions(-)
diff --git a/doc/README.uefi b/doc/README.uefi index d4031ef8e8..6b9759cfed 100644 --- a/doc/README.uefi +++ b/doc/README.uefi @@ -329,8 +329,6 @@ This driver is only available if U-Boot is configured with * persistence * runtime support
-* support bootefi booting ARMv7 in non-secure mode (CONFIG_ARMV7_NONSEC=y) - ## Links
* [1](http://uefi.org/specifications) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index df58e633d1..ce6a09f0b4 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -1,8 +1,6 @@ config EFI_LOADER bool "Support running EFI Applications in U-Boot" depends on (ARM || X86 || RISCV) && OF_LIBFDT - # We do not support bootefi booting ARMv7 in non-secure mode - depends on !ARMV7_NONSEC # We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB

This reverts commit c524997acb3d322e1bbd36c06ad02ef589705e7c.
Booting ARMv7 in non-secure mode using bootefi works now.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
Thanks, applied to efi-next
Alex

On 06/15/2018 11:47 PM, Mark Kettenis wrote:
This series makes it possible to run EFI applications in non-secure mode. It allows me to run OpenBSD on the Technexion PICO-PI-IMX7 and Banana Pi boards using the PSCI implementation provided by U-Boot.
The second version avoids using r3 to pass the original stack pointer. For some reason that register gets clobbered on the Banana Pi. Instead this version just migrates SP_svc to SP_hyp.
The third version avoids saving r3 on the stack and fixes an include guard as suggested by Alexander Graf.
This fourth version enables ARMV7_LPAE if HYP mode is supported sych that we enable the MMU and caches in HYP mode. It also makes sure we don't attempt to enter non-secure mode twice if we execute a 2nd EFI payload.
Mark Kettenis (5): ARM: HYP/non-sec: migrate stack efi_loader: ARM: run EFI payloads non-secure efi_loader: ARM: don't attempt to enter non-secure mode twice ARM: HYP/non-sec: enable ARMV7_LPAE if HYP mode is supported Revert "efi_loader: no support for ARMV7_NONSEC=y"
arch/arm/cpu/armv7/Kconfig | 2 +- arch/arm/cpu/armv7/nonsec_virt.S | 2 ++ cmd/bootefi.c | 36 ++++++++++++++++++++++++++++++++++++ doc/README.uefi | 2 -- lib/efi_loader/Kconfig | 2 -- 5 files changed, 39 insertions(+), 5 deletions(-)
Hello Mark,
I have built with your 5 patches added to git master (f58e779513be36e30ce46838fb467e12ac6a5539).
With your patch series iPXE starts normally.
In iPXE I can use network commands ping and nslookup.
I was not able to boot via iSCSI but I have the same problem without your patches 1-4.
Best regards
Heinrich
participants (3)
-
Alexander Graf
-
Heinrich Schuchardt
-
Mark Kettenis