aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi/efi-stub-helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/efi/efi-stub-helper.c')
-rw-r--r--drivers/firmware/efi/efi-stub-helper.c144
1 files changed, 107 insertions, 37 deletions
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 2c41eaece2c1..eb6d4be9e722 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -11,6 +11,10 @@
11 */ 11 */
12#define EFI_READ_CHUNK_SIZE (1024 * 1024) 12#define EFI_READ_CHUNK_SIZE (1024 * 1024)
13 13
14/* error code which can't be mistaken for valid address */
15#define EFI_ERROR (~0UL)
16
17
14struct file_info { 18struct file_info {
15 efi_file_handle_t *handle; 19 efi_file_handle_t *handle;
16 u64 size; 20 u64 size;
@@ -33,6 +37,9 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
33 } 37 }
34} 38}
35 39
40#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg)
41#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg)
42
36 43
37static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, 44static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
38 efi_memory_desc_t **map, 45 efi_memory_desc_t **map,
@@ -80,6 +87,32 @@ fail:
80 return status; 87 return status;
81} 88}
82 89
90
91static unsigned long __init get_dram_base(efi_system_table_t *sys_table_arg)
92{
93 efi_status_t status;
94 unsigned long map_size;
95 unsigned long membase = EFI_ERROR;
96 struct efi_memory_map map;
97 efi_memory_desc_t *md;
98
99 status = efi_get_memory_map(sys_table_arg, (efi_memory_desc_t **)&map.map,
100 &map_size, &map.desc_size, NULL, NULL);
101 if (status != EFI_SUCCESS)
102 return membase;
103
104 map.map_end = map.map + map_size;
105
106 for_each_efi_memory_desc(&map, md)
107 if (md->attribute & EFI_MEMORY_WB)
108 if (membase > md->phys_addr)
109 membase = md->phys_addr;
110
111 efi_call_early(free_pool, map.map);
112
113 return membase;
114}
115
83/* 116/*
84 * Allocate at the highest possible address that is not above 'max'. 117 * Allocate at the highest possible address that is not above 'max'.
85 */ 118 */
@@ -267,7 +300,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
267 struct file_info *files; 300 struct file_info *files;
268 unsigned long file_addr; 301 unsigned long file_addr;
269 u64 file_size_total; 302 u64 file_size_total;
270 efi_file_handle_t *fh; 303 efi_file_handle_t *fh = NULL;
271 efi_status_t status; 304 efi_status_t status;
272 int nr_files; 305 int nr_files;
273 char *str; 306 char *str;
@@ -310,7 +343,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
310 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, 343 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
311 nr_files * sizeof(*files), (void **)&files); 344 nr_files * sizeof(*files), (void **)&files);
312 if (status != EFI_SUCCESS) { 345 if (status != EFI_SUCCESS) {
313 efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); 346 pr_efi_err(sys_table_arg, "Failed to alloc mem for file handle list\n");
314 goto fail; 347 goto fail;
315 } 348 }
316 349
@@ -374,13 +407,13 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
374 status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, 407 status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000,
375 &file_addr, max_addr); 408 &file_addr, max_addr);
376 if (status != EFI_SUCCESS) { 409 if (status != EFI_SUCCESS) {
377 efi_printk(sys_table_arg, "Failed to alloc highmem for files\n"); 410 pr_efi_err(sys_table_arg, "Failed to alloc highmem for files\n");
378 goto close_handles; 411 goto close_handles;
379 } 412 }
380 413
381 /* We've run out of free low memory. */ 414 /* We've run out of free low memory. */
382 if (file_addr > max_addr) { 415 if (file_addr > max_addr) {
383 efi_printk(sys_table_arg, "We've run out of free low memory\n"); 416 pr_efi_err(sys_table_arg, "We've run out of free low memory\n");
384 status = EFI_INVALID_PARAMETER; 417 status = EFI_INVALID_PARAMETER;
385 goto free_file_total; 418 goto free_file_total;
386 } 419 }
@@ -401,7 +434,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
401 &chunksize, 434 &chunksize,
402 (void *)addr); 435 (void *)addr);
403 if (status != EFI_SUCCESS) { 436 if (status != EFI_SUCCESS) {
404 efi_printk(sys_table_arg, "Failed to read file\n"); 437 pr_efi_err(sys_table_arg, "Failed to read file\n");
405 goto free_file_total; 438 goto free_file_total;
406 } 439 }
407 addr += chunksize; 440 addr += chunksize;
@@ -486,7 +519,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
486 &new_addr); 519 &new_addr);
487 } 520 }
488 if (status != EFI_SUCCESS) { 521 if (status != EFI_SUCCESS) {
489 efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); 522 pr_efi_err(sys_table_arg, "Failed to allocate usable memory for kernel.\n");
490 return status; 523 return status;
491 } 524 }
492 525
@@ -503,62 +536,99 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
503} 536}
504 537
505/* 538/*
539 * Get the number of UTF-8 bytes corresponding to an UTF-16 character.
540 * This overestimates for surrogates, but that is okay.
541 */
542static int efi_utf8_bytes(u16 c)
543{
544 return 1 + (c >= 0x80) + (c >= 0x800);
545}
546
547/*
548 * Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
549 */
550static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
551{
552 unsigned int c;
553
554 while (n--) {
555 c = *src++;
556 if (n && c >= 0xd800 && c <= 0xdbff &&
557 *src >= 0xdc00 && *src <= 0xdfff) {
558 c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
559 src++;
560 n--;
561 }
562 if (c >= 0xd800 && c <= 0xdfff)
563 c = 0xfffd; /* Unmatched surrogate */
564 if (c < 0x80) {
565 *dst++ = c;
566 continue;
567 }
568 if (c < 0x800) {
569 *dst++ = 0xc0 + (c >> 6);
570 goto t1;
571 }
572 if (c < 0x10000) {
573 *dst++ = 0xe0 + (c >> 12);
574 goto t2;
575 }
576 *dst++ = 0xf0 + (c >> 18);
577 *dst++ = 0x80 + ((c >> 12) & 0x3f);
578 t2:
579 *dst++ = 0x80 + ((c >> 6) & 0x3f);
580 t1:
581 *dst++ = 0x80 + (c & 0x3f);
582 }
583
584 return dst;
585}
586
587/*
506 * Convert the unicode UEFI command line to ASCII to pass to kernel. 588 * Convert the unicode UEFI command line to ASCII to pass to kernel.
507 * Size of memory allocated return in *cmd_line_len. 589 * Size of memory allocated return in *cmd_line_len.
508 * Returns NULL on error. 590 * Returns NULL on error.
509 */ 591 */
510static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, 592static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
511 efi_loaded_image_t *image, 593 efi_loaded_image_t *image,
512 int *cmd_line_len) 594 int *cmd_line_len)
513{ 595{
514 u16 *s2; 596 const u16 *s2;
515 u8 *s1 = NULL; 597 u8 *s1 = NULL;
516 unsigned long cmdline_addr = 0; 598 unsigned long cmdline_addr = 0;
517 int load_options_size = image->load_options_size / 2; /* ASCII */ 599 int load_options_chars = image->load_options_size / 2; /* UTF-16 */
518 void *options = image->load_options; 600 const u16 *options = image->load_options;
519 int options_size = 0; 601 int options_bytes = 0; /* UTF-8 bytes */
602 int options_chars = 0; /* UTF-16 chars */
520 efi_status_t status; 603 efi_status_t status;
521 int i;
522 u16 zero = 0; 604 u16 zero = 0;
523 605
524 if (options) { 606 if (options) {
525 s2 = options; 607 s2 = options;
526 while (*s2 && *s2 != '\n' && options_size < load_options_size) { 608 while (*s2 && *s2 != '\n'
527 s2++; 609 && options_chars < load_options_chars) {
528 options_size++; 610 options_bytes += efi_utf8_bytes(*s2++);
611 options_chars++;
529 } 612 }
530 } 613 }
531 614
532 if (options_size == 0) { 615 if (!options_chars) {
533 /* No command line options, so return empty string*/ 616 /* No command line options, so return empty string*/
534 options_size = 1;
535 options = &zero; 617 options = &zero;
536 } 618 }
537 619
538 options_size++; /* NUL termination */ 620 options_bytes++; /* NUL termination */
539#ifdef CONFIG_ARM 621
540 /* 622 status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr);
541 * For ARM, allocate at a high address to avoid reserved
542 * regions at low addresses that we don't know the specfics of
543 * at the time we are processing the command line.
544 */
545 status = efi_high_alloc(sys_table_arg, options_size, 0,
546 &cmdline_addr, 0xfffff000);
547#else
548 status = efi_low_alloc(sys_table_arg, options_size, 0,
549 &cmdline_addr);
550#endif
551 if (status != EFI_SUCCESS) 623 if (status != EFI_SUCCESS)
552 return NULL; 624 return NULL;
553 625
554 s1 = (u8 *)cmdline_addr; 626 s1 = (u8 *)cmdline_addr;
555 s2 = (u16 *)options; 627 s2 = (const u16 *)options;
556
557 for (i = 0; i < options_size - 1; i++)
558 *s1++ = *s2++;
559 628
629 s1 = efi_utf16_to_utf8(s1, s2, options_chars);
560 *s1 = '\0'; 630 *s1 = '\0';
561 631
562 *cmd_line_len = options_size; 632 *cmd_line_len = options_bytes;
563 return (char *)cmdline_addr; 633 return (char *)cmdline_addr;
564} 634}