blob: 6017b968cef7da81a2c823168d0ead533c28bda0 [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
Ard Biesheuvel5193a332020-02-10 17:02:43 +010015static bool __efistub_global efi_nochunk;
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010016static bool __efistub_global efi_nokaslr;
17static bool __efistub_global efi_quiet;
18static bool __efistub_global efi_novamap;
19static bool __efistub_global efi_nosoftreserve;
Matthew Garrett4444f852020-01-03 12:39:50 +010020static bool __efistub_global efi_disable_pci_dma =
21 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 Biesheuvel7d4e3232019-12-24 16:10:24 +010031bool __pure is_quiet(void)
Ard Biesheuveleeff7d62017-04-04 17:09:09 +010032{
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010033 return efi_quiet;
Ard Biesheuveleeff7d62017-04-04 17:09:09 +010034}
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010035bool __pure novamap(void)
Ard Biesheuvel4e46c2a2019-02-02 10:41:16 +010036{
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010037 return efi_novamap;
Ard Biesheuvel4e46c2a2019-02-02 10:41:16 +010038}
Dan Williamsb617c522019-11-06 17:43:11 -080039bool __pure __efi_soft_reserve_enabled(void)
40{
41 return !efi_nosoftreserve;
42}
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010043
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010044void efi_printk(char *str)
Roy Franz7721da42013-09-22 15:45:27 -070045{
46 char *s8;
47
48 for (s8 = str; *s8; s8++) {
49 efi_char16_t ch[2] = { 0 };
50
51 ch[0] = *s8;
52 if (*s8 == '\n') {
53 efi_char16_t nl[2] = { '\r', 0 };
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010054 efi_char16_printk(nl);
Roy Franz7721da42013-09-22 15:45:27 -070055 }
56
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010057 efi_char16_printk(ch);
Roy Franz7721da42013-09-22 15:45:27 -070058 }
59}
60
Matt Fleming5a17dae2014-08-05 11:52:11 +010061/*
62 * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
63 * option, e.g. efi=nochunk.
64 *
65 * It should be noted that efi= is parsed in two very different
66 * environments, first in the early boot environment of the EFI boot
67 * stub, and subsequently during the kernel boot.
68 */
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010069efi_status_t efi_parse_options(char const *cmdline)
Matt Fleming5a17dae2014-08-05 11:52:11 +010070{
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010071 size_t len = strlen(cmdline) + 1;
72 efi_status_t status;
73 char *str, *buf;
Matt Fleming5a17dae2014-08-05 11:52:11 +010074
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010075 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf);
76 if (status != EFI_SUCCESS)
77 return status;
Ard Biesheuvelb3879a42017-02-06 11:22:46 +000078
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010079 str = skip_spaces(memcpy(buf, cmdline, len));
Ard Biesheuveleeff7d62017-04-04 17:09:09 +010080
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010081 while (*str) {
82 char *param, *val;
Matt Fleming5a17dae2014-08-05 11:52:11 +010083
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010084 str = next_arg(str, &param, &val);
Matt Fleming5a17dae2014-08-05 11:52:11 +010085
Ard Biesheuvel91d150c2020-02-10 17:02:46 +010086 if (!strcmp(param, "nokaslr")) {
87 efi_nokaslr = true;
88 } else if (!strcmp(param, "quiet")) {
89 efi_quiet = true;
90 } else if (!strcmp(param, "efi") && val) {
91 efi_nochunk = parse_option_str(val, "nochunk");
92 efi_novamap = parse_option_str(val, "novamap");
93
94 efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
95 parse_option_str(val, "nosoftreserve");
96
97 if (parse_option_str(val, "disable_early_pci_dma"))
98 efi_disable_pci_dma = true;
99 if (parse_option_str(val, "no_disable_early_pci_dma"))
100 efi_disable_pci_dma = false;
Matt Fleming5a17dae2014-08-05 11:52:11 +0100101 }
Matt Fleming5a17dae2014-08-05 11:52:11 +0100102 }
Ard Biesheuvel91d150c2020-02-10 17:02:46 +0100103 efi_bs_call(free_pool, buf);
Matt Fleming5a17dae2014-08-05 11:52:11 +0100104 return EFI_SUCCESS;
105}
Roy Franz7721da42013-09-22 15:45:27 -0700106
107/*
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500108 * Get the number of UTF-8 bytes corresponding to an UTF-16 character.
109 * This overestimates for surrogates, but that is okay.
110 */
111static int efi_utf8_bytes(u16 c)
112{
113 return 1 + (c >= 0x80) + (c >= 0x800);
114}
115
116/*
117 * Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
118 */
119static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
120{
121 unsigned int c;
122
123 while (n--) {
124 c = *src++;
125 if (n && c >= 0xd800 && c <= 0xdbff &&
126 *src >= 0xdc00 && *src <= 0xdfff) {
127 c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
128 src++;
129 n--;
130 }
131 if (c >= 0xd800 && c <= 0xdfff)
132 c = 0xfffd; /* Unmatched surrogate */
133 if (c < 0x80) {
134 *dst++ = c;
135 continue;
136 }
137 if (c < 0x800) {
138 *dst++ = 0xc0 + (c >> 6);
139 goto t1;
140 }
141 if (c < 0x10000) {
142 *dst++ = 0xe0 + (c >> 12);
143 goto t2;
144 }
145 *dst++ = 0xf0 + (c >> 18);
146 *dst++ = 0x80 + ((c >> 12) & 0x3f);
147 t2:
148 *dst++ = 0x80 + ((c >> 6) & 0x3f);
149 t1:
150 *dst++ = 0x80 + (c & 0x3f);
151 }
152
153 return dst;
154}
155
156/*
Roy Franz5fef3872013-09-22 15:45:33 -0700157 * Convert the unicode UEFI command line to ASCII to pass to kernel.
158 * Size of memory allocated return in *cmd_line_len.
159 * Returns NULL on error.
160 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100161char *efi_convert_cmdline(efi_loaded_image_t *image,
Ard Biesheuvel1e45bf72020-02-10 17:02:40 +0100162 int *cmd_line_len, unsigned long max_addr)
Roy Franz5fef3872013-09-22 15:45:33 -0700163{
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500164 const u16 *s2;
Roy Franz5fef3872013-09-22 15:45:33 -0700165 u8 *s1 = NULL;
166 unsigned long cmdline_addr = 0;
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500167 int load_options_chars = image->load_options_size / 2; /* UTF-16 */
168 const u16 *options = image->load_options;
169 int options_bytes = 0; /* UTF-8 bytes */
170 int options_chars = 0; /* UTF-16 chars */
Roy Franz5fef3872013-09-22 15:45:33 -0700171 efi_status_t status;
Roy Franz5fef3872013-09-22 15:45:33 -0700172 u16 zero = 0;
173
174 if (options) {
175 s2 = options;
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500176 while (*s2 && *s2 != '\n'
177 && options_chars < load_options_chars) {
178 options_bytes += efi_utf8_bytes(*s2++);
179 options_chars++;
Roy Franz5fef3872013-09-22 15:45:33 -0700180 }
181 }
182
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500183 if (!options_chars) {
Roy Franz5fef3872013-09-22 15:45:33 -0700184 /* No command line options, so return empty string*/
Roy Franz5fef3872013-09-22 15:45:33 -0700185 options = &zero;
186 }
187
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500188 options_bytes++; /* NUL termination */
Leif Lindholm9403e462014-04-04 13:25:46 +0100189
Ard Biesheuvel1e45bf72020-02-10 17:02:40 +0100190 status = efi_allocate_pages(options_bytes, &cmdline_addr, max_addr);
Roy Franz5fef3872013-09-22 15:45:33 -0700191 if (status != EFI_SUCCESS)
192 return NULL;
193
194 s1 = (u8 *)cmdline_addr;
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500195 s2 = (const u16 *)options;
Roy Franz5fef3872013-09-22 15:45:33 -0700196
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500197 s1 = efi_utf16_to_utf8(s1, s2, options_chars);
Roy Franz5fef3872013-09-22 15:45:33 -0700198 *s1 = '\0';
199
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500200 *cmd_line_len = options_bytes;
Roy Franz5fef3872013-09-22 15:45:33 -0700201 return (char *)cmdline_addr;
202}
Jeffrey Hugofc077162016-08-29 14:38:52 -0600203
204/*
205 * Handle calling ExitBootServices according to the requirements set out by the
206 * spec. Obtains the current memory map, and returns that info after calling
207 * ExitBootServices. The client must specify a function to perform any
208 * processing of the memory map data prior to ExitBootServices. A client
209 * specific structure may be passed to the function via priv. The client
210 * function may be called multiple times.
211 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100212efi_status_t efi_exit_boot_services(void *handle,
Jeffrey Hugofc077162016-08-29 14:38:52 -0600213 struct efi_boot_memmap *map,
214 void *priv,
215 efi_exit_boot_map_processing priv_func)
216{
217 efi_status_t status;
218
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100219 status = efi_get_memory_map(map);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600220
221 if (status != EFI_SUCCESS)
222 goto fail;
223
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100224 status = priv_func(map, priv);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600225 if (status != EFI_SUCCESS)
226 goto free_map;
227
Matthew Garrett4444f852020-01-03 12:39:50 +0100228 if (efi_disable_pci_dma)
229 efi_pci_disable_bridge_busmaster();
230
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100231 status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600232
233 if (status == EFI_INVALID_PARAMETER) {
234 /*
235 * The memory map changed between efi_get_memory_map() and
236 * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4:
237 * EFI_BOOT_SERVICES.ExitBootServices we need to get the
238 * updated map, and try again. The spec implies one retry
239 * should be sufficent, which is confirmed against the EDK2
240 * implementation. Per the spec, we can only invoke
241 * get_memory_map() and exit_boot_services() - we cannot alloc
242 * so efi_get_memory_map() cannot be used, and we must reuse
243 * the buffer. For all practical purposes, the headroom in the
244 * buffer should account for any changes in the map so the call
245 * to get_memory_map() is expected to succeed here.
246 */
247 *map->map_size = *map->buff_size;
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100248 status = efi_bs_call(get_memory_map,
249 map->map_size,
250 *map->map,
251 map->key_ptr,
252 map->desc_size,
253 map->desc_ver);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600254
255 /* exit_boot_services() was called, thus cannot free */
256 if (status != EFI_SUCCESS)
257 goto fail;
258
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100259 status = priv_func(map, priv);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600260 /* exit_boot_services() was called, thus cannot free */
261 if (status != EFI_SUCCESS)
262 goto fail;
263
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100264 status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600265 }
266
267 /* exit_boot_services() was called, thus cannot free */
268 if (status != EFI_SUCCESS)
269 goto fail;
270
271 return EFI_SUCCESS;
272
273free_map:
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100274 efi_bs_call(free_pool, *map->map);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600275fail:
276 return status;
277}
Matthew Garrett82d736a2019-06-07 13:51:46 -0700278
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100279void *get_efi_config_table(efi_guid_t guid)
Matthew Garrett82d736a2019-06-07 13:51:46 -0700280{
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100281 unsigned long tables = efi_table_attr(efi_system_table(), tables);
282 int nr_tables = efi_table_attr(efi_system_table(), nr_tables);
Ard Biesheuvelf958efe2019-12-24 16:10:09 +0100283 int i;
284
285 for (i = 0; i < nr_tables; i++) {
286 efi_config_table_t *t = (void *)tables;
287
288 if (efi_guidcmp(t->guid, guid) == 0)
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100289 return efi_table_attr(t, table);
Ard Biesheuvelf958efe2019-12-24 16:10:09 +0100290
291 tables += efi_is_native() ? sizeof(efi_config_table_t)
292 : sizeof(efi_config_table_32_t);
293 }
294 return NULL;
Matthew Garrett82d736a2019-06-07 13:51:46 -0700295}
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100296
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100297void efi_char16_printk(efi_char16_t *str)
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100298{
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100299 efi_call_proto(efi_table_attr(efi_system_table(), con_out),
Ard Biesheuvel47c0fd32019-12-24 16:10:21 +0100300 output_string, str);
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100301}
Ard Biesheuvelec93fc32020-02-03 23:45:14 +0000302
303/*
304 * The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way
305 * for the firmware or bootloader to expose the initrd data directly to the stub
306 * via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is
307 * very easy to implement. It is a simple Linux initrd specific conduit between
308 * kernel and firmware, allowing us to put the EFI stub (being part of the
309 * kernel) in charge of where and when to load the initrd, while leaving it up
310 * to the firmware to decide whether it needs to expose its filesystem hierarchy
311 * via EFI protocols.
312 */
313static const struct {
314 struct efi_vendor_dev_path vendor;
315 struct efi_generic_dev_path end;
316} __packed initrd_dev_path = {
317 {
318 {
319 EFI_DEV_MEDIA,
320 EFI_DEV_MEDIA_VENDOR,
321 sizeof(struct efi_vendor_dev_path),
322 },
323 LINUX_EFI_INITRD_MEDIA_GUID
324 }, {
325 EFI_DEV_END_PATH,
326 EFI_DEV_END_ENTIRE,
327 sizeof(struct efi_generic_dev_path)
328 }
329};
330
331/**
332 * efi_load_initrd_dev_path - load the initrd from the Linux initrd device path
333 * @load_addr: pointer to store the address where the initrd was loaded
334 * @load_size: pointer to store the size of the loaded initrd
335 * @max: upper limit for the initrd memory allocation
336 * @return: %EFI_SUCCESS if the initrd was loaded successfully, in which
337 * case @load_addr and @load_size are assigned accordingly
338 * %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd
339 * device path
340 * %EFI_INVALID_PARAMETER if load_addr == NULL or load_size == NULL
341 * %EFI_OUT_OF_RESOURCES if memory allocation failed
342 * %EFI_LOAD_ERROR in all other cases
343 */
344efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
345 unsigned long *load_size,
346 unsigned long max)
347{
348 efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
349 efi_device_path_protocol_t *dp;
350 efi_load_file2_protocol_t *lf2;
351 unsigned long initrd_addr;
352 unsigned long initrd_size;
353 efi_handle_t handle;
354 efi_status_t status;
355
356 if (!load_addr || !load_size)
357 return EFI_INVALID_PARAMETER;
358
359 dp = (efi_device_path_protocol_t *)&initrd_dev_path;
360 status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
361 if (status != EFI_SUCCESS)
362 return status;
363
364 status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid,
365 (void **)&lf2);
366 if (status != EFI_SUCCESS)
367 return status;
368
369 status = efi_call_proto(lf2, load_file, dp, false, &initrd_size, NULL);
370 if (status != EFI_BUFFER_TOO_SMALL)
371 return EFI_LOAD_ERROR;
372
373 status = efi_allocate_pages(initrd_size, &initrd_addr, max);
374 if (status != EFI_SUCCESS)
375 return status;
376
377 status = efi_call_proto(lf2, load_file, dp, false, &initrd_size,
378 (void *)initrd_addr);
379 if (status != EFI_SUCCESS) {
380 efi_free(initrd_size, initrd_addr);
381 return EFI_LOAD_ERROR;
382 }
383
384 *load_addr = initrd_addr;
385 *load_size = initrd_size;
386 return EFI_SUCCESS;
387}