diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/efi/efi-stub-helper.c | 87 |
1 files changed, 67 insertions, 20 deletions
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index a168dd20511f..eb6d4be9e722 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c | |||
@@ -536,52 +536,99 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, | |||
536 | } | 536 | } |
537 | 537 | ||
538 | /* | 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 | */ | ||
542 | static 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 | */ | ||
550 | static 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 | /* | ||
539 | * 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. |
540 | * Size of memory allocated return in *cmd_line_len. | 589 | * Size of memory allocated return in *cmd_line_len. |
541 | * Returns NULL on error. | 590 | * Returns NULL on error. |
542 | */ | 591 | */ |
543 | static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, | 592 | static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, |
544 | efi_loaded_image_t *image, | 593 | efi_loaded_image_t *image, |
545 | int *cmd_line_len) | 594 | int *cmd_line_len) |
546 | { | 595 | { |
547 | u16 *s2; | 596 | const u16 *s2; |
548 | u8 *s1 = NULL; | 597 | u8 *s1 = NULL; |
549 | unsigned long cmdline_addr = 0; | 598 | unsigned long cmdline_addr = 0; |
550 | int load_options_size = image->load_options_size / 2; /* ASCII */ | 599 | int load_options_chars = image->load_options_size / 2; /* UTF-16 */ |
551 | void *options = image->load_options; | 600 | const u16 *options = image->load_options; |
552 | int options_size = 0; | 601 | int options_bytes = 0; /* UTF-8 bytes */ |
602 | int options_chars = 0; /* UTF-16 chars */ | ||
553 | efi_status_t status; | 603 | efi_status_t status; |
554 | int i; | ||
555 | u16 zero = 0; | 604 | u16 zero = 0; |
556 | 605 | ||
557 | if (options) { | 606 | if (options) { |
558 | s2 = options; | 607 | s2 = options; |
559 | while (*s2 && *s2 != '\n' && options_size < load_options_size) { | 608 | while (*s2 && *s2 != '\n' |
560 | s2++; | 609 | && options_chars < load_options_chars) { |
561 | options_size++; | 610 | options_bytes += efi_utf8_bytes(*s2++); |
611 | options_chars++; | ||
562 | } | 612 | } |
563 | } | 613 | } |
564 | 614 | ||
565 | if (options_size == 0) { | 615 | if (!options_chars) { |
566 | /* No command line options, so return empty string*/ | 616 | /* No command line options, so return empty string*/ |
567 | options_size = 1; | ||
568 | options = &zero; | 617 | options = &zero; |
569 | } | 618 | } |
570 | 619 | ||
571 | options_size++; /* NUL termination */ | 620 | options_bytes++; /* NUL termination */ |
572 | 621 | ||
573 | status = efi_low_alloc(sys_table_arg, options_size, 0, &cmdline_addr); | 622 | status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr); |
574 | if (status != EFI_SUCCESS) | 623 | if (status != EFI_SUCCESS) |
575 | return NULL; | 624 | return NULL; |
576 | 625 | ||
577 | s1 = (u8 *)cmdline_addr; | 626 | s1 = (u8 *)cmdline_addr; |
578 | s2 = (u16 *)options; | 627 | s2 = (const u16 *)options; |
579 | |||
580 | for (i = 0; i < options_size - 1; i++) | ||
581 | *s1++ = *s2++; | ||
582 | 628 | ||
629 | s1 = efi_utf16_to_utf8(s1, s2, options_chars); | ||
583 | *s1 = '\0'; | 630 | *s1 = '\0'; |
584 | 631 | ||
585 | *cmd_line_len = options_size; | 632 | *cmd_line_len = options_bytes; |
586 | return (char *)cmdline_addr; | 633 | return (char *)cmdline_addr; |
587 | } | 634 | } |