[PATCH v3 22/31] bootstd: Add an implementation of EFI boot
Simon Glass
sjg at chromium.org
Sun Mar 6 04:08:23 CET 2022
Hi Heinrich,
On Wed, 19 Jan 2022 at 04:45, Heinrich Schuchardt <xypron.glpk at 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 <sjg at 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 <sjg at 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.
Of course there are no tests with the scripts so I am flying blind here.
Regards,
Simon
More information about the U-Boot
mailing list