On Wed, 19 Mar 2025 at 16:44, Adriano Cordova <adria...@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.cord...@canonical.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodi...@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 >