]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: Add LINUX_INITRD_MEDIA support to boot.c
authorJan Janssen <medhefgo@web.de>
Thu, 10 Mar 2022 11:53:16 +0000 (12:53 +0100)
committerLuca Boccassi <bluca@debian.org>
Sat, 21 May 2022 14:11:13 +0000 (15:11 +0100)
src/boot/efi/boot.c
src/boot/efi/initrd.h
src/boot/efi/linux.c
src/boot/efi/meson.build

index 7b0fcf20ffc79269341becdb0412f5c637d606aa..37bd6c756a54fa8a9b4e3fa095dcd035e85da4ba 100644 (file)
@@ -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;
index b26a81e3697515c24d8b42f1790cafe18263fdf0..d1478e3baf31d18e07b94f79090c60e7ec9edc4e 100644 (file)
@@ -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;
+}
index ce0f4985c04211cb2cb97c591dcaf42ab353597c..f04f81fb0567ce1bc53e8983e06b4a8f891ff527 100644 (file)
@@ -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;
index e17669478f70abd24d9f2cb6d1dc5f5580f482bf..8f1645202b4a3cd3eaaa4c1f362bb550e5b343a2 100644 (file)
@@ -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',
 )