[PATCH 3/6] efi_loader: Replace config option with EFI variable for initrd loading
Heinrich Schuchardt
xypron.glpk at gmx.de
Mon Dec 28 15:55:49 CET 2020
On 12/28/20 1:24 PM, Ilias Apalodimas wrote:
> Up to now we register EFI_LOAD_FILE2_PROTOCOL to load an initrd
> unconditionally. Although we correctly return various EFI return codes
> depending on the file status (i.e EFI_NO_MEDIA, EFI_NOT_FOUND etc), the
> kernel loader, only falls back to the cmdline interpreted initrd if the
> protocol is not registered.
>
> This creates a problem for EFI installers, since they won't be able to
> load their own initrd and continue the installation.
>
> So let's introduce a different logic that will decopouple the initrd
> path from the config option we currently support.
> When the EFI application is launched through the bootmgr, we'll try to
> match the BootCurrent value to an Initrd#### EFI variable.
> i.e Boot0000 -> Initrd0000, Boot0010 -> Initrd0010 etc.
>
> The Initrd#### EFI variable is expected to include the full file path,
> i.e 'mmc 0:1 initrd'. If the file is found, we'll register the
> appropriate protocol so the kernel's efi-stub load our initrd.
> If the file is not found the kernel will still try to load an initrd
> parsing the kernel cmdline, since the protocol won't be registered.
>
> This opens up another path using U-Boot and defines a new boot flow.
> A user will be able to control the kernel/initrd pairs without explicit
> cmdline args or GRUB. So we can base the whole boot flow on the Boot####
> and Initrd#### paired values.
>
> Suggested-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> Signed-off-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> ---
> lib/efi_loader/Kconfig | 12 ++---
> lib/efi_loader/Makefile | 2 +-
> lib/efi_loader/efi_bootmgr.c | 6 ++-
> lib/efi_loader/efi_load_initrd.c | 86 +++++++++-----------------------
> 4 files changed, 33 insertions(+), 73 deletions(-)
>
> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index dd8b93bd3c5a..eca24e82b8b1 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -212,14 +212,10 @@ config EFI_LOAD_FILE2_INITRD
> help
> Expose a EFI_FILE_LOAD2_PROTOCOL that the Linux UEFI stub can
> use to load the initial ramdisk. Once this is enabled using
> - initrd=<ramdisk> will stop working.
> -
> -config EFI_INITRD_FILESPEC
> - string "initramfs path"
> - default "host 0:1 initrd"
> - depends on EFI_LOAD_FILE2_INITRD
> - help
> - Full path of the initramfs file, e.g. mmc 0:2 initramfs.cpio.gz.
> + initrd=<ramdisk> will stop working. The protocol will only be
> + registered if bootmgr is used and the file is found on the defined
In UEFI speak protocols are not registered but installed.
further comment below
> + path. A boot entry of Boot0001 will try to match Initrd0001 and use
> + it. Initrd format 'mmc 0:1 <filename>'
>
> config EFI_SECURE_BOOT
> bool "Enable EFI secure boot support"
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index cd4b252a417c..793e5b7f8730 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -54,7 +54,7 @@ obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o
> obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
> obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
> obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o
> -obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o
> +obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_helper.o efi_load_initrd.o
> obj-y += efi_signature.o
>
> EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE))
> diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
> index 61dc72a23da8..ceca5c5b1bf3 100644
> --- a/lib/efi_loader/efi_bootmgr.c
> +++ b/lib/efi_loader/efi_bootmgr.c
> @@ -12,6 +12,7 @@
> #include <log.h>
> #include <malloc.h>
> #include <efi_loader.h>
> +#include <efi_load_initrd.h>
> #include <efi_variable.h>
> #include <asm/unaligned.h>
>
> @@ -348,8 +349,11 @@ efi_status_t efi_bootmgr_load(efi_handle_t *handle, void **load_options)
> log_debug("%s trying to load Boot%04X\n", __func__,
> bootorder[i]);
> ret = try_load_entry(bootorder[i], handle, load_options);
> - if (ret == EFI_SUCCESS)
> + if (ret == EFI_SUCCESS) {
> + if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD))
> + ret = efi_initrd_register();
I think this is not enough.
* We should uninstall the protocol once 'bootefi bootmgr' returns
to U-Boot.
* The EFI_LOAD_FILE2_PROTOCOL should be installed on the handle of
the loaded image for this purpose.
Best regards
Heinrich
> break;
> + }
> }
>
> free(bootorder);
> diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c
> index d517d686c330..984fea1bd679 100644
> --- a/lib/efi_loader/efi_load_initrd.c
> +++ b/lib/efi_loader/efi_load_initrd.c
> @@ -10,7 +10,9 @@
> #include <dm.h>
> #include <fs.h>
> #include <efi_loader.h>
> +#include <efi_variable.h>
> #include <efi_load_initrd.h>
> +#include <efi_helper.h>
>
> static const efi_guid_t efi_guid_load_file2_protocol =
> EFI_LOAD_FILE2_PROTOCOL_GUID;
> @@ -45,40 +47,7 @@ static const struct efi_initrd_dp dp = {
> };
>
> /**
> - * get_file_size() - retrieve the size of initramfs, set efi status on error
> - *
> - * @dev: device to read from, e.g. "mmc"
> - * @part: device partition, e.g. "0:1"
> - * @file: name of file
> - * @status: EFI exit code in case of failure
> - *
> - * Return: size of file
> - */
> -static loff_t get_file_size(const char *dev, const char *part, const char *file,
> - efi_status_t *status)
> -{
> - loff_t sz = 0;
> - int ret;
> -
> - ret = fs_set_blk_dev(dev, part, FS_TYPE_ANY);
> - if (ret) {
> - *status = EFI_NO_MEDIA;
> - goto out;
> - }
> -
> - ret = fs_size(file, &sz);
> - if (ret) {
> - sz = 0;
> - *status = EFI_NOT_FOUND;
> - goto out;
> - }
> -
> -out:
> - return sz;
> -}
> -
> -/**
> - * efi_load_file2initrd() - load initial RAM disk
> + * efi_load_file2_initrd() - load initial RAM disk
> *
> * This function implements the LoadFile service of the EFI_LOAD_FILE2_PROTOCOL
> * in order to load an initial RAM disk requested by the Linux kernel stub.
> @@ -98,21 +67,14 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this,
> struct efi_device_path *file_path, bool boot_policy,
> efi_uintn_t *buffer_size, void *buffer)
> {
> - char *filespec;
> efi_status_t status = EFI_NOT_FOUND;
> loff_t file_sz = 0, read_sz = 0;
> - char *dev, *part, *file;
> - char *pos;
> int ret;
> + struct load_file_info info;
>
> EFI_ENTRY("%p, %p, %d, %p, %p", this, file_path, boot_policy,
> buffer_size, buffer);
>
> - filespec = strdup(CONFIG_EFI_INITRD_FILESPEC);
> - if (!filespec)
> - goto out;
> - pos = filespec;
> -
> if (!this || this != &efi_lf2_protocol ||
> !buffer_size) {
> status = EFI_INVALID_PARAMETER;
> @@ -130,24 +92,11 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this,
> goto out;
> }
>
> - /*
> - * expect a string with three space separated parts:
> - *
> - * * a block device type, e.g. "mmc"
> - * * a device and partition identifier, e.g. "0:1"
> - * * a file path on the block device, e.g. "/boot/initrd.cpio.gz"
> - */
> - dev = strsep(&pos, " ");
> - if (!dev)
> - goto out;
> - part = strsep(&pos, " ");
> - if (!part)
> - goto out;
> - file = strsep(&pos, " ");
> - if (!file)
> + status = efi_get_fp_from_var(L"Initrd####", 6, &info);
> + if (status != EFI_SUCCESS)
> goto out;
>
> - file_sz = get_file_size(dev, part, file, &status);
> + file_sz = get_file_size(&info, &status);
> if (!file_sz)
> goto out;
>
> @@ -155,23 +104,25 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this,
> status = EFI_BUFFER_TOO_SMALL;
> *buffer_size = file_sz;
> } else {
> - ret = fs_set_blk_dev(dev, part, FS_TYPE_ANY);
> + ret = fs_set_blk_dev(info.dev, info.part,
> + FS_TYPE_ANY);
> if (ret) {
> status = EFI_NO_MEDIA;
> goto out;
> }
>
> - ret = fs_read(file, map_to_sysmem(buffer), 0, *buffer_size,
> - &read_sz);
> - if (ret || read_sz != file_sz)
> + ret = fs_read(info.filename, map_to_sysmem(buffer), 0,
> + *buffer_size, &read_sz);
> + if (ret || read_sz != file_sz) {
> + status = EFI_DEVICE_ERROR;
> goto out;
> + }
> *buffer_size = read_sz;
>
> status = EFI_SUCCESS;
> }
>
> out:
> - free(filespec);
> return EFI_EXIT(status);
> }
>
> @@ -189,6 +140,15 @@ efi_status_t efi_initrd_register(void)
> {
> efi_handle_t efi_initrd_handle = NULL;
> efi_status_t ret;
> + struct load_file_info info;
> +
> + ret = efi_get_fp_from_var(L"Initrd####", 6, &info);
> + /*
> + * Don't fail here. If we don't register the protocol the efi-stub will
> + * try to load and initrd parsing the kernel cmdline
> + */
> + if (ret != EFI_SUCCESS)
> + return EFI_SUCCESS;
>
> ret = EFI_CALL(efi_install_multiple_protocol_interfaces
> (&efi_initrd_handle,
>
More information about the U-Boot
mailing list