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.
This commit is contained in:
+1
-1
@@ -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);
|
||||
|
||||
+17
-1
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 += [
|
||||
|
||||
+5
-1
@@ -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. */
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user