From: Jan Janssen Date: Tue, 20 Sep 2022 08:08:05 +0000 (+0200) Subject: stub: Always use LINUX_INITRD_MEDIA_GUID if available X-Git-Tag: v252-rc1~124^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ba2a105c2babbe4706e2d50401f9fbb720d039c3;p=thirdparty%2Fsystemd.git stub: Always use LINUX_INITRD_MEDIA_GUID if available 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. --- diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index a7ef57cb99f..fdbc55b884f 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -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); diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c index 9750006f19d..7771058c3a2 100644 --- a/src/boot/efi/linux.c +++ b/src/boot/efi/linux.c @@ -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); diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h index 0dfe7446680..eab617e5798 100644 --- a/src/boot/efi/linux.h +++ b/src/boot/efi/linux.h @@ -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); diff --git a/src/boot/efi/linux_x86.c b/src/boot/efi/linux_x86.c index a8607b00bf8..83bd7b2c319 100644 --- a/src/boot/efi/linux_x86.c +++ b/src/boot/efi/linux_x86.c @@ -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; } diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index efe056c225a..b149735246e 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -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 += [ diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c index 8d7061d55b2..4602827f198 100644 --- a/src/boot/efi/pe.c +++ b/src/boot/efi/pe.c @@ -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. */ diff --git a/src/boot/efi/pe.h b/src/boot/efi/pe.h index ea4801ced59..ead2ba01ccf 100644 --- a/src/boot/efi/pe.h +++ b/src/boot/efi/pe.h @@ -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,