#define STUB_PAYLOAD_GUID \
{ 0x55c5d1f8, 0x04cd, 0x46b5, { 0x8a, 0x20, 0xe5, 0x6c, 0xbb, 0x30, 0x52, 0xd0 } }
+typedef struct {
+ MEMMAP_DEVICE_PATH memmap_path;
+ EFI_DEVICE_PATH end_path;
+} _packed_ KERNEL_FILE_PATH;
+
typedef struct {
const void *addr;
size_t len;
}
EFI_STATUS linux_exec(
- EFI_HANDLE parent,
+ EFI_HANDLE parent_image,
const char16_t *cmdline,
const struct iovec *kernel,
const struct iovec *initrd) {
uint64_t image_base;
EFI_STATUS err;
- assert(parent);
+ assert(parent_image);
assert(iovec_is_set(kernel));
assert(iovec_is_valid(initrd));
/* Kernel is too old to support LINUX_INITRD_MEDIA_GUID, try the deprecated EFI handover
* protocol. */
return linux_exec_efi_handover(
- parent,
+ parent_image,
cmdline,
kernel,
initrd,
if (err != EFI_SUCCESS)
return log_error_status(err, "Bad kernel image: %m");
+ /* Re-use the parent_image(_handle) and parent_loaded_image for the kernel image we are about to execute.
+ * We have to do this, because if kernel stub code passes its own handle to certain firmware functions,
+ * the firmware could cast EFI_LOADED_IMAGE_PROTOCOL * to a larger struct to access its own private data,
+ * and if we allocated a smaller struct, that could cause problems.
+ * This is modeled exactly after GRUB behaviour, which has proven to be functional. */
EFI_LOADED_IMAGE_PROTOCOL *parent_loaded_image;
err = BS->HandleProtocol(
- parent, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &parent_loaded_image);
+ parent_image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &parent_loaded_image);
if (err != EFI_SUCCESS)
return log_error_status(err, "Cannot get parent loaded image: %m");
*/
if (secure_boot_enabled() && (shim_loader_available() || (shim_loaded() && security_override_available())))
return load_via_boot_services(
- parent,
+ parent_image,
parent_loaded_image,
compat_entry_point,
cmdline,
h->VirtualSize - h->SizeOfRawData);
}
- _cleanup_free_ EFI_LOADED_IMAGE_PROTOCOL* loaded_image = xnew(EFI_LOADED_IMAGE_PROTOCOL, 1);
-
- VENDOR_DEVICE_PATH device_node = {
- .Header = {
- .Type = MEDIA_DEVICE_PATH,
- .SubType = MEDIA_VENDOR_DP,
- .Length = sizeof(device_node),
- },
- .Guid = STUB_PAYLOAD_GUID,
+ _cleanup_free_ KERNEL_FILE_PATH *kernel_file_path = xnew(KERNEL_FILE_PATH, 1);
+
+ *kernel_file_path = (KERNEL_FILE_PATH) {
+ .memmap_path = {
+ .Header = {
+ .Type = HARDWARE_DEVICE_PATH,
+ .SubType = HW_MEMMAP_DP,
+ .Length = sizeof(MEMMAP_DEVICE_PATH),
+ },
+ .MemoryType = EfiLoaderData,
+ .StartingAddress = POINTER_TO_PHYSICAL_ADDRESS(kernel->iov_base),
+ .EndingAddress = POINTER_TO_PHYSICAL_ADDRESS(kernel->iov_base) + kernel->iov_len,
+ },
+ .end_path = {
+ .Type = END_DEVICE_PATH_TYPE,
+ .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ .Length = sizeof(EFI_DEVICE_PATH),
+ },
};
- _cleanup_free_ EFI_DEVICE_PATH* file_path = device_path_replace_node(parent_loaded_image->FilePath, NULL, &device_node.Header);
-
- *loaded_image = (EFI_LOADED_IMAGE_PROTOCOL) {
- .Revision = 0x1000,
- .ParentHandle = parent,
- .SystemTable = ST,
- .DeviceHandle = parent_loaded_image->DeviceHandle,
- .FilePath = file_path,
- .ImageBase = loaded_kernel,
- .ImageSize = kernel_size_in_memory,
- .ImageCodeType = 1 /* EFI_LOADER_CODE */,
- .ImageDataType = 2 /* EFI_LOADER_DATA */,
- };
+ parent_loaded_image->ImageBase = loaded_kernel;
+ parent_loaded_image->ImageSize = kernel_size_in_memory;
if (cmdline) {
- loaded_image->LoadOptions = (void *) cmdline;
- loaded_image->LoadOptionsSize = strsize16(loaded_image->LoadOptions);
+ parent_loaded_image->LoadOptions = (void *) cmdline;
+ parent_loaded_image->LoadOptionsSize = strsize16(parent_loaded_image->LoadOptions);
}
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
if (err != EFI_SUCCESS)
return log_error_status(err, "Error registering initrd: %m");
- EFI_HANDLE kernel_image = NULL;
-
- err = BS->InstallMultipleProtocolInterfaces(
- &kernel_image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), loaded_image,
- NULL);
- if (err != EFI_SUCCESS)
- return log_error_status(err, "Cannot install loaded image protocol: %m");
-
log_wait();
if (entry_point > 0) {
EFI_IMAGE_ENTRY_POINT entry =
- (EFI_IMAGE_ENTRY_POINT) ((const uint8_t *) loaded_image->ImageBase + entry_point);
- err = entry(kernel_image, ST);
+ (EFI_IMAGE_ENTRY_POINT) ((const uint8_t *) parent_loaded_image->ImageBase + entry_point);
+ err = entry(parent_image, ST);
} else if (compat_entry_point > 0) {
/* Try calling the kernel compat entry point if one exists. */
EFI_IMAGE_ENTRY_POINT compat_entry =
- (EFI_IMAGE_ENTRY_POINT) ((const uint8_t *) loaded_image->ImageBase + compat_entry_point);
- err = compat_entry(kernel_image, ST);
+ (EFI_IMAGE_ENTRY_POINT) ((const uint8_t *) parent_loaded_image->ImageBase + compat_entry_point);
+ err = compat_entry(parent_image, ST);
}
- EFI_STATUS uninstall_err = BS->UninstallMultipleProtocolInterfaces(
- kernel_image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), loaded_image,
- NULL);
- if (uninstall_err != EFI_SUCCESS)
- return log_error_status(uninstall_err, "Cannot uninstall loaded image protocol: %m");
-
return log_error_status(err, "Error starting kernel image: %m");
}