1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Helper functions used by the EFI stub on multiple
4*4882a593Smuzhiyun * architectures. This should be #included by the EFI stub
5*4882a593Smuzhiyun * implementation files.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright 2011 Intel Corporation; author Matt Fleming
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <stdarg.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/ctype.h>
13*4882a593Smuzhiyun #include <linux/efi.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */
16*4882a593Smuzhiyun #include <asm/efi.h>
17*4882a593Smuzhiyun #include <asm/setup.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "efistub.h"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun bool efi_nochunk;
22*4882a593Smuzhiyun bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
23*4882a593Smuzhiyun bool efi_noinitrd;
24*4882a593Smuzhiyun int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
25*4882a593Smuzhiyun bool efi_novamap;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun static bool efi_nosoftreserve;
28*4882a593Smuzhiyun static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
29*4882a593Smuzhiyun
__efi_soft_reserve_enabled(void)30*4882a593Smuzhiyun bool __pure __efi_soft_reserve_enabled(void)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun return !efi_nosoftreserve;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /**
36*4882a593Smuzhiyun * efi_char16_puts() - Write a UCS-2 encoded string to the console
37*4882a593Smuzhiyun * @str: UCS-2 encoded string
38*4882a593Smuzhiyun */
efi_char16_puts(efi_char16_t * str)39*4882a593Smuzhiyun void efi_char16_puts(efi_char16_t *str)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun efi_call_proto(efi_table_attr(efi_system_table, con_out),
42*4882a593Smuzhiyun output_string, str);
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun static
utf8_to_utf32(const u8 ** s8)46*4882a593Smuzhiyun u32 utf8_to_utf32(const u8 **s8)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun u32 c32;
49*4882a593Smuzhiyun u8 c0, cx;
50*4882a593Smuzhiyun size_t clen, i;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun c0 = cx = *(*s8)++;
53*4882a593Smuzhiyun /*
54*4882a593Smuzhiyun * The position of the most-significant 0 bit gives us the length of
55*4882a593Smuzhiyun * a multi-octet encoding.
56*4882a593Smuzhiyun */
57*4882a593Smuzhiyun for (clen = 0; cx & 0x80; ++clen)
58*4882a593Smuzhiyun cx <<= 1;
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun * If the 0 bit is in position 8, this is a valid single-octet
61*4882a593Smuzhiyun * encoding. If the 0 bit is in position 7 or positions 1-3, the
62*4882a593Smuzhiyun * encoding is invalid.
63*4882a593Smuzhiyun * In either case, we just return the first octet.
64*4882a593Smuzhiyun */
65*4882a593Smuzhiyun if (clen < 2 || clen > 4)
66*4882a593Smuzhiyun return c0;
67*4882a593Smuzhiyun /* Get the bits from the first octet. */
68*4882a593Smuzhiyun c32 = cx >> clen--;
69*4882a593Smuzhiyun for (i = 0; i < clen; ++i) {
70*4882a593Smuzhiyun /* Trailing octets must have 10 in most significant bits. */
71*4882a593Smuzhiyun cx = (*s8)[i] ^ 0x80;
72*4882a593Smuzhiyun if (cx & 0xc0)
73*4882a593Smuzhiyun return c0;
74*4882a593Smuzhiyun c32 = (c32 << 6) | cx;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun /*
77*4882a593Smuzhiyun * Check for validity:
78*4882a593Smuzhiyun * - The character must be in the Unicode range.
79*4882a593Smuzhiyun * - It must not be a surrogate.
80*4882a593Smuzhiyun * - It must be encoded using the correct number of octets.
81*4882a593Smuzhiyun */
82*4882a593Smuzhiyun if (c32 > 0x10ffff ||
83*4882a593Smuzhiyun (c32 & 0xf800) == 0xd800 ||
84*4882a593Smuzhiyun clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000))
85*4882a593Smuzhiyun return c0;
86*4882a593Smuzhiyun *s8 += clen;
87*4882a593Smuzhiyun return c32;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /**
91*4882a593Smuzhiyun * efi_puts() - Write a UTF-8 encoded string to the console
92*4882a593Smuzhiyun * @str: UTF-8 encoded string
93*4882a593Smuzhiyun */
efi_puts(const char * str)94*4882a593Smuzhiyun void efi_puts(const char *str)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun efi_char16_t buf[128];
97*4882a593Smuzhiyun size_t pos = 0, lim = ARRAY_SIZE(buf);
98*4882a593Smuzhiyun const u8 *s8 = (const u8 *)str;
99*4882a593Smuzhiyun u32 c32;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun while (*s8) {
102*4882a593Smuzhiyun if (*s8 == '\n')
103*4882a593Smuzhiyun buf[pos++] = L'\r';
104*4882a593Smuzhiyun c32 = utf8_to_utf32(&s8);
105*4882a593Smuzhiyun if (c32 < 0x10000) {
106*4882a593Smuzhiyun /* Characters in plane 0 use a single word. */
107*4882a593Smuzhiyun buf[pos++] = c32;
108*4882a593Smuzhiyun } else {
109*4882a593Smuzhiyun /*
110*4882a593Smuzhiyun * Characters in other planes encode into a surrogate
111*4882a593Smuzhiyun * pair.
112*4882a593Smuzhiyun */
113*4882a593Smuzhiyun buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10);
114*4882a593Smuzhiyun buf[pos++] = 0xdc00 + (c32 & 0x3ff);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun if (*s8 == '\0' || pos >= lim - 2) {
117*4882a593Smuzhiyun buf[pos] = L'\0';
118*4882a593Smuzhiyun efi_char16_puts(buf);
119*4882a593Smuzhiyun pos = 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /**
125*4882a593Smuzhiyun * efi_printk() - Print a kernel message
126*4882a593Smuzhiyun * @fmt: format string
127*4882a593Smuzhiyun *
128*4882a593Smuzhiyun * The first letter of the format string is used to determine the logging level
129*4882a593Smuzhiyun * of the message. If the level is less then the current EFI logging level, the
130*4882a593Smuzhiyun * message is suppressed. The message will be truncated to 255 bytes.
131*4882a593Smuzhiyun *
132*4882a593Smuzhiyun * Return: number of printed characters
133*4882a593Smuzhiyun */
efi_printk(const char * fmt,...)134*4882a593Smuzhiyun int efi_printk(const char *fmt, ...)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun char printf_buf[256];
137*4882a593Smuzhiyun va_list args;
138*4882a593Smuzhiyun int printed;
139*4882a593Smuzhiyun int loglevel = printk_get_level(fmt);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun switch (loglevel) {
142*4882a593Smuzhiyun case '0' ... '9':
143*4882a593Smuzhiyun loglevel -= '0';
144*4882a593Smuzhiyun break;
145*4882a593Smuzhiyun default:
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun * Use loglevel -1 for cases where we just want to print to
148*4882a593Smuzhiyun * the screen.
149*4882a593Smuzhiyun */
150*4882a593Smuzhiyun loglevel = -1;
151*4882a593Smuzhiyun break;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (loglevel >= efi_loglevel)
155*4882a593Smuzhiyun return 0;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if (loglevel >= 0)
158*4882a593Smuzhiyun efi_puts("EFI stub: ");
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun fmt = printk_skip_level(fmt);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun va_start(args, fmt);
163*4882a593Smuzhiyun printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
164*4882a593Smuzhiyun va_end(args);
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun efi_puts(printf_buf);
167*4882a593Smuzhiyun if (printed >= sizeof(printf_buf)) {
168*4882a593Smuzhiyun efi_puts("[Message truncated]\n");
169*4882a593Smuzhiyun return -1;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return printed;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /**
176*4882a593Smuzhiyun * efi_parse_options() - Parse EFI command line options
177*4882a593Smuzhiyun * @cmdline: kernel command line
178*4882a593Smuzhiyun *
179*4882a593Smuzhiyun * Parse the ASCII string @cmdline for EFI options, denoted by the efi=
180*4882a593Smuzhiyun * option, e.g. efi=nochunk.
181*4882a593Smuzhiyun *
182*4882a593Smuzhiyun * It should be noted that efi= is parsed in two very different
183*4882a593Smuzhiyun * environments, first in the early boot environment of the EFI boot
184*4882a593Smuzhiyun * stub, and subsequently during the kernel boot.
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun * Return: status code
187*4882a593Smuzhiyun */
efi_parse_options(char const * cmdline)188*4882a593Smuzhiyun efi_status_t efi_parse_options(char const *cmdline)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun size_t len;
191*4882a593Smuzhiyun efi_status_t status;
192*4882a593Smuzhiyun char *str, *buf;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if (!cmdline)
195*4882a593Smuzhiyun return EFI_SUCCESS;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1;
198*4882a593Smuzhiyun status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf);
199*4882a593Smuzhiyun if (status != EFI_SUCCESS)
200*4882a593Smuzhiyun return status;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun memcpy(buf, cmdline, len - 1);
203*4882a593Smuzhiyun buf[len - 1] = '\0';
204*4882a593Smuzhiyun str = skip_spaces(buf);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun while (*str) {
207*4882a593Smuzhiyun char *param, *val;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun str = next_arg(str, ¶m, &val);
210*4882a593Smuzhiyun if (!val && !strcmp(param, "--"))
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (!strcmp(param, "nokaslr")) {
214*4882a593Smuzhiyun efi_nokaslr = true;
215*4882a593Smuzhiyun } else if (!strcmp(param, "quiet")) {
216*4882a593Smuzhiyun efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
217*4882a593Smuzhiyun } else if (!strcmp(param, "noinitrd")) {
218*4882a593Smuzhiyun efi_noinitrd = true;
219*4882a593Smuzhiyun } else if (!strcmp(param, "efi") && val) {
220*4882a593Smuzhiyun efi_nochunk = parse_option_str(val, "nochunk");
221*4882a593Smuzhiyun efi_novamap = parse_option_str(val, "novamap");
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
224*4882a593Smuzhiyun parse_option_str(val, "nosoftreserve");
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if (parse_option_str(val, "disable_early_pci_dma"))
227*4882a593Smuzhiyun efi_disable_pci_dma = true;
228*4882a593Smuzhiyun if (parse_option_str(val, "no_disable_early_pci_dma"))
229*4882a593Smuzhiyun efi_disable_pci_dma = false;
230*4882a593Smuzhiyun if (parse_option_str(val, "debug"))
231*4882a593Smuzhiyun efi_loglevel = CONSOLE_LOGLEVEL_DEBUG;
232*4882a593Smuzhiyun } else if (!strcmp(param, "video") &&
233*4882a593Smuzhiyun val && strstarts(val, "efifb:")) {
234*4882a593Smuzhiyun efi_parse_option_graphics(val + strlen("efifb:"));
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun efi_bs_call(free_pool, buf);
238*4882a593Smuzhiyun return EFI_SUCCESS;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun /*
242*4882a593Smuzhiyun * The EFI_LOAD_OPTION descriptor has the following layout:
243*4882a593Smuzhiyun * u32 Attributes;
244*4882a593Smuzhiyun * u16 FilePathListLength;
245*4882a593Smuzhiyun * u16 Description[];
246*4882a593Smuzhiyun * efi_device_path_protocol_t FilePathList[];
247*4882a593Smuzhiyun * u8 OptionalData[];
248*4882a593Smuzhiyun *
249*4882a593Smuzhiyun * This function validates and unpacks the variable-size data fields.
250*4882a593Smuzhiyun */
251*4882a593Smuzhiyun static
efi_load_option_unpack(efi_load_option_unpacked_t * dest,const efi_load_option_t * src,size_t size)252*4882a593Smuzhiyun bool efi_load_option_unpack(efi_load_option_unpacked_t *dest,
253*4882a593Smuzhiyun const efi_load_option_t *src, size_t size)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun const void *pos;
256*4882a593Smuzhiyun u16 c;
257*4882a593Smuzhiyun efi_device_path_protocol_t header;
258*4882a593Smuzhiyun const efi_char16_t *description;
259*4882a593Smuzhiyun const efi_device_path_protocol_t *file_path_list;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun if (size < offsetof(efi_load_option_t, variable_data))
262*4882a593Smuzhiyun return false;
263*4882a593Smuzhiyun pos = src->variable_data;
264*4882a593Smuzhiyun size -= offsetof(efi_load_option_t, variable_data);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if ((src->attributes & ~EFI_LOAD_OPTION_MASK) != 0)
267*4882a593Smuzhiyun return false;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /* Scan description. */
270*4882a593Smuzhiyun description = pos;
271*4882a593Smuzhiyun do {
272*4882a593Smuzhiyun if (size < sizeof(c))
273*4882a593Smuzhiyun return false;
274*4882a593Smuzhiyun c = *(const u16 *)pos;
275*4882a593Smuzhiyun pos += sizeof(c);
276*4882a593Smuzhiyun size -= sizeof(c);
277*4882a593Smuzhiyun } while (c != L'\0');
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* Scan file_path_list. */
280*4882a593Smuzhiyun file_path_list = pos;
281*4882a593Smuzhiyun do {
282*4882a593Smuzhiyun if (size < sizeof(header))
283*4882a593Smuzhiyun return false;
284*4882a593Smuzhiyun header = *(const efi_device_path_protocol_t *)pos;
285*4882a593Smuzhiyun if (header.length < sizeof(header))
286*4882a593Smuzhiyun return false;
287*4882a593Smuzhiyun if (size < header.length)
288*4882a593Smuzhiyun return false;
289*4882a593Smuzhiyun pos += header.length;
290*4882a593Smuzhiyun size -= header.length;
291*4882a593Smuzhiyun } while ((header.type != EFI_DEV_END_PATH && header.type != EFI_DEV_END_PATH2) ||
292*4882a593Smuzhiyun (header.sub_type != EFI_DEV_END_ENTIRE));
293*4882a593Smuzhiyun if (pos != (const void *)file_path_list + src->file_path_list_length)
294*4882a593Smuzhiyun return false;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun dest->attributes = src->attributes;
297*4882a593Smuzhiyun dest->file_path_list_length = src->file_path_list_length;
298*4882a593Smuzhiyun dest->description = description;
299*4882a593Smuzhiyun dest->file_path_list = file_path_list;
300*4882a593Smuzhiyun dest->optional_data_size = size;
301*4882a593Smuzhiyun dest->optional_data = size ? pos : NULL;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun return true;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun /*
307*4882a593Smuzhiyun * At least some versions of Dell firmware pass the entire contents of the
308*4882a593Smuzhiyun * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the
309*4882a593Smuzhiyun * OptionalData field.
310*4882a593Smuzhiyun *
311*4882a593Smuzhiyun * Detect this case and extract OptionalData.
312*4882a593Smuzhiyun */
efi_apply_loadoptions_quirk(const void ** load_options,int * load_options_size)313*4882a593Smuzhiyun void efi_apply_loadoptions_quirk(const void **load_options, int *load_options_size)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun const efi_load_option_t *load_option = *load_options;
316*4882a593Smuzhiyun efi_load_option_unpacked_t load_option_unpacked;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_X86))
319*4882a593Smuzhiyun return;
320*4882a593Smuzhiyun if (!load_option)
321*4882a593Smuzhiyun return;
322*4882a593Smuzhiyun if (*load_options_size < sizeof(*load_option))
323*4882a593Smuzhiyun return;
324*4882a593Smuzhiyun if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
325*4882a593Smuzhiyun return;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if (!efi_load_option_unpack(&load_option_unpacked, load_option, *load_options_size))
328*4882a593Smuzhiyun return;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n");
331*4882a593Smuzhiyun efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun *load_options = load_option_unpacked.optional_data;
334*4882a593Smuzhiyun *load_options_size = load_option_unpacked.optional_data_size;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /*
338*4882a593Smuzhiyun * Convert the unicode UEFI command line to ASCII to pass to kernel.
339*4882a593Smuzhiyun * Size of memory allocated return in *cmd_line_len.
340*4882a593Smuzhiyun * Returns NULL on error.
341*4882a593Smuzhiyun */
efi_convert_cmdline(efi_loaded_image_t * image,int * cmd_line_len)342*4882a593Smuzhiyun char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun const u16 *s2;
345*4882a593Smuzhiyun unsigned long cmdline_addr = 0;
346*4882a593Smuzhiyun int options_chars = efi_table_attr(image, load_options_size);
347*4882a593Smuzhiyun const u16 *options = efi_table_attr(image, load_options);
348*4882a593Smuzhiyun int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
349*4882a593Smuzhiyun bool in_quote = false;
350*4882a593Smuzhiyun efi_status_t status;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun efi_apply_loadoptions_quirk((const void **)&options, &options_chars);
353*4882a593Smuzhiyun options_chars /= sizeof(*options);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun if (options) {
356*4882a593Smuzhiyun s2 = options;
357*4882a593Smuzhiyun while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
358*4882a593Smuzhiyun u16 c = *s2++;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun if (c < 0x80) {
361*4882a593Smuzhiyun if (c == L'\0' || c == L'\n')
362*4882a593Smuzhiyun break;
363*4882a593Smuzhiyun if (c == L'"')
364*4882a593Smuzhiyun in_quote = !in_quote;
365*4882a593Smuzhiyun else if (!in_quote && isspace((char)c))
366*4882a593Smuzhiyun safe_options_bytes = options_bytes;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun options_bytes++;
369*4882a593Smuzhiyun continue;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun /*
373*4882a593Smuzhiyun * Get the number of UTF-8 bytes corresponding to a
374*4882a593Smuzhiyun * UTF-16 character.
375*4882a593Smuzhiyun * The first part handles everything in the BMP.
376*4882a593Smuzhiyun */
377*4882a593Smuzhiyun options_bytes += 2 + (c >= 0x800);
378*4882a593Smuzhiyun /*
379*4882a593Smuzhiyun * Add one more byte for valid surrogate pairs. Invalid
380*4882a593Smuzhiyun * surrogates will be replaced with 0xfffd and take up
381*4882a593Smuzhiyun * only 3 bytes.
382*4882a593Smuzhiyun */
383*4882a593Smuzhiyun if ((c & 0xfc00) == 0xd800) {
384*4882a593Smuzhiyun /*
385*4882a593Smuzhiyun * If the very last word is a high surrogate,
386*4882a593Smuzhiyun * we must ignore it since we can't access the
387*4882a593Smuzhiyun * low surrogate.
388*4882a593Smuzhiyun */
389*4882a593Smuzhiyun if (!options_chars) {
390*4882a593Smuzhiyun options_bytes -= 3;
391*4882a593Smuzhiyun } else if ((*s2 & 0xfc00) == 0xdc00) {
392*4882a593Smuzhiyun options_bytes++;
393*4882a593Smuzhiyun options_chars--;
394*4882a593Smuzhiyun s2++;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun if (options_bytes >= COMMAND_LINE_SIZE) {
399*4882a593Smuzhiyun options_bytes = safe_options_bytes;
400*4882a593Smuzhiyun efi_err("Command line is too long: truncated to %d bytes\n",
401*4882a593Smuzhiyun options_bytes);
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun options_bytes++; /* NUL termination */
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes,
408*4882a593Smuzhiyun (void **)&cmdline_addr);
409*4882a593Smuzhiyun if (status != EFI_SUCCESS)
410*4882a593Smuzhiyun return NULL;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
413*4882a593Smuzhiyun options_bytes - 1, options);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun *cmd_line_len = options_bytes;
416*4882a593Smuzhiyun return (char *)cmdline_addr;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun /**
420*4882a593Smuzhiyun * efi_exit_boot_services() - Exit boot services
421*4882a593Smuzhiyun * @handle: handle of the exiting image
422*4882a593Smuzhiyun * @map: pointer to receive the memory map
423*4882a593Smuzhiyun * @priv: argument to be passed to @priv_func
424*4882a593Smuzhiyun * @priv_func: function to process the memory map before exiting boot services
425*4882a593Smuzhiyun *
426*4882a593Smuzhiyun * Handle calling ExitBootServices according to the requirements set out by the
427*4882a593Smuzhiyun * spec. Obtains the current memory map, and returns that info after calling
428*4882a593Smuzhiyun * ExitBootServices. The client must specify a function to perform any
429*4882a593Smuzhiyun * processing of the memory map data prior to ExitBootServices. A client
430*4882a593Smuzhiyun * specific structure may be passed to the function via priv. The client
431*4882a593Smuzhiyun * function may be called multiple times.
432*4882a593Smuzhiyun *
433*4882a593Smuzhiyun * Return: status code
434*4882a593Smuzhiyun */
efi_exit_boot_services(void * handle,struct efi_boot_memmap * map,void * priv,efi_exit_boot_map_processing priv_func)435*4882a593Smuzhiyun efi_status_t efi_exit_boot_services(void *handle,
436*4882a593Smuzhiyun struct efi_boot_memmap *map,
437*4882a593Smuzhiyun void *priv,
438*4882a593Smuzhiyun efi_exit_boot_map_processing priv_func)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun efi_status_t status;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun status = efi_get_memory_map(map);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (status != EFI_SUCCESS)
445*4882a593Smuzhiyun goto fail;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun status = priv_func(map, priv);
448*4882a593Smuzhiyun if (status != EFI_SUCCESS)
449*4882a593Smuzhiyun goto free_map;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun if (efi_disable_pci_dma)
452*4882a593Smuzhiyun efi_pci_disable_bridge_busmaster();
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun if (status == EFI_INVALID_PARAMETER) {
457*4882a593Smuzhiyun /*
458*4882a593Smuzhiyun * The memory map changed between efi_get_memory_map() and
459*4882a593Smuzhiyun * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4:
460*4882a593Smuzhiyun * EFI_BOOT_SERVICES.ExitBootServices we need to get the
461*4882a593Smuzhiyun * updated map, and try again. The spec implies one retry
462*4882a593Smuzhiyun * should be sufficent, which is confirmed against the EDK2
463*4882a593Smuzhiyun * implementation. Per the spec, we can only invoke
464*4882a593Smuzhiyun * get_memory_map() and exit_boot_services() - we cannot alloc
465*4882a593Smuzhiyun * so efi_get_memory_map() cannot be used, and we must reuse
466*4882a593Smuzhiyun * the buffer. For all practical purposes, the headroom in the
467*4882a593Smuzhiyun * buffer should account for any changes in the map so the call
468*4882a593Smuzhiyun * to get_memory_map() is expected to succeed here.
469*4882a593Smuzhiyun */
470*4882a593Smuzhiyun *map->map_size = *map->buff_size;
471*4882a593Smuzhiyun status = efi_bs_call(get_memory_map,
472*4882a593Smuzhiyun map->map_size,
473*4882a593Smuzhiyun *map->map,
474*4882a593Smuzhiyun map->key_ptr,
475*4882a593Smuzhiyun map->desc_size,
476*4882a593Smuzhiyun map->desc_ver);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /* exit_boot_services() was called, thus cannot free */
479*4882a593Smuzhiyun if (status != EFI_SUCCESS)
480*4882a593Smuzhiyun goto fail;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun status = priv_func(map, priv);
483*4882a593Smuzhiyun /* exit_boot_services() was called, thus cannot free */
484*4882a593Smuzhiyun if (status != EFI_SUCCESS)
485*4882a593Smuzhiyun goto fail;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /* exit_boot_services() was called, thus cannot free */
491*4882a593Smuzhiyun if (status != EFI_SUCCESS)
492*4882a593Smuzhiyun goto fail;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun return EFI_SUCCESS;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun free_map:
497*4882a593Smuzhiyun efi_bs_call(free_pool, *map->map);
498*4882a593Smuzhiyun fail:
499*4882a593Smuzhiyun return status;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /**
503*4882a593Smuzhiyun * get_efi_config_table() - retrieve UEFI configuration table
504*4882a593Smuzhiyun * @guid: GUID of the configuration table to be retrieved
505*4882a593Smuzhiyun * Return: pointer to the configuration table or NULL
506*4882a593Smuzhiyun */
get_efi_config_table(efi_guid_t guid)507*4882a593Smuzhiyun void *get_efi_config_table(efi_guid_t guid)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun unsigned long tables = efi_table_attr(efi_system_table, tables);
510*4882a593Smuzhiyun int nr_tables = efi_table_attr(efi_system_table, nr_tables);
511*4882a593Smuzhiyun int i;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun for (i = 0; i < nr_tables; i++) {
514*4882a593Smuzhiyun efi_config_table_t *t = (void *)tables;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun if (efi_guidcmp(t->guid, guid) == 0)
517*4882a593Smuzhiyun return efi_table_attr(t, table);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun tables += efi_is_native() ? sizeof(efi_config_table_t)
520*4882a593Smuzhiyun : sizeof(efi_config_table_32_t);
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun return NULL;
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun /*
526*4882a593Smuzhiyun * The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way
527*4882a593Smuzhiyun * for the firmware or bootloader to expose the initrd data directly to the stub
528*4882a593Smuzhiyun * via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is
529*4882a593Smuzhiyun * very easy to implement. It is a simple Linux initrd specific conduit between
530*4882a593Smuzhiyun * kernel and firmware, allowing us to put the EFI stub (being part of the
531*4882a593Smuzhiyun * kernel) in charge of where and when to load the initrd, while leaving it up
532*4882a593Smuzhiyun * to the firmware to decide whether it needs to expose its filesystem hierarchy
533*4882a593Smuzhiyun * via EFI protocols.
534*4882a593Smuzhiyun */
535*4882a593Smuzhiyun static const struct {
536*4882a593Smuzhiyun struct efi_vendor_dev_path vendor;
537*4882a593Smuzhiyun struct efi_generic_dev_path end;
538*4882a593Smuzhiyun } __packed initrd_dev_path = {
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun EFI_DEV_MEDIA,
542*4882a593Smuzhiyun EFI_DEV_MEDIA_VENDOR,
543*4882a593Smuzhiyun sizeof(struct efi_vendor_dev_path),
544*4882a593Smuzhiyun },
545*4882a593Smuzhiyun LINUX_EFI_INITRD_MEDIA_GUID
546*4882a593Smuzhiyun }, {
547*4882a593Smuzhiyun EFI_DEV_END_PATH,
548*4882a593Smuzhiyun EFI_DEV_END_ENTIRE,
549*4882a593Smuzhiyun sizeof(struct efi_generic_dev_path)
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun };
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /**
554*4882a593Smuzhiyun * efi_load_initrd_dev_path() - load the initrd from the Linux initrd device path
555*4882a593Smuzhiyun * @load_addr: pointer to store the address where the initrd was loaded
556*4882a593Smuzhiyun * @load_size: pointer to store the size of the loaded initrd
557*4882a593Smuzhiyun * @max: upper limit for the initrd memory allocation
558*4882a593Smuzhiyun *
559*4882a593Smuzhiyun * Return:
560*4882a593Smuzhiyun * * %EFI_SUCCESS if the initrd was loaded successfully, in which
561*4882a593Smuzhiyun * case @load_addr and @load_size are assigned accordingly
562*4882a593Smuzhiyun * * %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd device path
563*4882a593Smuzhiyun * * %EFI_INVALID_PARAMETER if load_addr == NULL or load_size == NULL
564*4882a593Smuzhiyun * * %EFI_OUT_OF_RESOURCES if memory allocation failed
565*4882a593Smuzhiyun * * %EFI_LOAD_ERROR in all other cases
566*4882a593Smuzhiyun */
567*4882a593Smuzhiyun static
efi_load_initrd_dev_path(unsigned long * load_addr,unsigned long * load_size,unsigned long max)568*4882a593Smuzhiyun efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
569*4882a593Smuzhiyun unsigned long *load_size,
570*4882a593Smuzhiyun unsigned long max)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
573*4882a593Smuzhiyun efi_device_path_protocol_t *dp;
574*4882a593Smuzhiyun efi_load_file2_protocol_t *lf2;
575*4882a593Smuzhiyun unsigned long initrd_addr;
576*4882a593Smuzhiyun unsigned long initrd_size;
577*4882a593Smuzhiyun efi_handle_t handle;
578*4882a593Smuzhiyun efi_status_t status;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun dp = (efi_device_path_protocol_t *)&initrd_dev_path;
581*4882a593Smuzhiyun status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
582*4882a593Smuzhiyun if (status != EFI_SUCCESS)
583*4882a593Smuzhiyun return status;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid,
586*4882a593Smuzhiyun (void **)&lf2);
587*4882a593Smuzhiyun if (status != EFI_SUCCESS)
588*4882a593Smuzhiyun return status;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun status = efi_call_proto(lf2, load_file, dp, false, &initrd_size, NULL);
591*4882a593Smuzhiyun if (status != EFI_BUFFER_TOO_SMALL)
592*4882a593Smuzhiyun return EFI_LOAD_ERROR;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun status = efi_allocate_pages(initrd_size, &initrd_addr, max);
595*4882a593Smuzhiyun if (status != EFI_SUCCESS)
596*4882a593Smuzhiyun return status;
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun status = efi_call_proto(lf2, load_file, dp, false, &initrd_size,
599*4882a593Smuzhiyun (void *)initrd_addr);
600*4882a593Smuzhiyun if (status != EFI_SUCCESS) {
601*4882a593Smuzhiyun efi_free(initrd_size, initrd_addr);
602*4882a593Smuzhiyun return EFI_LOAD_ERROR;
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun *load_addr = initrd_addr;
606*4882a593Smuzhiyun *load_size = initrd_size;
607*4882a593Smuzhiyun return EFI_SUCCESS;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun static
efi_load_initrd_cmdline(efi_loaded_image_t * image,unsigned long * load_addr,unsigned long * load_size,unsigned long soft_limit,unsigned long hard_limit)611*4882a593Smuzhiyun efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image,
612*4882a593Smuzhiyun unsigned long *load_addr,
613*4882a593Smuzhiyun unsigned long *load_size,
614*4882a593Smuzhiyun unsigned long soft_limit,
615*4882a593Smuzhiyun unsigned long hard_limit)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER) ||
618*4882a593Smuzhiyun (IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL))) {
619*4882a593Smuzhiyun *load_addr = *load_size = 0;
620*4882a593Smuzhiyun return EFI_SUCCESS;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
624*4882a593Smuzhiyun soft_limit, hard_limit,
625*4882a593Smuzhiyun load_addr, load_size);
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun /**
629*4882a593Smuzhiyun * efi_load_initrd() - Load initial RAM disk
630*4882a593Smuzhiyun * @image: EFI loaded image protocol
631*4882a593Smuzhiyun * @load_addr: pointer to loaded initrd
632*4882a593Smuzhiyun * @load_size: size of loaded initrd
633*4882a593Smuzhiyun * @soft_limit: preferred size of allocated memory for loading the initrd
634*4882a593Smuzhiyun * @hard_limit: minimum size of allocated memory
635*4882a593Smuzhiyun *
636*4882a593Smuzhiyun * Return: status code
637*4882a593Smuzhiyun */
efi_load_initrd(efi_loaded_image_t * image,unsigned long * load_addr,unsigned long * load_size,unsigned long soft_limit,unsigned long hard_limit)638*4882a593Smuzhiyun efi_status_t efi_load_initrd(efi_loaded_image_t *image,
639*4882a593Smuzhiyun unsigned long *load_addr,
640*4882a593Smuzhiyun unsigned long *load_size,
641*4882a593Smuzhiyun unsigned long soft_limit,
642*4882a593Smuzhiyun unsigned long hard_limit)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun efi_status_t status;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun if (!load_addr || !load_size)
647*4882a593Smuzhiyun return EFI_INVALID_PARAMETER;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit);
650*4882a593Smuzhiyun if (status == EFI_SUCCESS) {
651*4882a593Smuzhiyun efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
652*4882a593Smuzhiyun } else if (status == EFI_NOT_FOUND) {
653*4882a593Smuzhiyun status = efi_load_initrd_cmdline(image, load_addr, load_size,
654*4882a593Smuzhiyun soft_limit, hard_limit);
655*4882a593Smuzhiyun if (status == EFI_SUCCESS && *load_size > 0)
656*4882a593Smuzhiyun efi_info("Loaded initrd from command line option\n");
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun return status;
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun /**
663*4882a593Smuzhiyun * efi_wait_for_key() - Wait for key stroke
664*4882a593Smuzhiyun * @usec: number of microseconds to wait for key stroke
665*4882a593Smuzhiyun * @key: key entered
666*4882a593Smuzhiyun *
667*4882a593Smuzhiyun * Wait for up to @usec microseconds for a key stroke.
668*4882a593Smuzhiyun *
669*4882a593Smuzhiyun * Return: status code, EFI_SUCCESS if key received
670*4882a593Smuzhiyun */
efi_wait_for_key(unsigned long usec,efi_input_key_t * key)671*4882a593Smuzhiyun efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
672*4882a593Smuzhiyun {
673*4882a593Smuzhiyun efi_event_t events[2], timer;
674*4882a593Smuzhiyun unsigned long index;
675*4882a593Smuzhiyun efi_simple_text_input_protocol_t *con_in;
676*4882a593Smuzhiyun efi_status_t status;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun con_in = efi_table_attr(efi_system_table, con_in);
679*4882a593Smuzhiyun if (!con_in)
680*4882a593Smuzhiyun return EFI_UNSUPPORTED;
681*4882a593Smuzhiyun efi_set_event_at(events, 0, efi_table_attr(con_in, wait_for_key));
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun status = efi_bs_call(create_event, EFI_EVT_TIMER, 0, NULL, NULL, &timer);
684*4882a593Smuzhiyun if (status != EFI_SUCCESS)
685*4882a593Smuzhiyun return status;
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun status = efi_bs_call(set_timer, timer, EfiTimerRelative,
688*4882a593Smuzhiyun EFI_100NSEC_PER_USEC * usec);
689*4882a593Smuzhiyun if (status != EFI_SUCCESS)
690*4882a593Smuzhiyun return status;
691*4882a593Smuzhiyun efi_set_event_at(events, 1, timer);
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun status = efi_bs_call(wait_for_event, 2, events, &index);
694*4882a593Smuzhiyun if (status == EFI_SUCCESS) {
695*4882a593Smuzhiyun if (index == 0)
696*4882a593Smuzhiyun status = efi_call_proto(con_in, read_keystroke, key);
697*4882a593Smuzhiyun else
698*4882a593Smuzhiyun status = EFI_TIMEOUT;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun efi_bs_call(close_event, timer);
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun return status;
704*4882a593Smuzhiyun }
705