[PATCH v2 1/3] efi_loader: efi_load_initrd: provide a memory mapped initrd
Ilias Apalodimas
ilias.apalodimas at linaro.org
Fri Mar 28 13:37:01 CET 2025
On Wed, 19 Mar 2025 at 16:44, Adriano Cordova <adrianox at gmail.com> wrote:
>
> U-Boot can pass an initrd to subsequent boot stages via the
> EFI_LOAD_FILE2_PROTOCOL. The current implementation only supports
> this functionality via the efi boot manager: the initrd is taken
> from the load options of the BootCurrent variable. This commit adds
> support for registering a memory mapped initrd, e.g. loaded from a
> FIT image. For now this new method takes precedence over loading the
> initrd from the BootCurrent variable (if both are present) because
> the BootCurrent variable is not cleared on exiting the boot manager.
>
> Signed-off-by: Adriano Cordova <adriano.cordova at canonical.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> ---
>
> (no changes since v1)
>
> include/efi_loader.h | 2 +-
> lib/efi_loader/efi_bootmgr.c | 2 +-
> lib/efi_loader/efi_load_initrd.c | 71 +++++++++++++++++++++++++++-----
> 3 files changed, 62 insertions(+), 13 deletions(-)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index e9c10819ba2..cc732dc4807 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -667,7 +667,7 @@ efi_status_t efi_http_register(const efi_handle_t handle,
> struct efi_service_binding_protocol *http_service_binding);
> /* Called by bootefi to make the watchdog available */
> efi_status_t efi_watchdog_register(void);
> -efi_status_t efi_initrd_register(void);
> +efi_status_t efi_initrd_register(struct efi_device_path *dp_initrd);
> efi_status_t efi_initrd_deregister(void);
> /* Called by bootefi to make SMBIOS tables available */
> /**
> diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
> index c6124c590d9..6e66cf3793c 100644
> --- a/lib/efi_loader/efi_bootmgr.c
> +++ b/lib/efi_loader/efi_bootmgr.c
> @@ -670,7 +670,7 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
>
> /* try to register load file2 for initrd's */
> if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) {
> - ret = efi_initrd_register();
> + ret = efi_initrd_register(NULL);
> if (ret != EFI_SUCCESS)
> goto error;
> }
> diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c
> index fb8cc7bcbe3..74b92f8bd66 100644
> --- a/lib/efi_loader/efi_load_initrd.c
> +++ b/lib/efi_loader/efi_load_initrd.c
> @@ -42,6 +42,7 @@ static const struct efi_lo_dp_prefix dp_lf2_handle = {
> };
>
> static efi_handle_t efi_initrd_handle;
> +static struct efi_device_path *efi_initrd_dp;
>
> /**
> * get_initrd_fp() - Get initrd device path from a FilePathList device path
> @@ -72,6 +73,41 @@ static efi_status_t get_initrd_fp(struct efi_device_path **initrd_fp)
> return EFI_SUCCESS;
> }
>
> +/**
> + * efi_initrd_from_mem() - load initial RAM disk from memory
> + *
> + * This function copies the initrd from the memory mapped device
> + * path pointed to by efi_initrd_dp
> + *
> + * @buffer_size: size of allocated buffer
> + * @buffer: buffer to load the file
> + *
> + * Return: status code
> + */
> +static efi_status_t efi_initrd_from_mem(efi_uintn_t *buffer_size, void *buffer)
> +{
> + efi_status_t ret = EFI_NOT_FOUND;
> + efi_uintn_t bs;
> + struct efi_device_path_memory *mdp;
> +
> + mdp = (struct efi_device_path_memory *)efi_initrd_dp;
> + if (!mdp)
> + return ret;
> +
> + bs = mdp->end_address - mdp->start_address;
> +
> + if (!buffer || *buffer_size < bs) {
> + ret = EFI_BUFFER_TOO_SMALL;
> + *buffer_size = bs;
> + } else {
> + memcpy(buffer, (void *)mdp->start_address, bs);
> + *buffer_size = bs;
> + ret = EFI_SUCCESS;
> + }
> +
> + return ret;
> +}
> +
> /**
> * efi_load_file2_initrd() - load initial RAM disk
> *
> @@ -118,6 +154,9 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this,
> goto out;
> }
>
> + if (efi_initrd_dp)
> + return EFI_EXIT(efi_initrd_from_mem(buffer_size, buffer));
> +
> ret = get_initrd_fp(&initrd_fp);
> if (ret != EFI_SUCCESS)
> goto out;
> @@ -209,6 +248,9 @@ efi_status_t efi_initrd_deregister(void)
> NULL);
> efi_initrd_handle = NULL;
>
> + efi_free_pool(efi_initrd_dp);
> + efi_initrd_dp = NULL;
> +
> return ret;
> }
>
> @@ -234,24 +276,31 @@ static void EFIAPI efi_initrd_return_notify(struct efi_event *event,
> * This function creates a new handle and installs a Linux specific vendor
> * device path and an EFI_LOAD_FILE2_PROTOCOL. Linux uses the device path
> * to identify the handle and then calls the LoadFile service of the
> - * EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk.
> + * EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk. If dp_initrd is
> + * not provided, the initrd will be taken from the BootCurrent variable
> + *
> + * @dp_initrd: optional device path containing an initrd
> *
> * Return: status code
> */
> -efi_status_t efi_initrd_register(void)
> +efi_status_t efi_initrd_register(struct efi_device_path *dp_initrd)
> {
> efi_status_t ret;
> struct efi_event *event;
>
> - /*
> - * Allow the user to continue if Boot#### file path is not set for
> - * an initrd
> - */
> - ret = check_initrd();
> - if (ret == EFI_INVALID_PARAMETER)
> - return EFI_SUCCESS;
> - if (ret != EFI_SUCCESS)
> - return ret;
> + if (dp_initrd) {
> + efi_initrd_dp = dp_initrd;
> + } else {
> + /*
> + * Allow the user to continue if Boot#### file path is not set for
> + * an initrd
> + */
> + ret = check_initrd();
> + if (ret == EFI_INVALID_PARAMETER)
> + return EFI_SUCCESS;
> + if (ret != EFI_SUCCESS)
> + return ret;
> + }
>
> ret = efi_install_multiple_protocol_interfaces(&efi_initrd_handle,
> /* initramfs */
> --
> 2.48.1
>
More information about the U-Boot
mailing list