xref: /OK3568_Linux_fs/kernel/drivers/firmware/efi/libstub/efi-stub-helper.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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, &param, &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