[PATCH v2 1/3] efi_loader: efi_load_initrd: provide a memory mapped initrd
Adriano Cordova
adrianox at gmail.com
Wed Mar 19 15:44:59 CET 2025
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>
---
(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