stub: rework linux handover to take "struct iovec"

This commit is contained in:
Lennart Poettering
2024-06-26 17:09:45 +02:00
parent a729187a19
commit 4a3659c5f4
4 changed files with 36 additions and 43 deletions
+9 -13
View File
@@ -93,19 +93,17 @@ static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len,
EFI_STATUS linux_exec(
EFI_HANDLE parent,
const char16_t *cmdline,
const void *linux_buffer,
size_t linux_length,
const void *initrd_buffer,
size_t initrd_length) {
const struct iovec *kernel,
const struct iovec *initrd) {
uint32_t compat_address;
EFI_STATUS err;
assert(parent);
assert(linux_buffer && linux_length > 0);
assert(initrd_buffer || initrd_length == 0);
assert(iovec_is_set(kernel));
assert(iovec_is_valid(initrd));
err = pe_kernel_info(linux_buffer, &compat_address);
err = pe_kernel_info(kernel->iov_base, &compat_address);
#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
@@ -113,16 +111,14 @@ EFI_STATUS linux_exec(
return linux_exec_efi_handover(
parent,
cmdline,
linux_buffer,
linux_length,
initrd_buffer,
initrd_length);
kernel,
initrd);
#endif
if (err != EFI_SUCCESS)
return log_error_status(err, "Bad kernel image: %m");
_cleanup_(unload_imagep) EFI_HANDLE kernel_image = NULL;
err = load_image(parent, linux_buffer, linux_length, &kernel_image);
err = load_image(parent, kernel->iov_base, kernel->iov_len, &kernel_image);
if (err != EFI_SUCCESS)
return log_error_status(err, "Error loading kernel image: %m");
@@ -138,7 +134,7 @@ EFI_STATUS linux_exec(
}
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
err = initrd_register(initrd->iov_base, initrd->iov_len, &initrd_handle);
if (err != EFI_SUCCESS)
return log_error_status(err, "Error registering initrd: %m");
+5 -8
View File
@@ -2,18 +2,15 @@
#pragma once
#include "efi.h"
#include "iovec-util-fundamental.h"
EFI_STATUS linux_exec(
EFI_HANDLE parent,
const char16_t *cmdline,
const void *linux_buffer,
size_t linux_length,
const void *initrd_buffer,
size_t initrd_length);
const struct iovec *kernel,
const struct iovec *initrd);
EFI_STATUS linux_exec_efi_handover(
EFI_HANDLE parent,
const char16_t *cmdline,
const void *linux_buffer,
size_t linux_length,
const void *initrd_buffer,
size_t initrd_length);
const struct iovec *kernel,
const struct iovec *initrd);
+21 -19
View File
@@ -123,19 +123,17 @@ static void linux_efi_handover(EFI_HANDLE parent, uintptr_t kernel, BootParams *
EFI_STATUS linux_exec_efi_handover(
EFI_HANDLE parent,
const char16_t *cmdline,
const void *linux_buffer,
size_t linux_length,
const void *initrd_buffer,
size_t initrd_length) {
const struct iovec *kernel,
const struct iovec *initrd) {
assert(parent);
assert(linux_buffer);
assert(initrd_buffer || initrd_length == 0);
assert(iovec_is_set(kernel));
assert(iovec_is_valid(initrd));
if (linux_length < sizeof(BootParams))
if (kernel->iov_len < sizeof(BootParams))
return EFI_LOAD_ERROR;
const BootParams *image_params = (const BootParams *) linux_buffer;
const BootParams *image_params = (const BootParams *) kernel->iov_base;
if (image_params->hdr.header != SETUP_MAGIC || image_params->hdr.boot_flag != BOOT_FLAG_MAGIC)
return log_error_status(EFI_UNSUPPORTED, "Unsupported kernel image.");
if (image_params->hdr.version < SETUP_VERSION_2_11)
@@ -155,22 +153,26 @@ EFI_STATUS linux_exec_efi_handover(
/* There is no way to pass the high bits of code32_start. Newer kernels seems to handle this
* just fine, but older kernels will fail even if they otherwise have above 4G boot support. */
_cleanup_pages_ Pages linux_relocated = {};
if (POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX) {
const void *linux_buffer;
if (POINTER_TO_PHYSICAL_ADDRESS(kernel->iov_base) + kernel->iov_len > UINT32_MAX) {
linux_relocated = xmalloc_pages(
AllocateMaxAddress, EfiLoaderCode, EFI_SIZE_TO_PAGES(linux_length), UINT32_MAX);
AllocateMaxAddress, EfiLoaderCode, EFI_SIZE_TO_PAGES(kernel->iov_len), UINT32_MAX);
linux_buffer = memcpy(
PHYSICAL_ADDRESS_TO_POINTER(linux_relocated.addr), linux_buffer, linux_length);
}
PHYSICAL_ADDRESS_TO_POINTER(linux_relocated.addr), kernel->iov_base, kernel->iov_len);
} else
linux_buffer = kernel->iov_base;
_cleanup_pages_ Pages initrd_relocated = {};
if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer) + initrd_length > UINT32_MAX) {
const void *initrd_buffer;
if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(initrd->iov_base) + initrd->iov_len > UINT32_MAX) {
initrd_relocated = xmalloc_pages(
AllocateMaxAddress, EfiLoaderData, EFI_SIZE_TO_PAGES(initrd_length), UINT32_MAX);
AllocateMaxAddress, EfiLoaderData, EFI_SIZE_TO_PAGES(initrd->iov_len), UINT32_MAX);
initrd_buffer = memcpy(
PHYSICAL_ADDRESS_TO_POINTER(initrd_relocated.addr),
initrd_buffer,
initrd_length);
}
initrd->iov_base,
initrd->iov_len);
} else
initrd_buffer = initrd->iov_base;
_cleanup_pages_ Pages boot_params_page = xmalloc_pages(
can_4g ? AllocateAnyPages : AllocateMaxAddress,
@@ -215,8 +217,8 @@ EFI_STATUS linux_exec_efi_handover(
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;
boot_params->hdr.ramdisk_size = initrd->iov_len;
boot_params->ext_ramdisk_size = ((uint64_t) initrd->iov_len) >> 32;
log_wait();
linux_efi_handover(parent, (uintptr_t) linux_buffer, boot_params);
+1 -3
View File
@@ -974,9 +974,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
(const uint8_t*) loaded_image->ImageBase + sections[UNIFIED_SECTION_LINUX].memory_offset,
sections[UNIFIED_SECTION_LINUX].size);
err = linux_exec(image, cmdline,
kernel.iov_base, kernel.iov_len,
final_initrd.iov_base, final_initrd.iov_len);
err = linux_exec(image, cmdline, &kernel, &final_initrd);
graphics_mode(false);
return err;
}