From 46ce6cf7747bdd228c4e16ec3a7d19661509def8 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Thu, 10 Mar 2022 12:53:16 +0100 Subject: [PATCH] boot: Add LINUX_INITRD_MEDIA support to boot.c --- src/boot/efi/boot.c | 49 ++++++++++++++++++++++++++++++++++++++-- src/boot/efi/initrd.h | 5 ++++ src/boot/efi/linux.c | 5 ---- src/boot/efi/meson.build | 2 +- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 7b0fcf20ff..37bd6c756a 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -2302,27 +2302,63 @@ static void config_load_xbootldr( static EFI_STATUS initrd_prepare( EFI_FILE *root, const ConfigEntry *entry, - CHAR16 **ret_options) { + CHAR16 **ret_options, + void **ret_initrd, + UINTN *ret_initrd_size) { assert(root); assert(entry); assert(ret_options); + assert(ret_initrd); + assert(ret_initrd_size); if (entry->type != LOADER_LINUX || !entry->initrd) { ret_options = NULL; + ret_initrd = NULL; + ret_initrd_size = 0; return EFI_SUCCESS; } + /* Note that order of initrds matters. The kernel will only look for microcode updates in the very + * first one it sees. */ + /* Add initrd= to options for older kernels that do not support LINUX_INITRD_MEDIA. Should be dropped * if linux_x86.c is dropped. */ _cleanup_freepool_ CHAR16 *options = NULL; + EFI_STATUS err; + UINTN size = 0; + _cleanup_freepool_ UINT8 *initrd = NULL; + STRV_FOREACH(i, entry->initrd) { _cleanup_freepool_ CHAR16 *o = options; if (o) options = xpool_print(L"%s initrd=%s", o, *i); else options = xpool_print(L"initrd=%s", *i); + + _cleanup_(file_closep) EFI_FILE *handle = NULL; + err = root->Open(root, &handle, *i, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(err)) + return err; + + _cleanup_freepool_ EFI_FILE_INFO *info = NULL; + err = get_file_info_harder(handle, &info, NULL); + if (EFI_ERROR(err)) + return err; + + UINTN new_size, read_size = info->FileSize; + if (__builtin_add_overflow(size, read_size, &new_size)) + return EFI_OUT_OF_RESOURCES; + initrd = xreallocate_pool(initrd, size, new_size); + + err = handle->Read(handle, &read_size, initrd + size); + if (EFI_ERROR(err)) + return err; + + /* Make sure the actual read size is what we expected. */ + assert(size + read_size == new_size); + size = new_size; } if (entry->options) { @@ -2331,6 +2367,8 @@ static EFI_STATUS initrd_prepare( } *ret_options = TAKE_PTR(options); + *ret_initrd = TAKE_PTR(initrd); + *ret_initrd_size = size; return EFI_SUCCESS; } @@ -2357,8 +2395,10 @@ static EFI_STATUS image_start( if (!path) return log_error_status_stall(EFI_INVALID_PARAMETER, L"Error getting device path."); + UINTN initrd_size = 0; + _cleanup_freepool_ void *initrd = NULL; _cleanup_freepool_ CHAR16 *options_initrd = NULL; - err = initrd_prepare(image_root, entry, &options_initrd); + err = initrd_prepare(image_root, entry, &options_initrd, &initrd, &initrd_size); if (EFI_ERROR(err)) return log_error_status_stall(err, L"Error preparing initrd: %r", err); @@ -2372,6 +2412,11 @@ static EFI_STATUS image_start( return log_error_status_stall(err, L"Error loading %s: %r", entry->devicetree, err); } + _cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL; + err = initrd_register(initrd, initrd_size, &initrd_handle); + if (EFI_ERROR(err)) + return log_error_status_stall(err, L"Error registering initrd: %r", err); + CHAR16 *options = options_initrd ?: entry->options; if (options) { EFI_LOADED_IMAGE *loaded_image; diff --git a/src/boot/efi/initrd.h b/src/boot/efi/initrd.h index b26a81e369..d1478e3baf 100644 --- a/src/boot/efi/initrd.h +++ b/src/boot/efi/initrd.h @@ -9,3 +9,8 @@ EFI_STATUS initrd_register( EFI_HANDLE *ret_initrd_handle); EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle); + +static inline void cleanup_initrd(EFI_HANDLE *initrd_handle) { + (void) initrd_unregister(*initrd_handle); + *initrd_handle = NULL; +} diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c index ce0f4985c0..f04f81fb05 100644 --- a/src/boot/efi/linux.c +++ b/src/boot/efi/linux.c @@ -87,11 +87,6 @@ static EFI_STATUS loaded_image_unregister(EFI_HANDLE loaded_image_handle) { return EFI_SUCCESS; } -static inline void cleanup_initrd(EFI_HANDLE *initrd_handle) { - (void) initrd_unregister(*initrd_handle); - *initrd_handle = NULL; -} - static inline void cleanup_loaded_image(EFI_HANDLE *loaded_image_handle) { (void) loaded_image_unregister(*loaded_image_handle); *loaded_image_handle = NULL; diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index e17669478f..8f1645202b 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -351,6 +351,7 @@ common_sources = files( 'devicetree.c', 'disk.c', 'graphics.c', + 'initrd.c', 'measure.c', 'pe.c', 'secure-boot.c', @@ -369,7 +370,6 @@ systemd_boot_sources = files( stub_sources = files( 'cpio.c', - 'initrd.c', 'splash.c', 'stub.c', ) -- 2.25.1