]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/linux.c
boot: Use proper security arch protocol names
[thirdparty/systemd.git] / src / boot / efi / linux.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
0fa2cac4 2
dc467928
MR
3/*
4 * Generic Linux boot protocol using the EFI/PE entry point of the kernel. Passes
5 * initrd with the LINUX_INITRD_MEDIA_GUID DevicePath and cmdline with
6 * EFI LoadedImageProtocol.
7 *
8 * This method works for Linux 5.8 and newer on ARM/Aarch64, x86/x68_64 and RISC-V.
9 */
10
0fa2cac4
KS
11#include <efi.h>
12#include <efilib.h>
13
a6089431 14#include "initrd.h"
dc467928
MR
15#include "linux.h"
16#include "pe.h"
cf0fbc49 17#include "util.h"
0fa2cac4 18
a529d818
JJ
19#define STUB_PAYLOAD_GUID \
20 { 0x55c5d1f8, 0x04cd, 0x46b5, { 0x8a, 0x20, 0xe5, 0x6c, 0xbb, 0x30, 0x52, 0xd0 } }
dc467928 21
a529d818
JJ
22EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len, EFI_HANDLE *ret_image) {
23 assert(parent);
24 assert(source);
dc467928 25 assert(ret_image);
4287d083 26
a529d818
JJ
27 /* We could pass a NULL device path, but it's nicer to provide something. */
28 struct {
29 VENDOR_DEVICE_PATH payload;
30 EFI_DEVICE_PATH end;
31 } _packed_ payload_device_path = {
32 .payload = {
33 .Header = {
34 .Type = MEDIA_DEVICE_PATH,
35 .SubType = MEDIA_VENDOR_DP,
36 .Length = { sizeof(payload_device_path.payload), 0 },
37 },
38 .Guid = STUB_PAYLOAD_GUID,
39 },
40 .end = {
41 .Type = END_DEVICE_PATH_TYPE,
42 .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE,
43 .Length = { sizeof(payload_device_path.end), 0 },
44 },
dc467928 45 };
0fa2cac4 46
a529d818
JJ
47 return BS->LoadImage(
48 /*BootPolicy=*/false,
49 parent,
50 &payload_device_path.payload.Header,
51 (void *) source,
52 len,
53 ret_image);
dc467928
MR
54}
55
a6089431 56EFI_STATUS linux_exec(
bfc075fa 57 EFI_HANDLE parent,
07d0fde4 58 const char *cmdline, UINTN cmdline_len,
70cd15e9
JJ
59 const void *linux_buffer, UINTN linux_length,
60 const void *initrd_buffer, UINTN initrd_length) {
0d43ce52 61
dcde6ae1 62 uint32_t compat_address;
0fa2cac4
KS
63 EFI_STATUS err;
64
bfc075fa 65 assert(parent);
a6089431 66 assert(cmdline || cmdline_len == 0);
dc467928 67 assert(linux_buffer && linux_length > 0);
a6089431 68 assert(initrd_buffer || initrd_length == 0);
508df915 69
dcde6ae1 70 err = pe_kernel_info(linux_buffer, &compat_address);
ba2a105c
JJ
71#if defined(__i386__) || defined(__x86_64__)
72 if (err == EFI_UNSUPPORTED)
73 /* Kernel is too old to support LINUX_INITRD_MEDIA_GUID, try the deprecated EFI handover
74 * protocol. */
75 return linux_exec_efi_handover(
bfc075fa 76 parent,
ba2a105c
JJ
77 cmdline,
78 cmdline_len,
79 linux_buffer,
80 linux_length,
81 initrd_buffer,
82 initrd_length);
83#endif
2a5e4fe4 84 if (err != EFI_SUCCESS)
a529d818
JJ
85 return log_error_status_stall(err, u"Bad kernel image: %r", err);
86
87 _cleanup_(unload_imagep) EFI_HANDLE kernel_image = NULL;
88 err = load_image(parent, linux_buffer, linux_length, &kernel_image);
89 if (err != EFI_SUCCESS)
90 return log_error_status_stall(err, u"Error loading kernel image: %r", err);
91
92 EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
93 err = BS->HandleProtocol(kernel_image, &LoadedImageProtocol, (void **) &loaded_image);
2a5e4fe4 94 if (err != EFI_SUCCESS)
a529d818
JJ
95 return log_error_status_stall(err, u"Error getting kernel loaded image protocol: %r", err);
96
97 if (cmdline) {
98 loaded_image->LoadOptions = xstra_to_str(cmdline);
99 loaded_image->LoadOptionsSize = strsize16(loaded_image->LoadOptions);
100 }
a6089431 101
a529d818 102 _cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
a6089431 103 err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
2a5e4fe4 104 if (err != EFI_SUCCESS)
a529d818
JJ
105 return log_error_status_stall(err, u"Error registering initrd: %r", err);
106
107 err = BS->StartImage(kernel_image, NULL, NULL);
108
109 /* Try calling the kernel compat entry point if one exists. */
dcde6ae1 110 if (err == EFI_UNSUPPORTED && compat_address > 0) {
a529d818 111 EFI_IMAGE_ENTRY_POINT compat_entry =
dcde6ae1 112 (EFI_IMAGE_ENTRY_POINT) ((uint8_t *) loaded_image->ImageBase + compat_address);
a529d818
JJ
113 err = compat_entry(kernel_image, ST);
114 }
dc467928 115
a529d818 116 return log_error_status_stall(err, u"Error starting kernel image: %r", err);
0fa2cac4 117}