aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2013-09-20 10:55:39 -0400
committerMatt Fleming <matt.fleming@intel.com>2014-04-17 07:29:25 -0400
commitc625d1c203941fad755eb4eb729db1f65d6e9836 (patch)
tree2b1cf021ceb69963092ec5db8fbb83c356b81f75
parent9bb40191e88d23563fd0467ac195debf5f6daaf9 (diff)
efi: x86: Handle arbitrary Unicode characters
Instead of truncating UTF-16 assuming all characters is ASCII, properly convert it to UTF-8. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> [ Bug and style fixes. ] Signed-off-by: Roy Franz <roy.franz@linaro.org> Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--arch/x86/boot/compressed/eboot.c3
-rw-r--r--drivers/firmware/efi/efi-stub-helper.c87
2 files changed, 68 insertions, 22 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 4703a6c4b8e3..0331d765c2bb 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -1087,8 +1087,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
1087 hdr->type_of_loader = 0x21; 1087 hdr->type_of_loader = 0x21;
1088 1088
1089 /* Convert unicode cmdline to ascii */ 1089 /* Convert unicode cmdline to ascii */
1090 cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image, 1090 cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
1091 &options_size);
1092 if (!cmdline_ptr) 1091 if (!cmdline_ptr)
1093 goto fail; 1092 goto fail;
1094 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr; 1093 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
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 */
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/*
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 */
543static 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,
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}