From 73c9a352705a29e3af6ea08c7075efeb12980f1d Mon Sep 17 00:00:00 2001 From: Adriano Cordova Date: Wed, 19 Mar 2025 11:44:59 -0300 Subject: efi_loader: efi_load_initrd: provide a memory mapped initrd 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 Reviewed-by: Ilias Apalodimas --- lib/efi_loader/efi_load_initrd.c | 71 +++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 11 deletions(-) (limited to 'lib/efi_loader/efi_load_initrd.c') diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c index fb8cc7bcbe3..b5d58943a80 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 *)(uintptr_t)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 */ -- cgit v1.2.3