blob: 74ddfb496140f8bbe004991e5dd8747d4a3a233a [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
Matt Fleming5a17dae2014-08-05 11:52:11 +010015/*
16 * Some firmware implementations have problems reading files in one go.
17 * A read chunk size of 1MB seems to work for most platforms.
18 *
19 * Unfortunately, reading files in chunks triggers *other* bugs on some
20 * platforms, so we provide a way to disable this workaround, which can
21 * be done by passing "efi=nochunk" on the EFI boot stub command line.
22 *
23 * If you experience issues with initrd images being corrupt it's worth
24 * trying efi=nochunk, but chunking is enabled by default because there
25 * are far more machines that require the workaround than those that
26 * break with it enabled.
27 */
Roy Franz7721da42013-09-22 15:45:27 -070028#define EFI_READ_CHUNK_SIZE (1024 * 1024)
29
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010030static unsigned long efi_chunk_size = EFI_READ_CHUNK_SIZE;
Matt Fleming5a17dae2014-08-05 11:52:11 +010031
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010032static bool __efistub_global efi_nokaslr;
33static bool __efistub_global efi_quiet;
34static bool __efistub_global efi_novamap;
35static bool __efistub_global efi_nosoftreserve;
Matthew Garrett4444f852020-01-03 12:39:50 +010036static bool __efistub_global efi_disable_pci_dma =
37 IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010038
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010039bool __pure nokaslr(void)
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010040{
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010041 return efi_nokaslr;
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010042}
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010043bool __pure is_quiet(void)
Ard Biesheuveleeff7d62017-04-04 17:09:09 +010044{
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010045 return efi_quiet;
Ard Biesheuveleeff7d62017-04-04 17:09:09 +010046}
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010047bool __pure novamap(void)
Ard Biesheuvel4e46c2a2019-02-02 10:41:16 +010048{
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +010049 return efi_novamap;
Ard Biesheuvel4e46c2a2019-02-02 10:41:16 +010050}
Dan Williamsb617c522019-11-06 17:43:11 -080051bool __pure __efi_soft_reserve_enabled(void)
52{
53 return !efi_nosoftreserve;
54}
Ard Biesheuvel60f38de2017-04-04 17:09:08 +010055
Jeffrey Hugodadb57a2016-08-29 14:38:51 -060056#define EFI_MMAP_NR_SLACK_SLOTS 8
57
Roy Franz36f89612013-09-22 15:45:40 -070058struct file_info {
Roy Franz7721da42013-09-22 15:45:27 -070059 efi_file_handle_t *handle;
60 u64 size;
61};
62
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010063void efi_printk(char *str)
Roy Franz7721da42013-09-22 15:45:27 -070064{
65 char *s8;
66
67 for (s8 = str; *s8; s8++) {
68 efi_char16_t ch[2] = { 0 };
69
70 ch[0] = *s8;
71 if (*s8 == '\n') {
72 efi_char16_t nl[2] = { '\r', 0 };
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010073 efi_char16_printk(nl);
Roy Franz7721da42013-09-22 15:45:27 -070074 }
75
Ard Biesheuvel8173ec72019-12-24 16:10:18 +010076 efi_char16_printk(ch);
Roy Franz7721da42013-09-22 15:45:27 -070077 }
78}
79
Jeffrey Hugodadb57a2016-08-29 14:38:51 -060080static inline bool mmap_has_headroom(unsigned long buff_size,
81 unsigned long map_size,
82 unsigned long desc_size)
83{
84 unsigned long slack = buff_size - map_size;
85
86 return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS;
87}
88
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +010089efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
Roy Franz7721da42013-09-22 15:45:27 -070090{
91 efi_memory_desc_t *m = NULL;
92 efi_status_t status;
93 unsigned long key;
94 u32 desc_version;
95
Jeffrey Hugodadb57a2016-08-29 14:38:51 -060096 *map->desc_size = sizeof(*m);
97 *map->map_size = *map->desc_size * 32;
98 *map->buff_size = *map->map_size;
Matt Fleming43a9f692015-02-13 15:46:56 +000099again:
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100100 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
101 *map->map_size, (void **)&m);
Roy Franz7721da42013-09-22 15:45:27 -0700102 if (status != EFI_SUCCESS)
103 goto fail;
104
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600105 *map->desc_size = 0;
Matt Fleming43a9f692015-02-13 15:46:56 +0000106 key = 0;
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100107 status = efi_bs_call(get_memory_map, map->map_size, m,
108 &key, map->desc_size, &desc_version);
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600109 if (status == EFI_BUFFER_TOO_SMALL ||
110 !mmap_has_headroom(*map->buff_size, *map->map_size,
111 *map->desc_size)) {
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100112 efi_bs_call(free_pool, m);
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600113 /*
114 * Make sure there is some entries of headroom so that the
115 * buffer can be reused for a new map after allocations are
116 * no longer permitted. Its unlikely that the map will grow to
117 * exceed this headroom once we are ready to trigger
118 * ExitBootServices()
119 */
120 *map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS;
121 *map->buff_size = *map->map_size;
Matt Fleming43a9f692015-02-13 15:46:56 +0000122 goto again;
Roy Franz7721da42013-09-22 15:45:27 -0700123 }
124
125 if (status != EFI_SUCCESS)
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100126 efi_bs_call(free_pool, m);
Matt Fleming54b52d82014-01-10 15:27:14 +0000127
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600128 if (map->key_ptr && status == EFI_SUCCESS)
129 *map->key_ptr = key;
130 if (map->desc_ver && status == EFI_SUCCESS)
131 *map->desc_ver = desc_version;
Roy Franz7721da42013-09-22 15:45:27 -0700132
133fail:
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600134 *map->map = m;
Roy Franz7721da42013-09-22 15:45:27 -0700135 return status;
136}
137
Roy Franz9bb40192014-01-28 10:41:28 -0800138
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100139unsigned long get_dram_base(void)
Roy Franz9bb40192014-01-28 10:41:28 -0800140{
141 efi_status_t status;
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600142 unsigned long map_size, buff_size;
Roy Franz9bb40192014-01-28 10:41:28 -0800143 unsigned long membase = EFI_ERROR;
144 struct efi_memory_map map;
145 efi_memory_desc_t *md;
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600146 struct efi_boot_memmap boot_map;
Roy Franz9bb40192014-01-28 10:41:28 -0800147
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600148 boot_map.map = (efi_memory_desc_t **)&map.map;
149 boot_map.map_size = &map_size;
150 boot_map.desc_size = &map.desc_size;
151 boot_map.desc_ver = NULL;
152 boot_map.key_ptr = NULL;
153 boot_map.buff_size = &buff_size;
154
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100155 status = efi_get_memory_map(&boot_map);
Roy Franz9bb40192014-01-28 10:41:28 -0800156 if (status != EFI_SUCCESS)
157 return membase;
158
159 map.map_end = map.map + map_size;
160
Matt Fleming78ce2482016-04-25 21:06:38 +0100161 for_each_efi_memory_desc_in_map(&map, md) {
162 if (md->attribute & EFI_MEMORY_WB) {
Roy Franz9bb40192014-01-28 10:41:28 -0800163 if (membase > md->phys_addr)
164 membase = md->phys_addr;
Matt Fleming78ce2482016-04-25 21:06:38 +0100165 }
166 }
Roy Franz9bb40192014-01-28 10:41:28 -0800167
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100168 efi_bs_call(free_pool, map.map);
Roy Franz9bb40192014-01-28 10:41:28 -0800169
170 return membase;
171}
172
Roy Franz7721da42013-09-22 15:45:27 -0700173/*
174 * Allocate at the highest possible address that is not above 'max'.
175 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100176efi_status_t efi_high_alloc(unsigned long size, unsigned long align,
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200177 unsigned long *addr, unsigned long max)
Roy Franz7721da42013-09-22 15:45:27 -0700178{
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600179 unsigned long map_size, desc_size, buff_size;
Roy Franz7721da42013-09-22 15:45:27 -0700180 efi_memory_desc_t *map;
181 efi_status_t status;
182 unsigned long nr_pages;
183 u64 max_addr = 0;
184 int i;
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600185 struct efi_boot_memmap boot_map;
Roy Franz7721da42013-09-22 15:45:27 -0700186
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600187 boot_map.map = &map;
188 boot_map.map_size = &map_size;
189 boot_map.desc_size = &desc_size;
190 boot_map.desc_ver = NULL;
191 boot_map.key_ptr = NULL;
192 boot_map.buff_size = &buff_size;
193
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100194 status = efi_get_memory_map(&boot_map);
Roy Franz7721da42013-09-22 15:45:27 -0700195 if (status != EFI_SUCCESS)
196 goto fail;
197
Roy Franz38dd9c02013-09-22 15:45:30 -0700198 /*
Roy Franz5b88a312016-11-12 21:32:29 +0000199 * Enforce minimum alignment that EFI or Linux requires when
200 * requesting a specific address. We are doing page-based (or
201 * larger) allocations, and both the address and size must meet
202 * alignment constraints.
Roy Franz38dd9c02013-09-22 15:45:30 -0700203 */
Ard Biesheuvelcf2b0f12014-11-17 13:46:44 +0100204 if (align < EFI_ALLOC_ALIGN)
205 align = EFI_ALLOC_ALIGN;
Roy Franz38dd9c02013-09-22 15:45:30 -0700206
Roy Franz5b88a312016-11-12 21:32:29 +0000207 size = round_up(size, EFI_ALLOC_ALIGN);
208 nr_pages = size / EFI_PAGE_SIZE;
Roy Franz7721da42013-09-22 15:45:27 -0700209again:
210 for (i = 0; i < map_size / desc_size; i++) {
211 efi_memory_desc_t *desc;
212 unsigned long m = (unsigned long)map;
213 u64 start, end;
214
Baoquan He02e43c22017-08-16 21:46:51 +0800215 desc = efi_early_memdesc_ptr(m, desc_size, i);
Roy Franz7721da42013-09-22 15:45:27 -0700216 if (desc->type != EFI_CONVENTIONAL_MEMORY)
217 continue;
218
Dan Williamsb617c522019-11-06 17:43:11 -0800219 if (efi_soft_reserve_enabled() &&
220 (desc->attribute & EFI_MEMORY_SP))
221 continue;
222
Roy Franz7721da42013-09-22 15:45:27 -0700223 if (desc->num_pages < nr_pages)
224 continue;
225
226 start = desc->phys_addr;
Roy Franz5b88a312016-11-12 21:32:29 +0000227 end = start + desc->num_pages * EFI_PAGE_SIZE;
Roy Franz7721da42013-09-22 15:45:27 -0700228
Yinghai Lu7ed620b2015-02-19 20:18:03 -0800229 if (end > max)
Roy Franz7721da42013-09-22 15:45:27 -0700230 end = max;
231
Yinghai Lu7ed620b2015-02-19 20:18:03 -0800232 if ((start + size) > end)
233 continue;
234
Roy Franz7721da42013-09-22 15:45:27 -0700235 if (round_down(end - size, align) < start)
236 continue;
237
238 start = round_down(end - size, align);
239
240 /*
241 * Don't allocate at 0x0. It will confuse code that
242 * checks pointers against NULL.
243 */
244 if (start == 0x0)
245 continue;
246
247 if (start > max_addr)
248 max_addr = start;
249 }
250
251 if (!max_addr)
252 status = EFI_NOT_FOUND;
253 else {
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100254 status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
255 EFI_LOADER_DATA, nr_pages, &max_addr);
Roy Franz7721da42013-09-22 15:45:27 -0700256 if (status != EFI_SUCCESS) {
257 max = max_addr;
258 max_addr = 0;
259 goto again;
260 }
261
262 *addr = max_addr;
263 }
264
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100265 efi_bs_call(free_pool, map);
Roy Franz7721da42013-09-22 15:45:27 -0700266fail:
267 return status;
268}
269
270/*
Kairui Song220dd762019-10-29 18:37:54 +0100271 * Allocate at the lowest possible address that is not below 'min'.
Roy Franz7721da42013-09-22 15:45:27 -0700272 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100273efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
Kairui Song220dd762019-10-29 18:37:54 +0100274 unsigned long *addr, unsigned long min)
Roy Franz7721da42013-09-22 15:45:27 -0700275{
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600276 unsigned long map_size, desc_size, buff_size;
Roy Franz7721da42013-09-22 15:45:27 -0700277 efi_memory_desc_t *map;
278 efi_status_t status;
279 unsigned long nr_pages;
280 int i;
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600281 struct efi_boot_memmap boot_map;
Roy Franz7721da42013-09-22 15:45:27 -0700282
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600283 boot_map.map = &map;
284 boot_map.map_size = &map_size;
285 boot_map.desc_size = &desc_size;
286 boot_map.desc_ver = NULL;
287 boot_map.key_ptr = NULL;
288 boot_map.buff_size = &buff_size;
289
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100290 status = efi_get_memory_map(&boot_map);
Roy Franz7721da42013-09-22 15:45:27 -0700291 if (status != EFI_SUCCESS)
292 goto fail;
293
Roy Franz38dd9c02013-09-22 15:45:30 -0700294 /*
Roy Franz5b88a312016-11-12 21:32:29 +0000295 * Enforce minimum alignment that EFI or Linux requires when
296 * requesting a specific address. We are doing page-based (or
297 * larger) allocations, and both the address and size must meet
298 * alignment constraints.
Roy Franz38dd9c02013-09-22 15:45:30 -0700299 */
Ard Biesheuvelcf2b0f12014-11-17 13:46:44 +0100300 if (align < EFI_ALLOC_ALIGN)
301 align = EFI_ALLOC_ALIGN;
Roy Franz38dd9c02013-09-22 15:45:30 -0700302
Roy Franz5b88a312016-11-12 21:32:29 +0000303 size = round_up(size, EFI_ALLOC_ALIGN);
304 nr_pages = size / EFI_PAGE_SIZE;
Roy Franz7721da42013-09-22 15:45:27 -0700305 for (i = 0; i < map_size / desc_size; i++) {
306 efi_memory_desc_t *desc;
307 unsigned long m = (unsigned long)map;
308 u64 start, end;
309
Baoquan He02e43c22017-08-16 21:46:51 +0800310 desc = efi_early_memdesc_ptr(m, desc_size, i);
Roy Franz7721da42013-09-22 15:45:27 -0700311
312 if (desc->type != EFI_CONVENTIONAL_MEMORY)
313 continue;
314
Dan Williamsb617c522019-11-06 17:43:11 -0800315 if (efi_soft_reserve_enabled() &&
316 (desc->attribute & EFI_MEMORY_SP))
317 continue;
318
Roy Franz7721da42013-09-22 15:45:27 -0700319 if (desc->num_pages < nr_pages)
320 continue;
321
322 start = desc->phys_addr;
Roy Franz5b88a312016-11-12 21:32:29 +0000323 end = start + desc->num_pages * EFI_PAGE_SIZE;
Roy Franz7721da42013-09-22 15:45:27 -0700324
Kairui Song220dd762019-10-29 18:37:54 +0100325 if (start < min)
326 start = min;
Roy Franz7721da42013-09-22 15:45:27 -0700327
328 start = round_up(start, align);
329 if ((start + size) > end)
330 continue;
331
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100332 status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
333 EFI_LOADER_DATA, nr_pages, &start);
Roy Franz7721da42013-09-22 15:45:27 -0700334 if (status == EFI_SUCCESS) {
335 *addr = start;
336 break;
337 }
338 }
339
340 if (i == map_size / desc_size)
341 status = EFI_NOT_FOUND;
342
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100343 efi_bs_call(free_pool, map);
Roy Franz7721da42013-09-22 15:45:27 -0700344fail:
345 return status;
346}
347
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100348void efi_free(unsigned long size, unsigned long addr)
Roy Franz7721da42013-09-22 15:45:27 -0700349{
350 unsigned long nr_pages;
351
Roy Franz0e1cadb2013-09-22 15:45:38 -0700352 if (!size)
353 return;
354
Ard Biesheuvelcf2b0f12014-11-17 13:46:44 +0100355 nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
Arvind Sankarea7d87f2020-01-03 12:39:49 +0100356 efi_bs_call(free_pages, addr, nr_pages);
Roy Franz7721da42013-09-22 15:45:27 -0700357}
358
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100359static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,
360 void **handle, u64 *file_sz)
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000361{
362 efi_file_handle_t *h, *fh = __fh;
363 efi_file_info_t *info;
364 efi_status_t status;
365 efi_guid_t info_guid = EFI_FILE_INFO_ID;
366 unsigned long info_sz;
367
Ard Biesheuvel14e900c2019-12-24 16:10:14 +0100368 status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, 0);
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000369 if (status != EFI_SUCCESS) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100370 efi_printk("Failed to open file: ");
371 efi_char16_printk(filename_16);
372 efi_printk("\n");
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000373 return status;
374 }
375
376 *handle = h;
377
378 info_sz = 0;
Ard Biesheuvel14e900c2019-12-24 16:10:14 +0100379 status = h->get_info(h, &info_guid, &info_sz, NULL);
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000380 if (status != EFI_BUFFER_TOO_SMALL) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100381 efi_printk("Failed to get file info size\n");
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000382 return status;
383 }
384
385grow:
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100386 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, info_sz,
387 (void **)&info);
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000388 if (status != EFI_SUCCESS) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100389 efi_printk("Failed to alloc mem for file info\n");
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000390 return status;
391 }
392
Ard Biesheuvel14e900c2019-12-24 16:10:14 +0100393 status = h->get_info(h, &info_guid, &info_sz, info);
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000394 if (status == EFI_BUFFER_TOO_SMALL) {
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100395 efi_bs_call(free_pool, info);
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000396 goto grow;
397 }
398
399 *file_sz = info->file_size;
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100400 efi_bs_call(free_pool, info);
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000401
402 if (status != EFI_SUCCESS)
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100403 efi_printk("Failed to get initrd info\n");
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000404
405 return status;
406}
407
Ard Biesheuvel960a8d02019-12-24 16:10:11 +0100408static efi_status_t efi_file_read(efi_file_handle_t *handle,
409 unsigned long *size, void *addr)
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000410{
Ard Biesheuvel14e900c2019-12-24 16:10:14 +0100411 return handle->read(handle, size, addr);
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000412}
413
Ard Biesheuvel960a8d02019-12-24 16:10:11 +0100414static efi_status_t efi_file_close(efi_file_handle_t *handle)
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000415{
Ard Biesheuvel14e900c2019-12-24 16:10:14 +0100416 return handle->close(handle);
Lukas Wunner2bd79f32017-01-31 13:21:33 +0000417}
418
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100419static efi_status_t efi_open_volume(efi_loaded_image_t *image,
Lukas Wunnerc4db9c12018-07-20 10:47:23 +0900420 efi_file_handle_t **__fh)
421{
422 efi_file_io_interface_t *io;
423 efi_file_handle_t *fh;
424 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
425 efi_status_t status;
Ard Biesheuvel14e900c2019-12-24 16:10:14 +0100426 efi_handle_t handle = image->device_handle;
Lukas Wunnerc4db9c12018-07-20 10:47:23 +0900427
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100428 status = efi_bs_call(handle_protocol, handle, &fs_proto, (void **)&io);
Lukas Wunnerc4db9c12018-07-20 10:47:23 +0900429 if (status != EFI_SUCCESS) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100430 efi_printk("Failed to handle fs_proto\n");
Lukas Wunnerc4db9c12018-07-20 10:47:23 +0900431 return status;
432 }
433
Ard Biesheuvel14e900c2019-12-24 16:10:14 +0100434 status = io->open_volume(io, &fh);
Lukas Wunnerc4db9c12018-07-20 10:47:23 +0900435 if (status != EFI_SUCCESS)
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100436 efi_printk("Failed to open volume\n");
Lukas Wunnerc4db9c12018-07-20 10:47:23 +0900437 else
438 *__fh = fh;
439
440 return status;
441}
442
Matt Fleming5a17dae2014-08-05 11:52:11 +0100443/*
444 * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
445 * option, e.g. efi=nochunk.
446 *
447 * It should be noted that efi= is parsed in two very different
448 * environments, first in the early boot environment of the EFI boot
449 * stub, and subsequently during the kernel boot.
450 */
Ard Biesheuvel60f38de2017-04-04 17:09:08 +0100451efi_status_t efi_parse_options(char const *cmdline)
Matt Fleming5a17dae2014-08-05 11:52:11 +0100452{
453 char *str;
454
Ard Biesheuvel60f38de2017-04-04 17:09:08 +0100455 str = strstr(cmdline, "nokaslr");
456 if (str == cmdline || (str && str > cmdline && *(str - 1) == ' '))
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +0100457 efi_nokaslr = true;
Ard Biesheuvelb3879a42017-02-06 11:22:46 +0000458
Ard Biesheuveleeff7d62017-04-04 17:09:09 +0100459 str = strstr(cmdline, "quiet");
460 if (str == cmdline || (str && str > cmdline && *(str - 1) == ' '))
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +0100461 efi_quiet = true;
Ard Biesheuveleeff7d62017-04-04 17:09:09 +0100462
Ard Biesheuvelb3879a42017-02-06 11:22:46 +0000463 /*
Matt Fleming5a17dae2014-08-05 11:52:11 +0100464 * If no EFI parameters were specified on the cmdline we've got
465 * nothing to do.
466 */
467 str = strstr(cmdline, "efi=");
468 if (!str)
469 return EFI_SUCCESS;
470
471 /* Skip ahead to first argument */
472 str += strlen("efi=");
473
474 /*
475 * Remember, because efi= is also used by the kernel we need to
476 * skip over arguments we don't understand.
477 */
Ard Biesheuvel4c3f14b2017-04-04 17:02:45 +0100478 while (*str && *str != ' ') {
Matt Fleming5a17dae2014-08-05 11:52:11 +0100479 if (!strncmp(str, "nochunk", 7)) {
480 str += strlen("nochunk");
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +0100481 efi_chunk_size = -1UL;
Matt Fleming5a17dae2014-08-05 11:52:11 +0100482 }
483
Ard Biesheuvel4e46c2a2019-02-02 10:41:16 +0100484 if (!strncmp(str, "novamap", 7)) {
485 str += strlen("novamap");
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +0100486 efi_novamap = true;
Ard Biesheuvel4e46c2a2019-02-02 10:41:16 +0100487 }
488
Dan Williamsb617c522019-11-06 17:43:11 -0800489 if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
490 !strncmp(str, "nosoftreserve", 7)) {
491 str += strlen("nosoftreserve");
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +0100492 efi_nosoftreserve = true;
Dan Williamsb617c522019-11-06 17:43:11 -0800493 }
494
Matthew Garrett4444f852020-01-03 12:39:50 +0100495 if (!strncmp(str, "disable_early_pci_dma", 21)) {
496 str += strlen("disable_early_pci_dma");
497 efi_disable_pci_dma = true;
498 }
499
500 if (!strncmp(str, "no_disable_early_pci_dma", 24)) {
501 str += strlen("no_disable_early_pci_dma");
502 efi_disable_pci_dma = false;
503 }
504
Matt Fleming5a17dae2014-08-05 11:52:11 +0100505 /* Group words together, delimited by "," */
Ard Biesheuvel4c3f14b2017-04-04 17:02:45 +0100506 while (*str && *str != ' ' && *str != ',')
Matt Fleming5a17dae2014-08-05 11:52:11 +0100507 str++;
508
509 if (*str == ',')
510 str++;
511 }
512
513 return EFI_SUCCESS;
514}
Roy Franz7721da42013-09-22 15:45:27 -0700515
516/*
Roy Franz36f89612013-09-22 15:45:40 -0700517 * Check the cmdline for a LILO-style file= arguments.
Roy Franz7721da42013-09-22 15:45:27 -0700518 *
Roy Franz36f89612013-09-22 15:45:40 -0700519 * We only support loading a file from the same filesystem as
520 * the kernel image.
Roy Franz7721da42013-09-22 15:45:27 -0700521 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100522efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200523 char *cmd_line, char *option_string,
524 unsigned long max_addr,
525 unsigned long *load_addr,
526 unsigned long *load_size)
Roy Franz7721da42013-09-22 15:45:27 -0700527{
Roy Franz36f89612013-09-22 15:45:40 -0700528 struct file_info *files;
529 unsigned long file_addr;
Roy Franz36f89612013-09-22 15:45:40 -0700530 u64 file_size_total;
Leif Lindholm9403e462014-04-04 13:25:46 +0100531 efi_file_handle_t *fh = NULL;
Roy Franz7721da42013-09-22 15:45:27 -0700532 efi_status_t status;
Roy Franz36f89612013-09-22 15:45:40 -0700533 int nr_files;
Roy Franz7721da42013-09-22 15:45:27 -0700534 char *str;
535 int i, j, k;
536
Roy Franz36f89612013-09-22 15:45:40 -0700537 file_addr = 0;
538 file_size_total = 0;
Roy Franz7721da42013-09-22 15:45:27 -0700539
Roy Franz46f45822013-09-22 15:45:39 -0700540 str = cmd_line;
Roy Franz7721da42013-09-22 15:45:27 -0700541
542 j = 0; /* See close_handles */
543
Roy Franz46f45822013-09-22 15:45:39 -0700544 if (!load_addr || !load_size)
545 return EFI_INVALID_PARAMETER;
546
547 *load_addr = 0;
548 *load_size = 0;
549
Roy Franz7721da42013-09-22 15:45:27 -0700550 if (!str || !*str)
551 return EFI_SUCCESS;
552
Roy Franz36f89612013-09-22 15:45:40 -0700553 for (nr_files = 0; *str; nr_files++) {
Roy Franz46f45822013-09-22 15:45:39 -0700554 str = strstr(str, option_string);
Roy Franz7721da42013-09-22 15:45:27 -0700555 if (!str)
556 break;
557
Roy Franz46f45822013-09-22 15:45:39 -0700558 str += strlen(option_string);
Roy Franz7721da42013-09-22 15:45:27 -0700559
560 /* Skip any leading slashes */
561 while (*str == '/' || *str == '\\')
562 str++;
563
564 while (*str && *str != ' ' && *str != '\n')
565 str++;
566 }
567
Roy Franz36f89612013-09-22 15:45:40 -0700568 if (!nr_files)
Roy Franz7721da42013-09-22 15:45:27 -0700569 return EFI_SUCCESS;
570
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100571 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
572 nr_files * sizeof(*files), (void **)&files);
Roy Franz7721da42013-09-22 15:45:27 -0700573 if (status != EFI_SUCCESS) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100574 pr_efi_err("Failed to alloc mem for file handle list\n");
Roy Franz7721da42013-09-22 15:45:27 -0700575 goto fail;
576 }
577
Roy Franz46f45822013-09-22 15:45:39 -0700578 str = cmd_line;
Roy Franz36f89612013-09-22 15:45:40 -0700579 for (i = 0; i < nr_files; i++) {
580 struct file_info *file;
Roy Franz7721da42013-09-22 15:45:27 -0700581 efi_char16_t filename_16[256];
Roy Franz7721da42013-09-22 15:45:27 -0700582 efi_char16_t *p;
Roy Franz7721da42013-09-22 15:45:27 -0700583
Roy Franz46f45822013-09-22 15:45:39 -0700584 str = strstr(str, option_string);
Roy Franz7721da42013-09-22 15:45:27 -0700585 if (!str)
586 break;
587
Roy Franz46f45822013-09-22 15:45:39 -0700588 str += strlen(option_string);
Roy Franz7721da42013-09-22 15:45:27 -0700589
Roy Franz36f89612013-09-22 15:45:40 -0700590 file = &files[i];
Roy Franz7721da42013-09-22 15:45:27 -0700591 p = filename_16;
592
593 /* Skip any leading slashes */
594 while (*str == '/' || *str == '\\')
595 str++;
596
597 while (*str && *str != ' ' && *str != '\n') {
598 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
599 break;
600
601 if (*str == '/') {
602 *p++ = '\\';
Roy Franz4e283082013-09-22 15:45:42 -0700603 str++;
Roy Franz7721da42013-09-22 15:45:27 -0700604 } else {
605 *p++ = *str++;
606 }
607 }
608
609 *p = '\0';
610
611 /* Only open the volume once. */
612 if (!i) {
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100613 status = efi_open_volume(image, &fh);
Matt Fleming54b52d82014-01-10 15:27:14 +0000614 if (status != EFI_SUCCESS)
Roy Franz36f89612013-09-22 15:45:40 -0700615 goto free_files;
Roy Franz7721da42013-09-22 15:45:27 -0700616 }
617
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100618 status = efi_file_size(fh, filename_16, (void **)&file->handle,
619 &file->size);
Matt Fleming54b52d82014-01-10 15:27:14 +0000620 if (status != EFI_SUCCESS)
Roy Franz7721da42013-09-22 15:45:27 -0700621 goto close_handles;
Roy Franz7721da42013-09-22 15:45:27 -0700622
Matt Fleming54b52d82014-01-10 15:27:14 +0000623 file_size_total += file->size;
Roy Franz7721da42013-09-22 15:45:27 -0700624 }
625
Roy Franz36f89612013-09-22 15:45:40 -0700626 if (file_size_total) {
Roy Franz7721da42013-09-22 15:45:27 -0700627 unsigned long addr;
628
629 /*
Roy Franz36f89612013-09-22 15:45:40 -0700630 * Multiple files need to be at consecutive addresses in memory,
631 * so allocate enough memory for all the files. This is used
632 * for loading multiple files.
Roy Franz7721da42013-09-22 15:45:27 -0700633 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100634 status = efi_high_alloc(file_size_total, 0x1000, &file_addr,
635 max_addr);
Roy Franz7721da42013-09-22 15:45:27 -0700636 if (status != EFI_SUCCESS) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100637 pr_efi_err("Failed to alloc highmem for files\n");
Roy Franz7721da42013-09-22 15:45:27 -0700638 goto close_handles;
639 }
640
641 /* We've run out of free low memory. */
Roy Franz36f89612013-09-22 15:45:40 -0700642 if (file_addr > max_addr) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100643 pr_efi_err("We've run out of free low memory\n");
Roy Franz7721da42013-09-22 15:45:27 -0700644 status = EFI_INVALID_PARAMETER;
Roy Franz36f89612013-09-22 15:45:40 -0700645 goto free_file_total;
Roy Franz7721da42013-09-22 15:45:27 -0700646 }
647
Roy Franz36f89612013-09-22 15:45:40 -0700648 addr = file_addr;
649 for (j = 0; j < nr_files; j++) {
Roy Franz6a5fe772013-09-22 15:45:41 -0700650 unsigned long size;
Roy Franz7721da42013-09-22 15:45:27 -0700651
Roy Franz36f89612013-09-22 15:45:40 -0700652 size = files[j].size;
Roy Franz7721da42013-09-22 15:45:27 -0700653 while (size) {
Roy Franz6a5fe772013-09-22 15:45:41 -0700654 unsigned long chunksize;
Ard Biesheuvelb3879a42017-02-06 11:22:46 +0000655
Ard Biesheuvel7d4e3232019-12-24 16:10:24 +0100656 if (IS_ENABLED(CONFIG_X86) && size > efi_chunk_size)
657 chunksize = efi_chunk_size;
Roy Franz7721da42013-09-22 15:45:27 -0700658 else
659 chunksize = size;
Matt Fleming54b52d82014-01-10 15:27:14 +0000660
Matt Fleming47514c92014-04-10 14:11:45 +0100661 status = efi_file_read(files[j].handle,
Matt Fleming54b52d82014-01-10 15:27:14 +0000662 &chunksize,
663 (void *)addr);
Roy Franz7721da42013-09-22 15:45:27 -0700664 if (status != EFI_SUCCESS) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100665 pr_efi_err("Failed to read file\n");
Roy Franz36f89612013-09-22 15:45:40 -0700666 goto free_file_total;
Roy Franz7721da42013-09-22 15:45:27 -0700667 }
668 addr += chunksize;
669 size -= chunksize;
670 }
671
Matt Fleming47514c92014-04-10 14:11:45 +0100672 efi_file_close(files[j].handle);
Roy Franz7721da42013-09-22 15:45:27 -0700673 }
674
675 }
676
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100677 efi_bs_call(free_pool, files);
Roy Franz7721da42013-09-22 15:45:27 -0700678
Roy Franz36f89612013-09-22 15:45:40 -0700679 *load_addr = file_addr;
680 *load_size = file_size_total;
Roy Franz7721da42013-09-22 15:45:27 -0700681
682 return status;
683
Roy Franz36f89612013-09-22 15:45:40 -0700684free_file_total:
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100685 efi_free(file_size_total, file_addr);
Roy Franz7721da42013-09-22 15:45:27 -0700686
687close_handles:
688 for (k = j; k < i; k++)
Matt Fleming47514c92014-04-10 14:11:45 +0100689 efi_file_close(files[k].handle);
Roy Franz36f89612013-09-22 15:45:40 -0700690free_files:
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100691 efi_bs_call(free_pool, files);
Roy Franz7721da42013-09-22 15:45:27 -0700692fail:
Roy Franz46f45822013-09-22 15:45:39 -0700693 *load_addr = 0;
694 *load_size = 0;
Roy Franz7721da42013-09-22 15:45:27 -0700695
696 return status;
697}
Roy Franz4a9f3a72013-09-22 15:45:32 -0700698/*
699 * Relocate a kernel image, either compressed or uncompressed.
700 * In the ARM64 case, all kernel images are currently
701 * uncompressed, and as such when we relocate it we need to
702 * allocate additional space for the BSS segment. Any low
703 * memory that this function should avoid needs to be
704 * unavailable in the EFI memory map, as if the preferred
705 * address is not available the lowest available address will
706 * be used.
707 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100708efi_status_t efi_relocate_kernel(unsigned long *image_addr,
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200709 unsigned long image_size,
710 unsigned long alloc_size,
711 unsigned long preferred_addr,
Kairui Song220dd762019-10-29 18:37:54 +0100712 unsigned long alignment,
713 unsigned long min_addr)
Roy Franzc6866d72013-09-22 15:45:31 -0700714{
Roy Franz4a9f3a72013-09-22 15:45:32 -0700715 unsigned long cur_image_addr;
716 unsigned long new_addr = 0;
Roy Franzc6866d72013-09-22 15:45:31 -0700717 efi_status_t status;
Roy Franz4a9f3a72013-09-22 15:45:32 -0700718 unsigned long nr_pages;
719 efi_physical_addr_t efi_addr = preferred_addr;
720
721 if (!image_addr || !image_size || !alloc_size)
722 return EFI_INVALID_PARAMETER;
723 if (alloc_size < image_size)
724 return EFI_INVALID_PARAMETER;
725
726 cur_image_addr = *image_addr;
Roy Franzc6866d72013-09-22 15:45:31 -0700727
728 /*
729 * The EFI firmware loader could have placed the kernel image
Roy Franz4a9f3a72013-09-22 15:45:32 -0700730 * anywhere in memory, but the kernel has restrictions on the
731 * max physical address it can run at. Some architectures
732 * also have a prefered address, so first try to relocate
733 * to the preferred address. If that fails, allocate as low
734 * as possible while respecting the required alignment.
735 */
Ard Biesheuvelcf2b0f12014-11-17 13:46:44 +0100736 nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100737 status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
738 EFI_LOADER_DATA, nr_pages, &efi_addr);
Roy Franz4a9f3a72013-09-22 15:45:32 -0700739 new_addr = efi_addr;
740 /*
741 * If preferred address allocation failed allocate as low as
Roy Franzc6866d72013-09-22 15:45:31 -0700742 * possible.
743 */
Roy Franzc6866d72013-09-22 15:45:31 -0700744 if (status != EFI_SUCCESS) {
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100745 status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
746 min_addr);
Roy Franz4a9f3a72013-09-22 15:45:32 -0700747 }
748 if (status != EFI_SUCCESS) {
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100749 pr_efi_err("Failed to allocate usable memory for kernel.\n");
Roy Franz4a9f3a72013-09-22 15:45:32 -0700750 return status;
Roy Franzc6866d72013-09-22 15:45:31 -0700751 }
752
Roy Franz4a9f3a72013-09-22 15:45:32 -0700753 /*
754 * We know source/dest won't overlap since both memory ranges
755 * have been allocated by UEFI, so we can safely use memcpy.
756 */
757 memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
Roy Franzc6866d72013-09-22 15:45:31 -0700758
Roy Franz4a9f3a72013-09-22 15:45:32 -0700759 /* Return the new address of the relocated image. */
760 *image_addr = new_addr;
Roy Franzc6866d72013-09-22 15:45:31 -0700761
762 return status;
763}
Roy Franz5fef3872013-09-22 15:45:33 -0700764
765/*
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500766 * Get the number of UTF-8 bytes corresponding to an UTF-16 character.
767 * This overestimates for surrogates, but that is okay.
768 */
769static int efi_utf8_bytes(u16 c)
770{
771 return 1 + (c >= 0x80) + (c >= 0x800);
772}
773
774/*
775 * Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
776 */
777static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
778{
779 unsigned int c;
780
781 while (n--) {
782 c = *src++;
783 if (n && c >= 0xd800 && c <= 0xdbff &&
784 *src >= 0xdc00 && *src <= 0xdfff) {
785 c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
786 src++;
787 n--;
788 }
789 if (c >= 0xd800 && c <= 0xdfff)
790 c = 0xfffd; /* Unmatched surrogate */
791 if (c < 0x80) {
792 *dst++ = c;
793 continue;
794 }
795 if (c < 0x800) {
796 *dst++ = 0xc0 + (c >> 6);
797 goto t1;
798 }
799 if (c < 0x10000) {
800 *dst++ = 0xe0 + (c >> 12);
801 goto t2;
802 }
803 *dst++ = 0xf0 + (c >> 18);
804 *dst++ = 0x80 + ((c >> 12) & 0x3f);
805 t2:
806 *dst++ = 0x80 + ((c >> 6) & 0x3f);
807 t1:
808 *dst++ = 0x80 + (c & 0x3f);
809 }
810
811 return dst;
812}
813
Ard Biesheuvel48fcb2d2016-01-11 11:47:49 +0100814#ifndef MAX_CMDLINE_ADDRESS
815#define MAX_CMDLINE_ADDRESS ULONG_MAX
816#endif
817
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500818/*
Roy Franz5fef3872013-09-22 15:45:33 -0700819 * Convert the unicode UEFI command line to ASCII to pass to kernel.
820 * Size of memory allocated return in *cmd_line_len.
821 * Returns NULL on error.
822 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100823char *efi_convert_cmdline(efi_loaded_image_t *image,
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200824 int *cmd_line_len)
Roy Franz5fef3872013-09-22 15:45:33 -0700825{
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500826 const u16 *s2;
Roy Franz5fef3872013-09-22 15:45:33 -0700827 u8 *s1 = NULL;
828 unsigned long cmdline_addr = 0;
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500829 int load_options_chars = image->load_options_size / 2; /* UTF-16 */
830 const u16 *options = image->load_options;
831 int options_bytes = 0; /* UTF-8 bytes */
832 int options_chars = 0; /* UTF-16 chars */
Roy Franz5fef3872013-09-22 15:45:33 -0700833 efi_status_t status;
Roy Franz5fef3872013-09-22 15:45:33 -0700834 u16 zero = 0;
835
836 if (options) {
837 s2 = options;
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500838 while (*s2 && *s2 != '\n'
839 && options_chars < load_options_chars) {
840 options_bytes += efi_utf8_bytes(*s2++);
841 options_chars++;
Roy Franz5fef3872013-09-22 15:45:33 -0700842 }
843 }
844
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500845 if (!options_chars) {
Roy Franz5fef3872013-09-22 15:45:33 -0700846 /* No command line options, so return empty string*/
Roy Franz5fef3872013-09-22 15:45:33 -0700847 options = &zero;
848 }
849
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500850 options_bytes++; /* NUL termination */
Leif Lindholm9403e462014-04-04 13:25:46 +0100851
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100852 status = efi_high_alloc(options_bytes, 0, &cmdline_addr,
853 MAX_CMDLINE_ADDRESS);
Roy Franz5fef3872013-09-22 15:45:33 -0700854 if (status != EFI_SUCCESS)
855 return NULL;
856
857 s1 = (u8 *)cmdline_addr;
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500858 s2 = (const u16 *)options;
Roy Franz5fef3872013-09-22 15:45:33 -0700859
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500860 s1 = efi_utf16_to_utf8(s1, s2, options_chars);
Roy Franz5fef3872013-09-22 15:45:33 -0700861 *s1 = '\0';
862
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500863 *cmd_line_len = options_bytes;
Roy Franz5fef3872013-09-22 15:45:33 -0700864 return (char *)cmdline_addr;
865}
Jeffrey Hugofc077162016-08-29 14:38:52 -0600866
867/*
868 * Handle calling ExitBootServices according to the requirements set out by the
869 * spec. Obtains the current memory map, and returns that info after calling
870 * ExitBootServices. The client must specify a function to perform any
871 * processing of the memory map data prior to ExitBootServices. A client
872 * specific structure may be passed to the function via priv. The client
873 * function may be called multiple times.
874 */
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100875efi_status_t efi_exit_boot_services(void *handle,
Jeffrey Hugofc077162016-08-29 14:38:52 -0600876 struct efi_boot_memmap *map,
877 void *priv,
878 efi_exit_boot_map_processing priv_func)
879{
880 efi_status_t status;
881
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100882 status = efi_get_memory_map(map);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600883
884 if (status != EFI_SUCCESS)
885 goto fail;
886
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100887 status = priv_func(map, priv);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600888 if (status != EFI_SUCCESS)
889 goto free_map;
890
Matthew Garrett4444f852020-01-03 12:39:50 +0100891 if (efi_disable_pci_dma)
892 efi_pci_disable_bridge_busmaster();
893
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100894 status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600895
896 if (status == EFI_INVALID_PARAMETER) {
897 /*
898 * The memory map changed between efi_get_memory_map() and
899 * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4:
900 * EFI_BOOT_SERVICES.ExitBootServices we need to get the
901 * updated map, and try again. The spec implies one retry
902 * should be sufficent, which is confirmed against the EDK2
903 * implementation. Per the spec, we can only invoke
904 * get_memory_map() and exit_boot_services() - we cannot alloc
905 * so efi_get_memory_map() cannot be used, and we must reuse
906 * the buffer. For all practical purposes, the headroom in the
907 * buffer should account for any changes in the map so the call
908 * to get_memory_map() is expected to succeed here.
909 */
910 *map->map_size = *map->buff_size;
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100911 status = efi_bs_call(get_memory_map,
912 map->map_size,
913 *map->map,
914 map->key_ptr,
915 map->desc_size,
916 map->desc_ver);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600917
918 /* exit_boot_services() was called, thus cannot free */
919 if (status != EFI_SUCCESS)
920 goto fail;
921
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100922 status = priv_func(map, priv);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600923 /* exit_boot_services() was called, thus cannot free */
924 if (status != EFI_SUCCESS)
925 goto fail;
926
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100927 status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600928 }
929
930 /* exit_boot_services() was called, thus cannot free */
931 if (status != EFI_SUCCESS)
932 goto fail;
933
934 return EFI_SUCCESS;
935
936free_map:
Ard Biesheuvel966291f2019-12-24 16:10:23 +0100937 efi_bs_call(free_pool, *map->map);
Jeffrey Hugofc077162016-08-29 14:38:52 -0600938fail:
939 return status;
940}
Matthew Garrett82d736a2019-06-07 13:51:46 -0700941
Ard Biesheuvelcd33a5c2019-12-24 16:10:19 +0100942void *get_efi_config_table(efi_guid_t guid)
Matthew Garrett82d736a2019-06-07 13:51:46 -0700943{
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100944 unsigned long tables = efi_table_attr(efi_system_table(), tables);
945 int nr_tables = efi_table_attr(efi_system_table(), nr_tables);
Ard Biesheuvelf958efe2019-12-24 16:10:09 +0100946 int i;
947
948 for (i = 0; i < nr_tables; i++) {
949 efi_config_table_t *t = (void *)tables;
950
951 if (efi_guidcmp(t->guid, guid) == 0)
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100952 return efi_table_attr(t, table);
Ard Biesheuvelf958efe2019-12-24 16:10:09 +0100953
954 tables += efi_is_native() ? sizeof(efi_config_table_t)
955 : sizeof(efi_config_table_32_t);
956 }
957 return NULL;
Matthew Garrett82d736a2019-06-07 13:51:46 -0700958}
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100959
Ard Biesheuvel8173ec72019-12-24 16:10:18 +0100960void efi_char16_printk(efi_char16_t *str)
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100961{
Ard Biesheuvel99ea8b12019-12-24 16:10:22 +0100962 efi_call_proto(efi_table_attr(efi_system_table(), con_out),
Ard Biesheuvel47c0fd32019-12-24 16:10:21 +0100963 output_string, str);
Ard Biesheuveldc29da12019-12-24 16:10:16 +0100964}