blob: 14e56a64f2082440e26276b496d484f8eaf0da0e [file] [log] [blame]
Ard Biesheuvel4febfb82019-02-02 10:41:15 +01001// SPDX-License-Identifier: GPL-2.0
Roy Franz7721da42013-09-22 15:45:27 -07002/*
3 * Helper functions used by the EFI stub on multiple
4 * architectures. This should be #included by the EFI stub
5 * implementation files.
6 *
7 * Copyright 2011 Intel Corporation; author Matt Fleming
Roy Franz7721da42013-09-22 15:45:27 -07008 */
Ard Biesheuvelbd669472014-07-02 14:54:42 +02009
10#include <linux/efi.h>
11#include <asm/efi.h>
12
13#include "efistub.h"
14
Arvind Sankar54439372020-04-16 11:12:27 -040015static bool efi_nochunk;
16static bool efi_nokaslr;
17static bool efi_noinitrd;
18static bool efi_quiet;
19static bool efi_novamap;
20static bool efi_nosoftreserve;
21static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010022
Ard Biesheuvel5193a332020-02-10 17:02:43 +010023bool __pure nochunk(void)
24{
25 return efi_nochunk;
26}
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010027bool __pure nokaslr(void)
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010028{
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010029 return efi_nokaslr;
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010030}
Ard Biesheuvel79d32192020-02-04 22:01:22 +000031bool __pure noinitrd(void)
32{
33 return efi_noinitrd;
34}
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010035bool __pure is_quiet(void)
Ard Biesheuveleeff7d62017-04-04 17:09:09 +010036{
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010037 return efi_quiet;
Ard Biesheuveleeff7d62017-04-04 17:09:09 +010038}
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010039bool __pure novamap(void)
Ard Biesheuvel4e46c2a2019-02-02 10:41:16 +010040{
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010041 return efi_novamap;
Ard Biesheuvel4e46c2a2019-02-02 10:41:16 +010042}
Dan Williamsb617c522019-11-06 17:43:11 -080043bool __pure __efi_soft_reserve_enabled(void)
44{
45 return !efi_nosoftreserve;
46}
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010047
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010048void efi_printk(char *str)
Roy Franz7721da42013-09-22 15:45:27 -070049{
50 char *s8;
51
52 for (s8 = str; *s8; s8++) {
53 efi_char16_t ch[2] = { 0 };
54
55 ch[0] = *s8;
56 if (*s8 == '\n') {
57 efi_char16_t nl[2] = { '\r', 0 };
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010058 efi_char16_printk(nl);
Roy Franz7721da42013-09-22 15:45:27 -070059 }
60
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010061 efi_char16_printk(ch);
Roy Franz7721da42013-09-22 15:45:27 -070062 }
63}
64
Matt Fleming5a17dae2014-08-05 11:52:11 +010065/*
66 * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
67 * option, e.g. efi=nochunk.
68 *
69 * It should be noted that efi= is parsed in two very different
70 * environments, first in the early boot environment of the EFI boot
71 * stub, and subsequently during the kernel boot.
72 */
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010073efi_status_t efi_parse_options(char const *cmdline)
Matt Fleming5a17dae2014-08-05 11:52:11 +010074{
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010075 size_t len = strlen(cmdline) + 1;
76 efi_status_t status;
77 char *str, *buf;
Matt Fleming5a17dae2014-08-05 11:52:11 +010078
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010079 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf);
80 if (status != EFI_SUCCESS)
81 return status;
Ard Biesheuvelb3879a42017-02-06 11:22:46 +000082
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010083 str = skip_spaces(memcpy(buf, cmdline, len));
Ard Biesheuveleeff7d62017-04-04 17:09:09 +010084
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010085 while (*str) {
86 char *param, *val;
Matt Fleming5a17dae2014-08-05 11:52:11 +010087
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010088 str = next_arg(str, &param, &val);
Matt Fleming5a17dae2014-08-05 11:52:11 +010089
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010090 if (!strcmp(param, "nokaslr")) {
91 efi_nokaslr = true;
92 } else if (!strcmp(param, "quiet")) {
93 efi_quiet = true;
Ard Biesheuvel79d32192020-02-04 22:01:22 +000094 } else if (!strcmp(param, "noinitrd")) {
95 efi_noinitrd = true;
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010096 } else if (!strcmp(param, "efi") && val) {
97 efi_nochunk = parse_option_str(val, "nochunk");
98 efi_novamap = parse_option_str(val, "novamap");
99
100 efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
101 parse_option_str(val, "nosoftreserve");
102
103 if (parse_option_str(val, "disable_early_pci_dma"))
104 efi_disable_pci_dma = true;
105 if (parse_option_str(val, "no_disable_early_pci_dma"))
106 efi_disable_pci_dma = false;
Arvind Sankarfffb6802020-03-19 22:00:25 -0400107 } else if (!strcmp(param, "video") &&
108 val && strstarts(val, "efifb:")) {
109 efi_parse_option_graphics(val + strlen("efifb:"));
Matt Fleming5a17dae2014-08-05 11:52:11 +0100110 }
Matt Fleming5a17dae2014-08-05 11:52:11 +0100111 }
Ard Biesheuvel91d150c2020-02-10 17:02:46 +0100112 efi_bs_call(free_pool, buf);
Matt Fleming5a17dae2014-08-05 11:52:11 +0100113 return EFI_SUCCESS;
114}
Roy Franz7721da42013-09-22 15:45:27 -0700115
116/*
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500117 * Get the number of UTF-8 bytes corresponding to an UTF-16 character.
118 * This overestimates for surrogates, but that is okay.
119 */
120static int efi_utf8_bytes(u16 c)
121{
122 return 1 + (c >= 0x80) + (c >= 0x800);
123}
124
125/*
126 * Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
127 */
128static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
129{
130 unsigned int c;
131
132 while (n--) {
133 c = *src++;
134 if (n && c >= 0xd800 && c <= 0xdbff &&
135 *src >= 0xdc00 && *src <= 0xdfff) {
136 c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
137 src++;
138 n--;
139 }
140 if (c >= 0xd800 && c <= 0xdfff)
141 c = 0xfffd; /* Unmatched surrogate */
142 if (c < 0x80) {
143 *dst++ = c;
144 continue;
145 }
146 if (c < 0x800) {
147 *dst++ = 0xc0 + (c >> 6);
148 goto t1;
149 }
150 if (c < 0x10000) {
151 *dst++ = 0xe0 + (c >> 12);
152 goto t2;
153 }
154 *dst++ = 0xf0 + (c >> 18);
155 *dst++ = 0x80 + ((c >> 12) & 0x3f);
156 t2:
157 *dst++ = 0x80 + ((c >> 6) & 0x3f);
158 t1:
159 *dst++ = 0x80 + (c & 0x3f);
160 }
161
162 return dst;
163}
164
165/*
Roy Franz5fef3872013-09-22 15:45:33 -0700166 * Convert the unicode UEFI command line to ASCII to pass to kernel.
167 * Size of memory allocated return in *cmd_line_len.
168 * Returns NULL on error.
169 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100170char *efi_convert_cmdline(efi_loaded_image_t *image,
Ard Biesheuvel1e45bf72020-02-10 17:02:40 +0100171 int *cmd_line_len, unsigned long max_addr)
Roy Franz5fef3872013-09-22 15:45:33 -0700172{
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500173 const u16 *s2;
Roy Franz5fef3872013-09-22 15:45:33 -0700174 u8 *s1 = NULL;
175 unsigned long cmdline_addr = 0;
Ard Biesheuvelf7b85b32020-02-14 14:29:21 +0100176 int load_options_chars = efi_table_attr(image, load_options_size) / 2;
177 const u16 *options = efi_table_attr(image, load_options);
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500178 int options_bytes = 0; /* UTF-8 bytes */
179 int options_chars = 0; /* UTF-16 chars */
Roy Franz5fef3872013-09-22 15:45:33 -0700180 efi_status_t status;
Roy Franz5fef3872013-09-22 15:45:33 -0700181 u16 zero = 0;
182
183 if (options) {
184 s2 = options;
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500185 while (*s2 && *s2 != '\n'
186 && options_chars < load_options_chars) {
187 options_bytes += efi_utf8_bytes(*s2++);
188 options_chars++;
Roy Franz5fef3872013-09-22 15:45:33 -0700189 }
190 }
191
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500192 if (!options_chars) {
Roy Franz5fef3872013-09-22 15:45:33 -0700193 /* No command line options, so return empty string*/
Roy Franz5fef3872013-09-22 15:45:33 -0700194 options = &zero;
195 }
196
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500197 options_bytes++; /* NUL termination */
Leif Lindholm9403e462014-04-04 13:25:46 +0100198
Ard Biesheuvel1e45bf72020-02-10 17:02:40 +0100199 status = efi_allocate_pages(options_bytes, &cmdline_addr, max_addr);
Roy Franz5fef3872013-09-22 15:45:33 -0700200 if (status != EFI_SUCCESS)
201 return NULL;
202
203 s1 = (u8 *)cmdline_addr;
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500204 s2 = (const u16 *)options;
Roy Franz5fef3872013-09-22 15:45:33 -0700205
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500206 s1 = efi_utf16_to_utf8(s1, s2, options_chars);
Roy Franz5fef3872013-09-22 15:45:33 -0700207 *s1 = '\0';
208
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500209 *cmd_line_len = options_bytes;
Roy Franz5fef3872013-09-22 15:45:33 -0700210 return (char *)cmdline_addr;
211}
Jeffrey Hugofc077162016-08-29 14:38:52 -0600212
213/*
214 * Handle calling ExitBootServices according to the requirements set out by the
215 * spec. Obtains the current memory map, and returns that info after calling
216 * ExitBootServices. The client must specify a function to perform any
217 * processing of the memory map data prior to ExitBootServices. A client
218 * specific structure may be passed to the function via priv. The client
219 * function may be called multiple times.
220 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100221efi_status_t efi_exit_boot_services(void *handle,
Jeffrey Hugofc077162016-08-29 14:38:52 -0600222 struct efi_boot_memmap *map,
223 void *priv,
224 efi_exit_boot_map_processing priv_func)
225{
226 efi_status_t status;
227
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100228 status = efi_get_memory_map(map);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600229
230 if (status != EFI_SUCCESS)
231 goto fail;
232
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100233 status = priv_func(map, priv);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600234 if (status != EFI_SUCCESS)
235 goto free_map;
236
Matthew Garrett4444f852020-01-03 12:39:50 +0100237 if (efi_disable_pci_dma)
238 efi_pci_disable_bridge_busmaster();
239
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100240 status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600241
242 if (status == EFI_INVALID_PARAMETER) {
243 /*
244 * The memory map changed between efi_get_memory_map() and
245 * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4:
246 * EFI_BOOT_SERVICES.ExitBootServices we need to get the
247 * updated map, and try again. The spec implies one retry
248 * should be sufficent, which is confirmed against the EDK2
249 * implementation. Per the spec, we can only invoke
250 * get_memory_map() and exit_boot_services() - we cannot alloc
251 * so efi_get_memory_map() cannot be used, and we must reuse
252 * the buffer. For all practical purposes, the headroom in the
253 * buffer should account for any changes in the map so the call
254 * to get_memory_map() is expected to succeed here.
255 */
256 *map->map_size = *map->buff_size;
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100257 status = efi_bs_call(get_memory_map,
258 map->map_size,
259 *map->map,
260 map->key_ptr,
261 map->desc_size,
262 map->desc_ver);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600263
264 /* exit_boot_services() was called, thus cannot free */
265 if (status != EFI_SUCCESS)
266 goto fail;
267
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100268 status = priv_func(map, priv);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600269 /* exit_boot_services() was called, thus cannot free */
270 if (status != EFI_SUCCESS)
271 goto fail;
272
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100273 status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600274 }
275
276 /* exit_boot_services() was called, thus cannot free */
277 if (status != EFI_SUCCESS)
278 goto fail;
279
280 return EFI_SUCCESS;
281
282free_map:
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100283 efi_bs_call(free_pool, *map->map);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600284fail:
285 return status;
286}
Matthew Garrett82d736a2019-06-07 13:51:46 -0700287
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100288void *get_efi_config_table(efi_guid_t guid)
Matthew Garrett82d736a2019-06-07 13:51:46 -0700289{
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100290 unsigned long tables = efi_table_attr(efi_system_table(), tables);
291 int nr_tables = efi_table_attr(efi_system_table(), nr_tables);
Ard Biesheuvelf958efe2019-12-24 16:10:09 +0100292 int i;
293
294 for (i = 0; i < nr_tables; i++) {
295 efi_config_table_t *t = (void *)tables;
296
297 if (efi_guidcmp(t->guid, guid) == 0)
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100298 return efi_table_attr(t, table);
Ard Biesheuvelf958efe2019-12-24 16:10:09 +0100299
300 tables += efi_is_native() ? sizeof(efi_config_table_t)
301 : sizeof(efi_config_table_32_t);
302 }
303 return NULL;
Matthew Garrett82d736a2019-06-07 13:51:46 -0700304}
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100305
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100306void efi_char16_printk(efi_char16_t *str)
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100307{
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100308 efi_call_proto(efi_table_attr(efi_system_table(), con_out),
Ard Biesheuvel47c0fd32019-12-24 16:10:21 +0100309 output_string, str);
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100310}
Ard Biesheuvelec93fc32020-02-03 23:45:14 +0000311
312/*
313 * The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way
314 * for the firmware or bootloader to expose the initrd data directly to the stub
315 * via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is
316 * very easy to implement. It is a simple Linux initrd specific conduit between
317 * kernel and firmware, allowing us to put the EFI stub (being part of the
318 * kernel) in charge of where and when to load the initrd, while leaving it up
319 * to the firmware to decide whether it needs to expose its filesystem hierarchy
320 * via EFI protocols.
321 */
322static const struct {
323 struct efi_vendor_dev_path vendor;
324 struct efi_generic_dev_path end;
325} __packed initrd_dev_path = {
326 {
327 {
328 EFI_DEV_MEDIA,
329 EFI_DEV_MEDIA_VENDOR,
330 sizeof(struct efi_vendor_dev_path),
331 },
332 LINUX_EFI_INITRD_MEDIA_GUID
333 }, {
334 EFI_DEV_END_PATH,
335 EFI_DEV_END_ENTIRE,
336 sizeof(struct efi_generic_dev_path)
337 }
338};
339
340/**
341 * efi_load_initrd_dev_path - load the initrd from the Linux initrd device path
342 * @load_addr: pointer to store the address where the initrd was loaded
343 * @load_size: pointer to store the size of the loaded initrd
344 * @max: upper limit for the initrd memory allocation
345 * @return: %EFI_SUCCESS if the initrd was loaded successfully, in which
346 * case @load_addr and @load_size are assigned accordingly
347 * %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd
348 * device path
349 * %EFI_INVALID_PARAMETER if load_addr == NULL or load_size == NULL
350 * %EFI_OUT_OF_RESOURCES if memory allocation failed
351 * %EFI_LOAD_ERROR in all other cases
352 */
353efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
354 unsigned long *load_size,
355 unsigned long max)
356{
357 efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
358 efi_device_path_protocol_t *dp;
359 efi_load_file2_protocol_t *lf2;
360 unsigned long initrd_addr;
361 unsigned long initrd_size;
362 efi_handle_t handle;
363 efi_status_t status;
364
365 if (!load_addr || !load_size)
366 return EFI_INVALID_PARAMETER;
367
368 dp = (efi_device_path_protocol_t *)&initrd_dev_path;
369 status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
370 if (status != EFI_SUCCESS)
371 return status;
372
373 status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid,
374 (void **)&lf2);
375 if (status != EFI_SUCCESS)
376 return status;
377
378 status = efi_call_proto(lf2, load_file, dp, false, &initrd_size, NULL);
379 if (status != EFI_BUFFER_TOO_SMALL)
380 return EFI_LOAD_ERROR;
381
382 status = efi_allocate_pages(initrd_size, &initrd_addr, max);
383 if (status != EFI_SUCCESS)
384 return status;
385
386 status = efi_call_proto(lf2, load_file, dp, false, &initrd_size,
387 (void *)initrd_addr);
388 if (status != EFI_SUCCESS) {
389 efi_free(initrd_size, initrd_addr);
390 return EFI_LOAD_ERROR;
391 }
392
393 *load_addr = initrd_addr;
394 *load_size = initrd_size;
395 return EFI_SUCCESS;
396}