>On Wed, 19 Jan 2022 at 04:45, Heinrich Schuchardt <xypron.g...@gmx.de> wrote: >> >> On 1/19/22 02:43, Simon Glass wrote: >> > Add a bootmeth driver which handles EFI boot, using EFI_LOADER. >> > >> > In effect, this provides the same functionality as the 'bootefi' command >> > and shares the same code. But the interface into it is via a bootmeth, >> > so it does not require any special scripts, etc. >> > >> > For now this requires the 'bootefi' command be enabled. Future work may >> > tidy this up so that it can be used without CONFIG_CMDLINE being enabled. >> > >> > There was much discussion about whether this is needed, but it seems >> > that it is, at least for now. >> > >> > Signed-off-by: Simon Glass <s...@chromium.org> >> > --- >> > >> > Changes in v3: >> > - Add a log category >> > - Use a short name when BOOTSTD_FULL is not enabled >> > - Align the EFI load address >> > - Use common bootmeth functions >> > >> > boot/Kconfig | 21 +++++ >> > boot/Makefile | 1 + >> > boot/bootmeth_efi.c | 183 ++++++++++++++++++++++++++++++++++++++++++++ >> > 3 files changed, 205 insertions(+) >> > create mode 100644 boot/bootmeth_efi.c >> > >> > diff --git a/boot/Kconfig b/boot/Kconfig >> > index 61df705141d..0fee35070b0 100644 >> > --- a/boot/Kconfig >> > +++ b/boot/Kconfig >> > @@ -338,6 +338,27 @@ config BOOTMETH_DISTRO_PXE >> > >> > This provides a way to try out standard boot on an existing boot >> > flow. >> > >> > +config BOOTMETH_EFILOADER >> > + bool "Bootdev support for EFI boot" >> > + depends on CMD_BOOTEFI >> > + default y >> > + help >> > + Enables support for EFI boot using bootdevs. This makes the >> > + bootdevs look for a 'boot<arch>.efi' on each filesystem >> > + they scan. The resulting file is booted after enabling U-Boot's >> > + EFI loader support. >> > + >> > + The <arch> depends on the architecture of the board: >> > + >> > + aa64 - aarch64 (ARM 64-bit) >> > + arm - ARM 32-bit >> > + ia32 - x86 32-bit >> > + x64 - x86 64-bit >> > + riscv32 - RISC-V 32-bit >> > + riscv64 - RISC-V 64-bit >> > + >> > + This provides a way to try out standard boot on an existing boot >> > flow. >> > + >> > endif >> > >> > config LEGACY_IMAGE_FORMAT >> > diff --git a/boot/Makefile b/boot/Makefile >> > index 170fcac8ec4..c2345435201 100644 >> > --- a/boot/Makefile >> > +++ b/boot/Makefile >> > @@ -30,6 +30,7 @@ obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootstd-uclass.o >> > >> > obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_DISTRO) += bootmeth_distro.o >> > obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_DISTRO_PXE) += bootmeth_pxe.o >> > +obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_EFILOADER) += bootmeth_efi.o >> > >> > obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o >> > obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o >> > diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c >> > new file mode 100644 >> > index 00000000000..4c0c3494c3b >> > --- /dev/null >> > +++ b/boot/bootmeth_efi.c >> > @@ -0,0 +1,183 @@ >> > +// SPDX-License-Identifier: GPL-2.0+ >> > +/* >> > + * Bootmethod for distro boot via EFI >> > + * >> > + * Copyright 2021 Google LLC >> > + * Written by Simon Glass <s...@chromium.org> >> > + */ >> > + >> > +#define LOG_CATEGORY UCLASS_BOOTSTD >> > + >> > +#include <common.h> >> > +#include <bootdev.h> >> > +#include <bootflow.h> >> > +#include <bootmeth.h> >> > +#include <command.h> >> > +#include <dm.h> >> > +#include <efi_loader.h> >> > +#include <fs.h> >> > +#include <malloc.h> >> > +#include <mapmem.h> >> > +#include <mmc.h> >> > +#include <pxe_utils.h> >> > + >> > +#define EFI_DIRNAME "efi/boot/" >> > + >> > +/** >> > + * get_efi_leafname() - Get the leaf name for the EFI file we expect >> > + * >> > + * @str: Place to put leaf name for this architecture, e.g. >> > "bootaa64.efi". >> > + * Must have at least 16 bytes of space >> > + * @max_len: Length of @str, must be >=16 >> > + */ >> > +static int get_efi_leafname(char *str, int max_len) >> > +{ >> > + const char *base; >> > + >> > + if (max_len < 16) >> > + return log_msg_ret("spc", -ENOSPC); >> > + if (IS_ENABLED(CONFIG_ARM64)) >> > + base = "bootaa64"; >> > + else if (IS_ENABLED(CONFIG_ARM)) >> > + base = "bootarm"; >> > + else if (IS_ENABLED(CONFIG_X86_RUN_32BIT)) >> > + base = "bootia32"; >> > + else if (IS_ENABLED(CONFIG_X86_RUN_64BIT)) >> > + base = "bootx64"; >> > + else if (IS_ENABLED(CONFIG_ARCH_RV32I)) >> > + base = "bootriscv32"; >> > + else if (IS_ENABLED(CONFIG_ARCH_RV64I)) >> > + base = "bootriscv64"; >> > + else if (IS_ENABLED(CONFIG_SANDBOX)) >> > + base = "bootsbox"; >> > + else >> > + return -EINVAL; >> > + >> > + strcpy(str, base); >> > + strcat(str, ".efi"); >> > + >> > + return 0; >> > +} >> > + >> > +static int efiload_read_file(struct blk_desc *desc, struct bootflow >> > *bflow) >> > +{ >> > + const struct udevice *media_dev; >> > + int size = bflow->size; >> > + char devnum_str[9]; >> > + char dirname[200]; >> > + char *last_slash; >> > + int ret; >> > + >> > + ret = bootmeth_alloc_file(bflow, 0x2000000, 0x10000); >> > + if (ret) >> > + return log_msg_ret("read", ret); >> > + >> > + /* >> > + * This is a horrible hack to tell EFI about this boot device. Once >> > we >> > + * unify EFI with the rest of U-Boot we can clean this up. The same >> > hack >> > + * exists in multiple places, e.g. in the fs, tftp and load commands. >> > + * >> > + * Once we can clean up the EFI code to make proper use of driver >> > model, >> > + * this can go away. >> > + */ >> > + media_dev = dev_get_parent(bflow->dev); >> > + snprintf(devnum_str, sizeof(devnum_str), "%x", dev_seq(media_dev)); >> > + >> > + strlcpy(dirname, bflow->fname, sizeof(dirname)); >> > + last_slash = strrchr(dirname, '/'); >> > + if (last_slash) >> > + *last_slash = '\0'; >> > + >> > + log_debug("setting bootdev %s, %s\n", dev_get_uclass_name(media_dev), >> > + bflow->fname); >> > + efi_set_bootdev(dev_get_uclass_name(media_dev), devnum_str, >> > + bflow->fname, bflow->buf, size); >> > + >> > + return 0; >> > +} >> > + >> > +static int distro_efi_check(struct udevice *dev, struct bootflow_iter >> > *iter) >> > +{ >> > + int ret; >> > + >> > + /* This only works on block devices */ >> > + ret = bootflow_iter_uses_blk_dev(iter); >> > + if (ret) >> > + return log_msg_ret("blk", ret); >> > + >> > + return 0; >> > +} >> > + >> > +static int distro_efi_read_bootflow(struct udevice *dev, struct bootflow >> > *bflow) >> > +{ >> > + struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); >> > + char fname[sizeof(EFI_DIRNAME) + 16]; >> > + int ret; >> > + >> > + /* We require a partition table */ >> > + if (!bflow->part) >> > + return -ENOENT; >> > + >> > + strcpy(fname, EFI_DIRNAME); >> > + ret = get_efi_leafname(fname + strlen(fname), >> > + sizeof(fname) - strlen(fname)); >> > + if (ret) >> > + return log_msg_ret("leaf", ret); >> > + >> > + ret = bootmeth_try_file(bflow, desc, NULL, fname); >> > + if (ret) >> > + return log_msg_ret("try", ret); >> > + >> > + ret = efiload_read_file(desc, bflow); >> > + if (ret) >> > + return log_msg_ret("read", -EINVAL); >> > + >> > + return 0; >> > +} >> > + >> > +int distro_efi_boot(struct udevice *dev, struct bootflow *bflow) >> > +{ >> > + char cmd[50]; >> > + >> > + /* >> > + * At some point we can add a real interface to bootefi so we can >> > call >> > + * this directly. For now, go through the CLI like distro boot. >> > + */ >> > + snprintf(cmd, sizeof(cmd), "bootefi %lx %lx", >> > + (ulong)map_to_sysmem(bflow->buf), >> > + (ulong)map_to_sysmem(gd->fdt_blob)); >> > + if (run_command(cmd, 0)) >> > + return log_msg_ret("run", -EINVAL); >> > + >> > + return 0; >> > +} >> > + >> > +static int distro_bootmeth_efi_bind(struct udevice *dev) >> > +{ >> > + struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); >> > + >> > + plat->desc = IS_ENABLED(CONFIG_BOOTSTD_FULL) ? >> > + "EFI boot from a .efi file" : "EFI"; >> >> nits: >> %s/a/an/ >> >> > + >> > + return 0; >> > +} >> > + >> > +static struct bootmeth_ops distro_efi_bootmeth_ops = { >> > + .check = distro_efi_check, >> > + .read_bootflow = distro_efi_read_bootflow, >> > + .read_file = bootmeth_common_read_file, >> > + .boot = distro_efi_boot, >> > +}; >> >> Where is the device tree read? > > I'm not sure...where is it read with the scripts? > > Do you know a distro that uses that feature? So far I don't have one.
At least the debian arm64 mini.iso should support it. See also https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=991141 -michael