[PATCH 00/35] efi: Improvements to U-Boot running on top of UEFI

At present U-Boot can be built as an EFI app, but it is really just for testing, with very few features. Instead, the payload build is used for booting on top of UEFI, where U-Boot takes over the machine immediately and supplies its own drivers.
But the app could be made more useful.
This series provides access to EFI block devices and the video console within U-Boot. It also restructures the app to make it possible to boot a kernel, although further work is needed to implement this.
This can be thought of as making U-Boot perform a little like 'grub', in that it runs purely based on UEFI-provided services.
Of course a lot more work is required, but this is a start.
Note: It would be very useful to include qemu tests of the app and stub in CI.
This is available at u-boot-dm/efi-working
Simon Glass (35): x86: Keep symbol information in u-boot ELF file x86: Create a new header for EFI x86: Show some EFI info with the bdinfo command x86: Tidy up global_data pointer for 64-bit efi: Add a script for building and testing U-Boot on UEFI x86: Create a 32/64-bit selection for the app efi: Create a 64-bit app x86: Don't duplicate global_ptr in 64-bit EFI app efi: Add a way to obtain boot services in the app efi: Add video support to the app RFC: efi: Drop code that doesn't work with driver model efi: Add EFI uclass for media efi: Add a media/block driver for EFI block devices efi: Locate all block devices in the app patman: Use a ValueError exception if tools.Run() fails binman: Report an error if test files fail to compile binman: Support reading the offset of an ELF-file symbol binman: Allow timeout to occur in the image or its section binman: Tidy up comments on _DoTestFile() binman: Support updating the dtb in an ELF file efi: serial: Support arrow keys bloblist: Move to rST format bloblist: Support allocating the bloblist x86: Allow booting a kernel from the EFI app x86: Don't process the kernel command line unless enabled x86: efi: Add room for the binman definition in the dtb efi: Add comments to struct efi_priv efi: Fix ll_boot_init() operation with the app efi: Add a few comments to the stub efi: Share struct efi_priv between the app and stub code efi: Move exit_boot_services into a function efi: Check for failure when initing the app efi: Mention that efi_info_get() is only used in the stub efi: Show when allocated pages are used efi: Allow easy selection of serial-only operation
arch/sandbox/dts/test.dts | 4 + arch/x86/config.mk | 4 +- arch/x86/cpu/efi/payload.c | 13 +- arch/x86/cpu/intel_common/Makefile | 2 +- arch/x86/cpu/u-boot-64.lds | 2 + arch/x86/cpu/x86_64/Makefile | 4 + arch/x86/cpu/x86_64/cpu.c | 32 +--- arch/x86/cpu/x86_64/misc.c | 41 ++++++ arch/x86/dts/Makefile | 2 +- arch/x86/dts/efi-x86_app.dts | 4 + arch/x86/include/asm/efi.h | 39 +++++ arch/x86/include/asm/global_data.h | 2 + arch/x86/include/asm/zimage.h | 3 - arch/x86/lib/Makefile | 1 + arch/x86/lib/bdinfo.c | 22 +++ arch/x86/lib/bootm.c | 11 +- arch/x86/lib/zimage.c | 14 +- board/efi/Kconfig | 15 +- board/efi/efi-x86_app/Kconfig | 6 +- board/efi/efi-x86_app/MAINTAINERS | 11 +- common/Kconfig | 15 +- common/bloblist.c | 16 +- common/board_f.c | 8 +- ..._app_defconfig => efi-x86_app32_defconfig} | 2 +- configs/efi-x86_app64_defconfig | 39 +++++ doc/{README.bloblist => develop/bloblist.rst} | 20 ++- doc/develop/index.rst | 1 + doc/develop/uefi/u-boot_on_efi.rst | 8 +- drivers/block/Kconfig | 33 +++++ drivers/block/Makefile | 4 + drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 ++ drivers/block/efi_blk.c | 115 +++++++++++++++ drivers/block/sb_efi_media.c | 21 +++ drivers/serial/serial_efi.c | 11 +- drivers/video/Kconfig | 2 +- drivers/video/efi.c | 45 +++++- include/configs/efi-x86_app.h | 31 +++- include/dm/uclass-id.h | 1 + include/efi.h | 117 ++++++++++++++- include/efi_api.h | 15 ++ include/init.h | 2 +- lib/efi/Kconfig | 34 ++++- lib/efi/efi.c | 108 ++++++++++++++ lib/efi/efi_app.c | 139 ++++++++++++++++-- lib/efi/efi_stub.c | 95 +++++------- lib/efi_driver/Makefile | 2 +- lib/efi_loader/Kconfig | 2 + lib/efi_loader/efi_device_path.c | 96 +++--------- lib/efi_loader/efi_disk.c | 48 ------ scripts/build-efi.sh | 111 ++++++++++++++ test/dm/Makefile | 1 + test/dm/efi_media.c | 24 +++ tools/binman/binman.rst | 36 +++++ tools/binman/cmdline.py | 2 + tools/binman/control.py | 11 ++ tools/binman/elf.py | 74 +++++++++- tools/binman/elf_test.py | 45 +++++- tools/binman/ftest.py | 91 +++++++++++- tools/binman/test/Makefile | 13 +- tools/binman/test/bss_data.c | 2 +- tools/binman/test/embed_data.c | 16 ++ tools/binman/test/embed_data.lds | 23 +++ tools/binman/test/u_boot_binman_embed.c | 13 ++ tools/binman/test/u_boot_binman_embed.lds | 29 ++++ tools/binman/test/u_boot_binman_embed_sm.c | 13 ++ tools/patman/tools.py | 2 +- 67 files changed, 1492 insertions(+), 293 deletions(-) create mode 100644 arch/x86/cpu/x86_64/misc.c create mode 100644 arch/x86/include/asm/efi.h create mode 100644 arch/x86/lib/bdinfo.c rename configs/{efi-x86_app_defconfig => efi-x86_app32_defconfig} (97%) create mode 100644 configs/efi-x86_app64_defconfig rename doc/{README.bloblist => develop/bloblist.rst} (77%) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/efi_blk.c create mode 100644 drivers/block/sb_efi_media.c create mode 100755 scripts/build-efi.sh create mode 100644 test/dm/efi_media.c create mode 100644 tools/binman/test/embed_data.c create mode 100644 tools/binman/test/embed_data.lds create mode 100644 tools/binman/test/u_boot_binman_embed.c create mode 100644 tools/binman/test/u_boot_binman_embed.lds create mode 100644 tools/binman/test/u_boot_binman_embed_sm.c

At present this information is stripped when linking. It is useful to keep it around. Strip it from the .efi files instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/config.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 7a8242562db..589f2aed2bc 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -37,7 +37,7 @@ KBUILD_LDFLAGS += -m $(if $(IS_32BIT),elf_i386,elf_x86_64) LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined -s
OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ - -j .rel -j .rela -j .reloc + -j .rel -j .rela -j .reloc --strip-all
# Compiler flags to be added when building UEFI applications CFLAGS_EFI := -fpic -fshort-wchar @@ -65,7 +65,7 @@ CPPFLAGS_crt0-efi-$(EFIARCH).o += $(CFLAGS_EFI) ifeq ($(CONFIG_EFI_APP),y)
PLATFORM_CPPFLAGS += $(CFLAGS_EFI) -LDFLAGS_FINAL += -znocombreloc -shared -s +LDFLAGS_FINAL += -znocombreloc -shared LDSCRIPT := $(LDSCRIPT_EFI)
else

The setup routines are called from zimage but don't really belong in the zimage header. Add a new EFI header to house these. Add comments so it is clear what the functions do.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/efi.h | 32 ++++++++++++++++++++++++++++++++ arch/x86/include/asm/zimage.h | 3 --- arch/x86/lib/zimage.c | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 arch/x86/include/asm/efi.h
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h new file mode 100644 index 00000000000..c1735e4dc5f --- /dev/null +++ b/arch/x86/include/asm/efi.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright Google LLC + */ + +#ifndef _ASM_EFI_H_ +#define _ASM_EFI_H_ + +struct efi_info; +struct screen_info; + +/** + * setup_video() - Set up the screen info in the x86 setup + * + * This is needed so Linux can use the display (when U-Boot is an EFI payload) + * + * @efi_info: Pointer to place to put the screen info in the x86 setup base + */ +void setup_video(struct screen_info *screen_info); + +/** + * setup_efi_info() - Set up the EFI info needed by Linux to boot + * + * This writes a suitable signature, table pointers, memory-map pointer, etc. + * These are needed for Linux to boot from U-Boot (when U-Boot is an EFI + * payload). + * + * @efi_info: Pointer to place to put the EFI info in the x86 setup base + */ +void setup_efi_info(struct efi_info *efi_info); + +#endif diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 6679767d16b..fa6e7f76e05 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -72,7 +72,4 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, */ void zimage_dump(struct boot_params *base_ptr);
-void setup_video(struct screen_info *screen_info); -void setup_efi_info(struct efi_info *efi_info); - #endif diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 9938c80a42b..7ce02226ef9 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -29,6 +29,7 @@ #include <asm/byteorder.h> #include <asm/bootm.h> #include <asm/bootparam.h> +#include <asm/efi.h> #include <asm/global_data.h> #ifdef CONFIG_SYS_COREBOOT #include <asm/arch/timestamp.h>

On 9/8/21 3:33 PM, Simon Glass wrote:
The setup routines are called from zimage but don't really belong in the zimage header. Add a new EFI header to house these. Add comments so it is clear what the functions do.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/efi.h | 32 ++++++++++++++++++++++++++++++++ arch/x86/include/asm/zimage.h | 3 --- arch/x86/lib/zimage.c | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 arch/x86/include/asm/efi.h
In the future we should be able to run the EFI app on any UEFI architecture. Given this background are the function definitions really x86 specific?
Best regards
Heinrich
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h new file mode 100644 index 00000000000..c1735e4dc5f --- /dev/null +++ b/arch/x86/include/asm/efi.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright Google LLC
- */
+#ifndef _ASM_EFI_H_ +#define _ASM_EFI_H_
+struct efi_info; +struct screen_info;
+/**
- setup_video() - Set up the screen info in the x86 setup
- This is needed so Linux can use the display (when U-Boot is an EFI payload)
- @efi_info: Pointer to place to put the screen info in the x86 setup base
- */
+void setup_video(struct screen_info *screen_info);
+/**
- setup_efi_info() - Set up the EFI info needed by Linux to boot
- This writes a suitable signature, table pointers, memory-map pointer, etc.
- These are needed for Linux to boot from U-Boot (when U-Boot is an EFI
- payload).
- @efi_info: Pointer to place to put the EFI info in the x86 setup base
- */
+void setup_efi_info(struct efi_info *efi_info);
+#endif diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 6679767d16b..fa6e7f76e05 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -72,7 +72,4 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, */ void zimage_dump(struct boot_params *base_ptr);
-void setup_video(struct screen_info *screen_info); -void setup_efi_info(struct efi_info *efi_info);
- #endif
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 9938c80a42b..7ce02226ef9 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -29,6 +29,7 @@ #include <asm/byteorder.h> #include <asm/bootm.h> #include <asm/bootparam.h> +#include <asm/efi.h> #include <asm/global_data.h> #ifdef CONFIG_SYS_COREBOOT #include <asm/arch/timestamp.h>

Hi Heinrich,
On Wed, 8 Sept 2021 at 11:27, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
The setup routines are called from zimage but don't really belong in the zimage header. Add a new EFI header to house these. Add comments so it is clear what the functions do.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/efi.h | 32 ++++++++++++++++++++++++++++++++ arch/x86/include/asm/zimage.h | 3 --- arch/x86/lib/zimage.c | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 arch/x86/include/asm/efi.h
In the future we should be able to run the EFI app on any UEFI architecture. Given this background are the function definitions really x86 specific?
Well firstly that seems like that would be future work for someone. Secondly, this relates to zimage which is really only used by x86 as far as I am aware.
Regards, Simon

On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:27, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
The setup routines are called from zimage but don't really belong in the zimage header. Add a new EFI header to house these. Add comments so it is clear what the functions do.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/efi.h | 32 ++++++++++++++++++++++++++++++++ arch/x86/include/asm/zimage.h | 3 --- arch/x86/lib/zimage.c | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 arch/x86/include/asm/efi.h
In the future we should be able to run the EFI app on any UEFI architecture. Given this background are the function definitions really x86 specific?
Well firstly that seems like that would be future work for someone.
I did not expect that you do that work. But we should not make that work more difficult than necessary.
Secondly, this relates to zimage which is really only used by x86 as far as I am aware.
setup_video() and setup_efi_info() do not sound like zImage nor like x86 specific.
Best regards
Heinrich

Hi Heinrich,
On Thu, 9 Sep 2021, 10:25 Heinrich Schuchardt, xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:27, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
The setup routines are called from zimage but don't really belong in the zimage header. Add a new EFI header to house these. Add comments so it is clear what the functions do.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/efi.h | 32 ++++++++++++++++++++++++++++++++ arch/x86/include/asm/zimage.h | 3 --- arch/x86/lib/zimage.c | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 arch/x86/include/asm/efi.h
In the future we should be able to run the EFI app on any UEFI architecture. Given this background are the function definitions really x86 specific?
Well firstly that seems like that would be future work for someone.
I did not expect that you do that work. But we should not make that work more difficult than necessary.
Secondly, this relates to zimage which is really only used by x86 as far as I am aware.
setup_video() and setup_efi_info() do not sound like zImage nor like x86 specific.
But actually they are. Please can you take a closer look? This is just using existing code...
Regards, Simon

It is useful to see some basic EFI info with the command as it forms part of the information about a board.
Add a hook for this and show the table address as a start.
While here, fix an invalid cast in setup_efi_info().
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/efi/payload.c | 13 +++++++++++-- arch/x86/include/asm/efi.h | 7 +++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/bdinfo.c | 22 ++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 arch/x86/lib/bdinfo.c
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index 9a73b768e9b..3a9f7d72868 100644 --- a/arch/x86/cpu/efi/payload.c +++ b/arch/x86/cpu/efi/payload.c @@ -280,15 +280,24 @@ void setup_efi_info(struct efi_info *efi_info) } efi_info->efi_memdesc_size = map->desc_size; efi_info->efi_memdesc_version = map->version; - efi_info->efi_memmap = (u32)(map->desc); + efi_info->efi_memmap = (ulong)(map->desc); efi_info->efi_memmap_size = size - sizeof(struct efi_entry_memmap);
#ifdef CONFIG_EFI_STUB_64BIT efi_info->efi_systab_hi = table->sys_table >> 32; - efi_info->efi_memmap_hi = (u64)(u32)(map->desc) >> 32; + efi_info->efi_memmap_hi = (u64)(ulong)map->desc >> 32; signature = EFI64_LOADER_SIGNATURE; #else signature = EFI32_LOADER_SIGNATURE; #endif memcpy(&efi_info->efi_loader_signature, signature, 4); } + +void efi_show_bdinfo(void) +{ + struct efi_entry_systable *table = NULL; + int size, ret; + + ret = efi_info_get(EFIET_SYS_TABLE, (void **)&table, &size); + bdinfo_print_num_l("efi_table", (ulong)table); +} diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index c1735e4dc5f..dfd858b78ba 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -29,4 +29,11 @@ void setup_video(struct screen_info *screen_info); */ void setup_efi_info(struct efi_info *efi_info);
+/** + * efi_show_bdinfo() - Show information about EFI for the 'bdinfo' command + * + * This looks up the EFI table pointer and shows related info + */ +void efi_show_bdinfo(void); + #endif diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 65d9b3bd6a3..18757b29aa9 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -3,6 +3,7 @@ # (C) Copyright 2002-2006 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+obj-y += bdinfo.o ifndef CONFIG_X86_64 ifndef CONFIG_TPL_BUILD obj-y += bios.o diff --git a/arch/x86/lib/bdinfo.c b/arch/x86/lib/bdinfo.c new file mode 100644 index 00000000000..0cb79b01bd3 --- /dev/null +++ b/arch/x86/lib/bdinfo.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * x86-specific information for the 'bd' command + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <efi.h> +#include <init.h> +#include <asm/efi.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +void arch_print_bdinfo(void) +{ + bdinfo_print_num_l("prev table", gd->arch.table); + + if (IS_ENABLED(CONFIG_EFI_STUB)) + efi_show_bdinfo(); +}

On 9/8/21 3:33 PM, Simon Glass wrote:
It is useful to see some basic EFI info with the command as it forms part of the information about a board.
Add a hook for this and show the table address as a start.
While here, fix an invalid cast in setup_efi_info().
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/efi/payload.c | 13 +++++++++++-- arch/x86/include/asm/efi.h | 7 +++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/bdinfo.c | 22 ++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 arch/x86/lib/bdinfo.c
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index 9a73b768e9b..3a9f7d72868 100644 --- a/arch/x86/cpu/efi/payload.c +++ b/arch/x86/cpu/efi/payload.c @@ -280,15 +280,24 @@ void setup_efi_info(struct efi_info *efi_info) } efi_info->efi_memdesc_size = map->desc_size; efi_info->efi_memdesc_version = map->version;
- efi_info->efi_memmap = (u32)(map->desc);
- efi_info->efi_memmap = (ulong)(map->desc);
When converting a pointer to integer we use (uintptr_t).
arch/x86/include/asm/bootparam.h defines efi_info->efi_memmap as u32. This type is too small to hold a pointer.
efi_info->efi_memmap_size = size - sizeof(struct efi_entry_memmap);
#ifdef CONFIG_EFI_STUB_64BIT efi_info->efi_systab_hi = table->sys_table >> 32;
- efi_info->efi_memmap_hi = (u64)(u32)(map->desc) >> 32;
- efi_info->efi_memmap_hi = (u64)(ulong)map->desc >> 32;
You should not use two fields to hold a single pointer.
Please, replace all of these duplicate fields.
Best regards
Heinrich
signature = EFI64_LOADER_SIGNATURE; #else signature = EFI32_LOADER_SIGNATURE; #endif memcpy(&efi_info->efi_loader_signature, signature, 4); }
+void efi_show_bdinfo(void) +{
- struct efi_entry_systable *table = NULL;
- int size, ret;
- ret = efi_info_get(EFIET_SYS_TABLE, (void **)&table, &size);
- bdinfo_print_num_l("efi_table", (ulong)table);
+} diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index c1735e4dc5f..dfd858b78ba 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -29,4 +29,11 @@ void setup_video(struct screen_info *screen_info); */ void setup_efi_info(struct efi_info *efi_info);
+/**
- efi_show_bdinfo() - Show information about EFI for the 'bdinfo' command
- This looks up the EFI table pointer and shows related info
- */
+void efi_show_bdinfo(void);
- #endif
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 65d9b3bd6a3..18757b29aa9 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -3,6 +3,7 @@ # (C) Copyright 2002-2006 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+obj-y += bdinfo.o ifndef CONFIG_X86_64 ifndef CONFIG_TPL_BUILD obj-y += bios.o diff --git a/arch/x86/lib/bdinfo.c b/arch/x86/lib/bdinfo.c new file mode 100644 index 00000000000..0cb79b01bd3 --- /dev/null +++ b/arch/x86/lib/bdinfo.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- x86-specific information for the 'bd' command
- Copyright 2021 Google LLC
- */
+#include <common.h> +#include <efi.h> +#include <init.h> +#include <asm/efi.h> +#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
+void arch_print_bdinfo(void) +{
- bdinfo_print_num_l("prev table", gd->arch.table);
- if (IS_ENABLED(CONFIG_EFI_STUB))
efi_show_bdinfo();
+}

Hi Heinrich,
On Wed, 8 Sept 2021 at 11:34, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
It is useful to see some basic EFI info with the command as it forms part of the information about a board.
Add a hook for this and show the table address as a start.
While here, fix an invalid cast in setup_efi_info().
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/efi/payload.c | 13 +++++++++++-- arch/x86/include/asm/efi.h | 7 +++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/bdinfo.c | 22 ++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 arch/x86/lib/bdinfo.c
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index 9a73b768e9b..3a9f7d72868 100644 --- a/arch/x86/cpu/efi/payload.c +++ b/arch/x86/cpu/efi/payload.c @@ -280,15 +280,24 @@ void setup_efi_info(struct efi_info *efi_info) } efi_info->efi_memdesc_size = map->desc_size; efi_info->efi_memdesc_version = map->version;
efi_info->efi_memmap = (u32)(map->desc);
efi_info->efi_memmap = (ulong)(map->desc);
When converting a pointer to integer we use (uintptr_t).
Generally in U-Boot it is ulong so I try to be consistent here. Anyway, u32 is clearly not right for a 64-bit build as it gives warnings.
arch/x86/include/asm/bootparam.h defines efi_info->efi_memmap as u32. This type is too small to hold a pointer.
efi_info->efi_memmap_size = size - sizeof(struct efi_entry_memmap);
#ifdef CONFIG_EFI_STUB_64BIT efi_info->efi_systab_hi = table->sys_table >> 32;
efi_info->efi_memmap_hi = (u64)(u32)(map->desc) >> 32;
efi_info->efi_memmap_hi = (u64)(ulong)map->desc >> 32;
You should not use two fields to hold a single pointer.
Please, replace all of these duplicate fields.
We do need to be compatible with what the kernel expects, otherwise there is no point in filling out this information.
Regards, Simon

On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:34, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
It is useful to see some basic EFI info with the command as it forms part of the information about a board.
Add a hook for this and show the table address as a start.
While here, fix an invalid cast in setup_efi_info().
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/efi/payload.c | 13 +++++++++++-- arch/x86/include/asm/efi.h | 7 +++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/bdinfo.c | 22 ++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 arch/x86/lib/bdinfo.c
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index 9a73b768e9b..3a9f7d72868 100644 --- a/arch/x86/cpu/efi/payload.c +++ b/arch/x86/cpu/efi/payload.c @@ -280,15 +280,24 @@ void setup_efi_info(struct efi_info *efi_info) } efi_info->efi_memdesc_size = map->desc_size; efi_info->efi_memdesc_version = map->version;
efi_info->efi_memmap = (u32)(map->desc);
efi_info->efi_memmap = (ulong)(map->desc);
When converting a pointer to integer we use (uintptr_t).
Generally in U-Boot it is ulong so I try to be consistent here.
Currently ulong and uintprt_t are the same technically. But for the sake of readability uintptr_t is much clearer.
We use uintptr_t in 935 code locations already. Just grep for it.
Anyway, u32 is clearly not right for a 64-bit build as it gives warnings.
arch/x86/include/asm/bootparam.h defines efi_info->efi_memmap as u32. This type is too small to hold a pointer.
efi_info->efi_memmap_size = size - sizeof(struct efi_entry_memmap);
#ifdef CONFIG_EFI_STUB_64BIT efi_info->efi_systab_hi = table->sys_table >> 32;
efi_info->efi_memmap_hi = (u64)(u32)(map->desc) >> 32;
efi_info->efi_memmap_hi = (u64)(ulong)map->desc >> 32;
You should not use two fields to hold a single pointer.
Please, replace all of these duplicate fields.
We do need to be compatible with what the kernel expects, otherwise there is no point in filling out this information.
Why should we have separate fields for the low and high 32 bits of a pointer?
Best regards
Heinrich

Hi Heinrich,
On Thu, 9 Sept 2021 at 03:34, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:34, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
It is useful to see some basic EFI info with the command as it forms part of the information about a board.
Add a hook for this and show the table address as a start.
While here, fix an invalid cast in setup_efi_info().
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/efi/payload.c | 13 +++++++++++-- arch/x86/include/asm/efi.h | 7 +++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/bdinfo.c | 22 ++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 arch/x86/lib/bdinfo.c
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index 9a73b768e9b..3a9f7d72868 100644 --- a/arch/x86/cpu/efi/payload.c +++ b/arch/x86/cpu/efi/payload.c @@ -280,15 +280,24 @@ void setup_efi_info(struct efi_info *efi_info) } efi_info->efi_memdesc_size = map->desc_size; efi_info->efi_memdesc_version = map->version;
efi_info->efi_memmap = (u32)(map->desc);
efi_info->efi_memmap = (ulong)(map->desc);
When converting a pointer to integer we use (uintptr_t).
Generally in U-Boot it is ulong so I try to be consistent here.
Currently ulong and uintprt_t are the same technically. But for the sake of readability uintptr_t is much clearer.
We use uintptr_t in 935 code locations already. Just grep for it.
$ git grep uintptr_t |wc -l 935 $ git grep ulong |wc -l 6006
Anyway, u32 is clearly not right for a 64-bit build as it gives warnings.
arch/x86/include/asm/bootparam.h defines efi_info->efi_memmap as u32. This type is too small to hold a pointer.
efi_info->efi_memmap_size = size - sizeof(struct efi_entry_memmap);
#ifdef CONFIG_EFI_STUB_64BIT efi_info->efi_systab_hi = table->sys_table >> 32;
efi_info->efi_memmap_hi = (u64)(u32)(map->desc) >> 32;
efi_info->efi_memmap_hi = (u64)(ulong)map->desc >> 32;
You should not use two fields to hold a single pointer.
Please, replace all of these duplicate fields.
We do need to be compatible with what the kernel expects, otherwise there is no point in filling out this information.
Why should we have separate fields for the low and high 32 bits of a pointer?
This patch does not change that...you need to take it up with the Linux project, which created this requirement. We should not rely on endianness being the same between a u64 and two u32 values, if that is what you are asking.
But in any case, why do you insist on critiquing code that is already there? By all means send a patch if you want to change it.
But please just review what this patch does.
Regards, Simon

Add an extern declaration so that it is possible to use this macro in files other than the one that defines it.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/x86_64/cpu.c | 3 +++ arch/x86/include/asm/global_data.h | 2 ++ 2 files changed, 5 insertions(+)
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index 90a766c3c57..e090b1b478a 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -8,6 +8,9 @@ #include <cpu_func.h> #include <debug_uart.h> #include <init.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR;
/* * Global declaration of gd. diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 3e4044593c8..f95fb5a1931 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -133,6 +133,8 @@ struct arch_global_data { #ifndef __ASSEMBLY__ # if defined(CONFIG_EFI_APP) || CONFIG_IS_ENABLED(X86_64)
+extern struct global_data *global_data_ptr; + /* TODO(sjg@chromium.org): Consider using a fixed register for gd on x86_64 */ #define gd global_data_ptr

On 9/8/21 3:33 PM, Simon Glass wrote:
Add an extern declaration so that it is possible to use this macro in files other than the one that defines it.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
arch/x86/cpu/x86_64/cpu.c | 3 +++ arch/x86/include/asm/global_data.h | 2 ++ 2 files changed, 5 insertions(+)
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index 90a766c3c57..e090b1b478a 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -8,6 +8,9 @@ #include <cpu_func.h> #include <debug_uart.h> #include <init.h> +#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
/*
- Global declaration of gd.
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 3e4044593c8..f95fb5a1931 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -133,6 +133,8 @@ struct arch_global_data { #ifndef __ASSEMBLY__ # if defined(CONFIG_EFI_APP) || CONFIG_IS_ENABLED(X86_64)
+extern struct global_data *global_data_ptr;
- /* TODO(sjg@chromium.org): Consider using a fixed register for gd on x86_64 */ #define gd global_data_ptr

It is quite complicating to run U-Boot on qemu since we have four different builds and they must use different versions of qemu and the UEFI binaries.
Add a script to help.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/develop/uefi/u-boot_on_efi.rst | 4 ++ scripts/build-efi.sh | 111 +++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100755 scripts/build-efi.sh
diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index c9a41bc919f..59ee3885295 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -96,6 +96,10 @@ that EFI does not support booting a 64-bit application from a 32-bit EFI (or vice versa). Also it will often fail to print an error message if you get this wrong.
+You may find the script `scripts/build-efi.sh` helpful for building and testing +U-Boot on UEFI on QEMU. It also includes links to UEFI binaries dating from +2021. +
Inner workings -------------- diff --git a/scripts/build-efi.sh b/scripts/build-efi.sh new file mode 100755 index 00000000000..8770c1fb311 --- /dev/null +++ b/scripts/build-efi.sh @@ -0,0 +1,111 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# +# Script to build an EFI thing suitable for booting with qemu, possibly running +# it also. + +# This just an example. It assumes that + +# - you build U-Boot in /tmp/b/<name> where <name> is the U-Boot board config +# - /mnt/x is a directory used for mounting +# - you have access to the 'pure UEFI' builds for qemu +# +# UEFI binaries for QEMU used for testing this script: +# +# OVMF-pure-efi.i386.fd at +# https://drive.google.com/file/d/1jWzOAZfQqMmS2_dAK2G518GhIgj9r2RY/view?usp=s... + +# OVMF-pure-efi.x64.fd at +# https://drive.google.com/file/d/1c39YI9QtpByGQ4V0UNNQtGqttEzS-eFV/view?usp=s... + +set -e + +usage() { + echo "Usage: $0 [-a | -p]" 1>&2 + echo 1>&2 + echo " -a - Package up the app" 1>&2 + echo " -o - Use old EFI app build (before 32/64 split)" 1>&2 + echo " -p - Package up the payload" 1>&2 + echo " -r - Run qemu with the image" 1>&2 + echo " -w - Use word version (32-bit)" 1>&2 + exit 1 +} + +# 32- or 64-bit EFI +bitness=64 + +# app or payload ? +type=app + +# run the image with qemu +run= + +# before the 32/64 split of the app +old= + +while getopts "aoprw" opt; do + case "${opt}" in + a) + type=app + ;; + p) + type=payload + ;; + r) + run=1 + ;; + w) + bitness=32 + ;; + o) + old=1 + ;; + *) + usage + ;; + esac +done + +run_qemu() { + if [[ "${bitness}" = "64" ]]; then + qemu=qemu-system-x86_64 + bios=OVMF-pure-efi.x64.fd + else + qemu=qemu-system-i386 + bios=OVMF-pure-efi.i386.fd + fi + echo "Running ${qemu}" + "${qemu}" -bios "${bios}" \ + -drive id=disk,file=try.img,if=none,format=raw \ + -nic none -device ahci,id=ahci \ + -device ide-hd,drive=disk,bus=ahci.0 +} + +TMP="/tmp/efi${bitness}${type}" +MNT=/mnt/x +BUILD="efi-x86_${type}${bitness}" + +if [[ -n "${old}" && "${bitness}" = "32" ]]; then + BUILD="efi-x86_${type}" +fi + +echo "Packaging ${BUILD}" +qemu-img create try.img 24M >/dev/null +mkfs.vfat try.img >/dev/null +mkdir -p $TMP +cat >$TMP/startup.nsh <<EOF +fs0:u-boot-${type}.efi +EOF +sudo cp /tmp/b/$BUILD/u-boot-${type}.efi $TMP + +# Can copy in other files here: +#sudo cp /tmp/b/$BUILD/image.bin $TMP/chromeos.rom +#sudo cp /boot/vmlinuz-5.4.0-77-generic $TMP/vmlinuz + +sudo mount -o loop try.img $MNT +sudo cp $TMP/* $MNT +sudo umount $MNT + +if [[ -n "${run}" ]]; then + run_qemu +fi

Most EFI implementations use 64-bit. In order to spupose a 64-bit app, update the Kconfig to add an option for 32/64 bit. Update the prompt for the existing option so it is clear it relates to the stub. Move both up to just under the choice that controls them, since this looks better and the menu.
Use CONFIG_EFI_APP in the Makefile instead of CONFIG_TARGET_EFI_APP, since the latter is specific to a single target and we will have two.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/intel_common/Makefile | 2 +- lib/efi/Kconfig | 34 +++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 8b9a810f66d..1dc17b45879 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -27,7 +27,7 @@ obj-y += fast_spi.o obj-y += lpc.o obj-y += lpss.o obj-$(CONFIG_$(SPL_)INTEL_GENERIC_WIFI) += generic_wifi.o -ifndef CONFIG_TARGET_EFI_APP +ifndef CONFIG_EFI_APP obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o ifndef CONFIG_$(SPL_)X86_64 obj-y += microcode.o diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index 93b85644920..e818cef0d15 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -26,18 +26,26 @@ config EFI_STUB
endchoice
-config EFI_RAM_SIZE - hex "Amount of EFI RAM for U-Boot" +choice + prompt "EFI app 32/64-bit selection" depends on EFI_APP - default 0x2000000 help - Set the amount of EFI RAM which is claimed by U-Boot for its own - use. U-Boot allocates this from EFI on start-up (along with a few - other smaller amounts) and it can never be increased after that. - It is used as the RAM size in with U-Boot. + EFI does not support mixing 32-bit and 64-bit modes. This is a + significant problem because it means that you must build a stub with + the correct type for EFI to load it correctly. If you are using + 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do + this may produce no error message - it just won't start! + +config EFI_APP_32BIT + bool "Produce an app for running with 32-bit EFI" + +config EFI_APP_64BIT + bool "Produce an app for running with 64-bit EFI" + +endchoice
choice - prompt "EFI 32/64-bit selection" + prompt "EFI stub 32/64-bit selection" depends on EFI_STUB help EFI does not support mixing 32-bit and 64-bit modes. This is a @@ -53,3 +61,13 @@ config EFI_STUB_64BIT bool "Produce a stub for running with 64-bit EFI"
endchoice + +config EFI_RAM_SIZE + hex "Amount of EFI RAM for U-Boot" + depends on EFI_APP + default 0x2000000 + help + Set the amount of EFI RAM which is claimed by U-Boot for its own + use. U-Boot allocates this from EFI on start-up (along with a few + other smaller amounts) and it can never be increased after that. + It is used as the RAM size in with U-Boot.

On 9/8/21 3:33 PM, Simon Glass wrote:
Most EFI implementations use 64-bit. In order to spupose a 64-bit app,
%s/spupose/support
update the Kconfig to add an option for 32/64 bit. Update the prompt for
This commit message is unclear. We already can compile U-Boot as an 64bit EFI application. "In order to support" would imply that we don't.
the existing option so it is clear it relates to the stub. Move both up to just under the choice that controls them, since this looks better and the menu.
Use CONFIG_EFI_APP in the Makefile instead of CONFIG_TARGET_EFI_APP, since the latter is specific to a single target and we will have two.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/intel_common/Makefile | 2 +- lib/efi/Kconfig | 34 +++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 8b9a810f66d..1dc17b45879 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -27,7 +27,7 @@ obj-y += fast_spi.o obj-y += lpc.o obj-y += lpss.o obj-$(CONFIG_$(SPL_)INTEL_GENERIC_WIFI) += generic_wifi.o -ifndef CONFIG_TARGET_EFI_APP +ifndef CONFIG_EFI_APP obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o ifndef CONFIG_$(SPL_)X86_64 obj-y += microcode.o diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index 93b85644920..e818cef0d15 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -26,18 +26,26 @@ config EFI_STUB
endchoice
-config EFI_RAM_SIZE
- hex "Amount of EFI RAM for U-Boot"
+choice
- prompt "EFI app 32/64-bit selection" depends on EFI_APP
- default 0x2000000 help
Set the amount of EFI RAM which is claimed by U-Boot for its own
use. U-Boot allocates this from EFI on start-up (along with a few
other smaller amounts) and it can never be increased after that.
It is used as the RAM size in with U-Boot.
EFI does not support mixing 32-bit and 64-bit modes. This is a
significant problem because it means that you must build a stub with
the correct type for EFI to load it correctly. If you are using
32-bit EFI, select 32-bit here, else select 64-bit. Failure to do
this may produce no error message - it just won't start!
+config EFI_APP_32BIT
- bool "Produce an app for running with 32-bit EFI"
+config EFI_APP_64BIT
- bool "Produce an app for running with 64-bit EFI"
+endchoice
choice
- prompt "EFI 32/64-bit selection"
- prompt "EFI stub 32/64-bit selection" depends on EFI_STUB help EFI does not support mixing 32-bit and 64-bit modes. This is a
@@ -53,3 +61,13 @@ config EFI_STUB_64BIT bool "Produce a stub for running with 64-bit EFI"
endchoice
+config EFI_RAM_SIZE
- hex "Amount of EFI RAM for U-Boot"
- depends on EFI_APP
- default 0x2000000
32 MiB is quite small for loading a kernel and an initrd.
Best regards
Heinrich
- help
Set the amount of EFI RAM which is claimed by U-Boot for its own
use. U-Boot allocates this from EFI on start-up (along with a few
other smaller amounts) and it can never be increased after that.
It is used as the RAM size in with U-Boot.

Hi Heinrich,
On Wed, 8 Sept 2021 at 11:40, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
Most EFI implementations use 64-bit. In order to spupose a 64-bit app,
%s/spupose/support
update the Kconfig to add an option for 32/64 bit. Update the prompt for
This commit message is unclear. We already can compile U-Boot as an 64bit EFI application. "In order to support" would imply that we don't.
Which board are you talking about? There is only the 64-bit payload at present, certainly no 64-bit app?
the existing option so it is clear it relates to the stub. Move both up to just under the choice that controls them, since this looks better and the menu.
Use CONFIG_EFI_APP in the Makefile instead of CONFIG_TARGET_EFI_APP, since the latter is specific to a single target and we will have two.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/intel_common/Makefile | 2 +- lib/efi/Kconfig | 34 +++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 8b9a810f66d..1dc17b45879 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -27,7 +27,7 @@ obj-y += fast_spi.o obj-y += lpc.o obj-y += lpss.o obj-$(CONFIG_$(SPL_)INTEL_GENERIC_WIFI) += generic_wifi.o -ifndef CONFIG_TARGET_EFI_APP +ifndef CONFIG_EFI_APP obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o ifndef CONFIG_$(SPL_)X86_64 obj-y += microcode.o diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index 93b85644920..e818cef0d15 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -26,18 +26,26 @@ config EFI_STUB
endchoice
-config EFI_RAM_SIZE
hex "Amount of EFI RAM for U-Boot"
+choice
prompt "EFI app 32/64-bit selection" depends on EFI_APP
default 0x2000000 help
Set the amount of EFI RAM which is claimed by U-Boot for its own
use. U-Boot allocates this from EFI on start-up (along with a few
other smaller amounts) and it can never be increased after that.
It is used as the RAM size in with U-Boot.
EFI does not support mixing 32-bit and 64-bit modes. This is a
significant problem because it means that you must build a stub with
the correct type for EFI to load it correctly. If you are using
32-bit EFI, select 32-bit here, else select 64-bit. Failure to do
this may produce no error message - it just won't start!
+config EFI_APP_32BIT
bool "Produce an app for running with 32-bit EFI"
+config EFI_APP_64BIT
bool "Produce an app for running with 64-bit EFI"
+endchoice
choice
prompt "EFI 32/64-bit selection"
prompt "EFI stub 32/64-bit selection" depends on EFI_STUB help EFI does not support mixing 32-bit and 64-bit modes. This is a
@@ -53,3 +61,13 @@ config EFI_STUB_64BIT bool "Produce a stub for running with 64-bit EFI"
endchoice
+config EFI_RAM_SIZE
hex "Amount of EFI RAM for U-Boot"
depends on EFI_APP
default 0x2000000
32 MiB is quite small for loading a kernel and an initrd.
It does run nicely in qemu though without needing a special -m value. What do you suggest?
Regards, Simon

Most modern platforms use 64-bit EFI so it is useful to have a U-Boot app that runs under that. Add a (non-functional) build for this.
Note that --whole-archive causes the gcc 9.2 linker to crash, so disable this for now. Once this is resolved, things should work.
For now, avoid meantioning the documentation for the 64-bit app, since it does not work.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/u-boot-64.lds | 2 + arch/x86/cpu/x86_64/Makefile | 4 ++ arch/x86/cpu/x86_64/cpu.c | 17 -------- arch/x86/cpu/x86_64/misc.c | 25 ++++++++++++ board/efi/Kconfig | 15 ++++++- board/efi/efi-x86_app/Kconfig | 2 +- board/efi/efi-x86_app/MAINTAINERS | 11 +++++- ..._app_defconfig => efi-x86_app32_defconfig} | 2 +- configs/efi-x86_app64_defconfig | 39 +++++++++++++++++++ doc/develop/uefi/u-boot_on_efi.rst | 4 +- 10 files changed, 96 insertions(+), 25 deletions(-) create mode 100644 arch/x86/cpu/x86_64/misc.c rename configs/{efi-x86_app_defconfig => efi-x86_app32_defconfig} (97%) create mode 100644 configs/efi-x86_app64_defconfig
diff --git a/arch/x86/cpu/u-boot-64.lds b/arch/x86/cpu/u-boot-64.lds index ee0812aefbc..92a30c2a387 100644 --- a/arch/x86/cpu/u-boot-64.lds +++ b/arch/x86/cpu/u-boot-64.lds @@ -15,7 +15,9 @@ SECTIONS /DISCARD/ : { *(.u_boot_list_2_cmd_*) } #endif
+#ifdef CONFIG_SYS_TEXT_BASE . = CONFIG_SYS_TEXT_BASE; /* Location of bootcode in flash */ +#endif __text_start = .;
.text.start : { *(.text.start); } diff --git a/arch/x86/cpu/x86_64/Makefile b/arch/x86/cpu/x86_64/Makefile index 400f0ffe397..e929563b2c1 100644 --- a/arch/x86/cpu/x86_64/Makefile +++ b/arch/x86/cpu/x86_64/Makefile @@ -4,3 +4,7 @@ #
obj-y += cpu.o interrupts.o setjmp.o + +ifndef CONFIG_EFI +obj-y += misc.o +endif diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index e090b1b478a..fb501218e25 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -52,23 +52,6 @@ int x86_mp_init(void) return 0; }
-int misc_init_r(void) -{ - return 0; -} - -#ifndef CONFIG_SYS_COREBOOT -int checkcpu(void) -{ - return 0; -} - -int print_cpuinfo(void) -{ - return 0; -} -#endif - int x86_cpu_reinit_f(void) { return 0; diff --git a/arch/x86/cpu/x86_64/misc.c b/arch/x86/cpu/x86_64/misc.c new file mode 100644 index 00000000000..02587ff0c50 --- /dev/null +++ b/arch/x86/cpu/x86_64/misc.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Google, Inc + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <init.h> + +int misc_init_r(void) +{ + return 0; +} + +#ifndef CONFIG_SYS_COREBOOT +int checkcpu(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + return 0; +} +#endif diff --git a/board/efi/Kconfig b/board/efi/Kconfig index 291bd2ca154..3df6e31c8ba 100644 --- a/board/efi/Kconfig +++ b/board/efi/Kconfig @@ -4,14 +4,25 @@ choice prompt "Mainboard model" optional
-config TARGET_EFI_APP - bool "efi application" +config TARGET_EFI_APP32 + bool "32-bit efi application" + select EFI_APP help This target is used for running U-Boot on top of EFI. In this case EFI does the early initialisation, and U-Boot takes over once the RAM, video and CPU are fully running. U-Boot is loaded as an application from EFI.
+config TARGET_EFI_APP64 + bool "64-bit efi application" + select EFI_APP + select X86_64 + help + This target is used for running U-Boot on top of EFI in 64-bit mode. + In this case EFI does the early initialisation, and U-Boot + takes over once the RAM, video and CPU are fully running. + U-Boot is loaded as an application from EFI. + config TARGET_EFI_PAYLOAD bool "efi payload" help diff --git a/board/efi/efi-x86_app/Kconfig b/board/efi/efi-x86_app/Kconfig index ae87bf34d37..e412702eed7 100644 --- a/board/efi/efi-x86_app/Kconfig +++ b/board/efi/efi-x86_app/Kconfig @@ -1,4 +1,4 @@ -if TARGET_EFI_APP +if EFI_APP
config SYS_BOARD default "efi-x86_app" diff --git a/board/efi/efi-x86_app/MAINTAINERS b/board/efi/efi-x86_app/MAINTAINERS index fb8a6b1c2fa..b292811a8f0 100644 --- a/board/efi/efi-x86_app/MAINTAINERS +++ b/board/efi/efi-x86_app/MAINTAINERS @@ -1,6 +1,13 @@ -EFI-X86_APP BOARD +EFI-X86_APP32 BOARD M: Simon Glass sjg@chromium.org S: Maintained F: board/efi/efi-x86_app/ F: include/configs/efi-x86_app.h -F: configs/efi-x86_app_defconfig +F: configs/efi-x86_app32_defconfig + +EFI-X86_APP64 BOARD +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/efi/efi-x86_app/ +F: include/configs/efi-x86_app.h +F: configs/efi-x86_app64_defconfig diff --git a/configs/efi-x86_app_defconfig b/configs/efi-x86_app32_defconfig similarity index 97% rename from configs/efi-x86_app_defconfig rename to configs/efi-x86_app32_defconfig index e9ee66250cf..43ab3fb99c7 100644 --- a/configs/efi-x86_app_defconfig +++ b/configs/efi-x86_app32_defconfig @@ -5,7 +5,7 @@ CONFIG_DEFAULT_DEVICE_TREE="efi-x86_app" CONFIG_DEBUG_UART_BASE=0 CONFIG_DEBUG_UART_CLOCK=0 CONFIG_VENDOR_EFI=y -CONFIG_TARGET_EFI_APP=y +CONFIG_TARGET_EFI_APP32=y CONFIG_DEBUG_UART=y CONFIG_FIT=y CONFIG_SHOW_BOOT_PROGRESS=y diff --git a/configs/efi-x86_app64_defconfig b/configs/efi-x86_app64_defconfig new file mode 100644 index 00000000000..a395d3eb27b --- /dev/null +++ b/configs/efi-x86_app64_defconfig @@ -0,0 +1,39 @@ +CONFIG_X86=y +CONFIG_NR_DRAM_BANKS=8 +CONFIG_ENV_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="efi-x86_app" +CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_CLOCK=0 +CONFIG_VENDOR_EFI=y +CONFIG_TARGET_EFI_APP64=y +CONFIG_DEBUG_UART=y +CONFIG_FIT=y +CONFIG_SHOW_BOOT_PROGRESS=y +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_LAST_STAGE_INIT=y +CONFIG_HUSH_PARSER=y +# CONFIG_CMD_BOOTM is not set +CONFIG_CMD_PART=y +# CONFIG_CMD_NET is not set +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_MAC_PARTITION=y +CONFIG_ISO_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_OF_EMBED=y +CONFIG_ENV_OVERWRITE=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +# CONFIG_DM_ETH is not set +# CONFIG_REGEX is not set +# CONFIG_GZIP is not set +CONFIG_EFI=y +# CONFIG_EFI_LOADER is not set diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 59ee3885295..5de7215f6d1 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -48,10 +48,10 @@ for that board. It will be either 32-bit or 64-bit. Alternatively, you can opt for using QEMU [1] and the OVMF [2], as detailed below.
To build U-Boot as an EFI application (32-bit EFI required), enable CONFIG_EFI -and CONFIG_EFI_APP. The efi-x86_app config (efi-x86_app_defconfig) is set up +and CONFIG_EFI_APP. The efi-x86_app config (efi-x86_app32_defconfig) is set up for this. Just build U-Boot as normal, e.g.::
- make efi-x86_app_defconfig + make efi-x86_app32_defconfig make
To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), enable

On 9/8/21 3:33 PM, Simon Glass wrote:
Most modern platforms use 64-bit EFI so it is useful to have a U-Boot app that runs under that. Add a (non-functional) build for this.
Note that --whole-archive causes the gcc 9.2 linker to crash, so disable this for now. Once this is resolved, things should work.
For now, avoid meantioning the documentation for the 64-bit app, since it
%s/meantioning/mentioning/
does not work.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/u-boot-64.lds | 2 + arch/x86/cpu/x86_64/Makefile | 4 ++ arch/x86/cpu/x86_64/cpu.c | 17 -------- arch/x86/cpu/x86_64/misc.c | 25 ++++++++++++ board/efi/Kconfig | 15 ++++++- board/efi/efi-x86_app/Kconfig | 2 +- board/efi/efi-x86_app/MAINTAINERS | 11 +++++- ..._app_defconfig => efi-x86_app32_defconfig} | 2 +- configs/efi-x86_app64_defconfig | 39 +++++++++++++++++++ doc/develop/uefi/u-boot_on_efi.rst | 4 +- 10 files changed, 96 insertions(+), 25 deletions(-) create mode 100644 arch/x86/cpu/x86_64/misc.c rename configs/{efi-x86_app_defconfig => efi-x86_app32_defconfig} (97%) create mode 100644 configs/efi-x86_app64_defconfig
diff --git a/arch/x86/cpu/u-boot-64.lds b/arch/x86/cpu/u-boot-64.lds index ee0812aefbc..92a30c2a387 100644 --- a/arch/x86/cpu/u-boot-64.lds +++ b/arch/x86/cpu/u-boot-64.lds @@ -15,7 +15,9 @@ SECTIONS /DISCARD/ : { *(.u_boot_list_2_cmd_*) } #endif
+#ifdef CONFIG_SYS_TEXT_BASE . = CONFIG_SYS_TEXT_BASE; /* Location of bootcode in flash */ +#endif __text_start = .;
.text.start : { *(.text.start); } diff --git a/arch/x86/cpu/x86_64/Makefile b/arch/x86/cpu/x86_64/Makefile index 400f0ffe397..e929563b2c1 100644 --- a/arch/x86/cpu/x86_64/Makefile +++ b/arch/x86/cpu/x86_64/Makefile @@ -4,3 +4,7 @@ #
obj-y += cpu.o interrupts.o setjmp.o
+ifndef CONFIG_EFI +obj-y += misc.o +endif diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index e090b1b478a..fb501218e25 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -52,23 +52,6 @@ int x86_mp_init(void) return 0; }
-int misc_init_r(void) -{
- return 0;
-}
-#ifndef CONFIG_SYS_COREBOOT -int checkcpu(void) -{
- return 0;
-}
-int print_cpuinfo(void) -{
- return 0;
-} -#endif
- int x86_cpu_reinit_f(void) { return 0;
diff --git a/arch/x86/cpu/x86_64/misc.c b/arch/x86/cpu/x86_64/misc.c new file mode 100644 index 00000000000..02587ff0c50 --- /dev/null +++ b/arch/x86/cpu/x86_64/misc.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- (C) Copyright 2016 Google, Inc
- Written by Simon Glass sjg@chromium.org
- */
+#include <common.h> +#include <init.h>
+int misc_init_r(void) +{
- return 0;
+}
+#ifndef CONFIG_SYS_COREBOOT +int checkcpu(void) +{
- return 0;
+}
+int print_cpuinfo(void) +{
- return 0;
+} +#endif diff --git a/board/efi/Kconfig b/board/efi/Kconfig index 291bd2ca154..3df6e31c8ba 100644 --- a/board/efi/Kconfig +++ b/board/efi/Kconfig @@ -4,14 +4,25 @@ choice prompt "Mainboard model" optional
-config TARGET_EFI_APP
- bool "efi application"
+config TARGET_EFI_APP32
- bool "32-bit efi application"
- select EFI_APP help This target is used for running U-Boot on top of EFI. In this case EFI does the early initialisation, and U-Boot takes over once the RAM, video and CPU are fully running. U-Boot is loaded as an application from EFI.
+config TARGET_EFI_APP64
- bool "64-bit efi application"
- select EFI_APP
- select X86_64
- help
This target is used for running U-Boot on top of EFI in 64-bit mode.
In this case EFI does the early initialisation, and U-Boot
takes over once the RAM, video and CPU are fully running.
U-Boot is loaded as an application from EFI.
- config TARGET_EFI_PAYLOAD bool "efi payload" help
diff --git a/board/efi/efi-x86_app/Kconfig b/board/efi/efi-x86_app/Kconfig index ae87bf34d37..e412702eed7 100644 --- a/board/efi/efi-x86_app/Kconfig +++ b/board/efi/efi-x86_app/Kconfig @@ -1,4 +1,4 @@ -if TARGET_EFI_APP +if EFI_APP
config SYS_BOARD default "efi-x86_app" diff --git a/board/efi/efi-x86_app/MAINTAINERS b/board/efi/efi-x86_app/MAINTAINERS index fb8a6b1c2fa..b292811a8f0 100644 --- a/board/efi/efi-x86_app/MAINTAINERS +++ b/board/efi/efi-x86_app/MAINTAINERS @@ -1,6 +1,13 @@ -EFI-X86_APP BOARD +EFI-X86_APP32 BOARD M: Simon Glass sjg@chromium.org S: Maintained F: board/efi/efi-x86_app/ F: include/configs/efi-x86_app.h -F: configs/efi-x86_app_defconfig +F: configs/efi-x86_app32_defconfig
+EFI-X86_APP64 BOARD +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/efi/efi-x86_app/ +F: include/configs/efi-x86_app.h +F: configs/efi-x86_app64_defconfig diff --git a/configs/efi-x86_app_defconfig b/configs/efi-x86_app32_defconfig similarity index 97% rename from configs/efi-x86_app_defconfig rename to configs/efi-x86_app32_defconfig index e9ee66250cf..43ab3fb99c7 100644 --- a/configs/efi-x86_app_defconfig +++ b/configs/efi-x86_app32_defconfig @@ -5,7 +5,7 @@ CONFIG_DEFAULT_DEVICE_TREE="efi-x86_app" CONFIG_DEBUG_UART_BASE=0 CONFIG_DEBUG_UART_CLOCK=0 CONFIG_VENDOR_EFI=y -CONFIG_TARGET_EFI_APP=y +CONFIG_TARGET_EFI_APP32=y CONFIG_DEBUG_UART=y CONFIG_FIT=y CONFIG_SHOW_BOOT_PROGRESS=y diff --git a/configs/efi-x86_app64_defconfig b/configs/efi-x86_app64_defconfig new file mode 100644 index 00000000000..a395d3eb27b --- /dev/null +++ b/configs/efi-x86_app64_defconfig @@ -0,0 +1,39 @@ +CONFIG_X86=y +CONFIG_NR_DRAM_BANKS=8 +CONFIG_ENV_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="efi-x86_app" +CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_CLOCK=0 +CONFIG_VENDOR_EFI=y +CONFIG_TARGET_EFI_APP64=y +CONFIG_DEBUG_UART=y +CONFIG_FIT=y +CONFIG_SHOW_BOOT_PROGRESS=y +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_LAST_STAGE_INIT=y +CONFIG_HUSH_PARSER=y +# CONFIG_CMD_BOOTM is not set +CONFIG_CMD_PART=y +# CONFIG_CMD_NET is not set +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_MAC_PARTITION=y +CONFIG_ISO_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_OF_EMBED=y +CONFIG_ENV_OVERWRITE=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +# CONFIG_DM_ETH is not set +# CONFIG_REGEX is not set +# CONFIG_GZIP is not set +CONFIG_EFI=y +# CONFIG_EFI_LOADER is not set diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 59ee3885295..5de7215f6d1 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -48,10 +48,10 @@ for that board. It will be either 32-bit or 64-bit. Alternatively, you can opt for using QEMU [1] and the OVMF [2], as detailed below.
To build U-Boot as an EFI application (32-bit EFI required), enable CONFIG_EFI -and CONFIG_EFI_APP. The efi-x86_app config (efi-x86_app_defconfig) is set up +and CONFIG_EFI_APP. The efi-x86_app config (efi-x86_app32_defconfig) is set up for this. Just build U-Boot as normal, e.g.::
- make efi-x86_app_defconfig
make efi-x86_app32_defconfig make
To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), enable

This variable is already defined by the EFI code. Drop the duplicate definition when building a 64-bit EFI app.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/x86_64/cpu.c | 16 ---------------- arch/x86/cpu/x86_64/misc.c | 16 ++++++++++++++++ lib/efi/efi.c | 9 +++++++++ 3 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index fb501218e25..a3674e8e29a 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -10,22 +10,6 @@ #include <init.h> #include <asm/global_data.h>
-DECLARE_GLOBAL_DATA_PTR; - -/* - * Global declaration of gd. - * - * As we write to it before relocation we have to make sure it is not put into - * a .bss section which may overlap a .rela section. Initialization forces it - * into a .data section which cannot overlap any .rela section. - */ -struct global_data *global_data_ptr = (struct global_data *)~0; - -void arch_setup_gd(gd_t *new_gd) -{ - global_data_ptr = new_gd; -} - int cpu_has_64bit(void) { return true; diff --git a/arch/x86/cpu/x86_64/misc.c b/arch/x86/cpu/x86_64/misc.c index 02587ff0c50..691b67ff68a 100644 --- a/arch/x86/cpu/x86_64/misc.c +++ b/arch/x86/cpu/x86_64/misc.c @@ -7,6 +7,22 @@ #include <common.h> #include <init.h>
+DECLARE_GLOBAL_DATA_PTR; + +/* + * Global declaration of gd. + * + * As we write to it before relocation we have to make sure it is not put into + * a .bss section which may overlap a .rela section. Initialization forces it + * into a .data section which cannot overlap any .rela section. + */ +struct global_data *global_data_ptr = (struct global_data *)~0; + +void arch_setup_gd(gd_t *new_gd) +{ + global_data_ptr = new_gd; +} + int misc_init_r(void) { return 0; diff --git a/lib/efi/efi.c b/lib/efi/efi.c index 0c16a5fdd38..69e52e45748 100644 --- a/lib/efi/efi.c +++ b/lib/efi/efi.c @@ -17,6 +17,15 @@ #include <efi.h> #include <efi_api.h>
+/* + * Global declaration of gd. + * + * As we write to it before relocation we have to make sure it is not put into + * a .bss section which may overlap a .rela section. Initialization forces it + * into a .data section which cannot overlap any .rela section. + */ +struct global_data *global_data_ptr = (struct global_data *)~0; + /* * Unfortunately we cannot access any code outside what is built especially * for the stub. lib/string.c is already being built for the U-Boot payload

Add a function to return this information along with a stub for the efi_info_get() function, since calling it otherwise hangs U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/efi.h | 8 +++++++- lib/efi/efi_app.c | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/include/efi.h b/include/efi.h index 18c13e0370a..b5835422b95 100644 --- a/include/efi.h +++ b/include/efi.h @@ -444,9 +444,15 @@ extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[]; * * @return pointer to EFI system table */ - struct efi_system_table *efi_get_sys_table(void);
+/** + * efi_get_boot() - Get access to the EFI boot services table + * + * @return pointer to EFI boot services table + */ +struct efi_boot_services *efi_get_boot(void); + /** * efi_get_ram_base() - Find the base of RAM * diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 907bacd716a..f61665686c5 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -31,11 +31,21 @@ struct efi_system_table *efi_get_sys_table(void) return global_priv->sys_table; }
+struct efi_boot_services *efi_get_boot(void) +{ + return global_priv->boot; +} + unsigned long efi_get_ram_base(void) { return global_priv->ram_base; }
+int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) +{ + return -ENOSYS; +} + static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;

The current EFI video driver only works when running in the stub. In that case the stub calls boot services (before jumping to U-Boot proper) and copies the graphics info over to the efi table. This is necessary because the stub exits boot services before jumping to U-Boot.
The app maintains access to boot services throughout its life, so does not need to do this. Update the driver to support calling boot services directly.
Enable video output for the app.
A sample qemu command-line for this case is:
qemu-system-x86_64 -bios /usr/share/edk2.git/ovmf-ia32/OVMF-pure-efi.fd -drive id=disk,file=try.img,if=none,format=raw -nic none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/dts/efi-x86_app.dts | 4 ++++ board/efi/efi-x86_app/Kconfig | 4 ++++ drivers/video/Kconfig | 2 +- drivers/video/efi.c | 45 ++++++++++++++++++++++++++++------- include/configs/efi-x86_app.h | 6 ++--- 5 files changed, 49 insertions(+), 12 deletions(-)
diff --git a/arch/x86/dts/efi-x86_app.dts b/arch/x86/dts/efi-x86_app.dts index 04e044a07a8..a5316e2a1a7 100644 --- a/arch/x86/dts/efi-x86_app.dts +++ b/arch/x86/dts/efi-x86_app.dts @@ -25,4 +25,8 @@ compatible = "efi,reset"; u-boot,dm-pre-reloc; }; + efi-fb { + compatible = "efi-fb"; + }; + }; diff --git a/board/efi/efi-x86_app/Kconfig b/board/efi/efi-x86_app/Kconfig index e412702eed7..ecd08d73146 100644 --- a/board/efi/efi-x86_app/Kconfig +++ b/board/efi/efi-x86_app/Kconfig @@ -12,4 +12,8 @@ config SYS_SOC config SYS_CONFIG_NAME default "efi-x86_app"
+config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + imply VIDEO_EFI + endif diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 8b940d70eb2..38a421690d9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -250,7 +250,7 @@ config VIDEO_COREBOOT
config VIDEO_EFI bool "Enable EFI framebuffer driver support" - depends on EFI_STUB + depends on EFI_STUB || EFI_APP help Turn on this option to enable a framebuffeer driver when U-Boot is loaded as a payload (see README.u-boot_on_efi) by an EFI BIOS where diff --git a/drivers/video/efi.c b/drivers/video/efi.c index c248bd352a7..4e13a3efcb1 100644 --- a/drivers/video/efi.c +++ b/drivers/video/efi.c @@ -50,6 +50,28 @@ static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) *size = len; }
+static int get_mode_info(struct vesa_mode_info *vesa) +{ + efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_gop_mode *mode; + struct efi_gop *gop; + int ret; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); + if (ret) + return log_msg_ret("prot", -ENOTSUPP); + + mode = gop->mode; + vesa->phys_base_ptr = mode->fb_base; + vesa->x_resolution = mode->info->width; + vesa->y_resolution = mode->info->height; + + return 0; +} + static int save_vesa_mode(struct vesa_mode_info *vesa) { struct efi_entry_gopmode *mode; @@ -57,16 +79,23 @@ static int save_vesa_mode(struct vesa_mode_info *vesa) int size; int ret;
- ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); - if (ret == -ENOENT) { - debug("efi graphics output protocol mode not found\n"); - return -ENXIO; + if (IS_ENABLED(CONFIG_EFI_APP)) { + ret = get_mode_info(vesa); + if (ret) { + printf("efi graphics output protocol not found\n"); + return -ENXIO; + } + } else { + ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); + if (ret == -ENOENT) { + printf("efi graphics output protocol mode not found\n"); + return -ENXIO; + } + vesa->phys_base_ptr = mode->fb_base; + vesa->x_resolution = mode->info->width; + vesa->y_resolution = mode->info->height; }
- vesa->phys_base_ptr = mode->fb_base; - vesa->x_resolution = mode->info->width; - vesa->y_resolution = mode->info->height; - if (mode->info->pixel_format < EFI_GOT_BITMASK) { fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; vesa->red_mask_size = fbinfo->red.size; diff --git a/include/configs/efi-x86_app.h b/include/configs/efi-x86_app.h index 33418cfbec4..6061a6db0a4 100644 --- a/include/configs/efi-x86_app.h +++ b/include/configs/efi-x86_app.h @@ -10,8 +10,8 @@
#undef CONFIG_TPM_TIS_BASE_ADDRESS
-#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ - "stdout=vga,serial\0" \ - "stderr=vga,serial\0" +#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \ + "stdout=vidconsole\0" \ + "stderr=vidconsole\0"
#endif

On 9/8/21 3:33 PM, Simon Glass wrote:
The current EFI video driver only works when running in the stub. In that case the stub calls boot services (before jumping to U-Boot proper) and copies the graphics info over to the efi table. This is necessary because the stub exits boot services before jumping to U-Boot.
The app maintains access to boot services throughout its life, so does not need to do this. Update the driver to support calling boot services directly.
Enable video output for the app.
Please, use the EFI_GRAPHICS_OUTPUT_PROTOCOL to implement video. Don't assume any VESA or VGA compatible card. This would not be portable to other architectures.
Best regards
Heinrich
A sample qemu command-line for this case is:
qemu-system-x86_64 -bios /usr/share/edk2.git/ovmf-ia32/OVMF-pure-efi.fd -drive id=disk,file=try.img,if=none,format=raw -nic none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/dts/efi-x86_app.dts | 4 ++++ board/efi/efi-x86_app/Kconfig | 4 ++++ drivers/video/Kconfig | 2 +- drivers/video/efi.c | 45 ++++++++++++++++++++++++++++------- include/configs/efi-x86_app.h | 6 ++--- 5 files changed, 49 insertions(+), 12 deletions(-)
diff --git a/arch/x86/dts/efi-x86_app.dts b/arch/x86/dts/efi-x86_app.dts index 04e044a07a8..a5316e2a1a7 100644 --- a/arch/x86/dts/efi-x86_app.dts +++ b/arch/x86/dts/efi-x86_app.dts @@ -25,4 +25,8 @@ compatible = "efi,reset"; u-boot,dm-pre-reloc; };
- efi-fb {
compatible = "efi-fb";
- };
- };
diff --git a/board/efi/efi-x86_app/Kconfig b/board/efi/efi-x86_app/Kconfig index e412702eed7..ecd08d73146 100644 --- a/board/efi/efi-x86_app/Kconfig +++ b/board/efi/efi-x86_app/Kconfig @@ -12,4 +12,8 @@ config SYS_SOC config SYS_CONFIG_NAME default "efi-x86_app"
+config BOARD_SPECIFIC_OPTIONS # dummy
- def_bool y
- imply VIDEO_EFI
- endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 8b940d70eb2..38a421690d9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -250,7 +250,7 @@ config VIDEO_COREBOOT
config VIDEO_EFI bool "Enable EFI framebuffer driver support"
- depends on EFI_STUB
- depends on EFI_STUB || EFI_APP help Turn on this option to enable a framebuffeer driver when U-Boot is loaded as a payload (see README.u-boot_on_efi) by an EFI BIOS where
diff --git a/drivers/video/efi.c b/drivers/video/efi.c index c248bd352a7..4e13a3efcb1 100644 --- a/drivers/video/efi.c +++ b/drivers/video/efi.c @@ -50,6 +50,28 @@ static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) *size = len; }
+static int get_mode_info(struct vesa_mode_info *vesa) +{
- efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_gop_mode *mode;
- struct efi_gop *gop;
- int ret;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop);
- if (ret)
return log_msg_ret("prot", -ENOTSUPP);
- mode = gop->mode;
- vesa->phys_base_ptr = mode->fb_base;
- vesa->x_resolution = mode->info->width;
- vesa->y_resolution = mode->info->height;
- return 0;
+}
- static int save_vesa_mode(struct vesa_mode_info *vesa) { struct efi_entry_gopmode *mode;
@@ -57,16 +79,23 @@ static int save_vesa_mode(struct vesa_mode_info *vesa) int size; int ret;
- ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size);
- if (ret == -ENOENT) {
debug("efi graphics output protocol mode not found\n");
return -ENXIO;
- if (IS_ENABLED(CONFIG_EFI_APP)) {
ret = get_mode_info(vesa);
if (ret) {
printf("efi graphics output protocol not found\n");
return -ENXIO;
}
- } else {
ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size);
if (ret == -ENOENT) {
printf("efi graphics output protocol mode not found\n");
return -ENXIO;
}
vesa->phys_base_ptr = mode->fb_base;
vesa->x_resolution = mode->info->width;
}vesa->y_resolution = mode->info->height;
- vesa->phys_base_ptr = mode->fb_base;
- vesa->x_resolution = mode->info->width;
- vesa->y_resolution = mode->info->height;
- if (mode->info->pixel_format < EFI_GOT_BITMASK) { fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; vesa->red_mask_size = fbinfo->red.size;
diff --git a/include/configs/efi-x86_app.h b/include/configs/efi-x86_app.h index 33418cfbec4..6061a6db0a4 100644 --- a/include/configs/efi-x86_app.h +++ b/include/configs/efi-x86_app.h @@ -10,8 +10,8 @@
#undef CONFIG_TPM_TIS_BASE_ADDRESS
-#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \
"stdout=vga,serial\0" \
"stderr=vga,serial\0"
+#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \
"stdout=vidconsole\0" \
"stderr=vidconsole\0"
#endif

Hi Heinrich,
On Wed, 8 Sept 2021 at 11:40, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
The current EFI video driver only works when running in the stub. In that case the stub calls boot services (before jumping to U-Boot proper) and copies the graphics info over to the efi table. This is necessary because the stub exits boot services before jumping to U-Boot.
The app maintains access to boot services throughout its life, so does not need to do this. Update the driver to support calling boot services directly.
Enable video output for the app.
Please, use the EFI_GRAPHICS_OUTPUT_PROTOCOL to implement video. Don't assume any VESA or VGA compatible card. This would not be portable to other architectures.
Isn't that what this patch is doing? If not, can you please be more specific?
Regards, Simon

This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/efi_driver/Makefile | 2 +- lib/efi_loader/Kconfig | 2 + lib/efi_loader/efi_device_path.c | 96 +++++++------------------------- lib/efi_loader/efi_disk.c | 48 ---------------- 4 files changed, 24 insertions(+), 124 deletions(-)
diff --git a/lib/efi_driver/Makefile b/lib/efi_driver/Makefile index 83baa1c9a49..f2b6c05cc24 100644 --- a/lib/efi_driver/Makefile +++ b/lib/efi_driver/Makefile @@ -6,6 +6,6 @@ # object inclusion implicitly depends on it
obj-y += efi_uclass.o -ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy) +ifeq ($(CONFIG_PARTITIONS),y) obj-y += efi_block_device.o endif diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index dacc3b58810..799aa1a7512 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -10,6 +10,8 @@ config EFI_LOADER depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT + depends on BLK + depends on DM_ETH || !NET default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8 select LIB_UUID select PARTITION_UUIDS diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index cbdb466da41..a09090a32e4 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -46,7 +46,7 @@ static const struct efi_device_path_vendor ROOT = { .guid = U_BOOT_GUID, };
-#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) /* * Determine if an MMC device is an SD card. * @@ -486,7 +486,6 @@ bool efi_dp_is_multi_instance(const struct efi_device_path *dp) return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END; }
-#ifdef CONFIG_DM /* size of device-path not including END node for device and all parents * up to the root device. */ @@ -503,7 +502,6 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) case UCLASS_ETH: return dp_size(dev->parent) + sizeof(struct efi_device_path_mac_addr); -#ifdef CONFIG_BLK case UCLASS_BLK: switch (dev->parent->uclass->uc_drv->id) { #ifdef CONFIG_IDE @@ -511,12 +509,12 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) return dp_size(dev->parent) + sizeof(struct efi_device_path_atapi); #endif -#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI) +#if defined(CONFIG_SCSI) case UCLASS_SCSI: return dp_size(dev->parent) + sizeof(struct efi_device_path_scsi); #endif -#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) case UCLASS_MMC: return dp_size(dev->parent) + sizeof(struct efi_device_path_sd_mmc_path); @@ -554,8 +552,7 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) default: return dp_size(dev->parent); } -#endif -#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) case UCLASS_MMC: return dp_size(dev->parent) + sizeof(struct efi_device_path_sd_mmc_path); @@ -590,7 +587,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) *vdp = ROOT; return &vdp[1]; } -#ifdef CONFIG_DM_ETH +#ifdef CONFIG_NET case UCLASS_ETH: { struct efi_device_path_mac_addr *dp = dp_fill(buf, dev->parent); @@ -607,7 +604,6 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return &dp[1]; } #endif -#ifdef CONFIG_BLK case UCLASS_BLK: switch (dev->parent->uclass->uc_drv->id) { #ifdef CONFIG_SANDBOX @@ -662,7 +658,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return &dp[1]; } #endif -#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI) +#if defined(CONFIG_SCSI) case UCLASS_SCSI: { struct efi_device_path_scsi *dp = dp_fill(buf, dev->parent); @@ -676,7 +672,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return &dp[1]; } #endif -#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) case UCLASS_MMC: { struct efi_device_path_sd_mmc_path *sddp = dp_fill(buf, dev->parent); @@ -727,8 +723,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) dev->name, dev->parent->uclass->uc_drv->id); return dp_fill(buf, dev->parent); } -#endif -#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) case UCLASS_MMC: { struct efi_device_path_sd_mmc_path *sddp = dp_fill(buf, dev->parent); @@ -770,24 +765,18 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return dp_fill(buf, dev->parent); } } -#endif
static unsigned dp_part_size(struct blk_desc *desc, int part) { unsigned dpsize; + struct udevice *dev; + int ret;
-#ifdef CONFIG_BLK - { - struct udevice *dev; - int ret = blk_find_device(desc->if_type, desc->devnum, &dev); + ret = blk_find_device(desc->if_type, desc->devnum, &dev);
- if (ret) - dev = desc->bdev->parent; - dpsize = dp_size(dev); - } -#else - dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb); -#endif + if (ret) + dev = desc->bdev->parent; + dpsize = dp_size(dev);
if (part == 0) /* the actual disk, not a partition */ return dpsize; @@ -877,36 +866,14 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part) */ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) { -#ifdef CONFIG_BLK - { - struct udevice *dev; - int ret = blk_find_device(desc->if_type, desc->devnum, &dev); + struct udevice *dev; + int ret;
- if (ret) - dev = desc->bdev->parent; - buf = dp_fill(buf, dev); - } -#else - /* - * We *could* make a more accurate path, by looking at if_type - * and handling all the different cases like we do for non- - * legacy (i.e. CONFIG_BLK=y) case. But most important thing - * is just to have a unique device-path for if_type+devnum. - * So map things to a fictitious USB device. - */ - struct efi_device_path_usb *udp; - - memcpy(buf, &ROOT, sizeof(ROOT)); - buf += sizeof(ROOT); - - udp = buf; - udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; - udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB; - udp->dp.length = sizeof(*udp); - udp->parent_port_number = desc->if_type; - udp->usb_interface = desc->devnum; - buf = &udp[1]; -#endif + ret = blk_find_device(desc->if_type, desc->devnum, &dev); + + if (ret) + dev = desc->bdev->parent; + buf = dp_fill(buf, dev);
if (part == 0) /* the actual disk, not a partition */ return buf; @@ -1051,39 +1018,18 @@ struct efi_device_path *efi_dp_from_uart(void) #ifdef CONFIG_NET struct efi_device_path *efi_dp_from_eth(void) { -#ifndef CONFIG_DM_ETH - struct efi_device_path_mac_addr *ndp; -#endif void *buf, *start; unsigned dpsize = 0;
assert(eth_get_dev());
-#ifdef CONFIG_DM_ETH dpsize += dp_size(eth_get_dev()); -#else - dpsize += sizeof(ROOT); - dpsize += sizeof(*ndp); -#endif
start = buf = dp_alloc(dpsize + sizeof(END)); if (!buf) return NULL;
-#ifdef CONFIG_DM_ETH buf = dp_fill(buf, eth_get_dev()); -#else - memcpy(buf, &ROOT, sizeof(ROOT)); - buf += sizeof(ROOT); - - ndp = buf; - ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; - ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR; - ndp->dp.length = sizeof(*ndp); - ndp->if_type = 1; /* Ethernet */ - memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN); - buf = &ndp[1]; -#endif
*((struct efi_device_path *)buf) = END;
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 988907ecb91..ef8b5c88ff9 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -555,7 +555,6 @@ efi_status_t efi_disk_register(void) struct efi_disk_obj *disk; int disks = 0; efi_status_t ret; -#ifdef CONFIG_BLK struct udevice *dev;
for (uclass_first_device_check(UCLASS_BLK, &dev); dev; @@ -583,54 +582,7 @@ efi_status_t efi_disk_register(void) &disk->header, desc, if_typename, desc->devnum, dev->name); } -#else - int i, if_type;
- /* Search for all available disk devices */ - for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) { - const struct blk_driver *cur_drvr; - const char *if_typename; - - cur_drvr = blk_driver_lookup_type(if_type); - if (!cur_drvr) - continue; - - if_typename = cur_drvr->if_typename; - log_info("Scanning disks on %s...\n", if_typename); - for (i = 0; i < 4; i++) { - struct blk_desc *desc; - char devname[32] = { 0 }; /* dp->str is u16[32] long */ - - desc = blk_get_devnum_by_type(if_type, i); - if (!desc) - continue; - if (desc->type == DEV_TYPE_UNKNOWN) - continue; - - snprintf(devname, sizeof(devname), "%s%d", - if_typename, i); - - /* Add block device for the full device */ - ret = efi_disk_add_dev(NULL, NULL, if_typename, desc, - i, NULL, 0, &disk); - if (ret == EFI_NOT_READY) { - log_notice("Disk %s not ready\n", devname); - continue; - } - if (ret) { - log_err("ERROR: failure to add disk device %s, r = %lu\n", - devname, ret & ~EFI_ERROR_MASK); - return ret; - } - disks++; - - /* Partitions show up as block devices in EFI */ - disks += efi_disk_create_partitions - (&disk->header, desc, - if_typename, i, devname); - } - } -#endif log_info("Found %d disks\n", disks);
return EFI_SUCCESS;

On 9/8/21 3:33 PM, Simon Glass wrote:
This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Best regards
Heinrich
lib/efi_driver/Makefile | 2 +- lib/efi_loader/Kconfig | 2 + lib/efi_loader/efi_device_path.c | 96 +++++++------------------------- lib/efi_loader/efi_disk.c | 48 ---------------- 4 files changed, 24 insertions(+), 124 deletions(-)
diff --git a/lib/efi_driver/Makefile b/lib/efi_driver/Makefile index 83baa1c9a49..f2b6c05cc24 100644 --- a/lib/efi_driver/Makefile +++ b/lib/efi_driver/Makefile @@ -6,6 +6,6 @@ # object inclusion implicitly depends on it
obj-y += efi_uclass.o -ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy) +ifeq ($(CONFIG_PARTITIONS),y) obj-y += efi_block_device.o endif diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index dacc3b58810..799aa1a7512 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -10,6 +10,8 @@ config EFI_LOADER depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT
- depends on BLK
- depends on DM_ETH || !NET default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8 select LIB_UUID select PARTITION_UUIDS
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index cbdb466da41..a09090a32e4 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -46,7 +46,7 @@ static const struct efi_device_path_vendor ROOT = { .guid = U_BOOT_GUID, };
-#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) /*
- Determine if an MMC device is an SD card.
@@ -486,7 +486,6 @@ bool efi_dp_is_multi_instance(const struct efi_device_path *dp) return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END; }
-#ifdef CONFIG_DM /* size of device-path not including END node for device and all parents
- up to the root device.
*/ @@ -503,7 +502,6 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) case UCLASS_ETH: return dp_size(dev->parent) + sizeof(struct efi_device_path_mac_addr); -#ifdef CONFIG_BLK case UCLASS_BLK: switch (dev->parent->uclass->uc_drv->id) { #ifdef CONFIG_IDE @@ -511,12 +509,12 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) return dp_size(dev->parent) + sizeof(struct efi_device_path_atapi); #endif -#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI) +#if defined(CONFIG_SCSI) case UCLASS_SCSI: return dp_size(dev->parent) + sizeof(struct efi_device_path_scsi); #endif -#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) case UCLASS_MMC: return dp_size(dev->parent) + sizeof(struct efi_device_path_sd_mmc_path); @@ -554,8 +552,7 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) default: return dp_size(dev->parent); } -#endif -#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) case UCLASS_MMC: return dp_size(dev->parent) + sizeof(struct efi_device_path_sd_mmc_path); @@ -590,7 +587,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) *vdp = ROOT; return &vdp[1]; } -#ifdef CONFIG_DM_ETH +#ifdef CONFIG_NET case UCLASS_ETH: { struct efi_device_path_mac_addr *dp = dp_fill(buf, dev->parent); @@ -607,7 +604,6 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return &dp[1]; } #endif -#ifdef CONFIG_BLK case UCLASS_BLK: switch (dev->parent->uclass->uc_drv->id) { #ifdef CONFIG_SANDBOX @@ -662,7 +658,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return &dp[1]; } #endif -#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI) +#if defined(CONFIG_SCSI) case UCLASS_SCSI: { struct efi_device_path_scsi *dp = dp_fill(buf, dev->parent); @@ -676,7 +672,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return &dp[1]; } #endif -#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) case UCLASS_MMC: { struct efi_device_path_sd_mmc_path *sddp = dp_fill(buf, dev->parent); @@ -727,8 +723,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) dev->name, dev->parent->uclass->uc_drv->id); return dp_fill(buf, dev->parent); } -#endif -#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) +#if defined(CONFIG_MMC) case UCLASS_MMC: { struct efi_device_path_sd_mmc_path *sddp = dp_fill(buf, dev->parent); @@ -770,24 +765,18 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return dp_fill(buf, dev->parent); } } -#endif
static unsigned dp_part_size(struct blk_desc *desc, int part) { unsigned dpsize;
- struct udevice *dev;
- int ret;
-#ifdef CONFIG_BLK
- {
struct udevice *dev;
int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
- ret = blk_find_device(desc->if_type, desc->devnum, &dev);
if (ret)
dev = desc->bdev->parent;
dpsize = dp_size(dev);
- }
-#else
- dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
-#endif
if (ret)
dev = desc->bdev->parent;
dpsize = dp_size(dev);
if (part == 0) /* the actual disk, not a partition */ return dpsize;
@@ -877,36 +866,14 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part) */ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) { -#ifdef CONFIG_BLK
- {
struct udevice *dev;
int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
- struct udevice *dev;
- int ret;
if (ret)
dev = desc->bdev->parent;
buf = dp_fill(buf, dev);
- }
-#else
- /*
* We *could* make a more accurate path, by looking at if_type
* and handling all the different cases like we do for non-
* legacy (i.e. CONFIG_BLK=y) case. But most important thing
* is just to have a unique device-path for if_type+devnum.
* So map things to a fictitious USB device.
*/
- struct efi_device_path_usb *udp;
- memcpy(buf, &ROOT, sizeof(ROOT));
- buf += sizeof(ROOT);
- udp = buf;
- udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
- udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
- udp->dp.length = sizeof(*udp);
- udp->parent_port_number = desc->if_type;
- udp->usb_interface = desc->devnum;
- buf = &udp[1];
-#endif
ret = blk_find_device(desc->if_type, desc->devnum, &dev);
if (ret)
dev = desc->bdev->parent;
buf = dp_fill(buf, dev);
if (part == 0) /* the actual disk, not a partition */ return buf;
@@ -1051,39 +1018,18 @@ struct efi_device_path *efi_dp_from_uart(void) #ifdef CONFIG_NET struct efi_device_path *efi_dp_from_eth(void) { -#ifndef CONFIG_DM_ETH
- struct efi_device_path_mac_addr *ndp;
-#endif void *buf, *start; unsigned dpsize = 0;
assert(eth_get_dev());
-#ifdef CONFIG_DM_ETH dpsize += dp_size(eth_get_dev()); -#else
- dpsize += sizeof(ROOT);
- dpsize += sizeof(*ndp);
-#endif
start = buf = dp_alloc(dpsize + sizeof(END)); if (!buf) return NULL;
-#ifdef CONFIG_DM_ETH buf = dp_fill(buf, eth_get_dev()); -#else
- memcpy(buf, &ROOT, sizeof(ROOT));
- buf += sizeof(ROOT);
- ndp = buf;
- ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
- ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
- ndp->dp.length = sizeof(*ndp);
- ndp->if_type = 1; /* Ethernet */
- memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
- buf = &ndp[1];
-#endif
*((struct efi_device_path *)buf) = END;
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 988907ecb91..ef8b5c88ff9 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -555,7 +555,6 @@ efi_status_t efi_disk_register(void) struct efi_disk_obj *disk; int disks = 0; efi_status_t ret; -#ifdef CONFIG_BLK struct udevice *dev;
for (uclass_first_device_check(UCLASS_BLK, &dev); dev; @@ -583,54 +582,7 @@ efi_status_t efi_disk_register(void) &disk->header, desc, if_typename, desc->devnum, dev->name); } -#else
int i, if_type;
/* Search for all available disk devices */
for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) {
const struct blk_driver *cur_drvr;
const char *if_typename;
cur_drvr = blk_driver_lookup_type(if_type);
if (!cur_drvr)
continue;
if_typename = cur_drvr->if_typename;
log_info("Scanning disks on %s...\n", if_typename);
for (i = 0; i < 4; i++) {
struct blk_desc *desc;
char devname[32] = { 0 }; /* dp->str is u16[32] long */
desc = blk_get_devnum_by_type(if_type, i);
if (!desc)
continue;
if (desc->type == DEV_TYPE_UNKNOWN)
continue;
snprintf(devname, sizeof(devname), "%s%d",
if_typename, i);
/* Add block device for the full device */
ret = efi_disk_add_dev(NULL, NULL, if_typename, desc,
i, NULL, 0, &disk);
if (ret == EFI_NOT_READY) {
log_notice("Disk %s not ready\n", devname);
continue;
}
if (ret) {
log_err("ERROR: failure to add disk device %s, r = %lu\n",
devname, ret & ~EFI_ERROR_MASK);
return ret;
}
disks++;
/* Partitions show up as block devices in EFI */
disks += efi_disk_create_partitions
(&disk->header, desc,
if_typename, i, devname);
}
}
-#endif log_info("Found %d disks\n", disks);
return EFI_SUCCESS;

Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Who is the maintainer?
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
Regards, Simon

On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
I already added CONFIG_BLK as a requirement for CONFIG_EFI_LOADER in a submitted patch.
Removing legacy code from lib/efi_loader/efi_disk.c and lib/efi_loader/efi_device_path.c could be done before all U-Boot on EFI patches.
Therefore I still think it makes sense to split the series in two:
1) Cleanup of the UEFI implementation 2) Rework of U-Boot on EFI
I hope merging in this sequence of patch series makes send to you.
Best regards
Heinrich

Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
OK.
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
OK, but why not require DM_ETH? The deadline passed a year ago.
I already added CONFIG_BLK as a requirement for CONFIG_EFI_LOADER in a submitted patch.
OK good.
Removing legacy code from lib/efi_loader/efi_disk.c and lib/efi_loader/efi_device_path.c could be done before all U-Boot on EFI patches.
Therefore I still think it makes sense to split the series in two:
- Cleanup of the UEFI implementation
- Rework of U-Boot on EFI
I hope merging in this sequence of patch series makes send to you.
I am fine if you want to take on the clean-up stuff for BLK, etc. In that case we can just drop this patch when applying. But I do need some sort of patch here, for things to work.
Regards, Simon

On Thu, Sep 09, 2021 at 01:57:39PM -0600, Simon Glass wrote:
Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
OK.
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
OK, but why not require DM_ETH? The deadline passed a year ago.
Note that it's still a while (about a year) before I forcefully yank out unmigrated systems.

From: Simon Glass sjg@chromium.org Date: Thu, 9 Sep 2021 13:57:39 -0600
Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
OK.
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
OK, but why not require DM_ETH? The deadline passed a year ago.
Because we support boards without network ports?

On Thu, Sep 09, 2021 at 10:15:44PM +0200, Mark Kettenis wrote:
From: Simon Glass sjg@chromium.org Date: Thu, 9 Sep 2021 13:57:39 -0600
Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
OK.
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
OK, but why not require DM_ETH? The deadline passed a year ago.
Because we support boards without network ports?
Boards without networking should disable the relevant code, and as needed the EFI code return the proper error code?

Date: Thu, 9 Sep 2021 16:23:08 -0400 From: Tom Rini trini@konsulko.com
On Thu, Sep 09, 2021 at 10:15:44PM +0200, Mark Kettenis wrote:
From: Simon Glass sjg@chromium.org Date: Thu, 9 Sep 2021 13:57:39 -0600
Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote: > This code should never have been added as it builds a new feature on top > of legacy code. Drop it and add a dependency on BLK for this feature. > > Boards which want EFI_LOADER should migrate to driver model first. > > Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
OK.
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
OK, but why not require DM_ETH? The deadline passed a year ago.
Because we support boards without network ports?
Boards without networking should disable the relevant code, and as needed the EFI code return the proper error code?
Yes, but it means you can't make DM_ETH a (hard) requirement for EFI_LOADER support. What I mean is that it should still be possible to build U-Boot with EFI_LOADER support even if DM_EFI isn't set for a board. It should just result in a UEFI implementation with no network support instead.

On Thu, Sep 09, 2021 at 11:45:08PM +0200, Mark Kettenis wrote:
Date: Thu, 9 Sep 2021 16:23:08 -0400 From: Tom Rini trini@konsulko.com
On Thu, Sep 09, 2021 at 10:15:44PM +0200, Mark Kettenis wrote:
From: Simon Glass sjg@chromium.org Date: Thu, 9 Sep 2021 13:57:39 -0600
Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote: > > > > On 9/8/21 3:33 PM, Simon Glass wrote: >> This code should never have been added as it builds a new feature on top >> of legacy code. Drop it and add a dependency on BLK for this feature. >> >> Boards which want EFI_LOADER should migrate to driver model first. >> >> Signed-off-by: Simon Glass sjg@chromium.org > > This patch is not related to the rest of the series and the code has a > different maintainer. > > So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
OK.
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
OK, but why not require DM_ETH? The deadline passed a year ago.
Because we support boards without network ports?
Boards without networking should disable the relevant code, and as needed the EFI code return the proper error code?
Yes, but it means you can't make DM_ETH a (hard) requirement for EFI_LOADER support. What I mean is that it should still be possible to build U-Boot with EFI_LOADER support even if DM_EFI isn't set for a board. It should just result in a UEFI implementation with no network support instead.
Yes, agreed. I was just trying to say that in the context of what DM code EFI_LOADER can demand, the deadline for BLK has passed and everything that didn't support it has been removed, so that's a good requirement and area of code to clean up as needed. But DM_ETH-or-bust isn't there, yet.

Hi Mark,
On Thu, 9 Sept 2021 at 15:45, Mark Kettenis mark.kettenis@xs4all.nl wrote:
Date: Thu, 9 Sep 2021 16:23:08 -0400 From: Tom Rini trini@konsulko.com
On Thu, Sep 09, 2021 at 10:15:44PM +0200, Mark Kettenis wrote:
From: Simon Glass sjg@chromium.org Date: Thu, 9 Sep 2021 13:57:39 -0600
Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote: > > > > On 9/8/21 3:33 PM, Simon Glass wrote: >> This code should never have been added as it builds a new feature on top >> of legacy code. Drop it and add a dependency on BLK for this feature. >> >> Boards which want EFI_LOADER should migrate to driver model first. >> >> Signed-off-by: Simon Glass sjg@chromium.org > > This patch is not related to the rest of the series and the code has a > different maintainer. > > So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
OK.
I need this patch for this series to work. You can still review things for other maintainers and in this case it is common for one maintainer to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
OK, but why not require DM_ETH? The deadline passed a year ago.
Because we support boards without network ports?
Boards without networking should disable the relevant code, and as needed the EFI code return the proper error code?
Yes, but it means you can't make DM_ETH a (hard) requirement for EFI_LOADER support. What I mean is that it should still be possible to build U-Boot with EFI_LOADER support even if DM_EFI isn't set for a board. It should just result in a UEFI implementation with no network support instead.
I think you are misunderstanding my patch. I have:
depends on DM_ETH || !NET
which means that if NET is used, DM_ETH must be. I think that is reasonable.
Regards, Simon

From: Simon Glass sjg@chromium.org Date: Thu, 23 Sep 2021 20:48:42 -0600
Hi Mark,
On Thu, 9 Sept 2021 at 15:45, Mark Kettenis mark.kettenis@xs4all.nl wrote:
Date: Thu, 9 Sep 2021 16:23:08 -0400 From: Tom Rini trini@konsulko.com
On Thu, Sep 09, 2021 at 10:15:44PM +0200, Mark Kettenis wrote:
From: Simon Glass sjg@chromium.org Date: Thu, 9 Sep 2021 13:57:39 -0600
Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote: > Hi Heinrich, > > On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote: >> >> >> >> On 9/8/21 3:33 PM, Simon Glass wrote: >>> This code should never have been added as it builds a new feature on top >>> of legacy code. Drop it and add a dependency on BLK for this feature. >>> >>> Boards which want EFI_LOADER should migrate to driver model first. >>> >>> Signed-off-by: Simon Glass sjg@chromium.org >> >> This patch is not related to the rest of the series and the code has a >> different maintainer. >> >> So, please, separate it from the series. > > Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
OK.
> > I need this patch for this series to work. You can still review things > for other maintainers and in this case it is common for one maintainer > to pick up the series once the others are happy.
The direction of this patch is completely correct.
There are some things that will have to be changed, e.g we should not require CONFIG_DM_ETH=y. I will work on reviewing this patch in detail.
OK, but why not require DM_ETH? The deadline passed a year ago.
Because we support boards without network ports?
Boards without networking should disable the relevant code, and as needed the EFI code return the proper error code?
Yes, but it means you can't make DM_ETH a (hard) requirement for EFI_LOADER support. What I mean is that it should still be possible to build U-Boot with EFI_LOADER support even if DM_EFI isn't set for a board. It should just result in a UEFI implementation with no network support instead.
I think you are misunderstanding my patch. I have:
depends on DM_ETH || !NET
which means that if NET is used, DM_ETH must be. I think that is reasonable.
Yes, that should be fine (Kconfig stuff doesn't always make sense to me).

Hi Heinrich,
On Thu, 9 Sept 2021 at 03:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 11:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
This code should never have been added as it builds a new feature on top of legacy code. Drop it and add a dependency on BLK for this feature.
Boards which want EFI_LOADER should migrate to driver model first.
Signed-off-by: Simon Glass sjg@chromium.org
This patch is not related to the rest of the series and the code has a different maintainer.
So, please, separate it from the series.
Who is the maintainer?
Until 623b3a57976 ("efi_selftest: provide an EFI selftest application") there was no official maintainer for lib/efi/ but you were the main contributor.
But with that patch directory lib/efi/ was assigned to EFI PAYLOAD.
I am happy if you would continue to care about U-Boot on EFI.
I can add myself as maintainer of that part of EFI if you like. I will include it in the v2 series. But it is a little fiddling because there are shared files, so I will just add a few for now.
Perhaps you could be co-maintainer for the app, given your EFI knowledge and that you review them? Also I expect they would still go through your tree.
Regards, Simon

At present UCLASS_EFI is used to represent an EFI filesystem The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media.
The existing implementation using UCLASS_EFI remains as is, for discussion.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/test.dts | 4 ++++ drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 21 +++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 9 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 962bdbe5567..af88cf681ae 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -486,6 +486,10 @@ compatible = "sandbox,clk-ccf"; };
+ efi-media { + compatible = "sandbox,efi-media"; + }; + eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4023332dd98..058956ee8ee 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -63,6 +63,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA + bool "Support EFI media drivers" + default y if EFI || SANDBOX + help + Enable this to support media devices on top of UEFI. This enables + just the uclass so you also need a specific driver to make this do + anything. + + For sandbox there is a test driver. + +if EFI_MEDIA + +config EFI_MEDIA_SANDBOX + bool "Sandbox EFI media driver" + depends on SANDBOX + default y + help + Enables a simple sandbox media driver, used for testing just the + EFI_MEDIA uclass. It does not do anything useful, since sandbox does + not actually support running on top of UEFI. + +endif # EFI_MEDIA + config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o + +obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME, - [IF_TYPE_EFI] = UCLASS_EFI, + [IF_TYPE_EFI] = UCLASS_EFI_MEDIA, [IF_TYPE_VIRTIO] = UCLASS_VIRTIO, [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK, }; diff --git a/drivers/block/efi-media-uclass.c b/drivers/block/efi-media-uclass.c new file mode 100644 index 00000000000..e012f6f2f4c --- /dev/null +++ b/drivers/block/efi-media-uclass.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Uclass for EFI media devices + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <dm.h> + +UCLASS_DRIVER(efi_media) = { + .id = UCLASS_EFI_MEDIA, + .name = "efi_media", + .flags = DM_UC_FLAG_SEQ_ALIAS, +}; diff --git a/drivers/block/sb_efi_media.c b/drivers/block/sb_efi_media.c new file mode 100644 index 00000000000..4f242aa13a4 --- /dev/null +++ b/drivers/block/sb_efi_media.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI_MEDIA driver for sandbox + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <dm.h> + +static const struct udevice_id sandbox_efi_media_ids[] = { + { .compatible = "sandbox,efi-media" }, + { } +}; + + +U_BOOT_DRIVER(sandbox_efi_media) = { + .name = "sandbox_efi_media", + .id = UCLASS_EFI_MEDIA, + .of_match = sandbox_efi_media_ids, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index e7edd409f30..4906eb836c2 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -49,6 +49,7 @@ enum uclass_id { UCLASS_DSA, /* Distributed (Ethernet) Switch Architecture */ UCLASS_ECDSA, /* Elliptic curve cryptographic device */ UCLASS_EFI, /* EFI managed devices */ + UCLASS_EFI_MEDIA, /* EFI media (e.g. a disk) */ UCLASS_ETH, /* Ethernet device */ UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 516f69d61cb..d9bc37d8313 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DMA) += dma.o obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o obj-$(CONFIG_DM_DSA) += dsa.o obj-$(CONFIG_ECDSA_VERIFY) += ecdsa.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += efi_media.o obj-$(CONFIG_DM_ETH) += eth.o ifneq ($(CONFIG_EFI_PARTITION),) obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o diff --git a/test/dm/efi_media.c b/test/dm/efi_media.c new file mode 100644 index 00000000000..e343a0e9c85 --- /dev/null +++ b/test/dm/efi_media.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for EFI_MEDIA uclass + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <asm/test.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h> + +/* Test that we can use the EFI_MEDIA uclass */ +static int dm_test_efi_media(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_EFI_MEDIA, &dev)); + + return 0; +} +DM_TEST(dm_test_efi_media, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);

On 9/8/21 3:33 PM, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media.
The existing implementation using UCLASS_EFI remains as is, for discussion.
UCLASS_EFI is not related to block devices. It is for drivers implementing the EFI_DRIVER_BINDING_PROTOCOL. efi_uclass.c simplifies writing such drivers. So your patch does not make sense to me.
Please, separate the series in two: one for U-Boot on EFI, one for the UEFI implementation in U-Boot.
Best regards
Heinrich
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/test.dts | 4 ++++ drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 21 +++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 9 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 962bdbe5567..af88cf681ae 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -486,6 +486,10 @@ compatible = "sandbox,clk-ccf"; };
- efi-media {
compatible = "sandbox,efi-media";
- };
- eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4023332dd98..058956ee8ee 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -63,6 +63,29 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL
+config EFI_MEDIA
- bool "Support EFI media drivers"
- default y if EFI || SANDBOX
- help
Enable this to support media devices on top of UEFI. This enables
just the uclass so you also need a specific driver to make this do
anything.
For sandbox there is a test driver.
+if EFI_MEDIA
+config EFI_MEDIA_SANDBOX
- bool "Sandbox EFI media driver"
- depends on SANDBOX
- default y
- help
Enables a simple sandbox media driver, used for testing just the
EFI_MEDIA uclass. It does not do anything useful, since sandbox does
not actually support running on top of UEFI.
+endif # EFI_MEDIA
- config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f906..3778633da1d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,6 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
+obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc181..2db7ce5de20 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -44,7 +44,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME,
- [IF_TYPE_EFI] = UCLASS_EFI,
- [IF_TYPE_EFI] = UCLASS_EFI_MEDIA, [IF_TYPE_VIRTIO] = UCLASS_VIRTIO, [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK, };
diff --git a/drivers/block/efi-media-uclass.c b/drivers/block/efi-media-uclass.c new file mode 100644 index 00000000000..e012f6f2f4c --- /dev/null +++ b/drivers/block/efi-media-uclass.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Uclass for EFI media devices
- Copyright 2021 Google LLC
- */
+#include <common.h> +#include <dm.h>
+UCLASS_DRIVER(efi_media) = {
- .id = UCLASS_EFI_MEDIA,
- .name = "efi_media",
- .flags = DM_UC_FLAG_SEQ_ALIAS,
+}; diff --git a/drivers/block/sb_efi_media.c b/drivers/block/sb_efi_media.c new file mode 100644 index 00000000000..4f242aa13a4 --- /dev/null +++ b/drivers/block/sb_efi_media.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- EFI_MEDIA driver for sandbox
- Copyright 2021 Google LLC
- */
+#include <common.h> +#include <dm.h>
+static const struct udevice_id sandbox_efi_media_ids[] = {
- { .compatible = "sandbox,efi-media" },
- { }
+};
+U_BOOT_DRIVER(sandbox_efi_media) = {
- .name = "sandbox_efi_media",
- .id = UCLASS_EFI_MEDIA,
- .of_match = sandbox_efi_media_ids,
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index e7edd409f30..4906eb836c2 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -49,6 +49,7 @@ enum uclass_id { UCLASS_DSA, /* Distributed (Ethernet) Switch Architecture */ UCLASS_ECDSA, /* Elliptic curve cryptographic device */ UCLASS_EFI, /* EFI managed devices */
- UCLASS_EFI_MEDIA, /* EFI media (e.g. a disk) */ UCLASS_ETH, /* Ethernet device */ UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */
diff --git a/test/dm/Makefile b/test/dm/Makefile index 516f69d61cb..d9bc37d8313 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DMA) += dma.o obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o obj-$(CONFIG_DM_DSA) += dsa.o obj-$(CONFIG_ECDSA_VERIFY) += ecdsa.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += efi_media.o obj-$(CONFIG_DM_ETH) += eth.o ifneq ($(CONFIG_EFI_PARTITION),) obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o diff --git a/test/dm/efi_media.c b/test/dm/efi_media.c new file mode 100644 index 00000000000..e343a0e9c85 --- /dev/null +++ b/test/dm/efi_media.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Test for EFI_MEDIA uclass
- Copyright 2021 Google LLC
- */
+#include <common.h> +#include <dm.h> +#include <asm/test.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h>
+/* Test that we can use the EFI_MEDIA uclass */ +static int dm_test_efi_media(struct unit_test_state *uts) +{
- struct udevice *dev;
- ut_assertok(uclass_first_device_err(UCLASS_EFI_MEDIA, &dev));
- return 0;
+} +DM_TEST(dm_test_efi_media, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);

Hi Heinrich,
On Wed, 8 Sept 2021 at 11:50, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
At present UCLASS_EFI is used to represent an EFI filesystem The description of this uclass is "EFI managed devices" which is pretty vague. The only driver that uses this uclass is in fact not a real U-Boot driver, since its operations do not include a struct udevice.
Rather than mess with this, create a new UCLASS_EFI_MEDIA uclass to handle EFI media such as disks. Make this the uclass to use for EFI media.
The existing implementation using UCLASS_EFI remains as is, for discussion.
UCLASS_EFI is not related to block devices. It is for drivers implementing the EFI_DRIVER_BINDING_PROTOCOL. efi_uclass.c simplifies writing such drivers. So your patch does not make sense to me.
Do you understand the issue here? The existing EFI uclass is not a real U-Boot uclass. It does not use DM-style operations or even devices. It actually isn't clear to me what it is for. So for the purposes of this patch, I ignored it.
Please, separate the series in two: one for U-Boot on EFI, one for the UEFI implementation in U-Boot.
This series is all about the former. If there is anything related to the latter, it is likely just refactoring to avoid duplicating code. But I can't think of anything at present - can you please be more specific?
Best regards
Heinrich
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/test.dts | 4 ++++ drivers/block/Kconfig | 23 +++++++++++++++++++++++ drivers/block/Makefile | 3 +++ drivers/block/blk-uclass.c | 2 +- drivers/block/efi-media-uclass.c | 15 +++++++++++++++ drivers/block/sb_efi_media.c | 21 +++++++++++++++++++++ include/dm/uclass-id.h | 1 + test/dm/Makefile | 1 + test/dm/efi_media.c | 24 ++++++++++++++++++++++++ 9 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 drivers/block/efi-media-uclass.c create mode 100644 drivers/block/sb_efi_media.c create mode 100644 test/dm/efi_media.c
Regards, Simon

Add a block driver which handles read/write for EFI block devices. This driver actually already exists ('efi_block') but is not really suitable for use as a real U-Boot driver:
- The operations do not provide a udevice - The code is designed for running as part of EFI loader, so uses EFI_PRINT() and EFI_CALL(). - It creates block devices for all the partitions too, which is not somthing we want to support in this way - The bind method probes the device, which is not permitted - It uses 'EFI' as its parent device
The new driver is more 'normal', just requiring its platform data be set up in advance.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/block/Kconfig | 10 ++++ drivers/block/Makefile | 1 + drivers/block/efi_blk.c | 115 ++++++++++++++++++++++++++++++++++++++++ include/efi.h | 11 ++++ 4 files changed, 137 insertions(+) create mode 100644 drivers/block/efi_blk.c
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 058956ee8ee..ab450a52e9e 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -84,6 +84,16 @@ config EFI_MEDIA_SANDBOX EFI_MEDIA uclass. It does not do anything useful, since sandbox does not actually support running on top of UEFI.
+config EFI_MEDIA_BLK + bool "EFI media block driver" + depends on EFI_APP + default y + help + Enables a block driver for providing access to UEFI devices. This + allows use of block devices detected by the underlying UEFI + implementation. With this it is possible to use filesystems on these + devices, for example. + endif # EFI_MEDIA
config IDE diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 3778633da1d..b221a7c6eea 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o +obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o diff --git a/drivers/block/efi_blk.c b/drivers/block/efi_blk.c new file mode 100644 index 00000000000..c00b0cc0b1c --- /dev/null +++ b/drivers/block/efi_blk.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Block driver for EFI devices + * This supports a media driver of UCLASS_EFI with a child UCLASS_BLK + * It allows block-level access to EFI devices made available via EFI boot + * services + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <blk.h> +#include <dm.h> +#include <efi.h> +#include <efi_api.h> + +struct efi_block_plat { + struct efi_block_io *blkio; +}; + +/** + * Read from block device + * + * @dev: device + * @blknr: first block to be read + * @blkcnt: number of blocks to read + * @buffer: output buffer + * Return: number of blocks transferred + */ +static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + void *buffer) +{ + struct efi_block_plat *plat = dev_get_plat(dev); + struct efi_block_io *io = plat->blkio; + efi_status_t ret; + + log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, + (ulong)blkcnt); + ret = io->read_blocks(io, io->media->media_id, blknr, + blkcnt * io->media->block_size, buffer); + log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK, + ret & ~EFI_ERROR_MASK); + if (ret) + return 0; + + return blkcnt; +} + +/** + * Write to block device + * + * @dev: device + * @blknr: first block to be write + * @blkcnt: number of blocks to write + * @buffer: input buffer + * Return: number of blocks transferred + */ +static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + const void *buffer) +{ + struct efi_block_plat *plat = dev_get_plat(dev); + struct efi_block_io *io = plat->blkio; + efi_status_t ret; + + log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, + (ulong)blkcnt); + ret = io->write_blocks(io, io->media->media_id, blknr, + blkcnt * io->media->block_size, (void *)buffer); + log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK, + ret & ~EFI_ERROR_MASK); + if (ret) + return 0; + + return blkcnt; +} + +/* Block device driver operators */ +static const struct blk_ops efi_blk_ops = { + .read = efi_bl_read, + .write = efi_bl_write, +}; + +U_BOOT_DRIVER(efi_block) = { + .name = "efi_block", + .id = UCLASS_BLK, + .ops = &efi_blk_ops, + .plat_auto = sizeof(struct efi_block_plat), +}; + +static int efi_media_bind(struct udevice *dev) +{ + struct efi_media_plat *plat = dev_get_plat(dev); + struct efi_block_plat *blk_plat; + struct udevice *blk; + int ret; + + ret = blk_create_devicef(dev, "efi_block", "blk", IF_TYPE_EFI, + dev_seq(dev), plat->blkio->media->block_size, + plat->blkio->media->last_block, &blk); + if (ret) { + debug("Cannot create block device\n"); + return ret; + } + blk_plat = dev_get_plat(blk); + blk_plat->blkio = plat->blkio; + + return 0; +} + +U_BOOT_DRIVER(efi_media) = { + .name = "efi_media", + .id = UCLASS_EFI_MEDIA, + .bind = efi_media_bind, + .plat_auto = sizeof(struct efi_media_plat), +}; diff --git a/include/efi.h b/include/efi.h index b5835422b95..0ec5913ddd1 100644 --- a/include/efi.h +++ b/include/efi.h @@ -414,6 +414,17 @@ struct efi_priv { void *next_hdr; };
+/* + * EFI attributes of the udevice handled by efi_media driver + * + * @handle: handle of the controller on which this driver is installed + * @blkio: block io protocol proxied by this driver + */ +struct efi_media_plat { + efi_handle_t handle; + struct efi_block_io *blkio; +}; + /* Base address of the EFI image */ extern char image_base[];

On 9/8/21 3:33 PM, Simon Glass wrote:
Add a block driver which handles read/write for EFI block devices. This driver actually already exists ('efi_block') but is not really suitable for use as a real U-Boot driver:
- The operations do not provide a udevice
efi_bl_bind() creates a udevice by calling blk_create_device() when an EFI application calls ConnectController() for a handle with an EFI_BLOCK_IO_PROTOCOL.
Please, explain in some detail what you think is wrong with the existing code.
- The code is designed for running as part of EFI loader, so uses EFI_PRINT() and EFI_CALL().
- It creates block devices for all the partitions too, which is not somthing we want to support in this way
- The bind method probes the device, which is not permitted
- It uses 'EFI' as its parent device
The new driver is more 'normal', just requiring its platform data be set up in advance.
Signed-off-by: Simon Glass sjg@chromium.org
Please, separate this series in two. One for U-Boot on EFI and one for U-Boot's UEFI implementation.
Best regardss
Heinrich
drivers/block/Kconfig | 10 ++++ drivers/block/Makefile | 1 + drivers/block/efi_blk.c | 115 ++++++++++++++++++++++++++++++++++++++++ include/efi.h | 11 ++++ 4 files changed, 137 insertions(+) create mode 100644 drivers/block/efi_blk.c
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 058956ee8ee..ab450a52e9e 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -84,6 +84,16 @@ config EFI_MEDIA_SANDBOX EFI_MEDIA uclass. It does not do anything useful, since sandbox does not actually support running on top of UEFI.
+config EFI_MEDIA_BLK
bool "EFI media block driver"
depends on EFI_APP
default y
help
Enables a block driver for providing access to UEFI devices. This
allows use of block devices detected by the underlying UEFI
implementation. With this it is possible to use filesystems on these
devices, for example.
endif # EFI_MEDIA
config IDE
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 3778633da1d..b221a7c6eea 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o +obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o diff --git a/drivers/block/efi_blk.c b/drivers/block/efi_blk.c new file mode 100644 index 00000000000..c00b0cc0b1c --- /dev/null +++ b/drivers/block/efi_blk.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Block driver for EFI devices
- This supports a media driver of UCLASS_EFI with a child UCLASS_BLK
- It allows block-level access to EFI devices made available via EFI boot
- services
- Copyright 2021 Google LLC
- */
+#include <common.h> +#include <blk.h> +#include <dm.h> +#include <efi.h> +#include <efi_api.h>
+struct efi_block_plat {
- struct efi_block_io *blkio;
+};
+/**
- Read from block device
- @dev: device
- @blknr: first block to be read
- @blkcnt: number of blocks to read
- @buffer: output buffer
- Return: number of blocks transferred
- */
+static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
+{
- struct efi_block_plat *plat = dev_get_plat(dev);
- struct efi_block_io *io = plat->blkio;
- efi_status_t ret;
- log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
- ret = io->read_blocks(io, io->media->media_id, blknr,
blkcnt * io->media->block_size, buffer);
- log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK,
ret & ~EFI_ERROR_MASK);
- if (ret)
return 0;
- return blkcnt;
+}
+/**
- Write to block device
- @dev: device
- @blknr: first block to be write
- @blkcnt: number of blocks to write
- @buffer: input buffer
- Return: number of blocks transferred
- */
+static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
+{
- struct efi_block_plat *plat = dev_get_plat(dev);
- struct efi_block_io *io = plat->blkio;
- efi_status_t ret;
- log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr,
(ulong)blkcnt);
- ret = io->write_blocks(io, io->media->media_id, blknr,
blkcnt * io->media->block_size, (void *)buffer);
- log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK,
ret & ~EFI_ERROR_MASK);
- if (ret)
return 0;
- return blkcnt;
+}
+/* Block device driver operators */ +static const struct blk_ops efi_blk_ops = {
- .read = efi_bl_read,
- .write = efi_bl_write,
+};
+U_BOOT_DRIVER(efi_block) = {
- .name = "efi_block",
- .id = UCLASS_BLK,
- .ops = &efi_blk_ops,
- .plat_auto = sizeof(struct efi_block_plat),
+};
+static int efi_media_bind(struct udevice *dev) +{
- struct efi_media_plat *plat = dev_get_plat(dev);
- struct efi_block_plat *blk_plat;
- struct udevice *blk;
- int ret;
- ret = blk_create_devicef(dev, "efi_block", "blk", IF_TYPE_EFI,
dev_seq(dev), plat->blkio->media->block_size,
plat->blkio->media->last_block, &blk);
- if (ret) {
debug("Cannot create block device\n");
return ret;
- }
- blk_plat = dev_get_plat(blk);
- blk_plat->blkio = plat->blkio;
- return 0;
+}
+U_BOOT_DRIVER(efi_media) = {
- .name = "efi_media",
- .id = UCLASS_EFI_MEDIA,
- .bind = efi_media_bind,
- .plat_auto = sizeof(struct efi_media_plat),
+}; diff --git a/include/efi.h b/include/efi.h index b5835422b95..0ec5913ddd1 100644 --- a/include/efi.h +++ b/include/efi.h @@ -414,6 +414,17 @@ struct efi_priv { void *next_hdr; };
+/*
- EFI attributes of the udevice handled by efi_media driver
- @handle: handle of the controller on which this driver is installed
- @blkio: block io protocol proxied by this driver
- */
+struct efi_media_plat {
- efi_handle_t handle;
- struct efi_block_io *blkio;
+};
- /* Base address of the EFI image */ extern char image_base[];

Hi Heinrich,
On Wed, 8 Sept 2021 at 12:04, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
Add a block driver which handles read/write for EFI block devices. This driver actually already exists ('efi_block') but is not really suitable for use as a real U-Boot driver:
- The operations do not provide a udevice
efi_bl_bind() creates a udevice by calling blk_create_device() when an EFI application calls ConnectController() for a handle with an EFI_BLOCK_IO_PROTOCOL.
Please, explain in some detail what you think is wrong with the existing code.
See below:
- The code is designed for running as part of EFI loader, so uses EFI_PRINT() and EFI_CALL().
- It creates block devices for all the partitions too, which is not somthing we want to support in this way
- The bind method probes the device, which is not permitted
- It uses 'EFI' as its parent device
The new driver is more 'normal', just requiring its platform data be set up in advance.
Signed-off-by: Simon Glass sjg@chromium.org
Please, separate this series in two. One for U-Boot on EFI and one for U-Boot's UEFI implementation.
Again I'm not sure what you mean here. Please point to something you don't want in this series, which is focussed on the app.
Best regardss
Heinrich
drivers/block/Kconfig | 10 ++++ drivers/block/Makefile | 1 + drivers/block/efi_blk.c | 115 ++++++++++++++++++++++++++++++++++++++++ include/efi.h | 11 ++++ 4 files changed, 137 insertions(+) create mode 100644 drivers/block/efi_blk.c
Regards, Simon

On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 12:04, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
Add a block driver which handles read/write for EFI block devices. This driver actually already exists ('efi_block') but is not really suitable for use as a real U-Boot driver:
- The operations do not provide a udevice
efi_bl_bind() creates a udevice by calling blk_create_device() when an EFI application calls ConnectController() for a handle with an EFI_BLOCK_IO_PROTOCOL.
Please, explain in some detail what you think is wrong with the existing code.
See below:
- The code is designed for running as part of EFI loader, so uses EFI_PRINT() and EFI_CALL().
- It creates block devices for all the partitions too, which is not somthing we want to support in this way
No, it creates a block device for the handle that was passed to ConnectController(). The handles for the partitions are created by U-Boot and these are not backed by separate block devices.
- The bind method probes the device, which is not permitted
- It uses 'EFI' as its parent device
All devices that the UEFI sub-system uses must be probed.
The new driver is more 'normal', just requiring its platform data be set up in advance.
No clue what you mean by "in advance". It is a software like iPXE that produces a handle at runtime and then calls ConnectController(). When that call is done we must create a block device which is in status probed, create handles for the partitions and install protocol interfaces on these partitions.
Best regards
Heinrich
Signed-off-by: Simon Glass sjg@chromium.org
Please, separate this series in two. One for U-Boot on EFI and one for U-Boot's UEFI implementation.
Again I'm not sure what you mean here. Please point to something you don't want in this series, which is focussed on the app.
Best regardss
Heinrich
drivers/block/Kconfig | 10 ++++ drivers/block/Makefile | 1 + drivers/block/efi_blk.c | 115 ++++++++++++++++++++++++++++++++++++++++ include/efi.h | 11 ++++ 4 files changed, 137 insertions(+) create mode 100644 drivers/block/efi_blk.c
Regards, Simon

Hi Heinrich,
On Thu, 9 Sept 2021 at 04:40, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 12:04, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
Add a block driver which handles read/write for EFI block devices. This driver actually already exists ('efi_block') but is not really suitable for use as a real U-Boot driver:
- The operations do not provide a udevice
efi_bl_bind() creates a udevice by calling blk_create_device() when an EFI application calls ConnectController() for a handle with an EFI_BLOCK_IO_PROTOCOL.
Please, explain in some detail what you think is wrong with the existing code.
See below:
- The code is designed for running as part of EFI loader, so uses EFI_PRINT() and EFI_CALL().
- It creates block devices for all the partitions too, which is not somthing we want to support in this way
No, it creates a block device for the handle that was passed to ConnectController(). The handles for the partitions are created by U-Boot and these are not backed by separate block devices.
OK, that is hard to discover so thank you for explaining it. The other items stand, in any case.
Best regards
Heinrich
- The bind method probes the device, which is not permitted
- It uses 'EFI' as its parent device
All devices that the UEFI sub-system uses must be probed.,
It is fine to probe a device but this must not be done in the bind() method. Hopefully the reason for this is obvious?
The new driver is more 'normal', just requiring its platform data be set up in advance.
No clue what you mean by "in advance". It is a software like iPXE that produces a handle at runtime and then calls ConnectController(). When that call is done we must create a block device which is in status probed, create handles for the partitions and install protocol interfaces on these partitions.
In advance of using the device. Basically we can pass the platform data into the device_bind() call, so it has it right from the start.
Please understand that, while the existing EFI uclass is wonky, for the reasons I have clearly explained in this patch, my intent in explaining this is to motivate adding a new uclass. I am not trying to change the existing uclass. It is just one of many wonky things in the original EFI implementation that predates your efforts.
- Simon
Best regards
Heinrich
Signed-off-by: Simon Glass sjg@chromium.org
Please, separate this series in two. One for U-Boot on EFI and one for U-Boot's UEFI implementation.
Again I'm not sure what you mean here. Please point to something you don't want in this series, which is focussed on the app.
Best regardss
Heinrich
drivers/block/Kconfig | 10 ++++ drivers/block/Makefile | 1 + drivers/block/efi_blk.c | 115 ++++++++++++++++++++++++++++++++++++++++ include/efi.h | 11 ++++ 4 files changed, 137 insertions(+) create mode 100644 drivers/block/efi_blk.c
Regards, Simon

When starting the app, locate all block devices and make them available to U-Boot. This allows listing partitions and accessing files in filesystems.
EFI also has the concept of 'disks', meaning boot media. For now, this is not obviously useful in U-Boot, but add code to at least locate these. This can be expanded later as needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/efi.h | 15 ++++++ include/efi_api.h | 15 ++++++ lib/efi/efi_app.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+)
diff --git a/include/efi.h b/include/efi.h index 0ec5913ddd1..c0fddf7f6cd 100644 --- a/include/efi.h +++ b/include/efi.h @@ -529,4 +529,19 @@ void efi_putc(struct efi_priv *priv, const char ch); */ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep);
+/** + * efi_bind_block() - bind a new block device to an EFI device + * + * Binds a new top-level EFI_MEDIA device as well as a child block device so + * that the block device can be accessed in U-Boot. + * + * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1', + * for example, just like any other interface type. + * + * @handle: handle of the controller on which this driver is installed + * @blkio: block io protocol proxied by this driver + * @return 0 if OK, -ve on error + */ +int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio); + #endif /* _LINUX_EFI_H */ diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb720..0e88b3e5dbe 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1994,4 +1994,19 @@ struct efi_firmware_management_protocol { const u16 *package_version_name); };
+#define EFI_DISK_IO_PROTOCOL_GUID \ + EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \ + 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + +struct efi_disk { + u64 revision; + efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id, + u64 offset, efi_uintn_t buffer_size, + void *buffer); + + efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id, + u64 offset, efi_uintn_t buffer_size, + void *buffer); +}; + #endif diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..9ba48517422 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,6 +21,9 @@ #include <efi.h> #include <efi_api.h> #include <sysreset.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -46,6 +49,33 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; }
+/** + * Create a block device so U-Boot can access an EFI device + * + * @handle: EFI handle to bind + * @blkio: block io protocol + * Return: 0 = success + */ +int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio) +{ + struct efi_media_plat plat; + struct udevice *dev; + char name[18]; + int ret; + + plat.handle = handle; + plat.blkio = blkio; + ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media", + &plat, ofnode_null(), &dev); + if (ret) + return log_msg_ret("bind", ret); + + snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev)); + device_set_name(dev, name); + + return 0; +} + static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot; @@ -105,6 +135,95 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
+static int setup_disks(void) +{ + /* This is not fully implemented yet */ + return 0; + + efi_guid_t efi_disk_guid = EFI_DISK_IO_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_disk *disk; + int ret; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + ret = boot->locate_protocol(&efi_disk_guid, NULL, (void **)&disk); + if (ret) + return log_msg_ret("prot", -ENOTSUPP); + + return 0; +} + +static int setup_block(void) +{ + efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID; + efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_block_io *blkio; + struct efi_device_path device_path; + efi_handle_t handle[100]; + efi_uintn_t buf_size; + int num_handles; + int ret, i; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + + buf_size = sizeof(handle); + ret = boot->locate_handle(BY_PROTOCOL, &efi_blkio_guid, NULL, + &buf_size, handle); + if (ret) + return log_msg_ret("loc", -ENOTSUPP); + + num_handles = buf_size / sizeof(efi_handle_t); + log_info("Found %d EFI handles\n", num_handles); + + for (i = 0; i < num_handles; i++) { + ret = boot->handle_protocol(handle[i], &efi_devpath_guid, + (void **)&device_path); + if (ret) { + log_warning("- devpath %d failed (ret=%d)\n", i, ret); + continue; + } + + ret = boot->handle_protocol(handle[i], &efi_blkio_guid, + (void **)&blkio); + if (ret) { + log_warning("- blkio %d failed (ret=%d)\n", i, ret); + continue; + } + + ret = efi_bind_block(handle[i], blkio); + if (ret) { + log_warning("- blkio bind %d failed (ret=%d)\n", i, ret); + continue; + } + } + if (ret) + return log_msg_ret("prot", -ENOTSUPP); + + return 0; +} + +int dm_scan_other(bool pre_reloc_only) +{ + if (gd->flags & GD_FLG_RELOC) { + int ret; + + /* Find all block devices and setup EFI devices for them */ + ret = setup_block(); + if (ret) + return ret; + + /* Not needed at present, but could be useful one day? */ + ret = setup_disks(); + if (ret) + return ret; + } + + return 0; +} + /** * efi_main() - Start an EFI image *

On 9/8/21 3:33 PM, Simon Glass wrote:
When starting the app, locate all block devices and make them available to U-Boot. This allows listing partitions and accessing files in filesystems.
EFI also has the concept of 'disks', meaning boot media. For now, this is not obviously useful in U-Boot, but add code to at least locate these. This can be expanded later as needed.
UEFI firmware handles with the EFI_BLOCK_IO_PROTOCOL for raw access to disks and partitions. It further provides the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on these handles to access files on formatted media.
Signed-off-by: Simon Glass sjg@chromium.org
include/efi.h | 15 ++++++ include/efi_api.h | 15 ++++++ lib/efi/efi_app.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+)
diff --git a/include/efi.h b/include/efi.h index 0ec5913ddd1..c0fddf7f6cd 100644 --- a/include/efi.h +++ b/include/efi.h @@ -529,4 +529,19 @@ void efi_putc(struct efi_priv *priv, const char ch); */ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep);
+/**
- efi_bind_block() - bind a new block device to an EFI device
- Binds a new top-level EFI_MEDIA device as well as a child block device so
- that the block device can be accessed in U-Boot.
- The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
- for example, just like any other interface type.
- @handle: handle of the controller on which this driver is installed
- @blkio: block io protocol proxied by this driver
- @return 0 if OK, -ve on error
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio);
- #endif /* _LINUX_EFI_H */
diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb720..0e88b3e5dbe 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1994,4 +1994,19 @@ struct efi_firmware_management_protocol { const u16 *package_version_name); };
+#define EFI_DISK_IO_PROTOCOL_GUID \
- EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \
0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+struct efi_disk {
- u64 revision;
- efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
- efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
+};
- #endif
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..9ba48517422 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,6 +21,9 @@ #include <efi.h> #include <efi_api.h> #include <sysreset.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -46,6 +49,33 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; }
+/**
- Create a block device so U-Boot can access an EFI device
- @handle: EFI handle to bind
- @blkio: block io protocol
- Return: 0 = success
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio) +{
- struct efi_media_plat plat;
- struct udevice *dev;
- char name[18];
- int ret;
- plat.handle = handle;
- plat.blkio = blkio;
- ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
&plat, ofnode_null(), &dev);
- if (ret)
return log_msg_ret("bind", ret);
- snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
- device_set_name(dev, name);
- return 0;
+}
- static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;
@@ -105,6 +135,95 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
+static int setup_disks(void) +{
- /* This is not fully implemented yet */
- return 0;
- efi_guid_t efi_disk_guid = EFI_DISK_IO_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_disk *disk;
- int ret;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- ret = boot->locate_protocol(&efi_disk_guid, NULL, (void **)&disk);
- if (ret)
return log_msg_ret("prot", -ENOTSUPP);
- return 0;
+}
+static int setup_block(void) +{
- efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
- efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_block_io *blkio;
- struct efi_device_path device_path;
- efi_handle_t handle[100];
- efi_uintn_t buf_size;
- int num_handles;
- int ret, i;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- buf_size = sizeof(handle);
- ret = boot->locate_handle(BY_PROTOCOL, &efi_blkio_guid, NULL,
&buf_size, handle);
You could use LocateHandleBuffer() here which will allocate enough memory for all matching handles.
- if (ret)
return log_msg_ret("loc", -ENOTSUPP);
- num_handles = buf_size / sizeof(efi_handle_t);
- log_info("Found %d EFI handles\n", num_handles);
- for (i = 0; i < num_handles; i++) {
ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
(void **)&device_path);
Why do you read the devicepath if you don't use it?
if (ret) {
log_warning("- devpath %d failed (ret=%d)\n", i, ret);
continue;
}
Here some analysis of devicepaths and installed protocols is missing to find out which of the handles represents a block device and which represents a partition:
If the last devicepath node is type 4 , Media Device Path with SubType 1 Hard Drive and the partition number is non-zero it is a partition.
If the devicepath without the last node relates to a handle with the EFI_BLOCK_IO_PROTOCOL, this also indicates that the current handle is for a partition.
Best regards
Heinrich
ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
(void **)&blkio);
if (ret) {
log_warning("- blkio %d failed (ret=%d)\n", i, ret);
continue;
}
ret = efi_bind_block(handle[i], blkio);
if (ret) {
log_warning("- blkio bind %d failed (ret=%d)\n", i, ret);
continue;
}
- }
- if (ret)
return log_msg_ret("prot", -ENOTSUPP);
- return 0;
+}
+int dm_scan_other(bool pre_reloc_only) +{
- if (gd->flags & GD_FLG_RELOC) {
int ret;
/* Find all block devices and setup EFI devices for them */
ret = setup_block();
if (ret)
return ret;
/* Not needed at present, but could be useful one day? */
ret = setup_disks();
if (ret)
return ret;
- }
- return 0;
+}
- /**
- efi_main() - Start an EFI image

Hi Simon,
On Wed, Sep 08, 2021 at 08:14:30PM +0200, Heinrich Schuchardt wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
When starting the app, locate all block devices and make them available to U-Boot. This allows listing partitions and accessing files in filesystems.
EFI also has the concept of 'disks', meaning boot media. For now, this is not obviously useful in U-Boot, but add code to at least locate these. This can be expanded later as needed.
UEFI firmware handles with the EFI_BLOCK_IO_PROTOCOL for raw access to disks and partitions. It further provides the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on these handles to access files on formatted media.
Do you want to implement "efifs" as a U-Boot's file system on top of SIMPLE_FILE_SYSTEM_PROTO? Just kidding.
I have one concern:
Signed-off-by: Simon Glass sjg@chromium.org
include/efi.h | 15 ++++++ include/efi_api.h | 15 ++++++ lib/efi/efi_app.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+)
diff --git a/include/efi.h b/include/efi.h index 0ec5913ddd1..c0fddf7f6cd 100644 --- a/include/efi.h +++ b/include/efi.h @@ -529,4 +529,19 @@ void efi_putc(struct efi_priv *priv, const char ch); */ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep);
+/**
- efi_bind_block() - bind a new block device to an EFI device
- Binds a new top-level EFI_MEDIA device as well as a child block device so
- that the block device can be accessed in U-Boot.
- The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
- for example, just like any other interface type.
- @handle: handle of the controller on which this driver is installed
- @blkio: block io protocol proxied by this driver
- @return 0 if OK, -ve on error
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio);
- #endif /* _LINUX_EFI_H */
diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb720..0e88b3e5dbe 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1994,4 +1994,19 @@ struct efi_firmware_management_protocol { const u16 *package_version_name); };
+#define EFI_DISK_IO_PROTOCOL_GUID \
- EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \
0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+struct efi_disk {
- u64 revision;
- efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
- efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
+};
- #endif
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..9ba48517422 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,6 +21,9 @@ #include <efi.h> #include <efi_api.h> #include <sysreset.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -46,6 +49,33 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; }
+/**
- Create a block device so U-Boot can access an EFI device
- @handle: EFI handle to bind
- @blkio: block io protocol
- Return: 0 = success
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio) +{
- struct efi_media_plat plat;
- struct udevice *dev;
- char name[18];
- int ret;
- plat.handle = handle;
- plat.blkio = blkio;
- ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
&plat, ofnode_null(), &dev);
- if (ret)
return log_msg_ret("bind", ret);
- snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
- device_set_name(dev, name);
- return 0;
+}
- static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;
@@ -105,6 +135,95 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
+static int setup_disks(void) +{
- /* This is not fully implemented yet */
- return 0;
- efi_guid_t efi_disk_guid = EFI_DISK_IO_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_disk *disk;
- int ret;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- ret = boot->locate_protocol(&efi_disk_guid, NULL, (void **)&disk);
- if (ret)
return log_msg_ret("prot", -ENOTSUPP);
- return 0;
+}
+static int setup_block(void) +{
- efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
- efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_block_io *blkio;
- struct efi_device_path device_path;
- efi_handle_t handle[100];
- efi_uintn_t buf_size;
- int num_handles;
- int ret, i;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- buf_size = sizeof(handle);
- ret = boot->locate_handle(BY_PROTOCOL, &efi_blkio_guid, NULL,
&buf_size, handle);
You could use LocateHandleBuffer() here which will allocate enough memory for all matching handles.
- if (ret)
return log_msg_ret("loc", -ENOTSUPP);
- num_handles = buf_size / sizeof(efi_handle_t);
- log_info("Found %d EFI handles\n", num_handles);
- for (i = 0; i < num_handles; i++) {
ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
(void **)&device_path);
Why do you read the devicepath if you don't use it?
if (ret) {
log_warning("- devpath %d failed (ret=%d)\n", i, ret);
continue;
}
Here some analysis of devicepaths and installed protocols is missing to find out which of the handles represents a block device and which represents a partition:
If the last devicepath node is type 4 , Media Device Path with SubType 1 Hard Drive and the partition number is non-zero it is a partition.
If the devicepath without the last node relates to a handle with the EFI_BLOCK_IO_PROTOCOL, this also indicates that the current handle is for a partition.
Best regards
Heinrich
ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
(void **)&blkio);
if (ret) {
log_warning("- blkio %d failed (ret=%d)\n", i, ret);
continue;
}
ret = efi_bind_block(handle[i], blkio);
Here you are trying to create a U-Boot block device for every UEFI block device (i.e.BLOCK_IO_PROTOCOL interface), but please remember that U-Boot UEFI has created UEFI block devices for all the existing U-Boot block devices at the initialization time.
So any physical disk may end up having one (original) U-Boot block device and another U-Boot block device rooted in UEFI object (and yet another U-Boot block device rooted in the second one and so on?).
-Takahiro Akashi
if (ret) {
log_warning("- blkio bind %d failed (ret=%d)\n", i, ret);
continue;
}
- }
- if (ret)
return log_msg_ret("prot", -ENOTSUPP);
- return 0;
+}
+int dm_scan_other(bool pre_reloc_only) +{
- if (gd->flags & GD_FLG_RELOC) {
int ret;
/* Find all block devices and setup EFI devices for them */
ret = setup_block();
if (ret)
return ret;
/* Not needed at present, but could be useful one day? */
ret = setup_disks();
if (ret)
return ret;
- }
- return 0;
+}
- /**
- efi_main() - Start an EFI image

Hi Takahiro,
On Wed, 8 Sept 2021 at 19:11, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Simon,
On Wed, Sep 08, 2021 at 08:14:30PM +0200, Heinrich Schuchardt wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
When starting the app, locate all block devices and make them available to U-Boot. This allows listing partitions and accessing files in filesystems.
EFI also has the concept of 'disks', meaning boot media. For now, this is not obviously useful in U-Boot, but add code to at least locate these. This can be expanded later as needed.
UEFI firmware handles with the EFI_BLOCK_IO_PROTOCOL for raw access to disks and partitions. It further provides the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on these handles to access files on formatted media.
Do you want to implement "efifs" as a U-Boot's file system on top of SIMPLE_FILE_SYSTEM_PROTO? Just kidding.
Eek.
I have one concern:
Signed-off-by: Simon Glass sjg@chromium.org
include/efi.h | 15 ++++++ include/efi_api.h | 15 ++++++ lib/efi/efi_app.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+)
diff --git a/include/efi.h b/include/efi.h index 0ec5913ddd1..c0fddf7f6cd 100644 --- a/include/efi.h +++ b/include/efi.h @@ -529,4 +529,19 @@ void efi_putc(struct efi_priv *priv, const char ch); */ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep);
+/**
- efi_bind_block() - bind a new block device to an EFI device
- Binds a new top-level EFI_MEDIA device as well as a child block device so
- that the block device can be accessed in U-Boot.
- The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
- for example, just like any other interface type.
- @handle: handle of the controller on which this driver is installed
- @blkio: block io protocol proxied by this driver
- @return 0 if OK, -ve on error
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio);
- #endif /* _LINUX_EFI_H */
diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb720..0e88b3e5dbe 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1994,4 +1994,19 @@ struct efi_firmware_management_protocol { const u16 *package_version_name); };
+#define EFI_DISK_IO_PROTOCOL_GUID \
- EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \
0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+struct efi_disk {
- u64 revision;
- efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
- efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
+};
- #endif
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..9ba48517422 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,6 +21,9 @@ #include <efi.h> #include <efi_api.h> #include <sysreset.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -46,6 +49,33 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; }
+/**
- Create a block device so U-Boot can access an EFI device
- @handle: EFI handle to bind
- @blkio: block io protocol
- Return: 0 = success
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio) +{
- struct efi_media_plat plat;
- struct udevice *dev;
- char name[18];
- int ret;
- plat.handle = handle;
- plat.blkio = blkio;
- ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
&plat, ofnode_null(), &dev);
- if (ret)
return log_msg_ret("bind", ret);
- snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
- device_set_name(dev, name);
- return 0;
+}
- static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;
@@ -105,6 +135,95 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
+static int setup_disks(void) +{
- /* This is not fully implemented yet */
- return 0;
- efi_guid_t efi_disk_guid = EFI_DISK_IO_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_disk *disk;
- int ret;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- ret = boot->locate_protocol(&efi_disk_guid, NULL, (void **)&disk);
- if (ret)
return log_msg_ret("prot", -ENOTSUPP);
- return 0;
+}
+static int setup_block(void) +{
- efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
- efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_block_io *blkio;
- struct efi_device_path device_path;
- efi_handle_t handle[100];
- efi_uintn_t buf_size;
- int num_handles;
- int ret, i;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- buf_size = sizeof(handle);
- ret = boot->locate_handle(BY_PROTOCOL, &efi_blkio_guid, NULL,
&buf_size, handle);
You could use LocateHandleBuffer() here which will allocate enough memory for all matching handles.
- if (ret)
return log_msg_ret("loc", -ENOTSUPP);
- num_handles = buf_size / sizeof(efi_handle_t);
- log_info("Found %d EFI handles\n", num_handles);
- for (i = 0; i < num_handles; i++) {
ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
(void **)&device_path);
Why do you read the devicepath if you don't use it?
if (ret) {
log_warning("- devpath %d failed (ret=%d)\n", i, ret);
continue;
}
Here some analysis of devicepaths and installed protocols is missing to find out which of the handles represents a block device and which represents a partition:
If the last devicepath node is type 4 , Media Device Path with SubType 1 Hard Drive and the partition number is non-zero it is a partition.
If the devicepath without the last node relates to a handle with the EFI_BLOCK_IO_PROTOCOL, this also indicates that the current handle is for a partition.
Best regards
Heinrich
ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
(void **)&blkio);
if (ret) {
log_warning("- blkio %d failed (ret=%d)\n", i, ret);
continue;
}
ret = efi_bind_block(handle[i], blkio);
Here you are trying to create a U-Boot block device for every UEFI block device (i.e.BLOCK_IO_PROTOCOL interface), but please remember that U-Boot UEFI has created UEFI block devices for all the existing U-Boot block devices at the initialization time.
Do you mean with EFI_LOADER? This code is for U-Boot as an app, where EFI_LOADER is disabled, at least at present.
So any physical disk may end up having one (original) U-Boot block device and another U-Boot block device rooted in UEFI object (and yet another U-Boot block device rooted in the second one and so on?).
Hopefully that is not an issue, for now. We will need to figure it out later, if we enable EFI_LOADER.
Regards, Simon
[..]

On Thu, Sep 09, 2021 at 02:09:12PM -0600, Simon Glass wrote:
Hi Takahiro,
On Wed, 8 Sept 2021 at 19:11, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Simon,
On Wed, Sep 08, 2021 at 08:14:30PM +0200, Heinrich Schuchardt wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
When starting the app, locate all block devices and make them available to U-Boot. This allows listing partitions and accessing files in filesystems.
EFI also has the concept of 'disks', meaning boot media. For now, this is not obviously useful in U-Boot, but add code to at least locate these. This can be expanded later as needed.
UEFI firmware handles with the EFI_BLOCK_IO_PROTOCOL for raw access to disks and partitions. It further provides the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on these handles to access files on formatted media.
Do you want to implement "efifs" as a U-Boot's file system on top of SIMPLE_FILE_SYSTEM_PROTO? Just kidding.
Eek.
I have one concern:
Signed-off-by: Simon Glass sjg@chromium.org
include/efi.h | 15 ++++++ include/efi_api.h | 15 ++++++ lib/efi/efi_app.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+)
diff --git a/include/efi.h b/include/efi.h index 0ec5913ddd1..c0fddf7f6cd 100644 --- a/include/efi.h +++ b/include/efi.h @@ -529,4 +529,19 @@ void efi_putc(struct efi_priv *priv, const char ch); */ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep);
+/**
- efi_bind_block() - bind a new block device to an EFI device
- Binds a new top-level EFI_MEDIA device as well as a child block device so
- that the block device can be accessed in U-Boot.
- The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
- for example, just like any other interface type.
- @handle: handle of the controller on which this driver is installed
- @blkio: block io protocol proxied by this driver
- @return 0 if OK, -ve on error
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio);
- #endif /* _LINUX_EFI_H */
diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb720..0e88b3e5dbe 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1994,4 +1994,19 @@ struct efi_firmware_management_protocol { const u16 *package_version_name); };
+#define EFI_DISK_IO_PROTOCOL_GUID \
- EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \
0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+struct efi_disk {
- u64 revision;
- efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
- efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
+};
- #endif
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..9ba48517422 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,6 +21,9 @@ #include <efi.h> #include <efi_api.h> #include <sysreset.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -46,6 +49,33 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; }
+/**
- Create a block device so U-Boot can access an EFI device
- @handle: EFI handle to bind
- @blkio: block io protocol
- Return: 0 = success
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio) +{
- struct efi_media_plat plat;
- struct udevice *dev;
- char name[18];
- int ret;
- plat.handle = handle;
- plat.blkio = blkio;
- ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
&plat, ofnode_null(), &dev);
- if (ret)
return log_msg_ret("bind", ret);
- snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
- device_set_name(dev, name);
- return 0;
+}
- static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;
@@ -105,6 +135,95 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
+static int setup_disks(void) +{
- /* This is not fully implemented yet */
- return 0;
- efi_guid_t efi_disk_guid = EFI_DISK_IO_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_disk *disk;
- int ret;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- ret = boot->locate_protocol(&efi_disk_guid, NULL, (void **)&disk);
- if (ret)
return log_msg_ret("prot", -ENOTSUPP);
- return 0;
+}
+static int setup_block(void) +{
- efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
- efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_block_io *blkio;
- struct efi_device_path device_path;
- efi_handle_t handle[100];
- efi_uintn_t buf_size;
- int num_handles;
- int ret, i;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- buf_size = sizeof(handle);
- ret = boot->locate_handle(BY_PROTOCOL, &efi_blkio_guid, NULL,
&buf_size, handle);
You could use LocateHandleBuffer() here which will allocate enough memory for all matching handles.
- if (ret)
return log_msg_ret("loc", -ENOTSUPP);
- num_handles = buf_size / sizeof(efi_handle_t);
- log_info("Found %d EFI handles\n", num_handles);
- for (i = 0; i < num_handles; i++) {
ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
(void **)&device_path);
Why do you read the devicepath if you don't use it?
if (ret) {
log_warning("- devpath %d failed (ret=%d)\n", i, ret);
continue;
}
Here some analysis of devicepaths and installed protocols is missing to find out which of the handles represents a block device and which represents a partition:
If the last devicepath node is type 4 , Media Device Path with SubType 1 Hard Drive and the partition number is non-zero it is a partition.
If the devicepath without the last node relates to a handle with the EFI_BLOCK_IO_PROTOCOL, this also indicates that the current handle is for a partition.
Best regards
Heinrich
ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
(void **)&blkio);
if (ret) {
log_warning("- blkio %d failed (ret=%d)\n", i, ret);
continue;
}
ret = efi_bind_block(handle[i], blkio);
Here you are trying to create a U-Boot block device for every UEFI block device (i.e.BLOCK_IO_PROTOCOL interface), but please remember that U-Boot UEFI has created UEFI block devices for all the existing U-Boot block devices at the initialization time.
Do you mean with EFI_LOADER? This code is for U-Boot as an app, where EFI_LOADER is disabled, at least at present.
Ah ok, but in this patch series, you touched some files under lib/efi_loader and lib/efi_driver and I thought you have assumed the option as well. So your patch#11 are fully independent from the rest.
-Takahiro Akashi
So any physical disk may end up having one (original) U-Boot block device and another U-Boot block device rooted in UEFI object (and yet another U-Boot block device rooted in the second one and so on?).
Hopefully that is not an issue, for now. We will need to figure it out later, if we enable EFI_LOADER.
Regards, Simon
[..]

Hi Heinrich,
On Wed, 8 Sept 2021 at 12:19, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
When starting the app, locate all block devices and make them available to U-Boot. This allows listing partitions and accessing files in filesystems.
EFI also has the concept of 'disks', meaning boot media. For now, this is not obviously useful in U-Boot, but add code to at least locate these. This can be expanded later as needed.
UEFI firmware handles with the EFI_BLOCK_IO_PROTOCOL for raw access to disks and partitions. It further provides the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on these handles to access files on formatted media.
OK ta.
Signed-off-by: Simon Glass sjg@chromium.org
include/efi.h | 15 ++++++ include/efi_api.h | 15 ++++++ lib/efi/efi_app.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+)
diff --git a/include/efi.h b/include/efi.h index 0ec5913ddd1..c0fddf7f6cd 100644 --- a/include/efi.h +++ b/include/efi.h @@ -529,4 +529,19 @@ void efi_putc(struct efi_priv *priv, const char ch); */ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep);
+/**
- efi_bind_block() - bind a new block device to an EFI device
- Binds a new top-level EFI_MEDIA device as well as a child block device so
- that the block device can be accessed in U-Boot.
- The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
- for example, just like any other interface type.
- @handle: handle of the controller on which this driver is installed
- @blkio: block io protocol proxied by this driver
- @return 0 if OK, -ve on error
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio);
- #endif /* _LINUX_EFI_H */
diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb720..0e88b3e5dbe 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1994,4 +1994,19 @@ struct efi_firmware_management_protocol { const u16 *package_version_name); };
+#define EFI_DISK_IO_PROTOCOL_GUID \
EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \
0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+struct efi_disk {
u64 revision;
efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id,
u64 offset, efi_uintn_t buffer_size,
void *buffer);
+};
- #endif
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..9ba48517422 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,6 +21,9 @@ #include <efi.h> #include <efi_api.h> #include <sysreset.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -46,6 +49,33 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; }
+/**
- Create a block device so U-Boot can access an EFI device
- @handle: EFI handle to bind
- @blkio: block io protocol
- Return: 0 = success
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio) +{
struct efi_media_plat plat;
struct udevice *dev;
char name[18];
int ret;
plat.handle = handle;
plat.blkio = blkio;
ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
&plat, ofnode_null(), &dev);
if (ret)
return log_msg_ret("bind", ret);
snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
device_set_name(dev, name);
return 0;
+}
- static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;
@@ -105,6 +135,95 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
+static int setup_disks(void) +{
/* This is not fully implemented yet */
return 0;
efi_guid_t efi_disk_guid = EFI_DISK_IO_PROTOCOL_GUID;
struct efi_boot_services *boot = efi_get_boot();
struct efi_disk *disk;
int ret;
if (!boot)
return log_msg_ret("sys", -ENOSYS);
ret = boot->locate_protocol(&efi_disk_guid, NULL, (void **)&disk);
if (ret)
return log_msg_ret("prot", -ENOTSUPP);
return 0;
+}
+static int setup_block(void) +{
efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
struct efi_boot_services *boot = efi_get_boot();
struct efi_block_io *blkio;
struct efi_device_path device_path;
efi_handle_t handle[100];
efi_uintn_t buf_size;
int num_handles;
int ret, i;
if (!boot)
return log_msg_ret("sys", -ENOSYS);
buf_size = sizeof(handle);
ret = boot->locate_handle(BY_PROTOCOL, &efi_blkio_guid, NULL,
&buf_size, handle);
You could use LocateHandleBuffer() here which will allocate enough memory for all matching handles.
OK ta.
if (ret)
return log_msg_ret("loc", -ENOTSUPP);
num_handles = buf_size / sizeof(efi_handle_t);
log_info("Found %d EFI handles\n", num_handles);
for (i = 0; i < num_handles; i++) {
ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
(void **)&device_path);
Why do you read the devicepath if you don't use it?
Well there is quite a bit of code here I am unsure about...e.g. will we need it later or is there something missing now? If not I can drop it.
if (ret) {
log_warning("- devpath %d failed (ret=%d)\n", i, ret);
continue;
}
Here some analysis of devicepaths and installed protocols is missing to find out which of the handles represents a block device and which represents a partition:
If the last devicepath node is type 4 , Media Device Path with SubType 1 Hard Drive and the partition number is non-zero it is a partition.
If the devicepath without the last node relates to a handle with the EFI_BLOCK_IO_PROTOCOL, this also indicates that the current handle is for a partition.
OK thanks, I will take a look.
Regards, Simon [..]

The Exception base class is a very vague and could be confusing to the test system. Use the more specific ValueError exception instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/patman/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/patman/tools.py b/tools/patman/tools.py index 877e37cd8da..23ddb124804 100644 --- a/tools/patman/tools.py +++ b/tools/patman/tools.py @@ -348,7 +348,7 @@ def Run(name, *args, **kwargs): result = command.RunPipe([all_args], capture=True, capture_stderr=True, env=env, raise_on_error=False, binary=binary) if result.return_code: - raise Exception("Error %d running '%s': %s" % + raise ValueError("Error %d running '%s': %s" % (result.return_code,' '.join(all_args), result.stderr)) return result.stdout

At present any error from the 'make' command is silently swallowed by the test system. Fix this by showing it when detected.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/elf_test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index 7a128018d9f..bcccd78c0a1 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -70,8 +70,12 @@ def BuildElfTestFiles(target_dir): # correctly. So drop any make flags here. if 'MAKEFLAGS' in os.environ: del os.environ['MAKEFLAGS'] - tools.Run('make', '-C', target_dir, '-f', - os.path.join(testdir, 'Makefile'), 'SRC=%s/' % testdir) + try: + tools.Run('make', '-C', target_dir, '-f', + os.path.join(testdir, 'Makefile'), 'SRC=%s/' % testdir) + except ValueError as e: + # The test system seems to suppress this in a strange way + print(e)
class TestElf(unittest.TestCase):

Binman needs to be able to update the contents of an ELF file after it has been build. To support this, add a function to locate the position of a symbol's contents within the file.
Fix the comments on bss_data.c and Symbol while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/elf.py | 53 ++++++++++++++++++++++++++++++-- tools/binman/elf_test.py | 37 ++++++++++++++++++++++ tools/binman/test/Makefile | 5 ++- tools/binman/test/bss_data.c | 2 +- tools/binman/test/embed_data.c | 16 ++++++++++ tools/binman/test/embed_data.lds | 23 ++++++++++++++ 6 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 tools/binman/test/embed_data.c create mode 100644 tools/binman/test/embed_data.lds
diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 03b49d7163c..4aca4f847ce 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -24,7 +24,14 @@ try: except: # pragma: no cover ELF_TOOLS = False
-Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak']) +# Information about an EFL symbol: +# section (str): Name of the section containing this symbol +# address (int): Address of the symbol (its value) +# size (int): Size of the symbol in bytes +# weak (bool): True if the symbol is weak +# offset (int or None): Offset of the symbol's data in the ELF file, or None if +# not known +Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak', 'offset'])
# Information about an ELF file: # data: Extracted program contents of ELF file (this would be loaded by an @@ -71,8 +78,48 @@ def GetSymbols(fname, patterns): section, size = parts[:2] if len(parts) > 2: name = parts[2] if parts[2] != '.hidden' else parts[3] - syms[name] = Symbol(section, int(value, 16), int(size,16), - flags[1] == 'w') + syms[name] = Symbol(section, int(value, 16), int(size, 16), + flags[1] == 'w', None) + + # Sort dict by address + return OrderedDict(sorted(syms.items(), key=lambda x: x[1].address)) + +def GetSymbolFileOffset(fname, patterns): + """Get the symbols from an ELF file + + Args: + fname: Filename of the ELF file to read + patterns: List of regex patterns to search for, each a string + + Returns: + None, if the file does not exist, or Dict: + key: Name of symbol + value: Hex value of symbol + """ + def _GetFileOffset(elf, addr): + for seg in elf.iter_segments(): + seg_end = seg['p_vaddr'] + seg['p_filesz'] + if seg.header['p_type'] == 'PT_LOAD': + if addr >= seg['p_vaddr'] and addr < seg_end: + return addr - seg['p_vaddr'] + seg['p_offset'] + + if not ELF_TOOLS: + raise ValueError('Python elftools package is not available') + + syms = {} + with open(fname, 'rb') as fd: + elf = ELFFile(fd) + + re_syms = re.compile('|'.join(patterns)) + for section in elf.iter_sections(): + if isinstance(section, SymbolTableSection): + for symbol in section.iter_symbols(): + if not re_syms or re_syms.search(symbol.name): + addr = symbol.entry['st_value'] + syms[symbol.name] = Symbol( + section.name, addr, symbol.entry['st_size'], + symbol.entry['st_info']['bind'] == 'STB_WEAK', + _GetFileOffset(elf, addr))
# Sort dict by address return OrderedDict(sorted(syms.items(), key=lambda x: x[1].address)) diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index bcccd78c0a1..ac69a95b654 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -6,6 +6,7 @@
import os import shutil +import struct import sys import tempfile import unittest @@ -221,6 +222,42 @@ class TestElf(unittest.TestCase): elf.DecodeElf(data, load + 2)) shutil.rmtree(outdir)
+ def testEmbedData(self): + """Test for the GetSymbolFileOffset() function""" + if not elf.ELF_TOOLS: + self.skipTest('Python elftools not available') + + fname = self.ElfTestFile('embed_data') + offset = elf.GetSymbolFileOffset(fname, ['embed_start', 'embed_end']) + start = offset['embed_start'].offset + end = offset['embed_end'].offset + data = tools.ReadFile(fname) + embed_data = data[start:end] + expect = struct.pack('<III', 0x1234, 0x5678, 0) + self.assertEqual(expect, embed_data) + + def testEmbedFail(self): + """Test calling GetSymbolFileOffset() without elftools""" + try: + old_val = elf.ELF_TOOLS + elf.ELF_TOOLS = False + fname = self.ElfTestFile('embed_data') + with self.assertRaises(ValueError) as e: + elf.GetSymbolFileOffset(fname, ['embed_start', 'embed_end']) + self.assertIn('Python elftools package is not available', + str(e.exception)) + finally: + elf.ELF_TOOLS = old_val + + def testEmbedDataNoSym(self): + """Test for GetSymbolFileOffset() getting no symbols""" + if not elf.ELF_TOOLS: + self.skipTest('Python elftools not available') + + fname = self.ElfTestFile('embed_data') + offset = elf.GetSymbolFileOffset(fname, ['missing_sym']) + self.assertEqual({}, offset) +
if __name__ == '__main__': unittest.main() diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile index 0b19b7d9935..6e6cc6de491 100644 --- a/tools/binman/test/Makefile +++ b/tools/binman/test/Makefile @@ -31,7 +31,7 @@ LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds
TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \ u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \ - u_boot_binman_syms_size u_boot_binman_syms_x86 + u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data
all: $(TARGETS)
@@ -44,6 +44,9 @@ u_boot_ucode_ptr: u_boot_ucode_ptr.c bss_data: CFLAGS += $(SRC)bss_data.lds bss_data: bss_data.c
+embed_data: CFLAGS += $(SRC)embed_data.lds +embed_data: embed_data.c + u_boot_binman_syms.bin: u_boot_binman_syms $(OBJCOPY) -O binary $< -R .note.gnu.build-id $@
diff --git a/tools/binman/test/bss_data.c b/tools/binman/test/bss_data.c index 79537c31b65..4f9b64cef9e 100644 --- a/tools/binman/test/bss_data.c +++ b/tools/binman/test/bss_data.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2016 Google, Inc * - * Simple program to create a _dt_ucode_base_size symbol which can be read + * Simple program to create a bss_data region so the symbol can be read * by binutils. This is used by binman tests. */
diff --git a/tools/binman/test/embed_data.c b/tools/binman/test/embed_data.c new file mode 100644 index 00000000000..47d8c38248c --- /dev/null +++ b/tools/binman/test/embed_data.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * + * Simple program including some embedded data that can be accessed by binman. + * This is used by binman tests. + */ + +int first[10] = {1}; +int embed[3] __attribute__((section(".embed"))) = {0x1234, 0x5678}; +int second[10] = {1}; + +int main(void) +{ + return 0; +} diff --git a/tools/binman/test/embed_data.lds b/tools/binman/test/embed_data.lds new file mode 100644 index 00000000000..908bf66c294 --- /dev/null +++ b/tools/binman/test/embed_data.lds @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2021 Google LLC + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + _start = .; + __data_start = .; + .data : + { + . = ALIGN(32); + embed_start = .; + *(.embed*) + embed_end = .; + . = ALIGN(32); + *(.data*) + } +}

At present testThreadTimeout() assumes that the expected timeout happens first when building the section, but it can just as easily happen at the top-level image. Update the test to cope with both.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/ftest.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index cea3ebf2b9f..8199a4fc7e0 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -4565,8 +4565,7 @@ class TestFunctional(unittest.TestCase): with self.assertRaises(ValueError) as e: self._DoTestFile('202_section_timeout.dts', test_section_timeout=True) - self.assertIn("Node '/binman/section@0': Timed out obtaining contents", - str(e.exception)) + self.assertIn("Timed out obtaining contents", str(e.exception))
def testTiming(self): """Test output of timing information"""

The comment for this function is missing an argument and the return value. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/ftest.py | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 8199a4fc7e0..39a4b94cd0b 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -334,6 +334,11 @@ class TestFunctional(unittest.TestCase): extra_indirs: Extra input directories to add using -I threads: Number of threads to use (None for default, 0 for single-threaded) + test_section_timeout: True to force the first time to timeout, as + used in testThreadTimeout() + + Returns: + int return code, 0 on success """ args = [] if debug:

WIth EFI we must embed the devicetree in an ELF image so that it is loaded as part of the executable file. We want it to include the binman definition in there also, which in some cases cannot be created until the ELF (u-boot) is built. Add an option to binman to support writing the updated dtb to the ELF file u-boot.out
This is useful with the EFI app, which is always packaged as an ELF file.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/binman.rst | 36 ++++++++++ tools/binman/cmdline.py | 2 + tools/binman/control.py | 11 +++ tools/binman/elf.py | 21 ++++++ tools/binman/ftest.py | 83 +++++++++++++++++++++- tools/binman/test/Makefile | 10 ++- tools/binman/test/u_boot_binman_embed.c | 13 ++++ tools/binman/test/u_boot_binman_embed.lds | 29 ++++++++ tools/binman/test/u_boot_binman_embed_sm.c | 13 ++++ 9 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 tools/binman/test/u_boot_binman_embed.c create mode 100644 tools/binman/test/u_boot_binman_embed.lds create mode 100644 tools/binman/test/u_boot_binman_embed_sm.c
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index 09e7b571982..e2c7083722d 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -822,6 +822,42 @@ the 'warning' line in scripts/Makefile.lib to see what it has found:: # u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
+Updating an ELF file +==================== + +For the EFI app, where U-Boot is loaded from UEFI and runs as an app, there is +no way to update the devicetree after U-Boot is built. Normally this works by +creating a new u-boot.dtb.out with he updated devicetree, which is automatically +built into the output image. With ELF this is not possible since the ELF is +not part of an image, just a stand-along file. We must create an updated ELF +file with the new devicetree. + +This is handled by the --update-fdt-in-elf option. It takes four arguments, +separated by comma: + + infile - filename of input ELF file, e.g. 'u-boot's + outfile - filename of output ELF file, e.g. 'u-boot.out' + begin_sym - symbol at the start of the embedded devicetree, e.g. + '__dtb_dt_begin' + end_sym - symbol at the start of the embedded devicetree, e.g. + '__dtb_dt_end' + +When this flag is used, U-Boot does all the normal packaging, but as an +additional step, it creates a new ELF file with the new devicetree embedded in +it. + +If logging is enabled you will see a message like this:: + + Updating file 'u-boot' with data length 0x400a (16394) between symbols + '__dtb_dt_begin' and '__dtb_dt_end' + +There must be enough space for the updated devicetree. If not, an error like +the following is produced:: + + ValueError: Not enough space in 'u-boot' for data length 0x400a (16394); + size is 0x1744 (5956) + + Entry Documentation ===================
diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py index d6156df408b..23729f16dcc 100644 --- a/tools/binman/cmdline.py +++ b/tools/binman/cmdline.py @@ -71,6 +71,8 @@ controlled by a description in the board device tree.''' 'given') build_parser.add_argument('-u', '--update-fdt', action='store_true', default=False, help='Update the binman node with offset/size info') + build_parser.add_argument('--update-fdt-in-elf', type=str, + help='Update an ELF file with the output dtb: infile,outfile,begin_sym,end_sym')
entry_parser = subparsers.add_parser('entry-docs', help='Write out entry documentation (see entries.rst)') diff --git a/tools/binman/control.py b/tools/binman/control.py index dcba02ff7f8..e73bc55252c 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -598,6 +598,13 @@ def Binman(args): tools.FinaliseOutputDir() return 0
+ elf_params = None + if args.update_fdt_in_elf: + elf_params = args.update_fdt_in_elf.split(',') + if len(elf_params) != 4: + raise ValueError('Invalid args %s to --update-fdt-in-elf: expected infile,outfile,begin_sym,end_sym' % + elf_params) + # Try to figure out which device tree contains our image description if args.dt: dtb_fname = args.dt @@ -644,6 +651,10 @@ def Binman(args): for dtb_item in state.GetAllFdts(): tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
+ if elf_params: + data = state.GetFdtForEtype('u-boot-dtb').GetContents() + elf.UpdateFile(*elf_params, data) + if missing: tout.Warning("\nSome images are invalid")
diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 4aca4f847ce..de2bb4651fa 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -348,3 +348,24 @@ def DecodeElf(data, location): segment.data()[offset:]) return ElfInfo(output, data_start, elf.header['e_entry'] + virt_to_phys, mem_end - data_start) + +def UpdateFile(infile, outfile, start_sym, end_sym, insert): + tout.Notice("Creating file '%s' with data length %#x (%d) between symbols '%s' and '%s'" % + (outfile, len(insert), len(insert), start_sym, end_sym)) + syms = GetSymbolFileOffset(infile, [start_sym, end_sym]) + if len(syms) != 2: + raise ValueError("Expected two symbols '%s' and '%s': got %d: %s" % + (start_sym, end_sym, len(syms), + ','.join(syms.keys()))) + + size = syms[end_sym].offset - syms[start_sym].offset + if len(insert) > size: + raise ValueError("Not enough space in '%s' for data length %#x (%d); size is %#x (%d)" % + (infile, len(insert), len(insert), size, size)) + + data = tools.ReadFile(infile) + newdata = data[:syms[start_sym].offset] + newdata += insert + tools.GetBytes(0, size - len(insert)) + newdata += data[syms[end_sym].offset:] + tools.WriteFile(outfile, newdata) + tout.Info('Written to offset %#x' % syms[start_sym].offset) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 39a4b94cd0b..6be003786e8 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -309,7 +309,7 @@ class TestFunctional(unittest.TestCase): entry_args=None, images=None, use_real_dtb=False, use_expanded=False, verbosity=None, allow_missing=False, extra_indirs=None, threads=None, - test_section_timeout=False): + test_section_timeout=False, update_fdt_in_elf=None): """Run binman with a given test file
Args: @@ -336,6 +336,7 @@ class TestFunctional(unittest.TestCase): single-threaded) test_section_timeout: True to force the first time to timeout, as used in testThreadTimeout() + update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Returns: int return code, 0 on success @@ -368,6 +369,8 @@ class TestFunctional(unittest.TestCase): args.append('-a%s=%s' % (arg, value)) if allow_missing: args.append('-M') + if update_fdt_in_elf: + args += ['--update-fdt-in-elf', update_fdt_in_elf] if images: for image in images: args += ['-i', image] @@ -4580,6 +4583,84 @@ class TestFunctional(unittest.TestCase): self.assertIn('read:', stdout.getvalue()) self.assertIn('compress:', stdout.getvalue())
+ def testUpdateFdtInElf(self): + """Test that we can update the devicetree in an ELF file""" + infile = elf_fname = self.ElfTestFile('u_boot_binman_embed') + outfile = os.path.join(self._indir, 'u-boot.out') + begin_sym = 'dtb_embed_begin' + end_sym = 'dtb_embed_end' + retcode = self._DoTestFile( + '060_fdt_update.dts', update_dtb=True, + update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym])) + self.assertEqual(0, retcode) + + # Check that the output file does in fact contact a dtb with the binman + # definition in the correct place + syms = elf.GetSymbolFileOffset(infile, + ['dtb_embed_begin', 'dtb_embed_end']) + data = tools.ReadFile(outfile) + dtb_data = data[syms['dtb_embed_begin'].offset: + syms['dtb_embed_end'].offset] + + dtb = fdt.Fdt.FromData(dtb_data) + dtb.Scan() + props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS) + self.assertEqual({ + 'image-pos': 0, + 'offset': 0, + '_testing:offset': 32, + '_testing:size': 2, + '_testing:image-pos': 32, + 'section@0/u-boot:offset': 0, + 'section@0/u-boot:size': len(U_BOOT_DATA), + 'section@0/u-boot:image-pos': 0, + 'section@0:offset': 0, + 'section@0:size': 16, + 'section@0:image-pos': 0, + + 'section@1/u-boot:offset': 0, + 'section@1/u-boot:size': len(U_BOOT_DATA), + 'section@1/u-boot:image-pos': 16, + 'section@1:offset': 16, + 'section@1:size': 16, + 'section@1:image-pos': 16, + 'size': 40 + }, props) + + def testUpdateFdtInElfInvalid(self): + """Test that invalid args are detected with --update-fdt-in-elf""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred') + self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf", + str(e.exception)) + + def testUpdateFdtInElfNoSyms(self): + """Test that missing symbols are detected with --update-fdt-in-elf""" + infile = elf_fname = self.ElfTestFile('u_boot_binman_embed') + outfile = '' + begin_sym = 'wrong_begin' + end_sym = 'wrong_end' + with self.assertRaises(ValueError) as e: + self._DoTestFile( + '060_fdt_update.dts', + update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym])) + self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:", + str(e.exception)) + + def testUpdateFdtInElfTooSmall(self): + """Test that an over-large dtb is detected with --update-fdt-in-elf""" + infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm') + outfile = os.path.join(self._indir, 'u-boot.out') + begin_sym = 'dtb_embed_begin' + end_sym = 'dtb_embed_end' + with self.assertRaises(ValueError) as e: + self._DoTestFile( + '060_fdt_update.dts', update_dtb=True, + update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym])) + self.assertRegex( + str(e.exception), + "Not enough space in '.*u_boot_binman_embed_sm' for data length.*") +
if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile index 6e6cc6de491..387ba163353 100644 --- a/tools/binman/test/Makefile +++ b/tools/binman/test/Makefile @@ -28,10 +28,12 @@ LDS_UCODE := -T $(SRC)u_boot_ucode_ptr.lds LDS_BINMAN := -T $(SRC)u_boot_binman_syms.lds LDS_BINMAN_BAD := -T $(SRC)u_boot_binman_syms_bad.lds LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds +LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \ u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \ - u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data + u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \ + u_boot_binman_embed u_boot_binman_embed_sm
all: $(TARGETS)
@@ -62,6 +64,12 @@ u_boot_binman_syms_bad: u_boot_binman_syms_bad.c u_boot_binman_syms_size: CFLAGS += $(LDS_BINMAN) u_boot_binman_syms_size: u_boot_binman_syms_size.c
+u_boot_binman_embed: CFLAGS += $(LDS_BINMAN_EMBED) +u_boot_binman_embed: u_boot_binman_embed.c + +u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED) +u_boot_binman_embed_sm: u_boot_binman_embed_sm.c + clean: rm -f $(TARGETS)
diff --git a/tools/binman/test/u_boot_binman_embed.c b/tools/binman/test/u_boot_binman_embed.c new file mode 100644 index 00000000000..75874bb6e23 --- /dev/null +++ b/tools/binman/test/u_boot_binman_embed.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * + * Simple program to embed a devicetree. This is used by binman tests. + */ + +int __attribute__((section(".mydtb"))) dtb_data[4096]; + +int main(void) +{ + return 0; +} diff --git a/tools/binman/test/u_boot_binman_embed.lds b/tools/binman/test/u_boot_binman_embed.lds new file mode 100644 index 00000000000..e213fa8a84c --- /dev/null +++ b/tools/binman/test/u_boot_binman_embed.lds @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2016 Google, Inc + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0x00000000; + _start = .; + + . = ALIGN(4); + .text : + { + *(.text*) + } + + . = ALIGN(4); + .data : { + dtb_embed_begin = .; + KEEP(*(.mydtb)); + dtb_embed_end = .; + } + .interp : { *(.interp*) } + +} diff --git a/tools/binman/test/u_boot_binman_embed_sm.c b/tools/binman/test/u_boot_binman_embed_sm.c new file mode 100644 index 00000000000..ae245d78a6a --- /dev/null +++ b/tools/binman/test/u_boot_binman_embed_sm.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * + * Simple program to embed a devicetree. This is used by binman tests. + */ + +int __attribute__((section(".mydtb"))) dtb_data[16]; + +int main(void) +{ + return 0; +}

At present only the backspace key is supported in U-Boot, when running as an EFI app. Add support for arrows, home and end as well, to make the CLI more friendly.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/serial/serial_efi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c index 33ddbd6080c..0067576389d 100644 --- a/drivers/serial/serial_efi.c +++ b/drivers/serial/serial_efi.c @@ -24,6 +24,9 @@ struct serial_efi_priv { bool have_key; };
+/* Convert a lower-case character to its ctrl-char equivalent */ +#define CTL_CH(c) ((c) - 'a' + 1) + int serial_efi_setbrg(struct udevice *dev, int baudrate) { return 0; @@ -49,6 +52,7 @@ static int serial_efi_get_key(struct serial_efi_priv *priv) static int serial_efi_getc(struct udevice *dev) { struct serial_efi_priv *priv = dev_get_priv(dev); + char conv_scan[10] = {0, 'p', 'n', 'f', 'b', 'a', 'e', 0, 8}; int ret, ch;
ret = serial_efi_get_key(priv); @@ -63,8 +67,11 @@ static int serial_efi_getc(struct udevice *dev) * key scan code of 8. Handle this so that backspace works correctly * in the U-Boot command line. */ - if (!ch && priv->key.scan_code == 8) - ch = 8; + if (!ch && priv->key.scan_code < sizeof(conv_scan)) { + ch = conv_scan[priv->key.scan_code]; + if (ch >= 'a') + ch -= 'a' - 1; + } debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code);
return ch;

Move this documentation to the new format.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/{README.bloblist => develop/bloblist.rst} | 4 ++-- doc/develop/index.rst | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) rename doc/{README.bloblist => develop/bloblist.rst} (97%)
diff --git a/doc/README.bloblist b/doc/develop/bloblist.rst similarity index 97% rename from doc/README.bloblist rename to doc/develop/bloblist.rst index 274c4605571..317ebc4919d 100644 --- a/doc/README.bloblist +++ b/doc/develop/bloblist.rst @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0+ +.. SPDX-License-Identifier: GPL-2.0+
Blob Lists - bloblist ===================== @@ -39,7 +39,7 @@ Blob tags
Each blob has a tag which is a 32-bit number. This uniquely identifies the owner of the blob. Blob tags are listed in enum blob_tag_t and are named -with a BLOBT_ prefix. +with a `BLOBT_` prefix.
Single structure diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 83c929babda..2a32645cfd2 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -9,6 +9,7 @@ Implementation .. toctree:: :maxdepth: 1
+ bloblist ci_testing commands devicetree/index

On 9/8/21 3:33 PM, Simon Glass wrote:
Move this documentation to the new format.
Signed-off-by: Simon Glass sjg@chromium.org
Acked-by: Heinrich Schuchardt xypron.glpk@gmx.de
doc/{README.bloblist => develop/bloblist.rst} | 4 ++-- doc/develop/index.rst | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) rename doc/{README.bloblist => develop/bloblist.rst} (97%)
diff --git a/doc/README.bloblist b/doc/develop/bloblist.rst similarity index 97% rename from doc/README.bloblist rename to doc/develop/bloblist.rst index 274c4605571..317ebc4919d 100644 --- a/doc/README.bloblist +++ b/doc/develop/bloblist.rst @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0+ +.. SPDX-License-Identifier: GPL-2.0+
Blob Lists - bloblist
@@ -39,7 +39,7 @@ Blob tags
Each blob has a tag which is a 32-bit number. This uniquely identifies the owner of the blob. Blob tags are listed in enum blob_tag_t and are named -with a BLOBT_ prefix. +with a `BLOBT_` prefix.
Single structure diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 83c929babda..2a32645cfd2 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -9,6 +9,7 @@ Implementation .. toctree:: :maxdepth: 1
- bloblist ci_testing commands devicetree/index

Typically the bloblist is positioned at a fixed address in memory until relocation. This is convenient when it is set up in SPL or before relocation.
But for EFI we want to set it up only when U-Boot proper is running. Add a way to allocate it using malloc() and update the documentation to cover this aspect of bloblist.
Note there are no tests of this feature at present, nor any direct testing of bloblist_init().
This can be added, e.g. by making this option controllable at runtime.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/Kconfig | 15 +++++++++++++-- common/bloblist.c | 16 ++++++++++++++-- common/board_f.c | 8 +++++++- doc/develop/bloblist.rst | 16 ++++++++++++++++ 4 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/common/Kconfig b/common/Kconfig index 2ab20a6c85b..36a648596d1 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -719,6 +719,8 @@ config TPL_BLOBLIST This enables a bloblist in TPL. The bloblist is set up in TPL and passed to SPL and U-Boot proper.
+if BLOBLIST + config BLOBLIST_SIZE hex "Size of bloblist" depends on BLOBLIST @@ -729,17 +731,24 @@ config BLOBLIST_SIZE is set up in the first part of U-Boot to run (TPL, SPL or U-Boot proper), and this sane bloblist is used for subsequent stages.
+config BLOBLIST_ALLOC + bool "Allocate bloblist" + help + Allocate the bloblist using malloc(). This avoids the need to + specify a fixed address on systems where this is unknown or can + change at runtime. + config BLOBLIST_ADDR hex "Address of bloblist" - depends on BLOBLIST default 0xc000 if SANDBOX help Sets the address of the bloblist, set up by the first part of U-Boot which runs. Subsequent U-Boot stages typically use the same address.
+ This is not used if BLOBLIST_ALLOC is selected. + config BLOBLIST_SIZE_RELOC hex "Size of bloblist after relocation" - depends on BLOBLIST default BLOBLIST_SIZE help Sets the size of the bloblist in bytes after relocation. Since U-Boot @@ -747,6 +756,8 @@ config BLOBLIST_SIZE_RELOC size than the one set up by SPL. This bloblist is set up during the relocation process.
+endif # BLOBLIST + endmenu
source "common/spl/Kconfig" diff --git a/common/bloblist.c b/common/bloblist.c index 1290fff8504..01b04103d91 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -7,6 +7,7 @@ #include <common.h> #include <bloblist.h> #include <log.h> +#include <malloc.h> #include <mapmem.h> #include <spl.h> #include <asm/global_data.h> @@ -416,10 +417,21 @@ int bloblist_init(void) ret = bloblist_check(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE); if (ret) { + ulong addr; + log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG, "Existing bloblist not found: creating new bloblist\n"); - ret = bloblist_new(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE, - 0); + if (IS_ENABLED(CONFIG_BLOBLIST_ALLOC)) { + void *ptr = memalign(BLOBLIST_ALIGN, + CONFIG_BLOBLIST_SIZE); + + if (!ptr) + return log_msg_ret("alloc", -ENOMEM); + addr = map_to_sysmem(ptr); + } else { + addr = CONFIG_BLOBLIST_ADDR; + } + ret = bloblist_new(addr, CONFIG_BLOBLIST_SIZE, 0); } else { log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n"); } diff --git a/common/board_f.c b/common/board_f.c index f2746537c96..a5448c50666 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -655,8 +655,14 @@ static int reloc_bootstage(void) static int reloc_bloblist(void) { #ifdef CONFIG_BLOBLIST - if (gd->flags & GD_FLG_SKIP_RELOC) + /* + * Relocate only if we are supposed to send it + */ + if ((gd->flags & GD_FLG_SKIP_RELOC) && + CONFIG_BLOBLIST_SIZE == CONFIG_BLOBLIST_SIZE_RELOC) { + debug("Not relocating bloblist\n"); return 0; + } if (gd->new_bloblist) { int size = CONFIG_BLOBLIST_SIZE;
diff --git a/doc/develop/bloblist.rst b/doc/develop/bloblist.rst index 317ebc4919d..47274cf8e26 100644 --- a/doc/develop/bloblist.rst +++ b/doc/develop/bloblist.rst @@ -59,6 +59,22 @@ Bloblist provides a fairly simple API which allows blobs to be created and found. All access is via the blob's tag. Blob records are zeroed when added.
+Placing the bloblist +-------------------- + +The bloblist is typically positioned at a fixed address by TPL, or SPL. This +is controlled by `CONFIG_BLOBLIST_ADDR`. But in some cases it is preferable to +allocate the bloblist in the malloc() space. Use the `CONFIG_BLOBLIST_ALLOC` +option to enable this. + +The bloblist is automatically relocated as part of U-Boot relocation. Sometimes +it is useful to expand the bloblist in U-Boot proper, since it may want to add +information for use by Linux. Note that this does not mean that Linux needs to +know anything about the bloblist format, just that it is convenient to use +bloblist to place things contiguously in memory. Set +`CONFIG_BLOBLIST_SIZE_RELOC` to define the expanded size, if needed. + + Finishing the bloblist ----------------------

At present this is disabled, but it should work so long as the kernel does not need EFI services. Enable it and add a note about remaining work.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/bootm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 733dd712570..ff0e9f6a085 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -179,10 +179,14 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) * U-Boot is setting them up that way for itself in * arch/i386/cpu/cpu.c. * - * Note that we cannot currently boot a kernel while running as - * an EFI application. Please use the payload option for that. + * Note: this is incomplete for EFI kernels! + * + * This can boot a kernel while running as an EFI application, + * but if the kernel requires EFI support then that support needs + * to be enabled first (see EFI_LOADER). Also the EFI information + * must enabled with setup_efi_info(). See setup_zimage() for + * how this is done with the stub. */ -#ifndef CONFIG_EFI_APP __asm__ __volatile__ ( "movl $0, %%ebp\n" "cli\n" @@ -191,7 +195,6 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) [boot_params] "S"(setup_base), "b"(0), "D"(0) ); -#endif }
/* We can't get to here */

On 9/8/21 3:33 PM, Simon Glass wrote:
At present this is disabled, but it should work so long as the kernel does not need EFI services. Enable it and add a note about remaining work.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/bootm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 733dd712570..ff0e9f6a085 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -179,10 +179,14 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) * U-Boot is setting them up that way for itself in * arch/i386/cpu/cpu.c. *
* Note that we cannot currently boot a kernel while running as
* an EFI application. Please use the payload option for that.
* Note: this is incomplete for EFI kernels!
*
* This can boot a kernel while running as an EFI application,
* but if the kernel requires EFI support then that support needs
* to be enabled first (see EFI_LOADER). Also the EFI information
* must enabled with setup_efi_info(). See setup_zimage() for
* how this is done with the stub.
Did you test launching an EFI application with EFI_LOADER from the EFI app? If you get it working, please provide a defconfig and a testcase that runs helloworld.efi.
Best regards
Heinrich
*/
-#ifndef CONFIG_EFI_APP __asm__ __volatile__ ( "movl $0, %%ebp\n" "cli\n" @@ -191,7 +195,6 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) [boot_params] "S"(setup_base), "b"(0), "D"(0) ); -#endif }
/* We can't get to here */

Hi Heinrich,
On Wed, 8 Sept 2021 at 12:22, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:33 PM, Simon Glass wrote:
At present this is disabled, but it should work so long as the kernel does not need EFI services. Enable it and add a note about remaining work.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/bootm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 733dd712570..ff0e9f6a085 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -179,10 +179,14 @@ int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit) * U-Boot is setting them up that way for itself in * arch/i386/cpu/cpu.c. *
* Note that we cannot currently boot a kernel while running as
* an EFI application. Please use the payload option for that.
* Note: this is incomplete for EFI kernels!
*
* This can boot a kernel while running as an EFI application,
* but if the kernel requires EFI support then that support needs
* to be enabled first (see EFI_LOADER). Also the EFI information
* must enabled with setup_efi_info(). See setup_zimage() for
* how this is done with the stub.
Did you test launching an EFI application with EFI_LOADER from the EFI app? If you get it working, please provide a defconfig and a testcase that runs helloworld.efi.
No unfortunately that cannot be built at present. This is just for kernels that don't use EFI_LOADER.
I am pretty sure it could be made to work, perhaps by passing the original UEFI system table through to the kernel.
Regards, Simon

If the 'bootm' command is not enabled then this code is not available and this causes a link error. Fix it.
Note that for the EFI app, there is no indication of missing code. It just hangs!
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/zimage.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 7ce02226ef9..9cc04490307 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -365,11 +365,14 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, strcpy(cmd_line, (char *)cmdline_force); else build_command_line(cmd_line, auto_boot); - ret = bootm_process_cmdline(cmd_line, max_size, BOOTM_CL_ALL); - if (ret) { - printf("Cmdline setup failed (max_size=%x, bootproto=%x, err=%d)\n", - max_size, bootproto, ret); - return ret; + if (IS_ENABLED(CONFIG_CMD_BOOTM)) { + ret = bootm_process_cmdline(cmd_line, max_size, + BOOTM_CL_ALL); + if (ret) { + printf("Cmdline setup failed (max_size=%x, bootproto=%x, err=%d)\n", + max_size, bootproto, ret); + return ret; + } } printf("Kernel command line: ""); puts(cmd_line);

At present only 4KB of spare space is left in the DTB when building the EFI app. Increase this to 32KB so there is plenty of space to insert the binman definition. This cannot be expanded later (as with OF_SEPARATE) because the ELF image has already been built.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/dts/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile index be209aaaf8f..5c8c05ec499 100644 --- a/arch/x86/dts/Makefile +++ b/arch/x86/dts/Makefile @@ -24,7 +24,7 @@ dtb-y += bayleybay.dtb \
targets += $(dtb-y)
-DTC_FLAGS += -R 4 -p 0x1000 +DTC_FLAGS += -R 4 -p $(if $(CONFIG_EFI_APP),0x8000,0x1000)
PHONY += dtbs dtbs: $(addprefix $(obj)/, $(dtb-y))

This structure is uncommented. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/efi.h | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/include/efi.h b/include/efi.h index c0fddf7f6cd..2db60a36f0b 100644 --- a/include/efi.h +++ b/include/efi.h @@ -400,15 +400,39 @@ static inline struct efi_mem_desc *efi_get_next_mem_desc( return (struct efi_mem_desc *)((ulong)desc + map->desc_size); }
+/** + * struct efi_priv - Information about the environment provided by EFI + * + * @parent_image: image passed into the EFI app or stub + * @sys_table: Pointer to system table + * @boot: Pointer to boot-services table + * @run: Pointer to runtime-services table + * + * Used by app only: + * @use_pool_for_malloc: true if all allocation should go through the EFI 'pool' + * methods allocate_pool() and free_pool(); false to use 'pages' methods + * allocate_pages() and free_pages() + * @ram_base: Base address of RAM (size CONFIG_EFI_RAM_SIZE) + * @image_data_type: Type of the loaded image (e.g. EFI_LOADER_CODE) + * + * Used by stub only: + * @info: Header of the info list, holding info collected by the stub and passed + * to U-Boot + * @info_size: Size of the info list, in bytes from @info + * @next_hdr: Pointer to where to put the next header when adding to the list + */ struct efi_priv { efi_handle_t parent_image; - struct efi_device_path *device_path; struct efi_system_table *sys_table; struct efi_boot_services *boot; struct efi_runtime_services *run; + + /* app: */ bool use_pool_for_malloc; unsigned long ram_base; unsigned int image_data_type; + + /* stub: */ struct efi_info_hdr *info; unsigned int info_size; void *next_hdr;

This should return false when the EFI app is running, since UEFI has done the required low-level init. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/init.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/init.h b/include/init.h index c781789e367..6d682b02b05 100644 --- a/include/init.h +++ b/include/init.h @@ -15,7 +15,7 @@ #include <linux/types.h>
/* Avoid using CONFIG_EFI_STUB directly as we may boot from other loaders */ -#ifdef CONFIG_EFI_STUB +#ifdef CONFIG_EFI #define ll_boot_init() false #else #include <asm/global_data.h>

Comment some functions that need more information.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/efi/efi_stub.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index b3393e47fae..156cbf0b928 100644 --- a/lib/efi/efi_stub.c +++ b/lib/efi/efi_stub.c @@ -225,6 +225,22 @@ static int get_codeseg32(void) return cs32; }
+/** + * setup_info_table() - sets up a table containing information from EFI + * + * We must call exit_boot_services() before jumping out of the stub into U-Boot + * proper, so that U-Boot has full control of peripherals, memory, etc. + * + * Once we do this, we cannot call any boot-services functions so we must find + * out everything we need to before doing that. + * + * Set up a struct efi_info_hdr table which can hold various records (e.g. + * struct efi_entry_memmap) with information obtained from EFI. + * + * @priv: Pointer to our private information which contains the list + * @size: Size of the table to allocate + * @return 0 if OK, non-zero on error + */ static int setup_info_table(struct efi_priv *priv, int size) { struct efi_info_hdr *info; @@ -248,6 +264,12 @@ static int setup_info_table(struct efi_priv *priv, int size) return 0; }
+/** + * add_entry_addr() - Add a new entry to the efi_info list + * + * @priv: Pointer to our private information which contains the list + * + */ static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type, void *ptr1, int size1, void *ptr2, int size2) {

At present each of these has its own static variable and helper functions. Move them into a shared file.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/efi.h | 21 +++++++++++++++++++++ lib/efi/efi.c | 29 +++++++++++++++++++++++++++++ lib/efi/efi_app.c | 21 ++------------------- lib/efi/efi_stub.c | 7 ++++--- 4 files changed, 56 insertions(+), 22 deletions(-)
diff --git a/include/efi.h b/include/efi.h index 2db60a36f0b..fd43dec15a2 100644 --- a/include/efi.h +++ b/include/efi.h @@ -474,6 +474,27 @@ extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[]; EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ EFI_VARIABLE_APPEND_WRITE)
+/** + * efi_get_priv() - Get access to the EFI-private information + * + * This struct it used by both the stub and the app to record things about the + * EFI environment. It is not available in U-Boot proper after the stub has + * jumped there. Use efi_info_get() to obtain info in that case. + * + * @return pointer to private info + */ +struct efi_priv *efi_get_priv(void); + +/** + * efi_set_priv() - Set up a pointer to the EFI-private information + * + * This is called in the stub and app to record the location of this + * information. + * + * @priv: New location of private data + */ +void efi_set_priv(struct efi_priv *priv); + /** * efi_get_sys_table() - Get access to the main EFI system table * diff --git a/lib/efi/efi.c b/lib/efi/efi.c index 69e52e45748..cd6bf47b180 100644 --- a/lib/efi/efi.c +++ b/lib/efi/efi.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* + * Functions shared by the app and stub + * * Copyright (c) 2015 Google, Inc * * EFI information obtained here: @@ -17,6 +19,33 @@ #include <efi.h> #include <efi_api.h>
+static struct efi_priv *global_priv; + +struct efi_priv *efi_get_priv(void) +{ + return global_priv; +} + +void efi_set_priv(struct efi_priv *priv) +{ + global_priv = priv; +} + +struct efi_system_table *efi_get_sys_table(void) +{ + return global_priv->sys_table; +} + +struct efi_boot_services *efi_get_boot(void) +{ + return global_priv->boot; +} + +unsigned long efi_get_ram_base(void) +{ + return global_priv->ram_base; +} + /* * Global declaration of gd. * diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 9ba48517422..c02f0c90c45 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -27,23 +27,6 @@
DECLARE_GLOBAL_DATA_PTR;
-static struct efi_priv *global_priv; - -struct efi_system_table *efi_get_sys_table(void) -{ - return global_priv->sys_table; -} - -struct efi_boot_services *efi_get_boot(void) -{ - return global_priv->boot; -} - -unsigned long efi_get_ram_base(void) -{ - return global_priv->ram_base; -} - int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) { return -ENOSYS; @@ -240,7 +223,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, /* Set up access to EFI data structures */ efi_init(priv, "App", image, sys_table);
- global_priv = priv; + efi_set_priv(priv);
/* * Set up the EFI debug UART so that printf() works. This is @@ -266,7 +249,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image,
static void efi_exit(void) { - struct efi_priv *priv = global_priv; + struct efi_priv *priv = efi_get_priv();
free_memory(priv); printf("U-Boot EFI exiting\n"); diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index 156cbf0b928..bc4c3a48720 100644 --- a/lib/efi/efi_stub.c +++ b/lib/efi/efi_stub.c @@ -31,7 +31,6 @@ #error "This file needs to be ported for use on architectures" #endif
-static struct efi_priv *global_priv; static bool use_uart;
struct __packed desctab_info { @@ -63,6 +62,8 @@ void _debug_uart_init(void)
void putc(const char ch) { + struct efi_priv *priv = efi_get_priv(); + if (ch == '\n') putc('\r');
@@ -73,7 +74,7 @@ void putc(const char ch) ; outb(ch, (ulong)&com_port->thr); } else { - efi_putc(global_priv, ch); + efi_putc(priv, ch); } }
@@ -313,7 +314,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, puts(" efi_init() failed\n"); return ret; } - global_priv = priv; + efi_set_priv(priv);
cs32 = get_codeseg32(); if (cs32 < 0)

At present this code is inline in the app and stub. But they do the same thing. The difference is that the stub does it immediately and the app doesn't want to do it until the end (when it boots a kernel) or not at all, if returning to UEFI.
Also store the memory map so that it can be accessed within the app if needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/efi.h | 32 +++++++++++++++++++++ lib/efi/efi.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ lib/efi/efi_app.c | 3 ++ lib/efi/efi_stub.c | 66 ++++++++----------------------------------- 4 files changed, 116 insertions(+), 55 deletions(-)
diff --git a/include/efi.h b/include/efi.h index fd43dec15a2..abc3fb2f94a 100644 --- a/include/efi.h +++ b/include/efi.h @@ -407,6 +407,12 @@ static inline struct efi_mem_desc *efi_get_next_mem_desc( * @sys_table: Pointer to system table * @boot: Pointer to boot-services table * @run: Pointer to runtime-services table + * @memmap_key: Key returned from get_memory_map() + * @memmap_desc: List of memory-map records + * @memmap_alloc: Amount of memory allocated for memory map list + * @memmap_size Size of memory-map list in bytes + * @memmap_desc_size: Size of an individual memory-map record, in bytes + * @memmap_version: Memory-map version * * Used by app only: * @use_pool_for_malloc: true if all allocation should go through the EFI 'pool' @@ -426,6 +432,12 @@ struct efi_priv { struct efi_system_table *sys_table; struct efi_boot_services *boot; struct efi_runtime_services *run; + efi_uintn_t memmap_key; + struct efi_mem_desc *memmap_desc; + efi_uintn_t memmap_alloc; + efi_uintn_t memmap_size; + efi_uintn_t memmap_desc_size; + u32 memmap_version;
/* app: */ bool use_pool_for_malloc; @@ -589,4 +601,24 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep); */ int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio);
+/** + * efi_store_memory_map() - Collect the memory-map info from EFI + * + * Collect the memory info and store it for later use, e.g. in calling + * exit_boot_services() + * + * @priv: Pointer to private EFI structure + * @return 0 if OK, non-zero on error + */ +int efi_store_memory_map(struct efi_priv *priv); + +/** + * efi_call_exit_boot_services() - Handlet eh exit-boot-service procedure + * + * Tell EFI we don't want their boot services anymore + * + * @return 0 if OK, non-zero on error + */ +int efi_call_exit_boot_services(void); + #endif /* _LINUX_EFI_H */ diff --git a/lib/efi/efi.c b/lib/efi/efi.c index cd6bf47b180..be53e890a91 100644 --- a/lib/efi/efi.c +++ b/lib/efi/efi.c @@ -135,3 +135,73 @@ void efi_free(struct efi_priv *priv, void *ptr)
boot->free_pool(ptr); } + +int efi_store_memory_map(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->sys_table->boottime; + efi_uintn_t size, desc_size; + efi_status_t ret; + + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &priv->memmap_key, + &priv->memmap_desc_size, + &priv->memmap_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + printhex2(EFI_BITS_PER_LONG); + putc(' '); + printhex2(ret); + puts(" No memory map\n"); + return ret; + } + /* + * Since doing a malloc() may change the memory map and also we want to + * be able to read the memory map in efi_call_exit_boot_services() + * below, after more changes have happened + */ + priv->memmap_alloc = size + 1024; + priv->memmap_size = priv->memmap_alloc; + priv->memmap_desc = efi_malloc(priv, size, &ret); + if (!priv->memmap_desc) { + printhex2(ret); + puts(" No memory for memory descriptor\n"); + return ret; + } + + ret = boot->get_memory_map(&priv->memmap_size, priv->memmap_desc, + &priv->memmap_key, &desc_size, + &priv->memmap_version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + printf("key=%x, image=%p\n", (uint)priv->memmap_key, + priv->parent_image); + + return 0; +} + +int efi_call_exit_boot_services(void) +{ + struct efi_priv *priv = efi_get_priv(); + const struct efi_boot_services *boot = priv->boot; + efi_uintn_t size; + u32 version; + efi_status_t ret; + + size = priv->memmap_alloc; + ret = boot->get_memory_map(&size, priv->memmap_desc, + &priv->memmap_key, + &priv->memmap_desc_size, &version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + ret = boot->exit_boot_services(priv->parent_image, priv->memmap_key); + if (ret) + return ret; + + return 0; +} diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index c02f0c90c45..6da3fbd5104 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -237,6 +237,9 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, printf("Failed to set up memory: ret=%lx\n", ret); return ret; } + ret = efi_store_memory_map(priv); + if (ret) + return ret;
printf("starting\n");
diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index bc4c3a48720..5b08c1c40c7 100644 --- a/lib/efi/efi_stub.c +++ b/lib/efi/efi_stub.c @@ -297,15 +297,12 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, { struct efi_priv local_priv, *priv = &local_priv; struct efi_boot_services *boot = sys_table->boottime; - struct efi_mem_desc *desc; struct efi_entry_memmap map; struct efi_gop *gop; struct efi_entry_gopmode mode; struct efi_entry_systable table; efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; - efi_uintn_t key, desc_size, size; efi_status_t ret; - u32 version; int cs32;
ret = efi_init(priv, "Payload", image, sys_table); @@ -320,24 +317,11 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, if (cs32 < 0) return EFI_UNSUPPORTED;
- /* Get the memory map so we can switch off EFI */ - size = 0; - ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); - if (ret != EFI_BUFFER_TOO_SMALL) { - printhex2(EFI_BITS_PER_LONG); - putc(' '); - printhex2(ret); - puts(" No memory map\n"); - return ret; - } - size += 1024; /* Since doing a malloc() may change the memory map! */ - desc = efi_malloc(priv, size, &ret); - if (!desc) { - printhex2(ret); - puts(" No memory for memory descriptor\n"); + ret = efi_store_memory_map(priv); + if (ret) return ret; - } - ret = setup_info_table(priv, size + 128); + + ret = setup_info_table(priv, priv->memmap_size + 128); if (ret) return ret;
@@ -353,48 +337,20 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, sizeof(struct efi_gop_mode_info)); }
- ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); - if (ret) { - printhex2(ret); - puts(" Can't get memory map\n"); - return ret; - } - table.sys_table = (ulong)sys_table; add_entry_addr(priv, EFIET_SYS_TABLE, &table, sizeof(table), NULL, 0);
- ret = boot->exit_boot_services(image, key); - if (ret) { - /* - * Unfortunately it happens that we cannot exit boot services - * the first time. But the second time it work. I don't know - * why but this seems to be a repeatable problem. To get - * around it, just try again. - */ - printhex2(ret); - puts(" Can't exit boot services\n"); - size = sizeof(desc); - ret = boot->get_memory_map(&size, desc, &key, &desc_size, - &version); - if (ret) { - printhex2(ret); - puts(" Can't get memory map\n"); - return ret; - } - ret = boot->exit_boot_services(image, key); - if (ret) { - printhex2(ret); - puts(" Can't exit boot services 2\n"); - return ret; - } - } + ret = efi_call_exit_boot_services(); + if (ret) + return ret;
/* The EFI UART won't work now, switch to a debug one */ use_uart = true;
- map.version = version; - map.desc_size = desc_size; - add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size); + map.version = priv->memmap_version; + map.desc_size = priv->memmap_desc_size; + add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), + priv->memmap_desc, priv->memmap_size); add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0);
memcpy((void *)CONFIG_SYS_TEXT_BASE, _binary_u_boot_bin_start,

The stub checks for failure with efi_init(). Add this for the app as well. It is unlikely that anything can be done, but we may as well stop.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/efi/efi_app.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 6da3fbd5104..e0666d1fae2 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -221,8 +221,11 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, efi_status_t ret;
/* Set up access to EFI data structures */ - efi_init(priv, "App", image, sys_table); - + ret = efi_init(priv, "App", image, sys_table); + if (ret) { + printf("Failed to set up ARP: err=%lx\n", ret); + return ret; + } efi_set_priv(priv);
/*

This provides access to EFI tables after U-Boot as exited boot services. It is not needed in the app since boot services remain alive and we can just call them whenever needed.
Add a comment to explain this.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/efi.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/efi.h b/include/efi.h index abc3fb2f94a..f624243d596 100644 --- a/include/efi.h +++ b/include/efi.h @@ -578,6 +578,10 @@ void efi_putc(struct efi_priv *priv, const char ch); /** * efi_info_get() - get an entry from an EFI table * + * This is called from U-Boot proper to read information set up by the EFI stub. + * It can only be used when running from the EFI stuff, not when U-Boot is + * running as an app. + * * @type: Entry type to search for * @datap: Returns pointer to entry data * @sizep: Returns pointer to entry size

Add a message here so that both paths of memory allocation are reported.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/efi/efi_app.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index e0666d1fae2..c8f4784eb7d 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -97,6 +97,7 @@ static efi_status_t setup_memory(struct efi_priv *priv) return ret; priv->use_pool_for_malloc = true; } else { + printf("(using allocated RAM address %lx) ", (ulong)addr); priv->ram_base = addr; } gd->ram_size = pages << 12;

On 9/8/21 3:34 PM, Simon Glass wrote:
Add a message here so that both paths of memory allocation are reported.
Signed-off-by: Simon Glass sjg@chromium.org
lib/efi/efi_app.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index e0666d1fae2..c8f4784eb7d 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -97,6 +97,7 @@ static efi_status_t setup_memory(struct efi_priv *priv) return ret; priv->use_pool_for_malloc = true; } else {
printf("(using allocated RAM address %lx) ", (ulong)addr);
Shouldn't this be log_debug()?
Best regards
Heinrich
priv->ram_base = addr;
} gd->ram_size = pages << 12;

Hi Heinrich,
On Wed, 8 Sept 2021 at 12:25, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:34 PM, Simon Glass wrote:
Add a message here so that both paths of memory allocation are reported.
Signed-off-by: Simon Glass sjg@chromium.org
lib/efi/efi_app.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index e0666d1fae2..c8f4784eb7d 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -97,6 +97,7 @@ static efi_status_t setup_memory(struct efi_priv *priv) return ret; priv->use_pool_for_malloc = true; } else {
printf("(using allocated RAM address %lx) ", (ulong)addr);
Shouldn't this be log_debug()?
It matches the one a few lines higher. I suppose it could be a debug statement, but allocation is an area that seems to different on different UEFIs, so I have it more prominent for the moment, until we figure it out.
Regards, Simon

On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 12:25, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:34 PM, Simon Glass wrote:
Add a message here so that both paths of memory allocation are reported.
Signed-off-by: Simon Glass sjg@chromium.org
lib/efi/efi_app.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index e0666d1fae2..c8f4784eb7d 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -97,6 +97,7 @@ static efi_status_t setup_memory(struct efi_priv *priv) return ret; priv->use_pool_for_malloc = true; } else {
printf("(using allocated RAM address %lx) ", (ulong)addr);
Shouldn't this be log_debug()?
It matches the one a few lines higher. I suppose it could be a debug statement, but allocation is an area that seems to different on different UEFIs, so I have it more prominent for the moment, until we figure it out.
If you want it more prominent, isn't it log_info() that you were promoting?
Best regards
Heinrich

Hi Heinrich.
On Thu, 9 Sept 2021 at 04:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/9/21 10:57 AM, Simon Glass wrote:
Hi Heinrich,
On Wed, 8 Sept 2021 at 12:25, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 9/8/21 3:34 PM, Simon Glass wrote:
Add a message here so that both paths of memory allocation are reported.
Signed-off-by: Simon Glass sjg@chromium.org
lib/efi/efi_app.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index e0666d1fae2..c8f4784eb7d 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -97,6 +97,7 @@ static efi_status_t setup_memory(struct efi_priv *priv) return ret; priv->use_pool_for_malloc = true; } else {
printf("(using allocated RAM address %lx) ", (ulong)addr);
Shouldn't this be log_debug()?
It matches the one a few lines higher. I suppose it could be a debug statement, but allocation is an area that seems to different on different UEFIs, so I have it more prominent for the moment, until we figure it out.
If you want it more prominent, isn't it log_info() that you were promoting?
OK I can change them both, so long as logging is enabled for EFI...will check.
Regards, Simon

Add info about how to select vidconsole or serial.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/configs/efi-x86_app.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/include/configs/efi-x86_app.h b/include/configs/efi-x86_app.h index 6061a6db0a4..cdd60be9f85 100644 --- a/include/configs/efi-x86_app.h +++ b/include/configs/efi-x86_app.h @@ -10,8 +10,33 @@
#undef CONFIG_TPM_TIS_BASE_ADDRESS
+/* + * Select the output device: Put an 'x' prefix before one of these to disable it + */ + +/* + * Video output - can normally continue after exit_boot_services has been + * called, since output to the display does not require EFI services at that + * point. U-Boot sets up the console memory and does its own drawing. + */ #define CONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \ "stdout=vidconsole\0" \ "stderr=vidconsole\0"
+/* + * Serial output with no console. Run qemu with: + * + * -display none -serial mon:stdio + * + * This will hang or fail to output on the console after exit_boot_services is + * called. + */ +#define xCONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \ + "stdout=serial\0" \ + "stderr=serial\0" + +#undef CONFIG_BOOTCOMMAND + +#define CONFIG_BOOTCOMMAND "part list efi 0" + #endif

Hi Simon,
On Wed, Sep 8, 2021 at 9:34 PM Simon Glass sjg@chromium.org wrote:
At present U-Boot can be built as an EFI app, but it is really just for testing, with very few features. Instead, the payload build is used for booting on top of UEFI, where U-Boot takes over the machine immediately and supplies its own drivers.
But the app could be made more useful.
This series provides access to EFI block devices and the video console within U-Boot. It also restructures the app to make it possible to boot a kernel, although further work is needed to implement this.
This can be thought of as making U-Boot perform a little like 'grub', in that it runs purely based on UEFI-provided services.
Of course a lot more work is required, but this is a start.
Thanks for working on this!
Note: It would be very useful to include qemu tests of the app and stub in CI.
This is available at u-boot-dm/efi-working
Do you have any idea of why this series did not land on patchwork?
Regards, Bin

On Fri, Sep 10, 2021 at 12:29:46AM +0800, Bin Meng wrote:
Hi Simon,
On Wed, Sep 8, 2021 at 9:34 PM Simon Glass sjg@chromium.org wrote:
At present U-Boot can be built as an EFI app, but it is really just for testing, with very few features. Instead, the payload build is used for booting on top of UEFI, where U-Boot takes over the machine immediately and supplies its own drivers.
But the app could be made more useful.
This series provides access to EFI block devices and the video console within U-Boot. It also restructures the app to make it possible to boot a kernel, although further work is needed to implement this.
This can be thought of as making U-Boot perform a little like 'grub', in that it runs purely based on UEFI-provided services.
Of course a lot more work is required, but this is a start.
Thanks for working on this!
Note: It would be very useful to include qemu tests of the app and stub in CI.
This is available at u-boot-dm/efi-working
Do you have any idea of why this series did not land on patchwork?
It did, I've just moved it to "Changes Requested" based on the feedback so far.
participants (6)
-
AKASHI Takahiro
-
Bin Meng
-
Heinrich Schuchardt
-
Mark Kettenis
-
Simon Glass
-
Tom Rini