]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
stub: Always use LINUX_INITRD_MEDIA_GUID if available 24751/head
authorJan Janssen <medhefgo@web.de>
Tue, 20 Sep 2022 08:08:05 +0000 (10:08 +0200)
committerJan Janssen <medhefgo@web.de>
Tue, 20 Sep 2022 11:05:41 +0000 (13:05 +0200)
The kernel PE image version can be used to detect support for this
feature, allowing us to prefer the generic code of the deprecated EFI
handover protocol.

src/boot/efi/boot.c
src/boot/efi/linux.c
src/boot/efi/linux.h
src/boot/efi/linux_x86.c
src/boot/efi/meson.build
src/boot/efi/pe.c
src/boot/efi/pe.h

index a7ef57cb99f621786f61ecb5232af57490ad412e..fdbc55b884fdfbf98f0c66c2176dfded810d4215 100644 (file)
@@ -2415,7 +2415,7 @@ static EFI_STATUS image_start(
         if (err == EFI_UNSUPPORTED && entry->type == LOADER_LINUX) {
                 uint32_t kernel_entry_address;
 
-                err = pe_alignment_info(loaded_image->ImageBase, &kernel_entry_address, NULL, NULL);
+                err = pe_kernel_info(loaded_image->ImageBase, &kernel_entry_address, NULL, NULL);
                 if (err != EFI_SUCCESS) {
                         if (err != EFI_UNSUPPORTED)
                                 return log_error_status_stall(err, L"Error finding kernel compat entry address: %r", err);
index 9750006f19d0360fc3514d8c21109ab91281593b..7771058c3a2e4c375687dbd3403a8652021ddd4a 100644 (file)
@@ -111,7 +111,20 @@ EFI_STATUS linux_exec(
         assert(initrd_buffer || initrd_length == 0);
 
         /* get the necessary fields from the PE header */
-        err = pe_alignment_info(linux_buffer, &kernel_entry_address, &kernel_size_of_image, &kernel_alignment);
+        err = pe_kernel_info(linux_buffer, &kernel_entry_address, &kernel_size_of_image, &kernel_alignment);
+#if defined(__i386__) || defined(__x86_64__)
+        if (err == EFI_UNSUPPORTED)
+                /* Kernel is too old to support LINUX_INITRD_MEDIA_GUID, try the deprecated EFI handover
+                 * protocol. */
+                return linux_exec_efi_handover(
+                                image,
+                                cmdline,
+                                cmdline_len,
+                                linux_buffer,
+                                linux_length,
+                                initrd_buffer,
+                                initrd_length);
+#endif
         if (err != EFI_SUCCESS)
                 return err;
         /* sanity check */
@@ -133,6 +146,9 @@ EFI_STATUS linux_exec(
                         EFI_SIZE_TO_PAGES(ALIGN_TO(kernel_size_of_image, kernel_alignment) + kernel_alignment),
                         0);
         new_buffer = PHYSICAL_ADDRESS_TO_POINTER(ALIGN_TO(kernel.addr, kernel_alignment));
+        if (!new_buffer) /* Silence gcc 11.2.0, assert(new_buffer) doesn't work. */
+                return EFI_OUT_OF_RESOURCES;
+
         memcpy(new_buffer, linux_buffer, linux_length);
         /* zero out rest of memory (probably not needed, but BSS section should be 0) */
         memset((uint8_t *)new_buffer + linux_length, 0, kernel_size_of_image - linux_length);
index 0dfe7446680326a217970e9fdb382096e7eef558..eab617e579877b46881f177d3eb8969bd652b839 100644 (file)
@@ -8,3 +8,8 @@ EFI_STATUS linux_exec(
                 const char *cmdline, UINTN cmdline_len,
                 const void *linux_buffer, UINTN linux_length,
                 const void *initrd_buffer, UINTN initrd_length);
+EFI_STATUS linux_exec_efi_handover(
+                EFI_HANDLE image,
+                const char *cmdline, UINTN cmdline_len,
+                const void *linux_buffer, UINTN linux_length,
+                const void *initrd_buffer, UINTN initrd_length);
index a8607b00bf874e779c017bd5e3346aea688c3855..83bd7b2c3193f75fb22925c5151382508fa41d8b 100644 (file)
@@ -23,6 +23,7 @@
 #define SETUP_MAGIC        0x53726448u /* "HdrS" */
 #define SETUP_VERSION_2_11 0x20bu
 #define SETUP_VERSION_2_12 0x20cu
+#define SETUP_VERSION_2_15 0x20fu
 #define CMDLINE_PTR_MAX    0xA0000u
 
 enum {
@@ -119,15 +120,12 @@ static void linux_efi_handover(EFI_HANDLE image, uintptr_t kernel, BootParams *p
         handover(image, ST, params);
 }
 
-EFI_STATUS linux_exec(
+EFI_STATUS linux_exec_efi_handover(
                 EFI_HANDLE image,
                 const char *cmdline, UINTN cmdline_len,
                 const void *linux_buffer, UINTN linux_length,
                 const void *initrd_buffer, UINTN initrd_length) {
 
-        EFI_HANDLE initrd_handle = NULL;
-        EFI_STATUS err;
-
         assert(image);
         assert(cmdline || cmdline_len == 0);
         assert(linux_buffer);
@@ -196,23 +194,11 @@ EFI_STATUS linux_exec(
                 assert(can_4g || cmdline_pages.addr <= CMDLINE_PTR_MAX);
         }
 
-        /* Providing the initrd via LINUX_INITRD_MEDIA_GUID is only supported by Linux 5.8+ (5.7+ on ARM64).
-           Until supported kernels become more established, we continue to set ramdisk in the handover struct.
-           This value is overridden by kernels that support LINUX_INITRD_MEDIA_GUID.
-           If you need to know which protocol was used by the kernel, pass "efi=debug" to the kernel,
-           this will print a line when InitrdMediaGuid was successfully used to load the initrd.
-         */
         boot_params->hdr.ramdisk_image = (uintptr_t) initrd_buffer;
         boot_params->ext_ramdisk_image = POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer) >> 32;
         boot_params->hdr.ramdisk_size = initrd_length;
         boot_params->ext_ramdisk_size = ((uint64_t) initrd_length) >> 32;
 
-        /* register LINUX_INITRD_MEDIA_GUID */
-        err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
-        if (err != EFI_SUCCESS)
-                return err;
         linux_efi_handover(image, (uintptr_t) linux_buffer, boot_params);
-        (void) initrd_unregister(initrd_handle);
-        initrd_handle = NULL;
         return EFI_LOAD_ERROR;
 }
index efe056c225a507b1d5cf8a3011c87e030dd9fe9f..b149735246e883c53a6162534061617db5835613 100644 (file)
@@ -392,14 +392,13 @@ systemd_boot_sources = files(
 
 stub_sources = files(
         'cpio.c',
+        'linux.c',
         'splash.c',
         'stub.c',
 )
 
 if efi_arch[1] in ['ia32', 'x86_64']
         stub_sources += files('linux_x86.c')
-else
-        stub_sources += files('linux.c')
 endif
 
 tests += [
index 8d7061d55b21e92b1860a8e1a2794658f7430411..4602827f198dbc655e9d235c03c506916adca3ff 100644 (file)
@@ -209,7 +209,7 @@ static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const
         return 0;
 }
 
-EFI_STATUS pe_alignment_info(
+EFI_STATUS pe_kernel_info(
                 const void *base,
                 uint32_t *ret_entry_point_address,
                 uint32_t *ret_size_of_image,
@@ -229,6 +229,10 @@ EFI_STATUS pe_alignment_info(
         if (!verify_pe(pe, /* allow_compatibility= */ true))
                 return EFI_LOAD_ERROR;
 
+        /* Support for LINUX_INITRD_MEDIA_GUID was added in kernel stub 1.0. */
+        if (pe->OptionalHeader.MajorImageVersion < 1)
+                return EFI_UNSUPPORTED;
+
         uint32_t entry_address = pe->OptionalHeader.AddressOfEntryPoint;
 
         /* Look for a compat entry point. */
index ea4801ced5963c65035403de2becfb53d48426a1..ead2ba01ccf61e1ce6c38e91f1de453936cbfbff 100644 (file)
@@ -17,7 +17,7 @@ EFI_STATUS pe_file_locate_sections(
                 UINTN *offsets,
                 UINTN *sizes);
 
-EFI_STATUS pe_alignment_info(
+EFI_STATUS pe_kernel_info(
                 const void *base,
                 uint32_t *ret_entry_point_address,
                 uint32_t *ret_size_of_image,