Commit | Line | Data |
---|---|---|
4febfb8d | 1 | // SPDX-License-Identifier: GPL-2.0 |
7721da4c RF |
2 | /* |
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 | |
7721da4c | 8 | */ |
7721da4c | 9 | |
bd669475 AB |
10 | #include <linux/efi.h> |
11 | #include <asm/efi.h> | |
12 | ||
13 | #include "efistub.h" | |
9bb40191 | 14 | |
5a17dae4 MF |
15 | /* |
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 | */ | |
bd669475 | 28 | #define EFI_READ_CHUNK_SIZE (1024 * 1024) |
9bb40191 | 29 | |
5a17dae4 MF |
30 | static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; |
31 | ||
60f38de7 | 32 | static int __section(.data) __nokaslr; |
eeff7d63 | 33 | static int __section(.data) __quiet; |
4e46c2a9 | 34 | static int __section(.data) __novamap; |
60f38de7 AB |
35 | |
36 | int __pure nokaslr(void) | |
37 | { | |
38 | return __nokaslr; | |
39 | } | |
eeff7d63 AB |
40 | int __pure is_quiet(void) |
41 | { | |
42 | return __quiet; | |
43 | } | |
4e46c2a9 AB |
44 | int __pure novamap(void) |
45 | { | |
46 | return __novamap; | |
47 | } | |
60f38de7 | 48 | |
dadb57ab JH |
49 | #define EFI_MMAP_NR_SLACK_SLOTS 8 |
50 | ||
36f8961c | 51 | struct file_info { |
7721da4c RF |
52 | efi_file_handle_t *handle; |
53 | u64 size; | |
54 | }; | |
55 | ||
bd669475 | 56 | void efi_printk(efi_system_table_t *sys_table_arg, char *str) |
7721da4c RF |
57 | { |
58 | char *s8; | |
59 | ||
60 | for (s8 = str; *s8; s8++) { | |
61 | efi_char16_t ch[2] = { 0 }; | |
62 | ||
63 | ch[0] = *s8; | |
64 | if (*s8 == '\n') { | |
65 | efi_char16_t nl[2] = { '\r', 0 }; | |
876dc36a | 66 | efi_char16_printk(sys_table_arg, nl); |
7721da4c RF |
67 | } |
68 | ||
876dc36a | 69 | efi_char16_printk(sys_table_arg, ch); |
7721da4c RF |
70 | } |
71 | } | |
72 | ||
dadb57ab JH |
73 | static inline bool mmap_has_headroom(unsigned long buff_size, |
74 | unsigned long map_size, | |
75 | unsigned long desc_size) | |
76 | { | |
77 | unsigned long slack = buff_size - map_size; | |
78 | ||
79 | return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS; | |
80 | } | |
81 | ||
bd669475 | 82 | efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, |
dadb57ab | 83 | struct efi_boot_memmap *map) |
7721da4c RF |
84 | { |
85 | efi_memory_desc_t *m = NULL; | |
86 | efi_status_t status; | |
87 | unsigned long key; | |
88 | u32 desc_version; | |
89 | ||
dadb57ab JH |
90 | *map->desc_size = sizeof(*m); |
91 | *map->map_size = *map->desc_size * 32; | |
92 | *map->buff_size = *map->map_size; | |
43a9f696 | 93 | again: |
204b0a1a | 94 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, |
dadb57ab | 95 | *map->map_size, (void **)&m); |
7721da4c RF |
96 | if (status != EFI_SUCCESS) |
97 | goto fail; | |
98 | ||
dadb57ab | 99 | *map->desc_size = 0; |
43a9f696 | 100 | key = 0; |
dadb57ab JH |
101 | status = efi_call_early(get_memory_map, map->map_size, m, |
102 | &key, map->desc_size, &desc_version); | |
103 | if (status == EFI_BUFFER_TOO_SMALL || | |
104 | !mmap_has_headroom(*map->buff_size, *map->map_size, | |
105 | *map->desc_size)) { | |
204b0a1a | 106 | efi_call_early(free_pool, m); |
dadb57ab JH |
107 | /* |
108 | * Make sure there is some entries of headroom so that the | |
109 | * buffer can be reused for a new map after allocations are | |
110 | * no longer permitted. Its unlikely that the map will grow to | |
111 | * exceed this headroom once we are ready to trigger | |
112 | * ExitBootServices() | |
113 | */ | |
114 | *map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS; | |
115 | *map->buff_size = *map->map_size; | |
43a9f696 | 116 | goto again; |
7721da4c RF |
117 | } |
118 | ||
119 | if (status != EFI_SUCCESS) | |
204b0a1a | 120 | efi_call_early(free_pool, m); |
54b52d87 | 121 | |
dadb57ab JH |
122 | if (map->key_ptr && status == EFI_SUCCESS) |
123 | *map->key_ptr = key; | |
124 | if (map->desc_ver && status == EFI_SUCCESS) | |
125 | *map->desc_ver = desc_version; | |
7721da4c RF |
126 | |
127 | fail: | |
dadb57ab | 128 | *map->map = m; |
7721da4c RF |
129 | return status; |
130 | } | |
131 | ||
9bb40191 | 132 | |
ddeeefe2 | 133 | unsigned long get_dram_base(efi_system_table_t *sys_table_arg) |
9bb40191 RF |
134 | { |
135 | efi_status_t status; | |
dadb57ab | 136 | unsigned long map_size, buff_size; |
9bb40191 RF |
137 | unsigned long membase = EFI_ERROR; |
138 | struct efi_memory_map map; | |
139 | efi_memory_desc_t *md; | |
dadb57ab | 140 | struct efi_boot_memmap boot_map; |
9bb40191 | 141 | |
dadb57ab JH |
142 | boot_map.map = (efi_memory_desc_t **)&map.map; |
143 | boot_map.map_size = &map_size; | |
144 | boot_map.desc_size = &map.desc_size; | |
145 | boot_map.desc_ver = NULL; | |
146 | boot_map.key_ptr = NULL; | |
147 | boot_map.buff_size = &buff_size; | |
148 | ||
149 | status = efi_get_memory_map(sys_table_arg, &boot_map); | |
9bb40191 RF |
150 | if (status != EFI_SUCCESS) |
151 | return membase; | |
152 | ||
153 | map.map_end = map.map + map_size; | |
154 | ||
78ce248f MF |
155 | for_each_efi_memory_desc_in_map(&map, md) { |
156 | if (md->attribute & EFI_MEMORY_WB) { | |
9bb40191 RF |
157 | if (membase > md->phys_addr) |
158 | membase = md->phys_addr; | |
78ce248f MF |
159 | } |
160 | } | |
9bb40191 RF |
161 | |
162 | efi_call_early(free_pool, map.map); | |
163 | ||
164 | return membase; | |
165 | } | |
166 | ||
7721da4c RF |
167 | /* |
168 | * Allocate at the highest possible address that is not above 'max'. | |
169 | */ | |
bd669475 AB |
170 | efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, |
171 | unsigned long size, unsigned long align, | |
172 | unsigned long *addr, unsigned long max) | |
7721da4c | 173 | { |
dadb57ab | 174 | unsigned long map_size, desc_size, buff_size; |
7721da4c RF |
175 | efi_memory_desc_t *map; |
176 | efi_status_t status; | |
177 | unsigned long nr_pages; | |
178 | u64 max_addr = 0; | |
179 | int i; | |
dadb57ab JH |
180 | struct efi_boot_memmap boot_map; |
181 | ||
182 | boot_map.map = ↦ | |
183 | boot_map.map_size = &map_size; | |
184 | boot_map.desc_size = &desc_size; | |
185 | boot_map.desc_ver = NULL; | |
186 | boot_map.key_ptr = NULL; | |
187 | boot_map.buff_size = &buff_size; | |
7721da4c | 188 | |
dadb57ab | 189 | status = efi_get_memory_map(sys_table_arg, &boot_map); |
7721da4c RF |
190 | if (status != EFI_SUCCESS) |
191 | goto fail; | |
192 | ||
38dd9c02 | 193 | /* |
5b88a31c RF |
194 | * Enforce minimum alignment that EFI or Linux requires when |
195 | * requesting a specific address. We are doing page-based (or | |
196 | * larger) allocations, and both the address and size must meet | |
197 | * alignment constraints. | |
38dd9c02 | 198 | */ |
cf2b0f10 AB |
199 | if (align < EFI_ALLOC_ALIGN) |
200 | align = EFI_ALLOC_ALIGN; | |
38dd9c02 | 201 | |
5b88a31c RF |
202 | size = round_up(size, EFI_ALLOC_ALIGN); |
203 | nr_pages = size / EFI_PAGE_SIZE; | |
7721da4c RF |
204 | again: |
205 | for (i = 0; i < map_size / desc_size; i++) { | |
206 | efi_memory_desc_t *desc; | |
207 | unsigned long m = (unsigned long)map; | |
208 | u64 start, end; | |
209 | ||
02e43c2d | 210 | desc = efi_early_memdesc_ptr(m, desc_size, i); |
7721da4c RF |
211 | if (desc->type != EFI_CONVENTIONAL_MEMORY) |
212 | continue; | |
213 | ||
214 | if (desc->num_pages < nr_pages) | |
215 | continue; | |
216 | ||
217 | start = desc->phys_addr; | |
5b88a31c | 218 | end = start + desc->num_pages * EFI_PAGE_SIZE; |
7721da4c | 219 | |
7ed620bb | 220 | if (end > max) |
7721da4c RF |
221 | end = max; |
222 | ||
7ed620bb YL |
223 | if ((start + size) > end) |
224 | continue; | |
225 | ||
7721da4c RF |
226 | if (round_down(end - size, align) < start) |
227 | continue; | |
228 | ||
229 | start = round_down(end - size, align); | |
230 | ||
231 | /* | |
232 | * Don't allocate at 0x0. It will confuse code that | |
233 | * checks pointers against NULL. | |
234 | */ | |
235 | if (start == 0x0) | |
236 | continue; | |
237 | ||
238 | if (start > max_addr) | |
239 | max_addr = start; | |
240 | } | |
241 | ||
242 | if (!max_addr) | |
243 | status = EFI_NOT_FOUND; | |
244 | else { | |
204b0a1a MF |
245 | status = efi_call_early(allocate_pages, |
246 | EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, | |
247 | nr_pages, &max_addr); | |
7721da4c RF |
248 | if (status != EFI_SUCCESS) { |
249 | max = max_addr; | |
250 | max_addr = 0; | |
251 | goto again; | |
252 | } | |
253 | ||
254 | *addr = max_addr; | |
255 | } | |
256 | ||
204b0a1a | 257 | efi_call_early(free_pool, map); |
7721da4c RF |
258 | fail: |
259 | return status; | |
260 | } | |
261 | ||
262 | /* | |
263 | * Allocate at the lowest possible address. | |
264 | */ | |
bd669475 AB |
265 | efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, |
266 | unsigned long size, unsigned long align, | |
267 | unsigned long *addr) | |
7721da4c | 268 | { |
dadb57ab | 269 | unsigned long map_size, desc_size, buff_size; |
7721da4c RF |
270 | efi_memory_desc_t *map; |
271 | efi_status_t status; | |
272 | unsigned long nr_pages; | |
273 | int i; | |
dadb57ab JH |
274 | struct efi_boot_memmap boot_map; |
275 | ||
276 | boot_map.map = ↦ | |
277 | boot_map.map_size = &map_size; | |
278 | boot_map.desc_size = &desc_size; | |
279 | boot_map.desc_ver = NULL; | |
280 | boot_map.key_ptr = NULL; | |
281 | boot_map.buff_size = &buff_size; | |
7721da4c | 282 | |
dadb57ab | 283 | status = efi_get_memory_map(sys_table_arg, &boot_map); |
7721da4c RF |
284 | if (status != EFI_SUCCESS) |
285 | goto fail; | |
286 | ||
38dd9c02 | 287 | /* |
5b88a31c RF |
288 | * Enforce minimum alignment that EFI or Linux requires when |
289 | * requesting a specific address. We are doing page-based (or | |
290 | * larger) allocations, and both the address and size must meet | |
291 | * alignment constraints. | |
38dd9c02 | 292 | */ |
cf2b0f10 AB |
293 | if (align < EFI_ALLOC_ALIGN) |
294 | align = EFI_ALLOC_ALIGN; | |
38dd9c02 | 295 | |
5b88a31c RF |
296 | size = round_up(size, EFI_ALLOC_ALIGN); |
297 | nr_pages = size / EFI_PAGE_SIZE; | |
7721da4c RF |
298 | for (i = 0; i < map_size / desc_size; i++) { |
299 | efi_memory_desc_t *desc; | |
300 | unsigned long m = (unsigned long)map; | |
301 | u64 start, end; | |
302 | ||
02e43c2d | 303 | desc = efi_early_memdesc_ptr(m, desc_size, i); |
7721da4c RF |
304 | |
305 | if (desc->type != EFI_CONVENTIONAL_MEMORY) | |
306 | continue; | |
307 | ||
308 | if (desc->num_pages < nr_pages) | |
309 | continue; | |
310 | ||
311 | start = desc->phys_addr; | |
5b88a31c | 312 | end = start + desc->num_pages * EFI_PAGE_SIZE; |
7721da4c RF |
313 | |
314 | /* | |
315 | * Don't allocate at 0x0. It will confuse code that | |
316 | * checks pointers against NULL. Skip the first 8 | |
317 | * bytes so we start at a nice even number. | |
318 | */ | |
319 | if (start == 0x0) | |
320 | start += 8; | |
321 | ||
322 | start = round_up(start, align); | |
323 | if ((start + size) > end) | |
324 | continue; | |
325 | ||
204b0a1a MF |
326 | status = efi_call_early(allocate_pages, |
327 | EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, | |
328 | nr_pages, &start); | |
7721da4c RF |
329 | if (status == EFI_SUCCESS) { |
330 | *addr = start; | |
331 | break; | |
332 | } | |
333 | } | |
334 | ||
335 | if (i == map_size / desc_size) | |
336 | status = EFI_NOT_FOUND; | |
337 | ||
204b0a1a | 338 | efi_call_early(free_pool, map); |
7721da4c RF |
339 | fail: |
340 | return status; | |
341 | } | |
342 | ||
bd669475 AB |
343 | void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, |
344 | unsigned long addr) | |
7721da4c RF |
345 | { |
346 | unsigned long nr_pages; | |
347 | ||
0e1cadb0 RF |
348 | if (!size) |
349 | return; | |
350 | ||
cf2b0f10 | 351 | nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; |
204b0a1a | 352 | efi_call_early(free_pages, addr, nr_pages); |
7721da4c RF |
353 | } |
354 | ||
2bd79f30 LW |
355 | static efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, |
356 | efi_char16_t *filename_16, void **handle, | |
357 | u64 *file_sz) | |
358 | { | |
359 | efi_file_handle_t *h, *fh = __fh; | |
360 | efi_file_info_t *info; | |
361 | efi_status_t status; | |
362 | efi_guid_t info_guid = EFI_FILE_INFO_ID; | |
363 | unsigned long info_sz; | |
364 | ||
365 | status = efi_call_proto(efi_file_handle, open, fh, &h, filename_16, | |
366 | EFI_FILE_MODE_READ, (u64)0); | |
367 | if (status != EFI_SUCCESS) { | |
368 | efi_printk(sys_table_arg, "Failed to open file: "); | |
369 | efi_char16_printk(sys_table_arg, filename_16); | |
370 | efi_printk(sys_table_arg, "\n"); | |
371 | return status; | |
372 | } | |
373 | ||
374 | *handle = h; | |
375 | ||
376 | info_sz = 0; | |
377 | status = efi_call_proto(efi_file_handle, get_info, h, &info_guid, | |
378 | &info_sz, NULL); | |
379 | if (status != EFI_BUFFER_TOO_SMALL) { | |
380 | efi_printk(sys_table_arg, "Failed to get file info size\n"); | |
381 | return status; | |
382 | } | |
383 | ||
384 | grow: | |
385 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, | |
386 | info_sz, (void **)&info); | |
387 | if (status != EFI_SUCCESS) { | |
388 | efi_printk(sys_table_arg, "Failed to alloc mem for file info\n"); | |
389 | return status; | |
390 | } | |
391 | ||
392 | status = efi_call_proto(efi_file_handle, get_info, h, &info_guid, | |
393 | &info_sz, info); | |
394 | if (status == EFI_BUFFER_TOO_SMALL) { | |
395 | efi_call_early(free_pool, info); | |
396 | goto grow; | |
397 | } | |
398 | ||
399 | *file_sz = info->file_size; | |
400 | efi_call_early(free_pool, info); | |
401 | ||
402 | if (status != EFI_SUCCESS) | |
403 | efi_printk(sys_table_arg, "Failed to get initrd info\n"); | |
404 | ||
405 | return status; | |
406 | } | |
407 | ||
408 | static efi_status_t efi_file_read(void *handle, unsigned long *size, void *addr) | |
409 | { | |
410 | return efi_call_proto(efi_file_handle, read, handle, size, addr); | |
411 | } | |
412 | ||
413 | static efi_status_t efi_file_close(void *handle) | |
414 | { | |
415 | return efi_call_proto(efi_file_handle, close, handle); | |
416 | } | |
417 | ||
c4db9c1e LW |
418 | static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, |
419 | efi_loaded_image_t *image, | |
420 | 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; | |
426 | void *handle = (void *)(unsigned long)efi_table_attr(efi_loaded_image, | |
427 | device_handle, | |
428 | image); | |
429 | ||
430 | status = efi_call_early(handle_protocol, handle, | |
431 | &fs_proto, (void **)&io); | |
432 | if (status != EFI_SUCCESS) { | |
433 | efi_printk(sys_table_arg, "Failed to handle fs_proto\n"); | |
434 | return status; | |
435 | } | |
436 | ||
437 | status = efi_call_proto(efi_file_io_interface, open_volume, io, &fh); | |
438 | if (status != EFI_SUCCESS) | |
439 | efi_printk(sys_table_arg, "Failed to open volume\n"); | |
440 | else | |
441 | *__fh = fh; | |
442 | ||
443 | return status; | |
444 | } | |
445 | ||
5a17dae4 MF |
446 | /* |
447 | * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi= | |
448 | * option, e.g. efi=nochunk. | |
449 | * | |
450 | * It should be noted that efi= is parsed in two very different | |
451 | * environments, first in the early boot environment of the EFI boot | |
452 | * stub, and subsequently during the kernel boot. | |
453 | */ | |
60f38de7 | 454 | efi_status_t efi_parse_options(char const *cmdline) |
5a17dae4 MF |
455 | { |
456 | char *str; | |
457 | ||
60f38de7 AB |
458 | str = strstr(cmdline, "nokaslr"); |
459 | if (str == cmdline || (str && str > cmdline && *(str - 1) == ' ')) | |
460 | __nokaslr = 1; | |
b3879a4d | 461 | |
eeff7d63 AB |
462 | str = strstr(cmdline, "quiet"); |
463 | if (str == cmdline || (str && str > cmdline && *(str - 1) == ' ')) | |
464 | __quiet = 1; | |
465 | ||
5a17dae4 MF |
466 | /* |
467 | * If no EFI parameters were specified on the cmdline we've got | |
468 | * nothing to do. | |
469 | */ | |
470 | str = strstr(cmdline, "efi="); | |
471 | if (!str) | |
472 | return EFI_SUCCESS; | |
473 | ||
474 | /* Skip ahead to first argument */ | |
475 | str += strlen("efi="); | |
476 | ||
477 | /* | |
478 | * Remember, because efi= is also used by the kernel we need to | |
479 | * skip over arguments we don't understand. | |
480 | */ | |
4c3f14bb | 481 | while (*str && *str != ' ') { |
5a17dae4 MF |
482 | if (!strncmp(str, "nochunk", 7)) { |
483 | str += strlen("nochunk"); | |
484 | __chunk_size = -1UL; | |
485 | } | |
486 | ||
4e46c2a9 AB |
487 | if (!strncmp(str, "novamap", 7)) { |
488 | str += strlen("novamap"); | |
489 | __novamap = 1; | |
490 | } | |
491 | ||
5a17dae4 | 492 | /* Group words together, delimited by "," */ |
4c3f14bb | 493 | while (*str && *str != ' ' && *str != ',') |
5a17dae4 MF |
494 | str++; |
495 | ||
496 | if (*str == ',') | |
497 | str++; | |
498 | } | |
499 | ||
500 | return EFI_SUCCESS; | |
501 | } | |
7721da4c RF |
502 | |
503 | /* | |
36f8961c | 504 | * Check the cmdline for a LILO-style file= arguments. |
7721da4c | 505 | * |
36f8961c RF |
506 | * We only support loading a file from the same filesystem as |
507 | * the kernel image. | |
7721da4c | 508 | */ |
bd669475 AB |
509 | efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, |
510 | efi_loaded_image_t *image, | |
511 | char *cmd_line, char *option_string, | |
512 | unsigned long max_addr, | |
513 | unsigned long *load_addr, | |
514 | unsigned long *load_size) | |
7721da4c | 515 | { |
36f8961c RF |
516 | struct file_info *files; |
517 | unsigned long file_addr; | |
36f8961c | 518 | u64 file_size_total; |
9403e462 | 519 | efi_file_handle_t *fh = NULL; |
7721da4c | 520 | efi_status_t status; |
36f8961c | 521 | int nr_files; |
7721da4c RF |
522 | char *str; |
523 | int i, j, k; | |
524 | ||
36f8961c RF |
525 | file_addr = 0; |
526 | file_size_total = 0; | |
7721da4c | 527 | |
46f4582e | 528 | str = cmd_line; |
7721da4c RF |
529 | |
530 | j = 0; /* See close_handles */ | |
531 | ||
46f4582e RF |
532 | if (!load_addr || !load_size) |
533 | return EFI_INVALID_PARAMETER; | |
534 | ||
535 | *load_addr = 0; | |
536 | *load_size = 0; | |
537 | ||
7721da4c RF |
538 | if (!str || !*str) |
539 | return EFI_SUCCESS; | |
540 | ||
36f8961c | 541 | for (nr_files = 0; *str; nr_files++) { |
46f4582e | 542 | str = strstr(str, option_string); |
7721da4c RF |
543 | if (!str) |
544 | break; | |
545 | ||
46f4582e | 546 | str += strlen(option_string); |
7721da4c RF |
547 | |
548 | /* Skip any leading slashes */ | |
549 | while (*str == '/' || *str == '\\') | |
550 | str++; | |
551 | ||
552 | while (*str && *str != ' ' && *str != '\n') | |
553 | str++; | |
554 | } | |
555 | ||
36f8961c | 556 | if (!nr_files) |
7721da4c RF |
557 | return EFI_SUCCESS; |
558 | ||
204b0a1a MF |
559 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, |
560 | nr_files * sizeof(*files), (void **)&files); | |
7721da4c | 561 | if (status != EFI_SUCCESS) { |
f966ea02 | 562 | pr_efi_err(sys_table_arg, "Failed to alloc mem for file handle list\n"); |
7721da4c RF |
563 | goto fail; |
564 | } | |
565 | ||
46f4582e | 566 | str = cmd_line; |
36f8961c RF |
567 | for (i = 0; i < nr_files; i++) { |
568 | struct file_info *file; | |
7721da4c | 569 | efi_char16_t filename_16[256]; |
7721da4c | 570 | efi_char16_t *p; |
7721da4c | 571 | |
46f4582e | 572 | str = strstr(str, option_string); |
7721da4c RF |
573 | if (!str) |
574 | break; | |
575 | ||
46f4582e | 576 | str += strlen(option_string); |
7721da4c | 577 | |
36f8961c | 578 | file = &files[i]; |
7721da4c RF |
579 | p = filename_16; |
580 | ||
581 | /* Skip any leading slashes */ | |
582 | while (*str == '/' || *str == '\\') | |
583 | str++; | |
584 | ||
585 | while (*str && *str != ' ' && *str != '\n') { | |
586 | if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) | |
587 | break; | |
588 | ||
589 | if (*str == '/') { | |
590 | *p++ = '\\'; | |
4e283088 | 591 | str++; |
7721da4c RF |
592 | } else { |
593 | *p++ = *str++; | |
594 | } | |
595 | } | |
596 | ||
597 | *p = '\0'; | |
598 | ||
599 | /* Only open the volume once. */ | |
600 | if (!i) { | |
c4db9c1e | 601 | status = efi_open_volume(sys_table_arg, image, &fh); |
54b52d87 | 602 | if (status != EFI_SUCCESS) |
36f8961c | 603 | goto free_files; |
7721da4c RF |
604 | } |
605 | ||
54b52d87 MF |
606 | status = efi_file_size(sys_table_arg, fh, filename_16, |
607 | (void **)&file->handle, &file->size); | |
608 | if (status != EFI_SUCCESS) | |
7721da4c | 609 | goto close_handles; |
7721da4c | 610 | |
54b52d87 | 611 | file_size_total += file->size; |
7721da4c RF |
612 | } |
613 | ||
36f8961c | 614 | if (file_size_total) { |
7721da4c RF |
615 | unsigned long addr; |
616 | ||
617 | /* | |
36f8961c RF |
618 | * Multiple files need to be at consecutive addresses in memory, |
619 | * so allocate enough memory for all the files. This is used | |
620 | * for loading multiple files. | |
7721da4c | 621 | */ |
36f8961c RF |
622 | status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, |
623 | &file_addr, max_addr); | |
7721da4c | 624 | if (status != EFI_SUCCESS) { |
f966ea02 | 625 | pr_efi_err(sys_table_arg, "Failed to alloc highmem for files\n"); |
7721da4c RF |
626 | goto close_handles; |
627 | } | |
628 | ||
629 | /* We've run out of free low memory. */ | |
36f8961c | 630 | if (file_addr > max_addr) { |
f966ea02 | 631 | pr_efi_err(sys_table_arg, "We've run out of free low memory\n"); |
7721da4c | 632 | status = EFI_INVALID_PARAMETER; |
36f8961c | 633 | goto free_file_total; |
7721da4c RF |
634 | } |
635 | ||
36f8961c RF |
636 | addr = file_addr; |
637 | for (j = 0; j < nr_files; j++) { | |
6a5fe770 | 638 | unsigned long size; |
7721da4c | 639 | |
36f8961c | 640 | size = files[j].size; |
7721da4c | 641 | while (size) { |
6a5fe770 | 642 | unsigned long chunksize; |
b3879a4d AB |
643 | |
644 | if (IS_ENABLED(CONFIG_X86) && size > __chunk_size) | |
5a17dae4 | 645 | chunksize = __chunk_size; |
7721da4c RF |
646 | else |
647 | chunksize = size; | |
54b52d87 | 648 | |
47514c99 | 649 | status = efi_file_read(files[j].handle, |
54b52d87 MF |
650 | &chunksize, |
651 | (void *)addr); | |
7721da4c | 652 | if (status != EFI_SUCCESS) { |
f966ea02 | 653 | pr_efi_err(sys_table_arg, "Failed to read file\n"); |
36f8961c | 654 | goto free_file_total; |
7721da4c RF |
655 | } |
656 | addr += chunksize; | |
657 | size -= chunksize; | |
658 | } | |
659 | ||
47514c99 | 660 | efi_file_close(files[j].handle); |
7721da4c RF |
661 | } |
662 | ||
663 | } | |
664 | ||
204b0a1a | 665 | efi_call_early(free_pool, files); |
7721da4c | 666 | |
36f8961c RF |
667 | *load_addr = file_addr; |
668 | *load_size = file_size_total; | |
7721da4c RF |
669 | |
670 | return status; | |
671 | ||
36f8961c RF |
672 | free_file_total: |
673 | efi_free(sys_table_arg, file_size_total, file_addr); | |
7721da4c RF |
674 | |
675 | close_handles: | |
676 | for (k = j; k < i; k++) | |
47514c99 | 677 | efi_file_close(files[k].handle); |
36f8961c | 678 | free_files: |
204b0a1a | 679 | efi_call_early(free_pool, files); |
7721da4c | 680 | fail: |
46f4582e RF |
681 | *load_addr = 0; |
682 | *load_size = 0; | |
7721da4c RF |
683 | |
684 | return status; | |
685 | } | |
4a9f3a7c RF |
686 | /* |
687 | * Relocate a kernel image, either compressed or uncompressed. | |
688 | * In the ARM64 case, all kernel images are currently | |
689 | * uncompressed, and as such when we relocate it we need to | |
690 | * allocate additional space for the BSS segment. Any low | |
691 | * memory that this function should avoid needs to be | |
692 | * unavailable in the EFI memory map, as if the preferred | |
693 | * address is not available the lowest available address will | |
694 | * be used. | |
695 | */ | |
bd669475 AB |
696 | efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, |
697 | unsigned long *image_addr, | |
698 | unsigned long image_size, | |
699 | unsigned long alloc_size, | |
700 | unsigned long preferred_addr, | |
701 | unsigned long alignment) | |
c6866d72 | 702 | { |
4a9f3a7c RF |
703 | unsigned long cur_image_addr; |
704 | unsigned long new_addr = 0; | |
c6866d72 | 705 | efi_status_t status; |
4a9f3a7c RF |
706 | unsigned long nr_pages; |
707 | efi_physical_addr_t efi_addr = preferred_addr; | |
708 | ||
709 | if (!image_addr || !image_size || !alloc_size) | |
710 | return EFI_INVALID_PARAMETER; | |
711 | if (alloc_size < image_size) | |
712 | return EFI_INVALID_PARAMETER; | |
713 | ||
714 | cur_image_addr = *image_addr; | |
c6866d72 RF |
715 | |
716 | /* | |
717 | * The EFI firmware loader could have placed the kernel image | |
4a9f3a7c RF |
718 | * anywhere in memory, but the kernel has restrictions on the |
719 | * max physical address it can run at. Some architectures | |
720 | * also have a prefered address, so first try to relocate | |
721 | * to the preferred address. If that fails, allocate as low | |
722 | * as possible while respecting the required alignment. | |
c6866d72 | 723 | */ |
cf2b0f10 | 724 | nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; |
204b0a1a MF |
725 | status = efi_call_early(allocate_pages, |
726 | EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, | |
727 | nr_pages, &efi_addr); | |
4a9f3a7c RF |
728 | new_addr = efi_addr; |
729 | /* | |
730 | * If preferred address allocation failed allocate as low as | |
731 | * possible. | |
732 | */ | |
c6866d72 | 733 | if (status != EFI_SUCCESS) { |
4a9f3a7c RF |
734 | status = efi_low_alloc(sys_table_arg, alloc_size, alignment, |
735 | &new_addr); | |
736 | } | |
737 | if (status != EFI_SUCCESS) { | |
f966ea02 | 738 | pr_efi_err(sys_table_arg, "Failed to allocate usable memory for kernel.\n"); |
4a9f3a7c | 739 | return status; |
c6866d72 RF |
740 | } |
741 | ||
4a9f3a7c RF |
742 | /* |
743 | * We know source/dest won't overlap since both memory ranges | |
744 | * have been allocated by UEFI, so we can safely use memcpy. | |
745 | */ | |
746 | memcpy((void *)new_addr, (void *)cur_image_addr, image_size); | |
c6866d72 | 747 | |
4a9f3a7c RF |
748 | /* Return the new address of the relocated image. */ |
749 | *image_addr = new_addr; | |
c6866d72 RF |
750 | |
751 | return status; | |
752 | } | |
5fef3870 | 753 | |
c625d1c2 PA |
754 | /* |
755 | * Get the number of UTF-8 bytes corresponding to an UTF-16 character. | |
756 | * This overestimates for surrogates, but that is okay. | |
757 | */ | |
758 | static int efi_utf8_bytes(u16 c) | |
759 | { | |
760 | return 1 + (c >= 0x80) + (c >= 0x800); | |
761 | } | |
762 | ||
763 | /* | |
764 | * Convert an UTF-16 string, not necessarily null terminated, to UTF-8. | |
765 | */ | |
766 | static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n) | |
767 | { | |
768 | unsigned int c; | |
769 | ||
770 | while (n--) { | |
771 | c = *src++; | |
772 | if (n && c >= 0xd800 && c <= 0xdbff && | |
773 | *src >= 0xdc00 && *src <= 0xdfff) { | |
774 | c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff); | |
775 | src++; | |
776 | n--; | |
777 | } | |
778 | if (c >= 0xd800 && c <= 0xdfff) | |
779 | c = 0xfffd; /* Unmatched surrogate */ | |
780 | if (c < 0x80) { | |
781 | *dst++ = c; | |
782 | continue; | |
783 | } | |
784 | if (c < 0x800) { | |
785 | *dst++ = 0xc0 + (c >> 6); | |
786 | goto t1; | |
787 | } | |
788 | if (c < 0x10000) { | |
789 | *dst++ = 0xe0 + (c >> 12); | |
790 | goto t2; | |
791 | } | |
792 | *dst++ = 0xf0 + (c >> 18); | |
793 | *dst++ = 0x80 + ((c >> 12) & 0x3f); | |
794 | t2: | |
795 | *dst++ = 0x80 + ((c >> 6) & 0x3f); | |
796 | t1: | |
797 | *dst++ = 0x80 + (c & 0x3f); | |
798 | } | |
799 | ||
800 | return dst; | |
801 | } | |
802 | ||
48fcb2d0 AB |
803 | #ifndef MAX_CMDLINE_ADDRESS |
804 | #define MAX_CMDLINE_ADDRESS ULONG_MAX | |
805 | #endif | |
806 | ||
5fef3870 RF |
807 | /* |
808 | * Convert the unicode UEFI command line to ASCII to pass to kernel. | |
809 | * Size of memory allocated return in *cmd_line_len. | |
810 | * Returns NULL on error. | |
811 | */ | |
bd669475 AB |
812 | char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, |
813 | efi_loaded_image_t *image, | |
814 | int *cmd_line_len) | |
5fef3870 | 815 | { |
c625d1c2 | 816 | const u16 *s2; |
5fef3870 RF |
817 | u8 *s1 = NULL; |
818 | unsigned long cmdline_addr = 0; | |
c625d1c2 PA |
819 | int load_options_chars = image->load_options_size / 2; /* UTF-16 */ |
820 | const u16 *options = image->load_options; | |
821 | int options_bytes = 0; /* UTF-8 bytes */ | |
822 | int options_chars = 0; /* UTF-16 chars */ | |
5fef3870 | 823 | efi_status_t status; |
5fef3870 RF |
824 | u16 zero = 0; |
825 | ||
826 | if (options) { | |
827 | s2 = options; | |
c625d1c2 PA |
828 | while (*s2 && *s2 != '\n' |
829 | && options_chars < load_options_chars) { | |
830 | options_bytes += efi_utf8_bytes(*s2++); | |
831 | options_chars++; | |
5fef3870 RF |
832 | } |
833 | } | |
834 | ||
c625d1c2 | 835 | if (!options_chars) { |
5fef3870 | 836 | /* No command line options, so return empty string*/ |
5fef3870 RF |
837 | options = &zero; |
838 | } | |
839 | ||
c625d1c2 | 840 | options_bytes++; /* NUL termination */ |
9403e462 | 841 | |
48fcb2d0 AB |
842 | status = efi_high_alloc(sys_table_arg, options_bytes, 0, |
843 | &cmdline_addr, MAX_CMDLINE_ADDRESS); | |
5fef3870 RF |
844 | if (status != EFI_SUCCESS) |
845 | return NULL; | |
846 | ||
847 | s1 = (u8 *)cmdline_addr; | |
c625d1c2 | 848 | s2 = (const u16 *)options; |
5fef3870 | 849 | |
c625d1c2 | 850 | s1 = efi_utf16_to_utf8(s1, s2, options_chars); |
5fef3870 RF |
851 | *s1 = '\0'; |
852 | ||
c625d1c2 | 853 | *cmd_line_len = options_bytes; |
5fef3870 RF |
854 | return (char *)cmdline_addr; |
855 | } | |
fc07716b JH |
856 | |
857 | /* | |
858 | * Handle calling ExitBootServices according to the requirements set out by the | |
859 | * spec. Obtains the current memory map, and returns that info after calling | |
860 | * ExitBootServices. The client must specify a function to perform any | |
861 | * processing of the memory map data prior to ExitBootServices. A client | |
862 | * specific structure may be passed to the function via priv. The client | |
863 | * function may be called multiple times. | |
864 | */ | |
865 | efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table_arg, | |
866 | void *handle, | |
867 | struct efi_boot_memmap *map, | |
868 | void *priv, | |
869 | efi_exit_boot_map_processing priv_func) | |
870 | { | |
871 | efi_status_t status; | |
872 | ||
873 | status = efi_get_memory_map(sys_table_arg, map); | |
874 | ||
875 | if (status != EFI_SUCCESS) | |
876 | goto fail; | |
877 | ||
878 | status = priv_func(sys_table_arg, map, priv); | |
879 | if (status != EFI_SUCCESS) | |
880 | goto free_map; | |
881 | ||
882 | status = efi_call_early(exit_boot_services, handle, *map->key_ptr); | |
883 | ||
884 | if (status == EFI_INVALID_PARAMETER) { | |
885 | /* | |
886 | * The memory map changed between efi_get_memory_map() and | |
887 | * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4: | |
888 | * EFI_BOOT_SERVICES.ExitBootServices we need to get the | |
889 | * updated map, and try again. The spec implies one retry | |
890 | * should be sufficent, which is confirmed against the EDK2 | |
891 | * implementation. Per the spec, we can only invoke | |
892 | * get_memory_map() and exit_boot_services() - we cannot alloc | |
893 | * so efi_get_memory_map() cannot be used, and we must reuse | |
894 | * the buffer. For all practical purposes, the headroom in the | |
895 | * buffer should account for any changes in the map so the call | |
896 | * to get_memory_map() is expected to succeed here. | |
897 | */ | |
898 | *map->map_size = *map->buff_size; | |
899 | status = efi_call_early(get_memory_map, | |
900 | map->map_size, | |
901 | *map->map, | |
902 | map->key_ptr, | |
903 | map->desc_size, | |
904 | map->desc_ver); | |
905 | ||
906 | /* exit_boot_services() was called, thus cannot free */ | |
907 | if (status != EFI_SUCCESS) | |
908 | goto fail; | |
909 | ||
910 | status = priv_func(sys_table_arg, map, priv); | |
911 | /* exit_boot_services() was called, thus cannot free */ | |
912 | if (status != EFI_SUCCESS) | |
913 | goto fail; | |
914 | ||
915 | status = efi_call_early(exit_boot_services, handle, *map->key_ptr); | |
916 | } | |
917 | ||
918 | /* exit_boot_services() was called, thus cannot free */ | |
919 | if (status != EFI_SUCCESS) | |
920 | goto fail; | |
921 | ||
922 | return EFI_SUCCESS; | |
923 | ||
924 | free_map: | |
925 | efi_call_early(free_pool, *map->map); | |
926 | fail: | |
927 | return status; | |
928 | } | |
82d736ac | 929 | |
b61fbc88 HG |
930 | #define GET_EFI_CONFIG_TABLE(bits) \ |
931 | static void *get_efi_config_table##bits(efi_system_table_t *_sys_table, \ | |
932 | efi_guid_t guid) \ | |
933 | { \ | |
934 | efi_system_table_##bits##_t *sys_table; \ | |
935 | efi_config_table_##bits##_t *tables; \ | |
936 | int i; \ | |
937 | \ | |
938 | sys_table = (typeof(sys_table))_sys_table; \ | |
939 | tables = (typeof(tables))(unsigned long)sys_table->tables; \ | |
940 | \ | |
941 | for (i = 0; i < sys_table->nr_tables; i++) { \ | |
942 | if (efi_guidcmp(tables[i].guid, guid) != 0) \ | |
943 | continue; \ | |
944 | \ | |
945 | return (void *)(unsigned long)tables[i].table; \ | |
946 | } \ | |
947 | \ | |
948 | return NULL; \ | |
949 | } | |
950 | GET_EFI_CONFIG_TABLE(32) | |
951 | GET_EFI_CONFIG_TABLE(64) | |
952 | ||
82d736ac MG |
953 | void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid) |
954 | { | |
b61fbc88 HG |
955 | if (efi_is_64bit()) |
956 | return get_efi_config_table64(sys_table, guid); | |
957 | else | |
958 | return get_efi_config_table32(sys_table, guid); | |
82d736ac | 959 | } |