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);
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 */
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);
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);
#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 {
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);
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;
}
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 += [
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,
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. */
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,