/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Generic Linux boot protocol using the EFI/PE entry point of the kernel. Passes
+ * initrd with the LINUX_INITRD_MEDIA_GUID DevicePath and cmdline with
+ * EFI LoadedImageProtocol.
+ *
+ * This method works for Linux 5.8 and newer on ARM/Aarch64, x86/x68_64 and RISC-V.
+ */
+
#include <efi.h>
#include <efilib.h>
-#include "linux.h"
#include "initrd.h"
+#include "linux.h"
+#include "pe.h"
#include "util.h"
-#ifdef __i386__
-#define __regparm0__ __attribute__((regparm(0)))
-#else
-#define __regparm0__
-#endif
+static EFI_LOADED_IMAGE * loaded_image_free(EFI_LOADED_IMAGE *img) {
+ if (!img)
+ return NULL;
+ mfree(img->LoadOptions);
+ return mfree(img);
+}
+
+static EFI_STATUS loaded_image_register(
+ const CHAR8 *cmdline, UINTN cmdline_len,
+ const VOID *linux_buffer, UINTN linux_length,
+ EFI_HANDLE *ret_image) {
+
+ EFI_LOADED_IMAGE *loaded_image = NULL;
+ EFI_STATUS err;
+
+ assert(cmdline || cmdline_len > 0);
+ assert(linux_buffer && linux_length > 0);
+ assert(ret_image);
-typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__;
+ /* create and install new LoadedImage Protocol */
+ loaded_image = AllocatePool(sizeof(EFI_LOADED_IMAGE));
+ if (!loaded_image)
+ return EFI_OUT_OF_RESOURCES;
-static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
- handover_f handover;
- UINTN start = (UINTN)params->hdr.code32_start;
+ /* provide the image base address and size */
+ *loaded_image = (EFI_LOADED_IMAGE) {
+ .ImageBase = (VOID *) linux_buffer,
+ .ImageSize = linux_length
+ };
- assert(params);
+ /* if a cmdline is set convert it to UTF16 */
+ if (cmdline) {
+ loaded_image->LoadOptions = stra_to_str(cmdline);
+ if (!loaded_image->LoadOptions) {
+ loaded_image = loaded_image_free(loaded_image);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ loaded_image->LoadOptionsSize = StrSize(loaded_image->LoadOptions);
+ }
-#ifdef __x86_64__
- asm volatile ("cli");
- start += 512;
-#endif
- handover = (handover_f)(start + params->hdr.handover_offset);
- handover(image, ST, params);
+ /* install a new LoadedImage protocol. ret_handle is a new image handle */
+ err = uefi_call_wrapper(BS->InstallMultipleProtocolInterfaces, 4,
+ ret_image,
+ &LoadedImageProtocol, loaded_image,
+ NULL);
+ if (EFI_ERROR(err))
+ loaded_image = loaded_image_free(loaded_image);
+
+ return err;
+}
+
+static EFI_STATUS loaded_image_unregister(EFI_HANDLE loaded_image_handle) {
+ EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
+ EFI_STATUS err;
+
+ if (!loaded_image_handle)
+ return EFI_SUCCESS;
+
+ /* get the LoadedImage protocol that we allocated earlier */
+ err = uefi_call_wrapper(
+ BS->OpenProtocol, 6,
+ loaded_image_handle, &LoadedImageProtocol, (VOID **) &loaded_image,
+ NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(err))
+ return err;
+
+ /* close the handle */
+ (void) uefi_call_wrapper(
+ BS->CloseProtocol, 4,
+ loaded_image_handle, &LoadedImageProtocol, NULL, NULL);
+ err = uefi_call_wrapper(BS->UninstallMultipleProtocolInterfaces, 4,
+ loaded_image_handle,
+ &LoadedImageProtocol, loaded_image,
+ NULL);
+ if (EFI_ERROR(err))
+ return err;
+ loaded_image_handle = NULL;
+ loaded_image = loaded_image_free(loaded_image);
+
+ return EFI_SUCCESS;
+}
+
+static inline void cleanup_initrd(EFI_HANDLE *initrd_handle) {
+ (void) initrd_unregister(*initrd_handle);
+ *initrd_handle = NULL;
+}
+
+static inline void cleanup_loaded_image(EFI_HANDLE *loaded_image_handle) {
+ (void) loaded_image_unregister(*loaded_image_handle);
+ *loaded_image_handle = NULL;
+}
+
+/* struct to call cleanup_pages */
+struct pages {
+ EFI_PHYSICAL_ADDRESS addr;
+ UINTN num;
+};
+
+static inline void cleanup_pages(struct pages *p) {
+ if (p->addr == 0)
+ return;
+ (void) uefi_call_wrapper(BS->FreePages, 2, p->addr, p->num);
}
EFI_STATUS linux_exec(
EFI_HANDLE image,
const CHAR8 *cmdline, UINTN cmdline_len,
- const VOID *linux_buffer,
+ const VOID *linux_buffer, UINTN linux_length,
const VOID *initrd_buffer, UINTN initrd_length) {
- const struct boot_params *image_params;
- struct boot_params *boot_params;
- EFI_HANDLE initrd_handle = NULL;
- EFI_PHYSICAL_ADDRESS addr;
- UINT8 setup_sectors;
+ _cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
+ _cleanup_(cleanup_loaded_image) EFI_HANDLE loaded_image_handle = NULL;
+ UINT32 kernel_alignment, kernel_size_of_image, kernel_entry_address;
+ EFI_IMAGE_ENTRY_POINT kernel_entry;
+ _cleanup_(cleanup_pages) struct pages kernel = {};
+ VOID *new_buffer;
EFI_STATUS err;
assert(image);
assert(cmdline || cmdline_len == 0);
- assert(linux_buffer);
+ assert(linux_buffer && linux_length > 0);
assert(initrd_buffer || initrd_length == 0);
- image_params = (const struct boot_params *) linux_buffer;
-
- if (image_params->hdr.boot_flag != 0xAA55 ||
- image_params->hdr.header != SETUP_MAGIC ||
- image_params->hdr.version < 0x20b ||
- !image_params->hdr.relocatable_kernel)
- return EFI_LOAD_ERROR;
-
- addr = UINT32_MAX; /* Below the 32bit boundary */
- err = uefi_call_wrapper(
- BS->AllocatePages, 4,
- AllocateMaxAddress,
- EfiLoaderData,
- EFI_SIZE_TO_PAGES(0x4000),
- &addr);
+ /* get the necessary fields from the PE header */
+ err = pe_alignment_info(linux_buffer, &kernel_entry_address, &kernel_size_of_image, &kernel_alignment);
if (EFI_ERROR(err))
return err;
+ /* sanity check */
+ assert(kernel_size_of_image >= linux_length);
+
+ /* Linux kernel complains if it's not loaded at a properly aligned memory address. The correct alignment
+ is provided by Linux as the SegmentAlignment in the PeOptionalHeader. Additionally the kernel needs to
+ be in a memory segment thats SizeOfImage (again from PeOptionalHeader) large, so that the Kernel has
+ space for its BSS section. SizeOfImage is always larger than linux_length, which is only the size of
+ Code, (static) Data and Headers.
+
+ Interrestingly only ARM/Aarch64 and RISC-V kernel stubs check these assertions and can even boot (with warnings)
+ if they are not met. x86 and x86_64 kernel stubs don't do checks and fail if the BSS section is too small.
+ */
+ /* allocate SizeOfImage + SectionAlignment because the new_buffer can move up to Alignment-1 bytes */
+ kernel.num = EFI_SIZE_TO_PAGES(ALIGN_TO(kernel_size_of_image, kernel_alignment) + kernel_alignment);
+ err = uefi_call_wrapper(
+ BS->AllocatePages, 4,
+ AllocateAnyPages, EfiLoaderData,
+ kernel.num, &kernel.addr);
+ if (EFI_ERROR(err))
+ return EFI_OUT_OF_RESOURCES;
+ new_buffer = PHYSICAL_ADDRESS_TO_POINTER(ALIGN_TO(kernel.addr, kernel_alignment));
+ CopyMem(new_buffer, linux_buffer, linux_length);
+ /* zero out rest of memory (probably not needed, but BSS section should be 0) */
+ SetMem((UINT8 *)new_buffer + linux_length, kernel_size_of_image - linux_length, 0);
- boot_params = (struct boot_params *) PHYSICAL_ADDRESS_TO_POINTER(addr);
- ZeroMem(boot_params, 0x4000);
- boot_params->hdr = image_params->hdr;
- boot_params->hdr.type_of_loader = 0xff;
- setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
- boot_params->hdr.code32_start = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + (setup_sectors + 1) * 512;
+ /* get the entry point inside the relocated kernel */
+ kernel_entry = (EFI_IMAGE_ENTRY_POINT) ((const UINT8 *)new_buffer + kernel_entry_address);
- if (cmdline) {
- addr = 0xA0000;
-
- err = uefi_call_wrapper(
- BS->AllocatePages, 4,
- AllocateMaxAddress,
- EfiLoaderData,
- EFI_SIZE_TO_PAGES(cmdline_len + 1),
- &addr);
- if (EFI_ERROR(err))
- return err;
-
- CopyMem(PHYSICAL_ADDRESS_TO_POINTER(addr), cmdline, cmdline_len);
- ((CHAR8 *) PHYSICAL_ADDRESS_TO_POINTER(addr))[cmdline_len] = 0;
- boot_params->hdr.cmd_line_ptr = (UINT32) addr;
- }
-
- /* 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 = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer);
- boot_params->hdr.ramdisk_size = (UINT32) initrd_length;
+ /* register a LoadedImage Protocol in order to pass on the commandline */
+ err = loaded_image_register(cmdline, cmdline_len, new_buffer, linux_length, &loaded_image_handle);
+ if (EFI_ERROR(err))
+ return err;
- /* register LINUX_INITRD_MEDIA_GUID */
+ /* register a LINUX_INITRD_MEDIA DevicePath to serve the initrd */
err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
if (EFI_ERROR(err))
return err;
- linux_efi_handover(image, boot_params);
- (void) initrd_unregister(initrd_handle);
- initrd_handle = NULL;
- return EFI_LOAD_ERROR;
+
+ /* call the kernel */
+ return uefi_call_wrapper(kernel_entry, 2, loaded_image_handle, ST);
}
#pragma once
#include <efi.h>
-#include "macro-fundamental.h"
-
-#define SETUP_MAGIC 0x53726448 /* "HdrS" */
-
-struct setup_header {
- UINT8 setup_sects;
- UINT16 root_flags;
- UINT32 syssize;
- UINT16 ram_size;
- UINT16 vid_mode;
- UINT16 root_dev;
- UINT16 boot_flag;
- UINT16 jump;
- UINT32 header;
- UINT16 version;
- UINT32 realmode_swtch;
- UINT16 start_sys_seg;
- UINT16 kernel_version;
- UINT8 type_of_loader;
- UINT8 loadflags;
- UINT16 setup_move_size;
- UINT32 code32_start;
- UINT32 ramdisk_image;
- UINT32 ramdisk_size;
- UINT32 bootsect_kludge;
- UINT16 heap_end_ptr;
- UINT8 ext_loader_ver;
- UINT8 ext_loader_type;
- UINT32 cmd_line_ptr;
- UINT32 initrd_addr_max;
- UINT32 kernel_alignment;
- UINT8 relocatable_kernel;
- UINT8 min_alignment;
- UINT16 xloadflags;
- UINT32 cmdline_size;
- UINT32 hardware_subarch;
- UINT64 hardware_subarch_data;
- UINT32 payload_offset;
- UINT32 payload_length;
- UINT64 setup_data;
- UINT64 pref_address;
- UINT32 init_size;
- UINT32 handover_offset;
-} _packed_;
-
-/* adapted from linux' bootparam.h */
-struct boot_params {
- UINT8 screen_info[64]; // was: struct screen_info
- UINT8 apm_bios_info[20]; // was: struct apm_bios_info
- UINT8 _pad2[4];
- UINT64 tboot_addr;
- UINT8 ist_info[16]; // was: struct ist_info
- UINT8 _pad3[16];
- UINT8 hd0_info[16];
- UINT8 hd1_info[16];
- UINT8 sys_desc_table[16]; // was: struct sys_desc_table
- UINT8 olpc_ofw_header[16]; // was: struct olpc_ofw_header
- UINT32 ext_ramdisk_image;
- UINT32 ext_ramdisk_size;
- UINT32 ext_cmd_line_ptr;
- UINT8 _pad4[116];
- UINT8 edid_info[128]; // was: struct edid_info
- UINT8 efi_info[32]; // was: struct efi_info
- UINT32 alt_mem_k;
- UINT32 scratch;
- UINT8 e820_entries;
- UINT8 eddbuf_entries;
- UINT8 edd_mbr_sig_buf_entries;
- UINT8 kbd_status;
- UINT8 secure_boot;
- UINT8 _pad5[2];
- UINT8 sentinel;
- UINT8 _pad6[1];
- struct setup_header hdr;
- UINT8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
- UINT32 edd_mbr_sig_buffer[16]; // was: edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]
- UINT8 e820_table[20*128]; // was: struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE]
- UINT8 _pad8[48];
- UINT8 eddbuf[6*82]; // was: struct edd_info eddbuf[EDDMAXNR]
- UINT8 _pad9[276];
-} _packed_;
EFI_STATUS linux_exec(
EFI_HANDLE image,
const CHAR8 *cmdline, UINTN cmdline_len,
- const VOID *linux_buffer,
+ const VOID *linux_buffer, UINTN linux_length,
const VOID *initrd_buffer, UINTN initrd_length);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+/*
+ * x86 specific code to for EFI handover boot protocol
+ * Linux kernels version 5.8 and newer support providing the initrd by
+ * LINUX_INITRD_MEDIA_GUID DevicePath. In order to support older kernels too,
+ * this x86 specific linux_exec function passes the initrd by setting the
+ * corresponding fields in the setup_header struct.
+ *
+ * see https://www.kernel.org/doc/html/latest/x86/boot.html
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "initrd.h"
+#include "linux.h"
+#include "macro-fundamental.h"
+#include "util.h"
+
+#define SETUP_MAGIC 0x53726448 /* "HdrS" */
+
+struct setup_header {
+ UINT8 setup_sects;
+ UINT16 root_flags;
+ UINT32 syssize;
+ UINT16 ram_size;
+ UINT16 vid_mode;
+ UINT16 root_dev;
+ UINT16 boot_flag;
+ UINT16 jump;
+ UINT32 header;
+ UINT16 version;
+ UINT32 realmode_swtch;
+ UINT16 start_sys_seg;
+ UINT16 kernel_version;
+ UINT8 type_of_loader;
+ UINT8 loadflags;
+ UINT16 setup_move_size;
+ UINT32 code32_start;
+ UINT32 ramdisk_image;
+ UINT32 ramdisk_size;
+ UINT32 bootsect_kludge;
+ UINT16 heap_end_ptr;
+ UINT8 ext_loader_ver;
+ UINT8 ext_loader_type;
+ UINT32 cmd_line_ptr;
+ UINT32 initrd_addr_max;
+ UINT32 kernel_alignment;
+ UINT8 relocatable_kernel;
+ UINT8 min_alignment;
+ UINT16 xloadflags;
+ UINT32 cmdline_size;
+ UINT32 hardware_subarch;
+ UINT64 hardware_subarch_data;
+ UINT32 payload_offset;
+ UINT32 payload_length;
+ UINT64 setup_data;
+ UINT64 pref_address;
+ UINT32 init_size;
+ UINT32 handover_offset;
+} _packed_;
+
+/* adapted from linux' bootparam.h */
+struct boot_params {
+ UINT8 screen_info[64]; // was: struct screen_info
+ UINT8 apm_bios_info[20]; // was: struct apm_bios_info
+ UINT8 _pad2[4];
+ UINT64 tboot_addr;
+ UINT8 ist_info[16]; // was: struct ist_info
+ UINT8 _pad3[16];
+ UINT8 hd0_info[16];
+ UINT8 hd1_info[16];
+ UINT8 sys_desc_table[16]; // was: struct sys_desc_table
+ UINT8 olpc_ofw_header[16]; // was: struct olpc_ofw_header
+ UINT32 ext_ramdisk_image;
+ UINT32 ext_ramdisk_size;
+ UINT32 ext_cmd_line_ptr;
+ UINT8 _pad4[116];
+ UINT8 edid_info[128]; // was: struct edid_info
+ UINT8 efi_info[32]; // was: struct efi_info
+ UINT32 alt_mem_k;
+ UINT32 scratch;
+ UINT8 e820_entries;
+ UINT8 eddbuf_entries;
+ UINT8 edd_mbr_sig_buf_entries;
+ UINT8 kbd_status;
+ UINT8 secure_boot;
+ UINT8 _pad5[2];
+ UINT8 sentinel;
+ UINT8 _pad6[1];
+ struct setup_header hdr;
+ UINT8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
+ UINT32 edd_mbr_sig_buffer[16]; // was: edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]
+ UINT8 e820_table[20*128]; // was: struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE]
+ UINT8 _pad8[48];
+ UINT8 eddbuf[6*82]; // was: struct edd_info eddbuf[EDDMAXNR]
+ UINT8 _pad9[276];
+} _packed_;
+
+#ifdef __i386__
+#define __regparm0__ __attribute__((regparm(0)))
+#else
+#define __regparm0__
+#endif
+
+typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__;
+
+static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
+ handover_f handover;
+ UINTN start = (UINTN)params->hdr.code32_start;
+
+ assert(params);
+
+#ifdef __x86_64__
+ asm volatile ("cli");
+ start += 512;
+#endif
+ handover = (handover_f)(start + params->hdr.handover_offset);
+ handover(image, ST, params);
+}
+
+EFI_STATUS linux_exec(
+ EFI_HANDLE image,
+ const CHAR8 *cmdline, UINTN cmdline_len,
+ const VOID *linux_buffer, UINTN linux_length,
+ const VOID *initrd_buffer, UINTN initrd_length) {
+
+ const struct boot_params *image_params;
+ struct boot_params *boot_params;
+ EFI_HANDLE initrd_handle = NULL;
+ EFI_PHYSICAL_ADDRESS addr;
+ UINT8 setup_sectors;
+ EFI_STATUS err;
+
+ assert(image);
+ assert(cmdline || cmdline_len == 0);
+ assert(linux_buffer);
+ assert(initrd_buffer || initrd_length == 0);
+
+ image_params = (const struct boot_params *) linux_buffer;
+
+ if (image_params->hdr.boot_flag != 0xAA55 ||
+ image_params->hdr.header != SETUP_MAGIC ||
+ image_params->hdr.version < 0x20b ||
+ !image_params->hdr.relocatable_kernel)
+ return EFI_LOAD_ERROR;
+
+ addr = UINT32_MAX; /* Below the 32bit boundary */
+ err = uefi_call_wrapper(
+ BS->AllocatePages, 4,
+ AllocateMaxAddress,
+ EfiLoaderData,
+ EFI_SIZE_TO_PAGES(0x4000),
+ &addr);
+ if (EFI_ERROR(err))
+ return err;
+
+ boot_params = (struct boot_params *) PHYSICAL_ADDRESS_TO_POINTER(addr);
+ ZeroMem(boot_params, 0x4000);
+ boot_params->hdr = image_params->hdr;
+ boot_params->hdr.type_of_loader = 0xff;
+ setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
+ boot_params->hdr.code32_start = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + (setup_sectors + 1) * 512;
+
+ if (cmdline) {
+ addr = 0xA0000;
+
+ err = uefi_call_wrapper(
+ BS->AllocatePages, 4,
+ AllocateMaxAddress,
+ EfiLoaderData,
+ EFI_SIZE_TO_PAGES(cmdline_len + 1),
+ &addr);
+ if (EFI_ERROR(err))
+ return err;
+
+ CopyMem(PHYSICAL_ADDRESS_TO_POINTER(addr), cmdline, cmdline_len);
+ ((CHAR8 *) PHYSICAL_ADDRESS_TO_POINTER(addr))[cmdline_len] = 0;
+ boot_params->hdr.cmd_line_ptr = (UINT32) addr;
+ }
+
+ /* 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 = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer);
+ boot_params->hdr.ramdisk_size = (UINT32) initrd_length;
+
+ /* register LINUX_INITRD_MEDIA_GUID */
+ err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
+ if (EFI_ERROR(err))
+ return err;
+ linux_efi_handover(image, boot_params);
+ (void) initrd_unregister(initrd_handle);
+ initrd_handle = NULL;
+ return EFI_LOAD_ERROR;
+}
'''.split()
stub_sources = '''
- linux.c
initrd.c
splash.c
stub.c
'-include', efi_config_h,
'-include', version_h,
]
+ if ['ia32', 'x86_64'].contains(efi_arch)
+ stub_sources += 'linux_x86.c'
+ else
+ stub_sources += 'linux.c'
+ endif
if efi_arch == 'x86_64'
compile_args += ['-mno-red-zone',
'-mno-sse',
UINT16 Characteristics;
} _packed_;
+#define OPTHDR32_MAGIC 0x10B /* PE32 OptionalHeader */
+#define OPTHDR64_MAGIC 0x20B /* PE32+ OptionalHeader */
+
+struct PeOptionalHeader {
+ UINT16 Magic;
+ UINT8 LinkerMajor;
+ UINT8 LinkerMinor;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializeData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ union {
+ struct { /* PE32 */
+ UINT32 BaseOfData;
+ UINT32 ImageBase32;
+ };
+ UINT64 ImageBase64; /* PE32+ */
+ };
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ /* fields with different sizes for 32/64 omitted */
+} _packed_;
+
struct PeFileHeader {
UINT8 Magic[4];
struct CoffFileHeader FileHeader;
- /* OptionalHeader omitted */
+ struct PeOptionalHeader OptionalHeader;
} _packed_;
struct PeSectionHeader {
static inline UINTN section_table_offset(const struct DosFileHeader *dos, const struct PeFileHeader *pe) {
assert(dos);
assert(pe);
- return dos->ExeHeader + sizeof(struct PeFileHeader) + pe->FileHeader.SizeOfOptionalHeader;
+ return dos->ExeHeader + OFFSETOF(struct PeFileHeader, OptionalHeader) + pe->FileHeader.SizeOfOptionalHeader;
}
static VOID locate_sections(
}
}
+EFI_STATUS pe_alignment_info(
+ const VOID *base,
+ UINT32 *ret_entry_point_address,
+ UINT32 *ret_size_of_image,
+ UINT32 *ret_section_alignment) {
+
+ const struct DosFileHeader *dos;
+ const struct PeFileHeader *pe;
+
+ assert(base);
+ assert(ret_entry_point_address);
+ assert(ret_size_of_image);
+ assert(ret_section_alignment);
+
+ dos = (const struct DosFileHeader *) base;
+ if (!verify_dos(dos))
+ return EFI_LOAD_ERROR;
+
+ pe = (const struct PeFileHeader*) ((const UINT8 *)base + dos->ExeHeader);
+ if (!verify_pe(pe))
+ return EFI_LOAD_ERROR;
+
+ *ret_entry_point_address = pe->OptionalHeader.AddressOfEntryPoint;
+
+ if (pe->OptionalHeader.Magic == OPTHDR32_MAGIC) {
+ *ret_size_of_image = pe->OptionalHeader.SizeOfImage;
+ *ret_section_alignment = pe->OptionalHeader.SectionAlignment;
+ } else if (pe->OptionalHeader.Magic == OPTHDR64_MAGIC) {
+ *ret_size_of_image = pe->OptionalHeader.SizeOfImage;
+ *ret_section_alignment = pe->OptionalHeader.SectionAlignment;
+ } else
+ return EFI_UNSUPPORTED;
+ return EFI_SUCCESS;
+}
+
EFI_STATUS pe_memory_locate_sections(
const CHAR8 *base,
const CHAR8 **sections,
const CHAR8 **sections,
UINTN *offsets,
UINTN *sizes);
+
+EFI_STATUS pe_alignment_info(
+ const VOID *base,
+ UINT32 *ret_entry_point_address,
+ UINT32 *ret_size_of_image,
+ UINT32 *ret_section_alignment);
NULL,
};
- UINTN cmdline_len = 0, initrd_size, credential_initrd_size = 0, sysext_initrd_size = 0;
+ UINTN cmdline_len = 0, linux_size, initrd_size, credential_initrd_size = 0, sysext_initrd_size = 0;
_cleanup_freepool_ VOID *credential_initrd = NULL, *sysext_initrd = NULL;
EFI_PHYSICAL_ADDRESS linux_base, initrd_base;
EFI_LOADED_IMAGE *loaded_image;
&sysext_initrd,
&sysext_initrd_size);
+ linux_size = szs[SECTION_LINUX];
linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_LINUX];
initrd_size = szs[SECTION_INITRD];
}
err = linux_exec(image, cmdline, cmdline_len,
- PHYSICAL_ADDRESS_TO_POINTER(linux_base),
+ PHYSICAL_ADDRESS_TO_POINTER(linux_base), linux_size,
PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
graphics_mode(FALSE);
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);