Skip to contentSkip to conversation

efi_loader: EFI_UNICODE_COLLATION_PROTOCOL

PATCH Superseded Heinrich Schuchardt 4 participants 44 messages Aug 11, 2018 – Aug 30, 2018

Subsystems (2)

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

cover efi_loader: EFI_UNICODE_COLLATION_PROTOCOL

This patchset implements the EFI_UNICODE_COLLATION_PROTOCOL and provides unit tests.

Additionally some errors when handling Unicode strings are fixed.
* possible stack overflow
* incorrect handling of precision attribute in printf()
* incorrect limit on variable length

Some old Unicode functions are replaced.

An error in Unicode handling in the FAT file system shall be fixed after merging Takahiro's FAT patches. Until then some redundancy between old and new Unicode functions remains.

Heinrich Schuchardt (15):
lib: build charset.o only if needed
efi_loader: rename utf16_strlen, utf16_strnlen
lib: charset: utility functions for Unicode
test: unit tests for Unicode functions
lib: vsprintf: correct printing of Unicode strings
test: test printing Unicode
efi_loader: remove limit on variable length
efi_loader: don't use unlimited stack as buffer
efi_loader: buffer size for load options
lib: charset: remove obsolete functions
efi_loader: capitalization table
lib: charset: upper/lower case conversion
test: tests for utf_to_lower() utf_to_upper().
efi_loader: EFI_UNICODE_COLLATION_PROTOCOL
efi_selftest: EFI_UNICODE_COLLATION_PROTOCOL

 MAINTAINERS                                   |    4 +
 cmd/bootefi.c                                 |    6 +-
 include/capitalization.h                      | 1909 +++++++++++++++++
 include/charset.h                             |  181 +-
 include/cp1250.h                              |   40 +
 include/cp437.h                               |   40 +
 include/efi_api.h                             |   21 +
 include/efi_loader.h                          |    5 +
 include/test/suites.h                         |    3 +-
 lib/Makefile                                  |    5 +
 lib/charset.c                                 |  359 +++-
 lib/efi_loader/Makefile                       |   18 +-
 lib/efi_loader/efi_bootmgr.c                  |    2 +-
 lib/efi_loader/efi_boottime.c                 |    6 +
 lib/efi_loader/efi_console.c                  |   20 +-
 lib/efi_loader/efi_file.c                     |    2 +-
 lib/efi_loader/efi_unicode_collation.c        |  218 ++
 lib/efi_loader/efi_variable.c                 |   52 +-
 lib/efi_selftest/Makefile                     |    1 +
 .../efi_selftest_unicode_collation.c          |  257 +++
 lib/vsprintf.c                                |   34 +-
 test/Kconfig                                  |    8 +
 test/Makefile                                 |    1 +
 test/cmd_ut.c                                 |   14 +-
 test/unicode_ut.c                             |  545 +++++
 25 files changed, 3587 insertions(+), 164 deletions(-)
 create mode 100644 include/capitalization.h
 create mode 100644 include/cp1250.h
 create mode 100644 include/cp437.h
 create mode 100644 lib/efi_loader/efi_unicode_collation.c
 create mode 100644 lib/efi_selftest/efi_selftest_unicode_collation.c
 create mode 100644 test/unicode_ut.c
Signature · 1 line
2.18.0
#1 lore raw

PATCH 1/15 lib: build charset.o only if needed

charset.o is only needed for the EFI subsystem

---
 lib/Makefile   |  5 ++++-
 lib/vsprintf.c | 12 ++++++++----
 2 files changed, 12 insertions(+), 5 deletions(-)
lib/Makefile +4 -1
index 5f583aed37..2fd32798a0 100644
@@ -19,7 +19,10 @@ obj-$(CONFIG_ARCH_AT91) += at91/
 obj-$(CONFIG_OPTEE) += optee/
 
 obj-$(CONFIG_AES) += aes.o
-obj-y += charset.o
+
+ifndef API_BUILD
+obj-$(CONFIG_EFI_LOADER) += charset.o
+endif
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
 obj-y += crc8.o
lib/vsprintf.c +8 -4
index 914fbd30cb..6100357858 100644
@@ -274,6 +274,8 @@ static char *string(char *buf, char *end, char *s, int field_width,
 	return buf;
 }
 
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
 static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
@@ -294,8 +296,6 @@ static char *string16(char *buf, char *end, u16 *s, int field_width,
 	return buf;
 }
 
-#if defined(CONFIG_EFI_LOADER) && \
-	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
 static char *device_path_string(char *buf, char *end, void *dp, int field_width,
 				int precision, int flags)
 {
@@ -612,10 +612,14 @@ repeat:
 			continue;
 
 		case 's':
-			if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) {
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+			if (qualifier == 'l') {
 				str = string16(str, end, va_arg(args, u16 *),
 					       field_width, precision, flags);
-			} else {
+			} else
+#endif
+			{
 				str = string(str, end, va_arg(args, char *),
 					     field_width, precision, flags);
 			}
Signature · 1 line
2.18.0
#2 lore raw

PATCH 1/15 lib: build charset.o only if needed

Quoted 29 lines · Heinrich Schuchardt

charset.o is only needed for the EFI subsystem

---
 lib/Makefile   |  5 ++++-
 lib/vsprintf.c | 12 ++++++++----
 2 files changed, 12 insertions(+), 5 deletions(-)
lib/Makefile +4 -1
index 5f583aed37..2fd32798a0 100644
@@ -19,7 +19,10 @@ obj-$(CONFIG_ARCH_AT91) += at91/
 obj-$(CONFIG_OPTEE) += optee/
 
 obj-$(CONFIG_AES) += aes.o
-obj-y += charset.o
+
+ifndef API_BUILD
+obj-$(CONFIG_EFI_LOADER) += charset.o
+endif
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
 obj-y += crc8.o
lib/vsprintf.c +0 -0
index 914fbd30cb..6100357858 100644

lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 278

Quoted 5 lines
lib/vsprintf.c +2 -0
@@ -274,6 +274,8 @@ static char *string(char *buf, char *end, char *s, int field_width,
 	return buf;
 }
 
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)

I believe you want #if CONFIG_IS_ENABLED(EFI_LOADER) here, right? We probably should move to that at other places where we explicitly check for SPL_BUILD too.

Quoted 13 lines
lib/vsprintf.c +0 -2
 static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
@@ -294,8 +296,6 @@ static char *string16(char *buf, char *end, u16 *s, int field_width,
 	return buf;
 }
 
-#if defined(CONFIG_EFI_LOADER) && \
-	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
 static char *device_path_string(char *buf, char *end, void *dp, int field_width,
 				int precision, int flags)
 {

lib/vsprintf.c repeat: · line 616

Quoted 6 lines
lib/vsprintf.c +2 -1
@@ -612,10 +612,14 @@ repeat:
 			continue;
 
 		case 's':
-			if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) {
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)

This #if deserves a comment.

Alex

Quoted 11 lines
lib/vsprintf.c +4 -1
+			if (qualifier == 'l') {
 				str = string16(str, end, va_arg(args, u16 *),
 					       field_width, precision, flags);
-			} else {
+			} else
+#endif
+			{
 				str = string(str, end, va_arg(args, char *),
 					     field_width, precision, flags);
 			}
#3 lore raw

PATCH 1/15 lib: build charset.o only if needed

Quoted 35 lines · Alexander Graf
Quoted 32 lines · Heinrich Schuchardt

charset.o is only needed for the EFI subsystem

---
 lib/Makefile   |  5 ++++-
 lib/vsprintf.c | 12 ++++++++----
 2 files changed, 12 insertions(+), 5 deletions(-)
lib/Makefile +4 -1
index 5f583aed37..2fd32798a0 100644
@@ -19,7 +19,10 @@ obj-$(CONFIG_ARCH_AT91) += at91/
 obj-$(CONFIG_OPTEE) += optee/
 
 obj-$(CONFIG_AES) += aes.o
-obj-y += charset.o
+
+ifndef API_BUILD
+obj-$(CONFIG_EFI_LOADER) += charset.o
+endif
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
 obj-y += crc8.o
lib/vsprintf.c +0 -0
index 914fbd30cb..6100357858 100644
@@ -274,6 +274,8 @@ static char *string(char *buf, char *end, char *s, int field_width,
 	return buf;
 }
 
Quoted 6 lines

lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 278

Quoted 2 lines
lib/vsprintf.c +2 -0
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)

I believe you want #if CONFIG_IS_ENABLED(EFI_LOADER) here, right? We probably should move to that at other places where we explicitly check for SPL_BUILD too.

Thanks for reviewing

Yes we can use that shorthand notation here. We still have to check API_BUILD.

Quoted 16 lines
Quoted 16 lines
lib/vsprintf.c +0 -2
 static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
@@ -294,8 +296,6 @@ static char *string16(char *buf, char *end, u16 *s, int field_width,
 	return buf;
 }
 
-#if defined(CONFIG_EFI_LOADER) && \
-	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
 static char *device_path_string(char *buf, char *end, void *dp, int field_width,
 				int precision, int flags)
 {
@@ -612,10 +612,14 @@ repeat:
 			continue;
 
Quoted 6 lines

lib/vsprintf.c repeat: · line 616

Quoted 4 lines
lib/vsprintf.c +2 -1
 		case 's':
-			if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) {
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)

This #if deserves a comment.

ok

Best regards

Heinrich

Quoted 16 lines

Alex

Quoted 11 lines
lib/vsprintf.c +4 -1
+			if (qualifier == 'l') {
 				str = string16(str, end, va_arg(args, u16 *),
 					       field_width, precision, flags);
-			} else {
+			} else
+#endif
+			{
 				str = string(str, end, va_arg(args, char *),
 					     field_width, precision, flags);
 			}
#4 lore raw

PATCH 2/15 efi_loader: rename utf16_strlen, utf16_strnlen

In reply to Heinrich Schuchardt

The function names utf16_strlen() and utf16_strnlen() are misnomers. The functions do not count utf-16 characters but non-zero words. So let's rename them to u16_strlen and u16_strnlen().

In utf16_dup() avoid assignment in if clause.

---
 include/charset.h             | 28 +++++++++++-----------------
 lib/charset.c                 | 10 +++++++---
 lib/efi_loader/efi_bootmgr.c  |  2 +-
 lib/efi_loader/efi_console.c  |  2 +-
 lib/efi_loader/efi_file.c     |  2 +-
 lib/efi_loader/efi_variable.c |  2 +-
 lib/vsprintf.c                |  2 +-
 7 files changed, 23 insertions(+), 25 deletions(-)
include/charset.h +11 -17
index 11832cbd12..2307559890 100644
@@ -13,29 +13,23 @@
 #define MAX_UTF8_PER_UTF16 3
 
 /**
- * utf16_strlen() - Get the length of an utf16 string
+ * u16_strlen - count non-zero words
  *
- * Returns the number of 16 bit characters in an utf16 string, not
- * including the terminating NULL character.
- *
- * @in     the string to measure
- * @return the string length
+ * @in:			utf-16 string
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
  */
-size_t utf16_strlen(const uint16_t *in);
+size_t u16_strlen(const u16 *in);
 
 /**
- * utf16_strnlen() - Get the length of a fixed-size utf16 string.
- *
- * Returns the number of 16 bit characters in an utf16 string,
- * not including the terminating NULL character, but at most
- * 'count' number of characters.  In doing this, utf16_strnlen()
- * looks at only the first 'count' characters.
+ * u16_strlen - count non-zero words
  *
- * @in     the string to measure
- * @count  the maximum number of characters to count
- * @return the string length, up to a maximum of 'count'
+ * @in:			utf-16 string
+ * @count:		maximum number of words to count
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
  */
-size_t utf16_strnlen(const uint16_t *in, size_t count);
+size_t u16_strnlen(const u16 *in, size_t count);
 
 /**
  * utf16_strcpy() - UTF16 equivalent of strcpy()
lib/charset.c +7 -3
index cd186a5a5a..8ff8d59957 100644
@@ -12,14 +12,14 @@
  * utf8/utf16 conversion mostly lifted from grub
  */
 
-size_t utf16_strlen(const uint16_t *in)
+size_t u16_strlen(const u16 *in)
 {
 	size_t i;
 	for (i = 0; in[i]; i++);
 	return i;
 }
 
-size_t utf16_strnlen(const uint16_t *in, size_t count)
+size_t u16_strnlen(const u16 *in, size_t count)
 {
 	size_t i;
 	for (i = 0; count-- && in[i]; i++);
@@ -39,7 +39,11 @@ uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src)
 uint16_t *utf16_strdup(const uint16_t *s)
 {
 	uint16_t *new;
-	if (!s || !(new = malloc((utf16_strlen(s) + 1) * 2)))
+
+	if (!s)
+		return NULL;
+	new = malloc((u16_strlen(s) + 1) * 2);
+	if (!new)
 		return NULL;
 	utf16_strcpy(new, s);
 	return new;
lib/efi_loader/efi_bootmgr.c +1 -1
index 853358ab93..0c5764db12 100644
@@ -60,7 +60,7 @@ static void parse_load_option(struct load_option *lo, void *ptr)
 	ptr += sizeof(u16);
 
 	lo->label = ptr;
-	ptr += (utf16_strlen(lo->label) + 1) * 2;
+	ptr += (u16_strlen(lo->label) + 1) * 2;
 
 	lo->file_path = ptr;
 	ptr += lo->file_path_length;
lib/efi_loader/efi_console.c +1 -1
index b487288785..f3d612880c 100644
@@ -114,7 +114,7 @@ static efi_status_t EFIAPI efi_cout_output_string(
 
 	EFI_ENTRY("%p, %p", this, string);
 
-	unsigned int n16 = utf16_strlen(string);
+	unsigned int n16 = u16_strlen(string);
 	char buf[MAX_UTF8_PER_UTF16 * n16 + 1];
 	u16 *p;
 
lib/efi_loader/efi_file.c +1 -1
index e6a15bcb52..c21881b32c 100644
@@ -139,7 +139,7 @@ static struct efi_file_handle *file_open(struct file_system *fs,
 
 	if (file_name) {
 		utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1);
-		flen = utf16_strlen((u16 *)file_name);
+		flen = u16_strlen((u16 *)file_name);
 	}
 
 	/* we could have a parent, but also an absolute path: */
lib/efi_loader/efi_variable.c +1 -1
index 90b637215e..770c67abb9 100644
@@ -106,7 +106,7 @@ static efi_status_t efi_to_native(char *native, u16 *variable_name,
 {
 	size_t len;
 
-	len = utf16_strlen((u16 *)variable_name);
+	len = u16_strlen((u16 *)variable_name);
 	if (len >= MAX_VAR_NAME)
 		return EFI_DEVICE_ERROR;
 
lib/vsprintf.c +1 -1
index 6100357858..a07128ad96 100644
@@ -280,7 +280,7 @@ static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
 	u16 *str = s ? s : L"<NULL>";
-	int utf16_len = utf16_strnlen(str, precision);
+	int utf16_len = u16_strnlen(str, precision);
 	u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
 	int utf8_len, i;
 
Signature · 1 line
2.18.0
#5 lore raw

PATCH 2/15 efi_loader: rename utf16_strlen, utf16_strnlen

Quoted 22 lines · Heinrich Schuchardt

The function names utf16_strlen() and utf16_strnlen() are misnomers. The functions do not count utf-16 characters but non-zero words. So let's rename them to u16_strlen and u16_strnlen().

In utf16_dup() avoid assignment in if clause.

---
 include/charset.h             | 28 +++++++++++-----------------
 lib/charset.c                 | 10 +++++++---
 lib/efi_loader/efi_bootmgr.c  |  2 +-
 lib/efi_loader/efi_console.c  |  2 +-
 lib/efi_loader/efi_file.c     |  2 +-
 lib/efi_loader/efi_variable.c |  2 +-
 lib/vsprintf.c                |  2 +-
 7 files changed, 23 insertions(+), 25 deletions(-)
include/charset.h +0 -0
index 11832cbd12..2307559890 100644

include/charset.h line 16

Quoted 5 lines
include/charset.h +1 -1
@@ -13,29 +13,23 @@
 #define MAX_UTF8_PER_UTF16 3
 
 /**
- * utf16_strlen() - Get the length of an utf16 string
+ * u16_strlen - count non-zero words

This really just implements wcslen() now, right?

include/charset.h line 18

Quoted 7 lines
include/charset.h +1 -5
  *
- * Returns the number of 16 bit characters in an utf16 string, not
- * including the terminating NULL character.
- *
- * @in     the string to measure
- * @return the string length
+ * @in:			utf-16 string

Is "in" really a utf-16 string? Probably rather a null-terminated string of words.

Quoted 4 lines
include/charset.h +2 -1
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
  */
-size_t utf16_strlen(const uint16_t *in);

include/charset.h line 25

Quoted 10 lines
include/charset.h +2 -6
+size_t u16_strlen(const u16 *in);
 
 /**
- * utf16_strnlen() - Get the length of a fixed-size utf16 string.
- *
- * Returns the number of 16 bit characters in an utf16 string,
- * not including the terminating NULL character, but at most
- * 'count' number of characters.  In doing this, utf16_strnlen()
- * looks at only the first 'count' characters.
+ * u16_strlen - count non-zero words

This really just implements wcsnlen() now, right?

include/charset.h line 27

Quoted 5 lines
include/charset.h +1 -3
  *
- * @in     the string to measure
- * @count  the maximum number of characters to count
- * @return the string length, up to a maximum of 'count'
+ * @in:			utf-16 string

Same comment here.

Alex

#6 lore raw

PATCH 2/15 efi_loader: rename utf16_strlen, utf16_strnlen

Quoted 41 lines · Alexander Graf
Quoted 22 lines · Heinrich Schuchardt

The function names utf16_strlen() and utf16_strnlen() are misnomers. The functions do not count utf-16 characters but non-zero words. So let's rename them to u16_strlen and u16_strnlen().

In utf16_dup() avoid assignment in if clause.

---
 include/charset.h             | 28 +++++++++++-----------------
 lib/charset.c                 | 10 +++++++---
 lib/efi_loader/efi_bootmgr.c  |  2 +-
 lib/efi_loader/efi_console.c  |  2 +-
 lib/efi_loader/efi_file.c     |  2 +-
 lib/efi_loader/efi_variable.c |  2 +-
 lib/vsprintf.c                |  2 +-
 7 files changed, 23 insertions(+), 25 deletions(-)
include/charset.h +0 -0
index 11832cbd12..2307559890 100644

include/charset.h line 16

Quoted 5 lines
include/charset.h +1 -1
@@ -13,29 +13,23 @@
 #define MAX_UTF8_PER_UTF16 3
 
 /**
- * utf16_strlen() - Get the length of an utf16 string
+ * u16_strlen - count non-zero words

This really just implements wcslen() now, right?

include/charset.h line 18

Quoted 7 lines
include/charset.h +1 -5
  *
- * Returns the number of 16 bit characters in an utf16 string, not
- * including the terminating NULL character.
- *
- * @in     the string to measure
- * @return the string length
+ * @in:			utf-16 string
Quoted 2 lines

Is "in" really a utf-16 string? Probably rather a null-terminated string of words.

I will update the comment.

Quoted 7 lines
Quoted 7 lines
include/charset.h +3 -1
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
  */
-size_t utf16_strlen(const uint16_t *in);
+size_t u16_strlen(const u16 *in);
 
Quoted 10 lines

include/charset.h line 25

Quoted 8 lines
include/charset.h +1 -6
 /**
- * utf16_strnlen() - Get the length of a fixed-size utf16 string.
- *
- * Returns the number of 16 bit characters in an utf16 string,
- * not including the terminating NULL character, but at most
- * 'count' number of characters.  In doing this, utf16_strnlen()
- * looks at only the first 'count' characters.
+ * u16_strlen - count non-zero words

This really just implements wcsnlen() now, right?

Currently we have set wchar size to 16bit using a compiler flag. In my opinion this was not necessary. In C11 we could have use the u"text" notation for utf-8 string constants instead of L"text".

This function really is for u16[] and not for wchar_t[].

I would hesitate to call this function wcsnlen() as the working of wcsnlen() depends on said compiler setting.

Quoted 7 lines

include/charset.h line 27

Quoted 6 lines
include/charset.h +1 -3
  *
- * @in     the string to measure
- * @count  the maximum number of characters to count
- * @return the string length, up to a maximum of 'count'
+ * @in:			utf-16 string

Yes u16 string.

Thanks for reviewing.

Heinrich

Quoted 5 lines

Same comment here.

Alex

#7 lore raw

PATCH 2/15 efi_loader: rename utf16_strlen, utf16_strnlen

Quoted 65 lines · Heinrich Schuchardt
Quoted 41 lines · Alexander Graf
Quoted 22 lines · Heinrich Schuchardt

The function names utf16_strlen() and utf16_strnlen() are misnomers. The functions do not count utf-16 characters but non-zero words. So let's rename them to u16_strlen and u16_strnlen().

In utf16_dup() avoid assignment in if clause.

---
 include/charset.h             | 28 +++++++++++-----------------
 lib/charset.c                 | 10 +++++++---
 lib/efi_loader/efi_bootmgr.c  |  2 +-
 lib/efi_loader/efi_console.c  |  2 +-
 lib/efi_loader/efi_file.c     |  2 +-
 lib/efi_loader/efi_variable.c |  2 +-
 lib/vsprintf.c                |  2 +-
 7 files changed, 23 insertions(+), 25 deletions(-)
include/charset.h +0 -0
index 11832cbd12..2307559890 100644

include/charset.h line 16

Quoted 5 lines
include/charset.h +1 -1
@@ -13,29 +13,23 @@
 #define MAX_UTF8_PER_UTF16 3
 
 /**
- * utf16_strlen() - Get the length of an utf16 string
+ * u16_strlen - count non-zero words

This really just implements wcslen() now, right?

include/charset.h line 18

Quoted 7 lines
include/charset.h +1 -5
  *
- * Returns the number of 16 bit characters in an utf16 string, not
- * including the terminating NULL character.
- *
- * @in     the string to measure
- * @return the string length
+ * @in:			utf-16 string
Quoted 2 lines

Is "in" really a utf-16 string? Probably rather a null-terminated string of words.

I will update the comment.

Quoted 7 lines
Quoted 7 lines
include/charset.h +3 -1
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
  */
-size_t utf16_strlen(const uint16_t *in);
+size_t u16_strlen(const u16 *in);
 
Quoted 10 lines

include/charset.h line 25

Quoted 8 lines
include/charset.h +1 -6
 /**
- * utf16_strnlen() - Get the length of a fixed-size utf16 string.
- *
- * Returns the number of 16 bit characters in an utf16 string,
- * not including the terminating NULL character, but at most
- * 'count' number of characters.  In doing this, utf16_strnlen()
- * looks at only the first 'count' characters.
+ * u16_strlen - count non-zero words

This really just implements wcsnlen() now, right?

Quoted 3 lines

Currently we have set wchar size to 16bit using a compiler flag. In my opinion this was not necessary. In C11 we could have use the u"text" notation for utf-8 string constants instead of L"text".

I thought the idea was to get utf-16 string constants?

Quoted 5 lines

This function really is for u16[] and not for wchar_t[].

I would hesitate to call this function wcsnlen() as the working of wcsnlen() depends on said compiler setting.

*shrug* either way works for me. By calling them their official names we could've potentially given gcc the chance to optimize/inline them better.

Alex

#8 lore raw

PATCH 2/15 efi_loader: rename utf16_strlen, utf16_strnlen

Quoted 68 lines · Alexander Graf
Quoted 65 lines · Heinrich Schuchardt
Quoted 41 lines · Alexander Graf
Quoted 22 lines · Heinrich Schuchardt

The function names utf16_strlen() and utf16_strnlen() are misnomers. The functions do not count utf-16 characters but non-zero words. So let's rename them to u16_strlen and u16_strnlen().

In utf16_dup() avoid assignment in if clause.

---
 include/charset.h             | 28 +++++++++++-----------------
 lib/charset.c                 | 10 +++++++---
 lib/efi_loader/efi_bootmgr.c  |  2 +-
 lib/efi_loader/efi_console.c  |  2 +-
 lib/efi_loader/efi_file.c     |  2 +-
 lib/efi_loader/efi_variable.c |  2 +-
 lib/vsprintf.c                |  2 +-
 7 files changed, 23 insertions(+), 25 deletions(-)
include/charset.h +0 -0
index 11832cbd12..2307559890 100644

include/charset.h line 16

Quoted 5 lines
include/charset.h +1 -1
@@ -13,29 +13,23 @@
 #define MAX_UTF8_PER_UTF16 3
 
 /**
- * utf16_strlen() - Get the length of an utf16 string
+ * u16_strlen - count non-zero words

This really just implements wcslen() now, right?

include/charset.h line 18

Quoted 7 lines
include/charset.h +1 -5
  *
- * Returns the number of 16 bit characters in an utf16 string, not
- * including the terminating NULL character.
- *
- * @in     the string to measure
- * @return the string length
+ * @in:			utf-16 string
Quoted 2 lines

Is "in" really a utf-16 string? Probably rather a null-terminated string of words.

I will update the comment.

Quoted 17 lines
Quoted 5 lines
include/charset.h +2 -1
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
  */
-size_t utf16_strlen(const uint16_t *in);

include/charset.h line 25

Quoted 10 lines
include/charset.h +2 -6
+size_t u16_strlen(const u16 *in);
 
 /**
- * utf16_strnlen() - Get the length of a fixed-size utf16 string.
- *
- * Returns the number of 16 bit characters in an utf16 string,
- * not including the terminating NULL character, but at most
- * 'count' number of characters.  In doing this, utf16_strnlen()
- * looks at only the first 'count' characters.
+ * u16_strlen - count non-zero words

This really just implements wcsnlen() now, right?

Quoted 5 lines
Quoted 3 lines

Currently we have set wchar size to 16bit using a compiler flag. In my opinion this was not necessary. In C11 we could have use the u"text" notation for utf-8 string constants instead of L"text".

I thought the idea was to get utf-16 string constants?

Yes, but the C11 way is not using a compiler flag but using the right prefix (which was not available with C99). So once we do not have to support outdated gcc versions anymore we could get rid of the compiler flag.

Quoted 9 lines
Quoted 6 lines

This function really is for u16[] and not for wchar_t[].

I would hesitate to call this function wcsnlen() as the working of wcsnlen() depends on said compiler setting.

*shrug* either way works for me. By calling them their official names we could've potentially given gcc the chance to optimize/inline them better.

Do have any hint that gcc really provides better compilation results based on the function name?

From what I see in the gcc code only the address sanitizer is aware that wcsnlen() is accessing a memory range.

Best regards

Heinrich

Quoted 4 lines

Alex

#9 lore raw

PATCH 2/15 efi_loader: rename utf16_strlen, utf16_strnlen

Quoted 73 lines · Heinrich Schuchardt
Quoted 72 lines · Alexander Graf
Quoted 68 lines · Heinrich Schuchardt
Quoted 41 lines · Alexander Graf
Quoted 22 lines · Heinrich Schuchardt

The function names utf16_strlen() and utf16_strnlen() are misnomers. The functions do not count utf-16 characters but non-zero words. So let's rename them to u16_strlen and u16_strnlen().

In utf16_dup() avoid assignment in if clause.

---
 include/charset.h             | 28 +++++++++++-----------------
 lib/charset.c                 | 10 +++++++---
 lib/efi_loader/efi_bootmgr.c  |  2 +-
 lib/efi_loader/efi_console.c  |  2 +-
 lib/efi_loader/efi_file.c     |  2 +-
 lib/efi_loader/efi_variable.c |  2 +-
 lib/vsprintf.c                |  2 +-
 7 files changed, 23 insertions(+), 25 deletions(-)
include/charset.h +0 -0
index 11832cbd12..2307559890 100644

include/charset.h line 16

Quoted 5 lines
include/charset.h +1 -1
@@ -13,29 +13,23 @@
 #define MAX_UTF8_PER_UTF16 3
 
 /**
- * utf16_strlen() - Get the length of an utf16 string
+ * u16_strlen - count non-zero words

This really just implements wcslen() now, right?

include/charset.h line 18

Quoted 7 lines
include/charset.h +1 -5
  *
- * Returns the number of 16 bit characters in an utf16 string, not
- * including the terminating NULL character.
- *
- * @in     the string to measure
- * @return the string length
+ * @in:			utf-16 string
Quoted 2 lines

Is "in" really a utf-16 string? Probably rather a null-terminated string of words.

I will update the comment.

Quoted 7 lines
Quoted 7 lines
include/charset.h +3 -1
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
  */
-size_t utf16_strlen(const uint16_t *in);
+size_t u16_strlen(const u16 *in);
 
Quoted 10 lines

include/charset.h line 25

Quoted 8 lines
include/charset.h +1 -6
 /**
- * utf16_strnlen() - Get the length of a fixed-size utf16 string.
- *
- * Returns the number of 16 bit characters in an utf16 string,
- * not including the terminating NULL character, but at most
- * 'count' number of characters.  In doing this, utf16_strnlen()
- * looks at only the first 'count' characters.
+ * u16_strlen - count non-zero words

This really just implements wcsnlen() now, right?

Currently we have set wchar size to 16bit using a compiler flag. In my opinion this was not necessary. In C11 we could have use the u"text" notation for utf-8 string constants instead of L"text".

Quoted 5 lines
Quoted 1 line

I thought the idea was to get utf-16 string constants?

Yes, but the C11 way is not using a compiler flag but using the right prefix (which was not available with C99). So once we do not have to support outdated gcc versions anymore we could get rid of the compiler flag.

I think we are in agreement, I just wanted to point out that u"text" creates a utf-16 string rather than a utf-8 one :).

Unfortunately I don't know when we can bump the compiler requirement, but it can't be forever and we should keep it in mind, I agree.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

This function really is for u16[] and not for wchar_t[].

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

I would hesitate to call this function wcsnlen() as the working of wcsnlen() depends on said compiler setting.

*shrug* either way works for me. By calling them their official names we could've potentially given gcc the chance to optimize/inline them better.

Do have any hint that gcc really provides better compilation results based on the function name?

I seem to recall that gcc at least allowed for strcpy() and friends to get inlined. The point was really more about using function names that do exactly what people are used to.

I don't have a terribly string feeling towards it though, as strlen() is definitely much wider used than wcslen() and thus much more well known.

Alex

#10 lore raw

PATCH 3/15 lib: charset: utility functions for Unicode

In reply to Heinrich Schuchardt

utf8_get() - get next UTF-8 code point from buffer
utf8_put() - write UTF-8 code point to buffer utf8_utf16_strnlen() - length of a utf-8 string after conversion to utf-16 utf8_utf16_strncpy() - copy a utf-8 string to utf-16 utf16_get() - get next UTF-16 code point from buffer utf16_put() - write UTF-16 code point to buffer utf16_utf8_strnlen() - length of a utf-16 string after conversion to utf-8 utf16_utf8_strncpy() - copy a utf-16 string to utf-8

---
 include/charset.h | 130 +++++++++++++++++++++++++
 lib/Makefile      |   4 +-
 lib/charset.c     | 243 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 373 insertions(+), 4 deletions(-)
include/charset.h +130 -0
index 2307559890..81e31d1b26 100644
@@ -8,10 +8,140 @@
 #ifndef __CHARSET_H_
 #define __CHARSET_H_
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 
 #define MAX_UTF8_PER_UTF16 3
 
+/**
+ * utf8_get() - get next UTF-8 code point from buffer
+ *
+ * @src:		pointer to current byte, updated to point to next byte
+ * Return:		code point, or 0 for end of string, or -1 if no legal
+ *			code point is found. In case of an error src points to
+ *			the incorrect byte.
+ */
+s32 utf8_get(const char **src);
+
+/**
+ * utf8_put() - write UTF-8 code point to buffer
+ *
+ * @code:		code point
+ * @dst:		pointer to destination buffer, updated to next position
+ * Return:		-1 if the input parameters are invalid
+ */
+int utf8_put(s32 code, char **dst);
+
+/**
+ * utf8_utf16_strnlen() - length of a truncated utf-8 string after conversion
+ *			  to utf-16
+ *
+ * @src:		utf-8 string
+ * @count:		maximum number of code points to convert
+ * Return:		length in bytes after conversion to utf-16 without the
+ *			trailing \0. If an invalid UTF-8 sequence is hit one
+ *			word will be reserved for a replacement character.
+ */
+size_t utf8_utf16_strnlen(const char *src, size_t count);
+
+/**
+ * utf8_utf16_strlen() - length of a utf-8 string after conversion to utf-16
+ *
+ * @src:		utf-8 string
+ * Return:		length in bytes after conversion to utf-16 without the
+ *			trailing \0. -1 if the utf-8 string is not valid.
+ */
+#define utf8_utf16_strlen(a) utf8_utf16_strnlen((a), SIZE_MAX)
+
+/**
+ * utf8_utf16_strncpy() - copy utf-8 string to utf-16 string
+ *
+ * @dst:		destination buffer
+ * @src:		source buffer
+ * @count:		maximum number of code points to copy
+ * Return:		-1 if the input parameters are invalid
+ */
+int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count);
+
+/**
+ * utf8_utf16_strcpy() - copy utf-8 string to utf-16 string
+ *
+ * @dst:		destination buffer
+ * @src:		source buffer
+ * Return:		-1 if the input parameters are invalid
+ */
+#define utf8_utf16_strcpy(d, s) utf8_utf16_strncpy((d), (s), SIZE_MAX)
+
+/**
+ * utf16_get() - get next UTF-16 code point from buffer
+ *
+ * @src:		pointer to current word, updated to point to next word
+ * Return:		code point, or 0 for end of string, or -1 if no legal
+ *			code point is found. In case of an error src points to
+ *			the incorrect word.
+ */
+s32 utf16_get(const u16 **src);
+
+/**
+ * utf16_put() - write UTF-16 code point to buffer
+ *
+ * @code:		code point
+ * @dst:		pointer to destination buffer, updated to next position
+ * Return:		-1 if the input parameters are invalid
+ */
+int utf16_put(s32 code, u16 **dst);
+
+/**
+ * utf16_strnlen() - length of a truncated utf-16 string
+ *
+ * @src:		utf-16 string
+ * @count:		maximum number of code points to convert
+ * Return:		length in code points. If an invalid UTF-16 sequence is
+ *			hit one position will be reserved for a replacement
+ *			character.
+ */
+size_t utf16_strnlen(const u16 *src, size_t count);
+
+/**
+ * utf16_utf8_strnlen() - length of a truncated utf-16 string after conversion
+ *			  to utf-8
+ *
+ * @src:		utf-16 string
+ * @count:		maximum number of code points to convert
+ * Return:		length in bytes after conversion to utf-8 without the
+ *			trailing \0. If an invalid UTF-16 sequence is hit one
+ *			byte will be reserved for a replacement character.
+ */
+size_t utf16_utf8_strnlen(const u16 *src, size_t count);
+
+/**
+ * utf16_utf8_strlen() - length of a utf-16 string after conversion to utf-8
+ *
+ * @src:		utf-16 string
+ * Return:		length in bytes after conversion to utf-8 without the
+ *			trailing \0. -1 if the utf-16 string is not valid.
+ */
+#define utf16_utf8_strlen(a) utf16_utf8_strnlen((a), SIZE_MAX)
+
+/**
+ * utf16_utf8_strncpy() - copy utf-16 string to utf-8 string
+ *
+ * @dst:		destination buffer
+ * @src:		source buffer
+ * @count:		maximum number of code points to copy
+ * Return:		-1 if the input parameters are invalid
+ */
+int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count);
+
+/**
+ * utf16_utf8_strcpy() - copy utf-16 string to utf-8 string
+ *
+ * @dst:		destination buffer
+ * @src:		source buffer
+ * Return:		-1 if the input parameters are invalid
+ */
+#define utf16_utf8_strcpy(d, s) utf16_utf8_strncpy((d), (s), SIZE_MAX)
+
 /**
  * u16_strlen - count non-zero words
  *
lib/Makefile +3 -1
index 2fd32798a0..f169644850 100644
@@ -21,7 +21,9 @@ obj-$(CONFIG_OPTEE) += optee/
 obj-$(CONFIG_AES) += aes.o
 
 ifndef API_BUILD
-obj-$(CONFIG_EFI_LOADER) += charset.o
+ifneq ($(CONFIG_UT_UNICODE)$(CONFIG_EFI_LOADER),)
+obj-y += charset.o
+endif
 endif
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
lib/charset.c +240 -3

249 lines not on this page · raw message

Signature · 1 line
2.18.0
#11 lore raw

PATCH 3/15 lib: charset: utility functions for Unicode

Quoted 10 lines · Heinrich Schuchardt

utf8_get() - get next UTF-8 code point from buffer
utf8_put() - write UTF-8 code point to buffer utf8_utf16_strnlen() - length of a utf-8 string after conversion to utf-16 utf8_utf16_strncpy() - copy a utf-8 string to utf-16 utf16_get() - get next UTF-16 code point from buffer utf16_put() - write UTF-16 code point to buffer utf16_utf8_strnlen() - length of a utf-16 string after conversion to utf-8 utf16_utf8_strncpy() - copy a utf-16 string to utf-8

I can't promise that all the conversion logic is correct though ;).

Alex

#12 lore raw

PATCH 4/15 test: unit tests for Unicode functions

In reply to Heinrich Schuchardt

Provide unit tests for Unicode functions.

---
 MAINTAINERS           |   1 +
 include/test/suites.h |   3 +-
 test/Kconfig          |   8 +
 test/Makefile         |   1 +
 test/cmd_ut.c         |  14 +-
 test/unicode_ut.c     | 470 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 493 insertions(+), 4 deletions(-)
 create mode 100644 test/unicode_ut.c
MAINTAINERS +1 -0
index 51a1472cf8..a324139471 100644
@@ -374,6 +374,7 @@ F:	include/asm-generic/pe.h
 F:	lib/charset.c
 F:	lib/efi*/
 F:	test/py/tests/test_efi*
+F:	test/unicode_ut.c
 F:	cmd/bootefi.c
 F:	tools/file2include.c
 
include/test/suites.h +2 -1
index b5019a7cd2..8e4eac60eb 100644
@@ -23,10 +23,11 @@ struct unit_test;
 int cmd_ut_category(const char *name, struct unit_test *tests, int n_ents,
 		    int argc, char * const argv[]);
 
+int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
-int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 
 #endif /* __TEST_SUITES_H__ */
test/Kconfig +8 -0
index 3643761bc6..de16d179d0 100644
@@ -15,6 +15,14 @@ config UT_TIME
 	  problems. But if you are having problems with udelay() and the like,
 	  this is a good place to start.
 
+config UT_UNICODE
+	bool "Unit tests for Unicode functions"
+	depends on UNIT_TEST
+	default y
+	help
+	  Enables the 'ut unicode' command which tests that the functions for
+	  manipulating Unicode strings work correctly.
+
 source "test/dm/Kconfig"
 source "test/env/Kconfig"
 source "test/overlay/Kconfig"
test/Makefile +1 -0
index 1092011fdb..a5f52fd5ad 100644
@@ -8,4 +8,5 @@ obj-$(CONFIG_SANDBOX) += command_ut.o
 obj-$(CONFIG_SANDBOX) += compression.o
 obj-$(CONFIG_SANDBOX) += print_ut.o
 obj-$(CONFIG_UT_TIME) += time_ut.o
+obj-$(CONFIG_UT_UNICODE) += unicode_ut.o
 obj-$(CONFIG_$(SPL_)LOG) += log/
test/cmd_ut.c +11 -3
index 934a5a931b..d6a2593850 100644
@@ -49,6 +49,10 @@ static cmd_tbl_t cmd_ut_sub[] = {
 #ifdef CONFIG_UT_TIME
 	U_BOOT_CMD_MKENT(time, CONFIG_SYS_MAXARGS, 1, do_ut_time, "", ""),
 #endif
+#if defined(CONFIG_UT_UNICODE) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+	U_BOOT_CMD_MKENT(unicode, CONFIG_SYS_MAXARGS, 1, do_ut_unicode, "", ""),
+#endif
 #ifdef CONFIG_SANDBOX
 	U_BOOT_CMD_MKENT(compression, CONFIG_SYS_MAXARGS, 1, do_ut_compression,
 			 "", ""),
@@ -93,6 +97,9 @@ static int do_ut(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 #ifdef CONFIG_SYS_LONGHELP
 static char ut_help_text[] =
 	"all - execute all enabled tests\n"
+#ifdef CONFIG_SANDBOX
+	"ut compression - Test compressors and bootm decompression\n"
+#endif
 #ifdef CONFIG_UT_DM
 	"ut dm [test-name]\n"
 #endif
@@ -105,11 +112,12 @@ static char ut_help_text[] =
 #ifdef CONFIG_UT_TIME
 	"ut time - Very basic test of time functions\n"
 #endif
-#ifdef CONFIG_SANDBOX
-	"ut compression - Test compressors and bootm decompression\n"
+#if defined(CONFIG_UT_UNICODE) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+	"ut unicode - test Unicode functions\n"
 #endif
 	;
-#endif
+#endif /* CONFIG_SYS_LONGHELP */
 
 U_BOOT_CMD(
 	ut, CONFIG_SYS_MAXARGS, 1, do_ut,
test/unicode_ut.c new file +470 -0

470 lines not on this page · raw message

Signature · 1 line
2.18.0
#13 lore raw

PATCH 4/15 test: unit tests for Unicode functions

Quoted 47 lines · Heinrich Schuchardt

Provide unit tests for Unicode functions.

---
 MAINTAINERS           |   1 +
 include/test/suites.h |   3 +-
 test/Kconfig          |   8 +
 test/Makefile         |   1 +
 test/cmd_ut.c         |  14 +-
 test/unicode_ut.c     | 470 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 493 insertions(+), 4 deletions(-)
 create mode 100644 test/unicode_ut.c
MAINTAINERS +1 -0
index 51a1472cf8..a324139471 100644
@@ -374,6 +374,7 @@ F:	include/asm-generic/pe.h
 F:	lib/charset.c
 F:	lib/efi*/
 F:	test/py/tests/test_efi*
+F:	test/unicode_ut.c
 F:	cmd/bootefi.c
 F:	tools/file2include.c
 
include/test/suites.h +2 -1
index b5019a7cd2..8e4eac60eb 100644
@@ -23,10 +23,11 @@ struct unit_test;
 int cmd_ut_category(const char *name, struct unit_test *tests, int n_ents,
 		    int argc, char * const argv[]);
 
+int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
-int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 
 #endif /* __TEST_SUITES_H__ */
test/Kconfig +0 -0
index 3643761bc6..de16d179d0 100644

test/Kconfig config UT_TIME · line 18

Quoted 4 lines
test/Kconfig +1 -0
@@ -15,6 +15,14 @@ config UT_TIME
 	  problems. But if you are having problems with udelay() and the like,
 	  this is a good place to start.
 
+config UT_UNICODE

You probably want to move the hunk that actually builds charset.o with CONFIG_UT_UNICODE set to this patch as well ;).

Quoted 25 lines
test/Kconfig +7 -0
+	bool "Unit tests for Unicode functions"
+	depends on UNIT_TEST
+	default y
+	help
+	  Enables the 'ut unicode' command which tests that the functions for
+	  manipulating Unicode strings work correctly.
+
 source "test/dm/Kconfig"
 source "test/env/Kconfig"
 source "test/overlay/Kconfig"
test/Makefile +1 -0
index 1092011fdb..a5f52fd5ad 100644
@@ -8,4 +8,5 @@ obj-$(CONFIG_SANDBOX) += command_ut.o
 obj-$(CONFIG_SANDBOX) += compression.o
 obj-$(CONFIG_SANDBOX) += print_ut.o
 obj-$(CONFIG_UT_TIME) += time_ut.o
+obj-$(CONFIG_UT_UNICODE) += unicode_ut.o
 obj-$(CONFIG_$(SPL_)LOG) += log/
test/cmd_ut.c +0 -0
index 934a5a931b..d6a2593850 100644

test/cmd_ut.c static cmd_tbl_t cmd_ut_sub[] = { · line 53

Quoted 5 lines
test/cmd_ut.c +2 -0
@@ -49,6 +49,10 @@ static cmd_tbl_t cmd_ut_sub[] = {
 #ifdef CONFIG_UT_TIME
 	U_BOOT_CMD_MKENT(time, CONFIG_SYS_MAXARGS, 1, do_ut_time, "", ""),
 #endif
+#if defined(CONFIG_UT_UNICODE) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)

CONFIG_IS_ENABLED()

Alex

#14 lore raw

PATCH 4/15 test: unit tests for Unicode functions

Quoted 53 lines · Alexander Graf
Quoted 50 lines · Heinrich Schuchardt

Provide unit tests for Unicode functions.

---
 MAINTAINERS           |   1 +
 include/test/suites.h |   3 +-
 test/Kconfig          |   8 +
 test/Makefile         |   1 +
 test/cmd_ut.c         |  14 +-
 test/unicode_ut.c     | 470 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 493 insertions(+), 4 deletions(-)
 create mode 100644 test/unicode_ut.c
MAINTAINERS +1 -0
index 51a1472cf8..a324139471 100644
@@ -374,6 +374,7 @@ F:	include/asm-generic/pe.h
 F:	lib/charset.c
 F:	lib/efi*/
 F:	test/py/tests/test_efi*
+F:	test/unicode_ut.c
 F:	cmd/bootefi.c
 F:	tools/file2include.c
 
include/test/suites.h +2 -1
index b5019a7cd2..8e4eac60eb 100644
@@ -23,10 +23,11 @@ struct unit_test;
 int cmd_ut_category(const char *name, struct unit_test *tests, int n_ents,
 		    int argc, char * const argv[]);
 
+int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
-int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 
 #endif /* __TEST_SUITES_H__ */
test/Kconfig +0 -0
index 3643761bc6..de16d179d0 100644
@@ -15,6 +15,14 @@ config UT_TIME
 	  problems. But if you are having problems with udelay() and the like,
 	  this is a good place to start.
 
Quoted 4 lines

test/Kconfig config UT_TIME · line 18

Quoted 1 line
test/Kconfig +1 -0
+config UT_UNICODE

You probably want to move the hunk that actually builds charset.o with CONFIG_UT_UNICODE set to this patch as well ;).

Yes there is a bit in patch "lib: charset: utility functions for Unicode" that could move to this patch.

Quoted 25 lines
Quoted 25 lines
test/Kconfig +7 -0
+	bool "Unit tests for Unicode functions"
+	depends on UNIT_TEST
+	default y
+	help
+	  Enables the 'ut unicode' command which tests that the functions for
+	  manipulating Unicode strings work correctly.
+
 source "test/dm/Kconfig"
 source "test/env/Kconfig"
 source "test/overlay/Kconfig"
test/Makefile +1 -0
index 1092011fdb..a5f52fd5ad 100644
@@ -8,4 +8,5 @@ obj-$(CONFIG_SANDBOX) += command_ut.o
 obj-$(CONFIG_SANDBOX) += compression.o
 obj-$(CONFIG_SANDBOX) += print_ut.o
 obj-$(CONFIG_UT_TIME) += time_ut.o
+obj-$(CONFIG_UT_UNICODE) += unicode_ut.o
 obj-$(CONFIG_$(SPL_)LOG) += log/
test/cmd_ut.c +0 -0
index 934a5a931b..d6a2593850 100644
Quoted 8 lines

test/cmd_ut.c static cmd_tbl_t cmd_ut_sub[] = { · line 53

Quoted 6 lines
test/cmd_ut.c +2 -0
@@ -49,6 +49,10 @@ static cmd_tbl_t cmd_ut_sub[] = {
 #ifdef CONFIG_UT_TIME
 	U_BOOT_CMD_MKENT(time, CONFIG_SYS_MAXARGS, 1, do_ut_time, "", ""),
 #endif
+#if defined(CONFIG_UT_UNICODE) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)

CONFIG_IS_ENABLED()

ok

Heinrich.

Quoted 3 lines

Alex

#15 lore raw

PATCH 5/15 lib: vsprintf: correct printing of Unicode strings

In reply to Heinrich Schuchardt

The width and precision of the printf() function refer to the number of characters not to the number of bytes printed.

---
 lib/vsprintf.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)
lib/vsprintf.c +13 -9
index a07128ad96..b7eb9d5f5e 100644
@@ -280,18 +280,22 @@ static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
 	u16 *str = s ? s : L"<NULL>";
-	int utf16_len = u16_strnlen(str, precision);
-	u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
-	int utf8_len, i;
-
-	utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8;
+	ssize_t i, len = utf16_strnlen(str, precision);
 
 	if (!(flags & LEFT))
-		while (utf8_len < field_width--)
+		for (; len < field_width; --field_width)
 			ADDCH(buf, ' ');
-	for (i = 0; i < utf8_len; ++i)
-		ADDCH(buf, utf8[i]);
-	while (utf8_len < field_width--)
+	for (i = 0; i < len; ++i) {
+		s32 code = utf16_get((const u16 **)&str);
+
+		if (code < 0) {
+			code = '?';
+			if (*str)
+				++str;
+		}
+		utf8_put(code, &buf);
+	}
+	for (; i < field_width; --field_width)
 		ADDCH(buf, ' ');
 	return buf;
 }
Signature · 1 line
2.18.0
#16 lore raw

PATCH 5/15 lib: vsprintf: correct printing of Unicode strings

Quoted 29 lines · Heinrich Schuchardt

The width and precision of the printf() function refer to the number of characters not to the number of bytes printed.

---
 lib/vsprintf.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)
lib/vsprintf.c +2 -8
index a07128ad96..b7eb9d5f5e 100644
@@ -280,18 +280,22 @@ static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
 	u16 *str = s ? s : L"<NULL>";
-	int utf16_len = u16_strnlen(str, precision);
-	u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
-	int utf8_len, i;
-
-	utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8;
+	ssize_t i, len = utf16_strnlen(str, precision);
 
 	if (!(flags & LEFT))
-		while (utf8_len < field_width--)
+		for (; len < field_width; --field_width)
 			ADDCH(buf, ' ');
-	for (i = 0; i < utf8_len; ++i)
-		ADDCH(buf, utf8[i]);

lib/vsprintf.c static char *string16(char *buf, char *end, u16 *s, int field_width, · line 296

Quoted 10 lines
lib/vsprintf.c +9 -1
-	while (utf8_len < field_width--)
+	for (i = 0; i < len; ++i) {
+		s32 code = utf16_get((const u16 **)&str);
+
+		if (code < 0) {
+			code = '?';
+			if (*str)
+				++str;
+		}
+		utf8_put(code, &buf);

Can you introduce or reuse a strcpy() helper in charset.c for this? That way the compiler has the chance to inline utf16_get() and utf8_put() and make the function fast.

Alex

#17 lore raw

PATCH 5/15 lib: vsprintf: correct printing of Unicode strings

Quoted 38 lines · Alexander Graf
Quoted 35 lines · Heinrich Schuchardt

The width and precision of the printf() function refer to the number of characters not to the number of bytes printed.

---
 lib/vsprintf.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)
lib/vsprintf.c +7 -9
index a07128ad96..b7eb9d5f5e 100644
@@ -280,18 +280,22 @@ static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
 	u16 *str = s ? s : L"<NULL>";
-	int utf16_len = u16_strnlen(str, precision);
-	u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
-	int utf8_len, i;
-
-	utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8;
+	ssize_t i, len = utf16_strnlen(str, precision);
 
 	if (!(flags & LEFT))
-		while (utf8_len < field_width--)
+		for (; len < field_width; --field_width)
 			ADDCH(buf, ' ');
-	for (i = 0; i < utf8_len; ++i)
-		ADDCH(buf, utf8[i]);
-	while (utf8_len < field_width--)
+	for (i = 0; i < len; ++i) {
+		s32 code = utf16_get((const u16 **)&str);
+
+		if (code < 0) {
+			code = '?';
Quoted 8 lines

lib/vsprintf.c static char *string16(char *buf, char *end, u16 *s, int field_width, · line 296

Quoted 4 lines
lib/vsprintf.c +4 -0
+			if (*str)
+				++str;
+		}
+		utf8_put(code, &buf);

Can you introduce or reuse a strcpy() helper in charset.c for this? That way the compiler has the chance to inline utf16_get() and utf8_put() and make the function fast.

strcpy() works on bytes not on multi-byte utf-8 characters. So it is unclear to me how I should make use of strcpy() here.

Of cause we could define utf8_put() and utf8_get() as inline function. But that would increase code size. Is this what you would prefer? I would guess that the serial interface is always the slowest part of text output anyway.

Regards

Heinrich

Quoted 4 lines

Alex

#18 lore raw

PATCH 5/15 lib: vsprintf: correct printing of Unicode strings

Quoted 48 lines · Heinrich Schuchardt
Quoted 38 lines · Alexander Graf
Quoted 35 lines · Heinrich Schuchardt

The width and precision of the printf() function refer to the number of characters not to the number of bytes printed.

---
 lib/vsprintf.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)
lib/vsprintf.c +7 -9
index a07128ad96..b7eb9d5f5e 100644
@@ -280,18 +280,22 @@ static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
 	u16 *str = s ? s : L"<NULL>";
-	int utf16_len = u16_strnlen(str, precision);
-	u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
-	int utf8_len, i;
-
-	utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8;
+	ssize_t i, len = utf16_strnlen(str, precision);
 
 	if (!(flags & LEFT))
-		while (utf8_len < field_width--)
+		for (; len < field_width; --field_width)
 			ADDCH(buf, ' ');
-	for (i = 0; i < utf8_len; ++i)
-		ADDCH(buf, utf8[i]);
-	while (utf8_len < field_width--)
+	for (i = 0; i < len; ++i) {
+		s32 code = utf16_get((const u16 **)&str);
+
+		if (code < 0) {
+			code = '?';
Quoted 8 lines

lib/vsprintf.c static char *string16(char *buf, char *end, u16 *s, int field_width, · line 296

Quoted 4 lines
lib/vsprintf.c +4 -0
+			if (*str)
+				++str;
+		}
+		utf8_put(code, &buf);

Can you introduce or reuse a strcpy() helper in charset.c for this? That way the compiler has the chance to inline utf16_get() and utf8_put() and make the function fast.

Quoted 2 lines

strcpy() works on bytes not on multi-byte utf-8 characters. So it is unclear to me how I should make use of strcpy() here.

What I was trying to imply is that what you're doing here is very similar to utf8_utf16_strncpy(). Maybe we can reuse the same function or at least something very similar.

Quoted 4 lines

Of cause we could define utf8_put() and utf8_get() as inline function. But that would increase code size. Is this what you would prefer? I would guess that the serial interface is always the slowest part of text output anyway.

Real serial output is definitely orders of magnitude slower, I agree. But if we can make the code easier to read along the way I'm all for it ;).

I think what it boils down to is that I'd prefer if we keep utf{8,16}_{get,put}() as local to charset.c as we can and instead put slightly higher level wrappers around them, like you did for pretty much everything else.

Alex

#19 lore raw

PATCH 6/15 test: test printing Unicode

In reply to Heinrich Schuchardt

Test printing of Unicode strings

---
 test/unicode_ut.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
test/unicode_ut.c +37 -0
index 29316606c4..8e8c4d189e 100644
@@ -34,6 +34,42 @@ static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89,
 static const char d4[] = {0xf0, 0x90, 0x92, 0x8d, 0xf0, 0x90, 0x92, 0x96,
 			  0xf0, 0x90, 0x92, 0x87, 0x00};
 
+static int ut_string16(void)
+{
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+	char buf[20];
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%8.6ls", c2);
+	if (buf[1] != ' ')
+		return -1;
+	if (strncmp(&buf[2], d2, 7))
+		return -1;
+	if (buf[9])
+		return -1;
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%8.6ls", c4);
+	if (buf[4] != ' ')
+		return -1;
+	if (strncmp(&buf[5], d4, 12))
+		return -1;
+	if (buf[17])
+		return -1;
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%-8.2ls", c4);
+	if (strncmp(buf, d4, 8))
+		return -1;
+	if (buf[8] != ' ')
+		return -1;
+	if (buf[14])
+		return -1;
+#endif
+	return 0;
+}
+
 static int ut_utf8_get(void)
 {
 	const char *s;
@@ -451,6 +487,7 @@ int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int ret = 0;
 
+	ret |= ut_string16();
 	ret |= ut_utf8_get();
 	ret |= ut_utf8_put();
 	ret |= ut_utf8_utf16_strlen();
Signature · 1 line
2.18.0
#20 lore raw

PATCH 6/15 test: test printing Unicode

Quoted 38 lines · Heinrich Schuchardt

Test printing of Unicode strings

---
 test/unicode_ut.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
test/unicode_ut.c +23 -0
index 29316606c4..8e8c4d189e 100644
@@ -34,6 +34,42 @@ static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89,
 static const char d4[] = {0xf0, 0x90, 0x92, 0x8d, 0xf0, 0x90, 0x92, 0x96,
 			  0xf0, 0x90, 0x92, 0x87, 0x00};
 
+static int ut_string16(void)
+{
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+	char buf[20];
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%8.6ls", c2);
+	if (buf[1] != ' ')
+		return -1;
+	if (strncmp(&buf[2], d2, 7))
+		return -1;
+	if (buf[9])
+		return -1;
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%8.6ls", c4);
+	if (buf[4] != ' ')
+		return -1;
+	if (strncmp(&buf[5], d4, 12))
+		return -1;
+	if (buf[17])
+		return -1;

test/unicode_ut.c static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89, · line 69

Quoted 10 lines
test/unicode_ut.c +10 -0
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%-8.2ls", c4);
+	if (strncmp(buf, d4, 8))
+		return -1;
+	if (buf[8] != ' ')
+		return -1;
+	if (buf[14])
+		return -1;
+#endif

Does this check the illegal character '?' case as well?

Alex

#21 lore raw

PATCH 6/15 test: test printing Unicode

Quoted 45 lines · Alexander Graf
Quoted 42 lines · Heinrich Schuchardt

Test printing of Unicode strings

---
 test/unicode_ut.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
test/unicode_ut.c +27 -0
index 29316606c4..8e8c4d189e 100644
@@ -34,6 +34,42 @@ static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89,
 static const char d4[] = {0xf0, 0x90, 0x92, 0x8d, 0xf0, 0x90, 0x92, 0x96,
 			  0xf0, 0x90, 0x92, 0x87, 0x00};
 
+static int ut_string16(void)
+{
+#if defined(CONFIG_EFI_LOADER) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+	char buf[20];
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%8.6ls", c2);
+	if (buf[1] != ' ')
+		return -1;
+	if (strncmp(&buf[2], d2, 7))
+		return -1;
+	if (buf[9])
+		return -1;
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%8.6ls", c4);
+	if (buf[4] != ' ')
+		return -1;
+	if (strncmp(&buf[5], d4, 12))
+		return -1;
+	if (buf[17])
+		return -1;
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%-8.2ls", c4);
+	if (strncmp(buf, d4, 8))
Quoted 8 lines

test/unicode_ut.c static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89, · line 69

Quoted 6 lines
test/unicode_ut.c +6 -0
+		return -1;
+	if (buf[8] != ' ')
+		return -1;
+	if (buf[14])
+		return -1;
+#endif

Does this check the illegal character '?' case as well?

No. I can add this.

Best regards

Heinrich

Quoted 4 lines

Alex

#22 lore raw

PATCH 7/15 efi_loader: remove limit on variable length

In reply to Heinrich Schuchardt

The EFI spec does not provide a length limit for variables.

---
 lib/efi_loader/efi_variable.c | 52 ++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 22 deletions(-)
lib/efi_loader/efi_variable.c +30 -22
index 770c67abb9..495738884b 100644
@@ -44,10 +44,7 @@
  * converted to utf16?
  */
 
-#define MAX_VAR_NAME 31
-#define MAX_NATIVE_VAR_NAME \
-	(strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \
-		(MAX_VAR_NAME * MAX_UTF8_PER_UTF16))
+#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_"))
 
 static int hex(int ch)
 {
@@ -101,18 +98,20 @@ static char *mem2hex(char *hexstr, const u8 *mem, int count)
 	return hexstr;
 }
 
-static efi_status_t efi_to_native(char *native, u16 *variable_name,
+static efi_status_t efi_to_native(char **native, const u16 *variable_name,
 				  efi_guid_t *vendor)
 {
 	size_t len;
+	char *pos;
 
-	len = u16_strlen((u16 *)variable_name);
-	if (len >= MAX_VAR_NAME)
-		return EFI_DEVICE_ERROR;
+	len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
+	*native = malloc(len);
+	if (!*native)
+		return EFI_OUT_OF_RESOURCES;
 
-	native += sprintf(native, "efi_%pUl_", vendor);
-	native  = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len);
-	*native = '\0';
+	pos = *native;
+	pos += sprintf(pos, "efi_%pUl_", vendor);
+	utf16_utf8_strcpy(&pos, variable_name);
 
 	return EFI_SUCCESS;
 }
@@ -168,7 +167,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor,
 				     u32 *attributes, efi_uintn_t *data_size,
 				     void *data)
 {
-	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	char *native_name;
 	efi_status_t ret;
 	unsigned long in_size;
 	const char *val, *s;
@@ -180,13 +179,14 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor,
 	if (!variable_name || !vendor || !data_size)
 		return EFI_EXIT(EFI_INVALID_PARAMETER);
 
-	ret = efi_to_native(native_name, variable_name, vendor);
+	ret = efi_to_native(&native_name, variable_name, vendor);
 	if (ret)
 		return EFI_EXIT(ret);
 
 	debug("%s: get '%s'\n", __func__, native_name);
 
 	val = env_get(native_name);
+	free(native_name);
 	if (!val)
 		return EFI_EXIT(EFI_NOT_FOUND);
 
@@ -256,35 +256,41 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor,
 				     u32 attributes, efi_uintn_t data_size,
 				     void *data)
 {
-	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	char *native_name = NULL, *val = NULL, *s;
 	efi_status_t ret = EFI_SUCCESS;
-	char *val, *s;
 	u32 attr;
 
 	EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
 		  data_size, data);
 
-	if (!variable_name || !vendor)
-		return EFI_EXIT(EFI_INVALID_PARAMETER);
+	if (!variable_name || !vendor) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
 
-	ret = efi_to_native(native_name, variable_name, vendor);
+	ret = efi_to_native(&native_name, variable_name, vendor);
 	if (ret)
-		return EFI_EXIT(ret);
+		goto out;
 
 #define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)
 
 	if ((data_size == 0) || !(attributes & ACCESS_ATTR)) {
 		/* delete the variable: */
 		env_set(native_name, NULL);
-		return EFI_EXIT(EFI_SUCCESS);
+		ret = EFI_SUCCESS;
+		goto out;
 	}
 
 	val = env_get(native_name);
 	if (val) {
 		parse_attr(val, &attr);
 
-		if (attr & READ_ONLY)
-			return EFI_EXIT(EFI_WRITE_PROTECTED);
+		if (attr & READ_ONLY) {
+			/* We should not free val */
+			val = NULL;
+			ret = EFI_WRITE_PROTECTED;
+			goto out;
+		}
 	}
 
 	val = malloc(2 * data_size + strlen("{ro,run,boot}(blob)") + 1);
@@ -320,6 +326,8 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor,
 	if (env_set(native_name, val))
 		ret = EFI_DEVICE_ERROR;
 
+out:
+	free(native_name);
 	free(val);
 
 	return EFI_EXIT(ret);
Signature · 1 line
2.18.0
#23 lore raw

PATCH 7/15 efi_loader: remove limit on variable length

Quoted 52 lines · Heinrich Schuchardt

The EFI spec does not provide a length limit for variables.

---
 lib/efi_loader/efi_variable.c | 52 ++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 22 deletions(-)
lib/efi_loader/efi_variable.c +10 -11
index 770c67abb9..495738884b 100644
@@ -44,10 +44,7 @@
  * converted to utf16?
  */
 
-#define MAX_VAR_NAME 31
-#define MAX_NATIVE_VAR_NAME \
-	(strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \
-		(MAX_VAR_NAME * MAX_UTF8_PER_UTF16))
+#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_"))
 
 static int hex(int ch)
 {
@@ -101,18 +98,20 @@ static char *mem2hex(char *hexstr, const u8 *mem, int count)
 	return hexstr;
 }
 
-static efi_status_t efi_to_native(char *native, u16 *variable_name,
+static efi_status_t efi_to_native(char **native, const u16 *variable_name,
 				  efi_guid_t *vendor)
 {
 	size_t len;
+	char *pos;
 
-	len = u16_strlen((u16 *)variable_name);
-	if (len >= MAX_VAR_NAME)
-		return EFI_DEVICE_ERROR;
+	len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
+	*native = malloc(len);
+	if (!*native)
+		return EFI_OUT_OF_RESOURCES;
 
-	native += sprintf(native, "efi_%pUl_", vendor);
-	native  = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len);
-	*native = '\0';
+	pos = *native;
+	pos += sprintf(pos, "efi_%pUl_", vendor);
+	utf16_utf8_strcpy(&pos, variable_name);
 
 	return EFI_SUCCESS;
 }

lib/efi_loader/efi_variable.c efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor, · line 170

Quoted 5 lines
lib/efi_loader/efi_variable.c +1 -1
@@ -168,7 +167,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor,
 				     u32 *attributes, efi_uintn_t *data_size,
 				     void *data)
 {
-	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	char *native_name;

I think you want to predefine this to = NULL to make sure that an error path doesn't give you uninitialized values on free().

Alex

#24 lore raw

PATCH 7/15 efi_loader: remove limit on variable length

Quoted 52 lines · Alexander Graf
Quoted 49 lines · Heinrich Schuchardt

The EFI spec does not provide a length limit for variables.

---
 lib/efi_loader/efi_variable.c | 52 ++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 22 deletions(-)
lib/efi_loader/efi_variable.c +10 -11
index 770c67abb9..495738884b 100644
@@ -44,10 +44,7 @@
  * converted to utf16?
  */
 
-#define MAX_VAR_NAME 31
-#define MAX_NATIVE_VAR_NAME \
-	(strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \
-		(MAX_VAR_NAME * MAX_UTF8_PER_UTF16))
+#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_"))
 
 static int hex(int ch)
 {
@@ -101,18 +98,20 @@ static char *mem2hex(char *hexstr, const u8 *mem, int count)
 	return hexstr;
 }
 
-static efi_status_t efi_to_native(char *native, u16 *variable_name,
+static efi_status_t efi_to_native(char **native, const u16 *variable_name,
 				  efi_guid_t *vendor)
 {
 	size_t len;
+	char *pos;
 
-	len = u16_strlen((u16 *)variable_name);
-	if (len >= MAX_VAR_NAME)
-		return EFI_DEVICE_ERROR;
+	len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
+	*native = malloc(len);
+	if (!*native)
+		return EFI_OUT_OF_RESOURCES;
 
-	native += sprintf(native, "efi_%pUl_", vendor);
-	native  = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len);
-	*native = '\0';
+	pos = *native;
+	pos += sprintf(pos, "efi_%pUl_", vendor);
+	utf16_utf8_strcpy(&pos, variable_name);
 
Quoted 11 lines

lib/efi_loader/efi_variable.c efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor, · line 170

Quoted 8 lines
lib/efi_loader/efi_variable.c +1 -1
 	return EFI_SUCCESS;
 }
@@ -168,7 +167,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor,
 				     u32 *attributes, efi_uintn_t *data_size,
 				     void *data)
 {
-	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	char *native_name;

I think you want to predefine this to = NULL to make sure that an error path doesn't give you uninitialized values on free().

efi_to_native() returns EFI_OUT_OF_RESOURCES if the pointer cannot be assigned and the return value is checked. So how should I reach free(native_name) in this case?

Best regards

Heinrich

Quoted 4 lines

Alex

#25 lore raw

PATCH 7/15 efi_loader: remove limit on variable length

Quoted 65 lines · Heinrich Schuchardt
Quoted 52 lines · Alexander Graf
Quoted 49 lines · Heinrich Schuchardt

The EFI spec does not provide a length limit for variables.

---
 lib/efi_loader/efi_variable.c | 52 ++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 22 deletions(-)
lib/efi_loader/efi_variable.c +10 -11
index 770c67abb9..495738884b 100644
@@ -44,10 +44,7 @@
  * converted to utf16?
  */
 
-#define MAX_VAR_NAME 31
-#define MAX_NATIVE_VAR_NAME \
-	(strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \
-		(MAX_VAR_NAME * MAX_UTF8_PER_UTF16))
+#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_"))
 
 static int hex(int ch)
 {
@@ -101,18 +98,20 @@ static char *mem2hex(char *hexstr, const u8 *mem, int count)
 	return hexstr;
 }
 
-static efi_status_t efi_to_native(char *native, u16 *variable_name,
+static efi_status_t efi_to_native(char **native, const u16 *variable_name,
 				  efi_guid_t *vendor)
 {
 	size_t len;
+	char *pos;
 
-	len = u16_strlen((u16 *)variable_name);
-	if (len >= MAX_VAR_NAME)
-		return EFI_DEVICE_ERROR;
+	len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
+	*native = malloc(len);
+	if (!*native)
+		return EFI_OUT_OF_RESOURCES;
 
-	native += sprintf(native, "efi_%pUl_", vendor);
-	native  = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len);
-	*native = '\0';
+	pos = *native;
+	pos += sprintf(pos, "efi_%pUl_", vendor);
+	utf16_utf8_strcpy(&pos, variable_name);
 
Quoted 11 lines

lib/efi_loader/efi_variable.c efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor, · line 170

Quoted 8 lines
lib/efi_loader/efi_variable.c +1 -1
 	return EFI_SUCCESS;
 }
@@ -168,7 +167,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor,
 				     u32 *attributes, efi_uintn_t *data_size,
 				     void *data)
 {
-	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	char *native_name;

I think you want to predefine this to = NULL to make sure that an error path doesn't give you uninitialized values on free().

Quoted 3 lines

efi_to_native() returns EFI_OUT_OF_RESOURCES if the pointer cannot be assigned and the return value is checked. So how should I reach free(native_name) in this case?

True, convinced. I thought I saw a case where you could hit an uninitialized native_name variable, but now I can't see it anymore.

Alex

#26 lore raw

PATCH 8/15 efi_loader: don't use unlimited stack as buffer

In reply to Heinrich Schuchardt

The length of a string printed to the console by the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL is not limited by the UEFI spec. Hence should not allocate a buffer for it on the stack.

---
 lib/efi_loader/efi_console.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
lib/efi_loader/efi_console.c +13 -7
index f3d612880c..f5f3f256dd 100644
@@ -111,16 +111,21 @@ static efi_status_t EFIAPI efi_cout_output_string(
 {
 	struct simple_text_output_mode *con = &efi_con_mode;
 	struct cout_mode *mode = &efi_cout_modes[con->mode];
-
-	EFI_ENTRY("%p, %p", this, string);
-
-	unsigned int n16 = u16_strlen(string);
-	char buf[MAX_UTF8_PER_UTF16 * n16 + 1];
+	char *buf, *pos;
 	u16 *p;
+	efi_status_t ret = EFI_SUCCESS;
 
-	*utf16_to_utf8((u8 *)buf, string, n16) = '\0';
+	EFI_ENTRY("%p, %p", this, string);
 
+	buf = malloc(utf16_utf8_strlen(string) + 1);
+	if (!buf) {
+		ret = EFI_OUT_OF_RESOURCES;
+		goto out;
+	}
+	pos = buf;
+	utf16_utf8_strcpy(&pos, string);
 	fputs(stdout, buf);
+	free(buf);
 
 	/*
 	 * Update the cursor position.
@@ -158,7 +163,8 @@ static efi_status_t EFIAPI efi_cout_output_string(
 		con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
 	}
 
-	return EFI_EXIT(EFI_SUCCESS);
+out:
+	return EFI_EXIT(ret);
 }
 
 static efi_status_t EFIAPI efi_cout_test_string(
Signature · 1 line
2.18.0
#28 lore raw

PATCH 9/15 efi_loader: buffer size for load options

In reply to Heinrich Schuchardt

The number of bytes in an utf-8 string is an upper limit for the number of words in the equivalent utf-16 string. In so far the inumbant coding works correctly. For non-ASCII characters the utf-16 string is shorter. With the patch only the necessary buffer size is allocated for the load options.

---
 cmd/bootefi.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
cmd/bootefi.c +4 -2
index b60c151fb4..708113b16e 100644
@@ -116,18 +116,20 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info,
 {
 	size_t size;
 	const char *env = env_get(env_var);
+	u16 *pos;
 
 	loaded_image_info->load_options = NULL;
 	loaded_image_info->load_options_size = 0;
 	if (!env)
 		return;
-	size = strlen(env) + 1;
+	size = utf8_utf16_strlen(env) + 1;
 	loaded_image_info->load_options = calloc(size, sizeof(u16));
 	if (!loaded_image_info->load_options) {
 		printf("ERROR: Out of memory\n");
 		return;
 	}
-	utf8_to_utf16(loaded_image_info->load_options, (u8 *)env, size);
+	pos = loaded_image_info->load_options;
+	utf8_utf16_strcpy(&pos, env);
 	loaded_image_info->load_options_size = size * 2;
 }
 
Signature · 1 line
2.18.0
#29 lore raw

PATCH 9/15 efi_loader: buffer size for load options

Quoted 6 lines · Heinrich Schuchardt

The number of bytes in an utf-8 string is an upper limit for the number of words in the equivalent utf-16 string. In so far the inumbant coding works correctly. For non-ASCII characters the utf-16 string is shorter. With the patch only the necessary buffer size is allocated for the load options.

Alex

#30 lore raw

PATCH 10/15 lib: charset: remove obsolete functions

In reply to Heinrich Schuchardt

Remove functions:
- utf8_to_utf16()
- utf16_strcpy()
- utf16_strdup()

---
 include/charset.h | 23 --------------
 lib/charset.c     | 79 -----------------------------------------------
 2 files changed, 102 deletions(-)
include/charset.h +0 -23
index 81e31d1b26..1c0976dde6 100644
@@ -161,16 +161,6 @@ size_t u16_strlen(const u16 *in);
  */
 size_t u16_strnlen(const u16 *in, size_t count);
 
-/**
- * utf16_strcpy() - UTF16 equivalent of strcpy()
- */
-uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src);
-
-/**
- * utf16_strdup() - UTF16 equivalent of strdup()
- */
-uint16_t *utf16_strdup(const uint16_t *s);
-
 /**
  * utf16_to_utf8() - Convert an utf16 string to utf8
  *
@@ -187,17 +177,4 @@ uint16_t *utf16_strdup(const uint16_t *s);
  */
 uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size);
 
-/**
- * utf8_to_utf16() - Convert an utf8 string to utf16
- *
- * Converts up to 'size' characters of the utf16 string 'src' to utf8
- * written to the 'dest' buffer. Stops at 0x00.
- *
- * @dest   the destination buffer to write the utf8 characters
- * @src    the source utf16 string
- * @size   maximum number of utf16 characters to convert
- * @return the pointer to the first unwritten byte in 'dest'
- */
-uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size);
-
 #endif /* __CHARSET_H_ */
lib/charset.c +0 -79

88 lines not on this page · raw message

Signature · 1 line
2.18.0
#31 lore raw

PATCH 11/15 efi_loader: capitalization table

In reply to Heinrich Schuchardt

This patch provides a define to initialize a table that maps lower to capital letters for Unicode code point 0x0000 - 0xffff.

---
 MAINTAINERS              |    1 +
 include/capitalization.h | 1909 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 1910 insertions(+)
 create mode 100644 include/capitalization.h
MAINTAINERS +1 -0
index a324139471..0a543309f2 100644
@@ -368,6 +368,7 @@ F:	doc/DocBook/efi.tmpl
 F:	doc/README.uefi
 F:	doc/README.iscsi
 F:	Documentation/efi.rst
+F:	include/capitalization.h
 F:	include/efi*
 F:	include/pe.h
 F:	include/asm-generic/pe.h
include/capitalization.h new file +1909 -0

1,909 lines not on this page · raw message

Signature · 1 line
2.18.0
#32 lore raw

PATCH 11/15 efi_loader: capitalization table

Quoted 30 lines · Heinrich Schuchardt

This patch provides a define to initialize a table that maps lower to capital letters for Unicode code point 0x0000 - 0xffff.

---
 MAINTAINERS              |    1 +
 include/capitalization.h | 1909 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 1910 insertions(+)
 create mode 100644 include/capitalization.h
MAINTAINERS +1 -0
index a324139471..0a543309f2 100644
@@ -368,6 +368,7 @@ F:	doc/DocBook/efi.tmpl
 F:	doc/README.uefi
 F:	doc/README.iscsi
 F:	Documentation/efi.rst
+F:	include/capitalization.h
 F:	include/efi*
 F:	include/pe.h
 F:	include/asm-generic/pe.h
include/capitalization.h new file +2 -0
new file mode 100644
index 0000000000..50d5108f98
@@ -0,0 +1,1909 @@
+/* SPDX-License-Identifier: Unicode-DFS-2016 */
+/*

include/capitalization.h line 12

Quoted 10 lines
include/capitalization.h new file +10 -0
+ * Correspondence table for small and capital Unicode letters in the range of
+ * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt
+ */
+
+struct capitalization_table {
+	u16 upper;
+	u16 lower;
+};
+
+#define UNICODE_CAPITALIZATION_TABLE { \

Ugh, that is a *lot* of data. How much does the binary size grow with the table compiled in?

Is there any slightly more sophisticated pattern in the table maybe that we could just express as code? Would that turn out smaller maybe?

Alex

Quoted 7 lines
include/capitalization.h new file +7 -0
+	{ 0x0531, /* ARMENIAN CAPITAL LETTER AYB */ \
+	  0x0561, /* ARMENIAN SMALL LETTER AYB */ }, \
+	{ 0x0532, /* ARMENIAN CAPITAL LETTER BEN */ \
+	  0x0562, /* ARMENIAN SMALL LETTER BEN */ }, \
+	{ 0x053E, /* ARMENIAN CAPITAL LETTER CA */ \
+	  0x056E, /* ARMENIAN SMALL LETTER CA */ }, \
+	{ 0x0549, /* ARMENIAN CAPITAL LETTER CHA */ \

[...]

#33 lore raw

PATCH 11/15 efi_loader: capitalization table

Quoted 47 lines · Alexander Graf
Quoted 30 lines · Heinrich Schuchardt

This patch provides a define to initialize a table that maps lower to capital letters for Unicode code point 0x0000 - 0xffff.

---
 MAINTAINERS              |    1 +
 include/capitalization.h | 1909 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 1910 insertions(+)
 create mode 100644 include/capitalization.h
MAINTAINERS +1 -0
index a324139471..0a543309f2 100644
@@ -368,6 +368,7 @@ F:	doc/DocBook/efi.tmpl
 F:	doc/README.uefi
 F:	doc/README.iscsi
 F:	Documentation/efi.rst
+F:	include/capitalization.h
 F:	include/efi*
 F:	include/pe.h
 F:	include/asm-generic/pe.h
include/capitalization.h new file +2 -0
new file mode 100644
index 0000000000..50d5108f98
@@ -0,0 +1,1909 @@
+/* SPDX-License-Identifier: Unicode-DFS-2016 */
+/*

include/capitalization.h line 12

Quoted 10 lines
include/capitalization.h new file +10 -0
+ * Correspondence table for small and capital Unicode letters in the range of
+ * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt
+ */
+
+struct capitalization_table {
+	u16 upper;
+	u16 lower;
+};
+
+#define UNICODE_CAPITALIZATION_TABLE { \

Ugh, that is a *lot* of data. How much does the binary size grow with the table compiled in?

Quoted 2 lines

Is there any slightly more sophisticated pattern in the table maybe that we could just express as code? Would that turn out smaller maybe?

This is 3792 bytes of data. Unicode capitalization is quite random in arranging lower and upper letters.

We could resort to zlib or gzip. But these libraries are not built by default.

Most urgently we will need the capitalization table for generating and checking short FAT filenames, so we could create a configuration switch that would reduce this table to codepage 437 or codepage 1250 letters depending on the chosen native character set.

In EDK2 I only found code for codepage 1250.

Best regards

Heinrich

Quoted 14 lines

Alex

Quoted 7 lines
include/capitalization.h new file +7 -0
+	{ 0x0531, /* ARMENIAN CAPITAL LETTER AYB */ \
+	  0x0561, /* ARMENIAN SMALL LETTER AYB */ }, \
+	{ 0x0532, /* ARMENIAN CAPITAL LETTER BEN */ \
+	  0x0562, /* ARMENIAN SMALL LETTER BEN */ }, \
+	{ 0x053E, /* ARMENIAN CAPITAL LETTER CA */ \
+	  0x056E, /* ARMENIAN SMALL LETTER CA */ }, \
+	{ 0x0549, /* ARMENIAN CAPITAL LETTER CHA */ \

[...]

#34 lore raw

PATCH 11/15 efi_loader: capitalization table

Quoted 48 lines · Heinrich Schuchardt
Quoted 47 lines · Alexander Graf
Quoted 30 lines · Heinrich Schuchardt

This patch provides a define to initialize a table that maps lower to capital letters for Unicode code point 0x0000 - 0xffff.

---
 MAINTAINERS              |    1 +
 include/capitalization.h | 1909 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 1910 insertions(+)
 create mode 100644 include/capitalization.h
MAINTAINERS +1 -0
index a324139471..0a543309f2 100644
@@ -368,6 +368,7 @@ F:	doc/DocBook/efi.tmpl
 F:	doc/README.uefi
 F:	doc/README.iscsi
 F:	Documentation/efi.rst
+F:	include/capitalization.h
 F:	include/efi*
 F:	include/pe.h
 F:	include/asm-generic/pe.h
include/capitalization.h new file +2 -0
new file mode 100644
index 0000000000..50d5108f98
@@ -0,0 +1,1909 @@
+/* SPDX-License-Identifier: Unicode-DFS-2016 */
+/*

include/capitalization.h line 12

Quoted 10 lines
include/capitalization.h new file +10 -0
+ * Correspondence table for small and capital Unicode letters in the range of
+ * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt
+ */
+
+struct capitalization_table {
+	u16 upper;
+	u16 lower;
+};
+
+#define UNICODE_CAPITALIZATION_TABLE { \

Ugh, that is a *lot* of data. How much does the binary size grow with the table compiled in?

Quoted 8 lines
Quoted 2 lines

Is there any slightly more sophisticated pattern in the table maybe that we could just express as code? Would that turn out smaller maybe?

This is 3792 bytes of data. Unicode capitalization is quite random in arranging lower and upper letters.

We could resort to zlib or gzip. But these libraries are not built by default.

Yeah, and that only adds to more overhead.

Quoted 4 lines

Most urgently we will need the capitalization table for generating and checking short FAT filenames, so we could create a configuration switch that would reduce this table to codepage 437 or codepage 1250 letters depending on the chosen native character set.

I think that's a great idea. There probably is a lot of overlap even between the two, so maybe just make it a config option for "non-latin upper/lower case conversion".

Quoted 1 line

In EDK2 I only found code for codepage 1250.

Yeah, I'd be surprised if people really needed more. In fact, how about you just default the config option to =n by default?

Alex

#35 lore raw

PATCH 11/15 efi_loader: capitalization table

Alexander Graf <[email protected]> ã�•ã‚“ã�¯æ›¸ã��ã�¾ã�—ã�Ÿ:

Quoted 40 lines · Heinrich Schuchardt
Quoted 39 lines · Alexander Graf
Quoted 38 lines · Heinrich Schuchardt
Quoted 35 lines

This patch provides a define to initialize a table that maps lower to capital letters for Unicode code point 0x0000 - 0xffff.

---
 MAINTAINERS              |    1 +
 include/capitalization.h | 1909 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 1910 insertions(+)
 create mode 100644 include/capitalization.h
MAINTAINERS +1 -0
index a324139471..0a543309f2 100644
@@ -368,6 +368,7 @@ F:	doc/DocBook/efi.tmpl
 F:	doc/README.uefi
 F:	doc/README.iscsi
 F:	Documentation/efi.rst
+F:	include/capitalization.h
 F:	include/efi*
 F:	include/pe.h
 F:	include/asm-generic/pe.h
include/capitalization.h new file +7 -0
new file mode 100644
index 0000000000..50d5108f98
@@ -0,0 +1,1909 @@
+/* SPDX-License-Identifier: Unicode-DFS-2016 */
+/*
+ * Correspondence table for small and capital Unicode letters in the range of
+ * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt
+ */
+
+struct capitalization_table {
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

include/capitalization.h line 12

Quoted 5 lines
include/capitalization.h new file +5 -0
+	u16 upper;
+	u16 lower;
+};
+
+#define UNICODE_CAPITALIZATION_TABLE { \

Ugh, that is a *lot* of data. How much does the binary size grow with the table compiled in?

That data is also in glibc. I don’t know whether you use glibc though
...

Quoted 28 lines
Quoted 8 lines
Quoted 2 lines

Is there any slightly more sophisticated pattern in the table maybe that we could just express as code? Would that turn out smaller maybe?

This is 3792 bytes of data. Unicode capitalization is quite random in arranging lower and upper letters.

We could resort to zlib or gzip. But these libraries are not built by default.

Yeah, and that only adds to more overhead.

Quoted 4 lines

Most urgently we will need the capitalization table for generating and checking short FAT filenames, so we could create a configuration switch that would reduce this table to codepage 437 or codepage 1250 letters depending on the chosen native character set.

I think that's a great idea. There probably is a lot of overlap even between the two, so maybe just make it a config option for "non-latin upper/lower case conversion".

Quoted 1 line

In EDK2 I only found code for codepage 1250.

Yeah, I'd be surprised if people really needed more. In fact, how about you just default the config option to =n by default?

Alex

Signature · 2 lines
📧 Mike FABIAN   <[email protected]>
�眠�足���仕事�敵�。
#36 lore raw

PATCH 11/15 efi_loader: capitalization table

Quoted 55 lines

Am 27.08.2018 um 10:30 schrieb Mike FABIAN <[email protected]>:

Alexander Graf <[email protected]> さんは書きました:

Quoted 40 lines
Quoted 40 lines · Heinrich Schuchardt
Quoted 39 lines · Alexander Graf
Quoted 38 lines · Heinrich Schuchardt

This patch provides a define to initialize a table that maps lower to capital letters for Unicode code point 0x0000 - 0xffff.

---
MAINTAINERS | 1 +
include/capitalization.h | 1909 ++++++++++++++++++++++++++++++++++++++

2 files changed, 1910 insertions(+)

create mode 100644 include/capitalization.h

MAINTAINERS +0 -0
index a324139471..0a543309f2 100644
@@ -368,6 +368,7 @@ F:    doc/DocBook/efi.tmpl
F:    doc/README.uefi
F:    doc/README.iscsi
F:    Documentation/efi.rst
+F:    include/capitalization.h
F:    include/efi*
F:    include/pe.h
F:    include/asm-generic/pe.h
include/capitalization.h new file +7 -0
new file mode 100644
index 0000000000..50d5108f98
@@ -0,0 +1,1909 @@
+/* SPDX-License-Identifier: Unicode-DFS-2016 */
+/*
+ * Correspondence table for small and capital Unicode letters in the range of
+ * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt
+ */
+
+struct capitalization_table {
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

include/capitalization.h line 12

Quoted 5 lines
include/capitalization.h new file +5 -0
+    u16 upper;
+    u16 lower;
+};
+
+#define UNICODE_CAPITALIZATION_TABLE { \

Ugh, that is a *lot* of data. How much does the binary size grow with the table compiled in?

Quoted 2 lines

That data is also in glibc. I don’t know whether you use glibc though
...

U-Boot is a standalone OS so to say, we do not use glibc (except for sandbox, but that's a special target).

The main problem is that some times people cram U-Boot into very tight spaces, like small flash chips or even on-chip RAM. So we have to be very cautious on space requirements.

Alex

#37 lore raw

PATCH 11/15 efi_loader: capitalization table

Hi,

Quoted 55 lines · Alexander Graf
Quoted 55 lines

Am 27.08.2018 um 10:30 schrieb Mike FABIAN <[email protected]>:

Alexander Graf <[email protected]> さんは書きました:

Quoted 48 lines
Quoted 48 lines · Heinrich Schuchardt
Quoted 47 lines · Alexander Graf
Quoted 33 lines · Heinrich Schuchardt

This patch provides a define to initialize a table that maps lower to capital letters for Unicode code point 0x0000 - 0xffff.

---
MAINTAINERS | 1 +
include/capitalization.h | 1909 ++++++++++++++++++++++++++++++++++++++

2 files changed, 1910 insertions(+)

create mode 100644 include/capitalization.h

MAINTAINERS +0 -0
index a324139471..0a543309f2 100644
@@ -368,6 +368,7 @@ F:    doc/DocBook/efi.tmpl
F:    doc/README.uefi
F:    doc/README.iscsi
F:    Documentation/efi.rst
+F:    include/capitalization.h
F:    include/efi*
F:    include/pe.h
F:    include/asm-generic/pe.h
include/capitalization.h new file +2 -0
new file mode 100644
index 0000000000..50d5108f98
@@ -0,0 +1,1909 @@
+/* SPDX-License-Identifier: Unicode-DFS-2016 */
+/*

include/capitalization.h line 12

Quoted 10 lines
include/capitalization.h new file +10 -0
+ * Correspondence table for small and capital Unicode letters in the range of
+ * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt
+ */
+
+struct capitalization_table {
+    u16 upper;
+    u16 lower;
+};
+
+#define UNICODE_CAPITALIZATION_TABLE { \

Ugh, that is a *lot* of data. How much does the binary size grow with the table compiled in?

Quoted 6 lines
Quoted 2 lines

That data is also in glibc. I don’t know whether you use glibc though
...

U-Boot is a standalone OS so to say, we do not use glibc (except for sandbox, but that's a special target).

The main problem is that some times people cram U-Boot into very tight spaces, like small flash chips or even on-chip RAM. So we have to be very cautious on space requirements.

Indeed.

Most archs use a private glib so do not build with one that supports this table.

Wouldn't it be better to put this in a C file as a const struct?

If it is big that's OK, we just need to add a CONFIG option for it. If we already have EFI enabled, perhaps it doesn't matter, since it is pretty big.

Regards,
Simon

#38 lore raw

PATCH 11/15 efi_loader: capitalization table

Quoted 67 lines · Simon Glass

Hi,

Quoted 55 lines · Alexander Graf
Quoted 55 lines

Am 27.08.2018 um 10:30 schrieb Mike FABIAN <[email protected]>:

Alexander Graf <[email protected]> さんは書きました:

Quoted 48 lines
Quoted 48 lines · Heinrich Schuchardt
Quoted 47 lines · Alexander Graf
Quoted 33 lines · Heinrich Schuchardt

This patch provides a define to initialize a table that maps lower to capital letters for Unicode code point 0x0000 - 0xffff.

---
MAINTAINERS | 1 +
include/capitalization.h | 1909 ++++++++++++++++++++++++++++++++++++++

2 files changed, 1910 insertions(+)

create mode 100644 include/capitalization.h

MAINTAINERS +0 -0
index a324139471..0a543309f2 100644
@@ -368,6 +368,7 @@ F:    doc/DocBook/efi.tmpl
F:    doc/README.uefi
F:    doc/README.iscsi
F:    Documentation/efi.rst
+F:    include/capitalization.h
F:    include/efi*
F:    include/pe.h
F:    include/asm-generic/pe.h
include/capitalization.h new file +2 -0
new file mode 100644
index 0000000000..50d5108f98
@@ -0,0 +1,1909 @@
+/* SPDX-License-Identifier: Unicode-DFS-2016 */
+/*

include/capitalization.h line 12

Quoted 10 lines
include/capitalization.h new file +10 -0
+ * Correspondence table for small and capital Unicode letters in the range of
+ * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt
+ */
+
+struct capitalization_table {
+    u16 upper;
+    u16 lower;
+};
+
+#define UNICODE_CAPITALIZATION_TABLE { \

Ugh, that is a *lot* of data. How much does the binary size grow with the table compiled in?

Quoted 6 lines
Quoted 2 lines

That data is also in glibc. I don’t know whether you use glibc though
...

U-Boot is a standalone OS so to say, we do not use glibc (except for sandbox, but that's a special target).

The main problem is that some times people cram U-Boot into very tight spaces, like small flash chips or even on-chip RAM. So we have to be very cautious on space requirements.

Indeed.

Quoted 7 lines

Most archs use a private glib so do not build with one that supports this table.

Wouldn't it be better to put this in a C file as a const struct?

If it is big that's OK, we just need to add a CONFIG option for it. If we already have EFI enabled, perhaps it doesn't matter, since it is pretty big.

EFI support when it started was about 10kb. I assume it grew by now, so maybe we're at 15kb by now. Adding another 4kb for the upper/lower translation is *massive* by comparison.

Edk2 only supports upper/lower conversion for English anyway, so we're not worse off if we don't support all the fancy unicode conversions.

Alex

#39 lore raw

PATCH 12/15 lib: charset: upper/lower case conversion

In reply to Heinrich Schuchardt

Provide functions for upper and lower case conversion.

---
 include/charset.h | 16 ++++++++++++++++
 lib/charset.c     | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)
include/charset.h +16 -0
index 1c0976dde6..6fdfaa9579 100644
@@ -142,6 +142,22 @@ int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count);
  */
 #define utf16_utf8_strcpy(d, s) utf16_utf8_strncpy((d), (s), SIZE_MAX)
 
+/**
+ * utf_to_lower() - convert a Unicode letter to lower case
+ *
+ * @code:		letter to convert
+ * Return:		lower case letter or unchanged letter
+ */
+s32 utf_to_lower(const s32 code);
+
+/**
+ * utf_to_upper() - convert a Unicode letter to upper case
+ *
+ * @code:		letter to convert
+ * Return:		upper case letter or unchanged letter
+ */
+s32 utf_to_upper(const s32 code);
+
 /**
  * u16_strlen - count non-zero words
  *
lib/charset.c +41 -0

55 lines not on this page · raw message

Signature · 1 line
2.18.0
#40 lore raw

PATCH 13/15 test: tests for utf_to_lower() utf_to_upper().

In reply to Heinrich Schuchardt

Provide unit tests for utf_to_lower() utf_to_upper().

---
 test/unicode_ut.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
test/unicode_ut.c +38 -0
index 8e8c4d189e..ae14fb0eff 100644
@@ -483,6 +483,42 @@ int ut_utf16_utf8_strncpy(void)
 	return 0;
 }
 
+int ut_utf_to_lower(void)
+{
+	if (utf_to_lower('@') != '@')
+		return 1;
+	if (utf_to_lower('A') != 'a')
+		return 1;
+	if (utf_to_lower('Z') != 'z')
+		return 1;
+	if (utf_to_lower('[') != '[')
+		return 1;
+	if (utf_to_lower('m') != 'm')
+		return 1;
+	/* Cyrillic letter I*/
+	if (utf_to_lower(0x0418) != 0x0438)
+		return 0;
+	return 0;
+}
+
+int ut_utf_to_upper(void)
+{
+	if (utf_to_upper('M') != 'M')
+		return 1;
+	if (utf_to_lower('`') != '`')
+		return 1;
+	if (utf_to_upper('a') != 'A')
+		return 1;
+	if (utf_to_upper('z') != 'Z')
+		return 1;
+	if (utf_to_upper('{') != '{')
+		return 1;
+	/* Cyrillic letter I */
+	if (utf_to_upper(0x0438) != 0x0418)
+		return 1;
+	return 0;
+}
+
 int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int ret = 0;
@@ -500,6 +536,8 @@ int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	ret |= ut_utf16_utf8_strnlen();
 	ret |= ut_utf16_utf8_strcpy();
 	ret |= ut_utf16_utf8_strncpy();
+	ret |= ut_utf_to_lower();
+	ret |= ut_utf_to_upper();
 
 	printf("Test %s\n", ret ? "failed" : "passed");
 
Signature · 1 line
2.18.0
#41 lore raw

PATCH 14/15 efi_loader: EFI_UNICODE_COLLATION_PROTOCOL

In reply to Heinrich Schuchardt

The patch implements the EFI_UNICODE_COLLATION_PROTOCOL.

---
 MAINTAINERS                            |   2 +
 include/cp1250.h                       |  40 +++++
 include/cp437.h                        |  40 +++++
 include/efi_api.h                      |  21 +++
 include/efi_loader.h                   |   5 +
 lib/efi_loader/Makefile                |  18 +-
 lib/efi_loader/efi_boottime.c          |   6 +
 lib/efi_loader/efi_unicode_collation.c | 218 +++++++++++++++++++++++++
 8 files changed, 346 insertions(+), 4 deletions(-)
 create mode 100644 include/cp1250.h
 create mode 100644 include/cp437.h
 create mode 100644 lib/efi_loader/efi_unicode_collation.c
MAINTAINERS +2 -0
index 0a543309f2..33d5d545bd 100644
@@ -369,6 +369,8 @@ F:	doc/README.uefi
 F:	doc/README.iscsi
 F:	Documentation/efi.rst
 F:	include/capitalization.h
+F:	include/cp1250.h
+F:	include/cp437.h
 F:	include/efi*
 F:	include/pe.h
 F:	include/asm-generic/pe.h
include/cp1250.h new file +40 -0
new file mode 100644
index 0000000000..adacf8a958
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * Constant CP1250 contains the Unicode code points for characters 0x80 - 0xff
+ * of the code page 1250.
+ */
+#define CP1250 { \
+	0x20ac, 0x0000, 0x201a, 0x0000, \
+	0x201e, 0x2026, 0x2020, 0x2021, \
+	0x0000, 0x2030, 0x0160, 0x2039, \
+	0x015a, 0x0164, 0x017d, 0x0179, \
+	0x0000, 0x2018, 0x2019, 0x201c, \
+	0x201d, 0x2022, 0x2013, 0x2014, \
+	0x0000, 0x2122, 0x0161, 0x203a, \
+	0x015b, 0x0165, 0x017e, 0x017a, \
+	0x00a0, 0x02c7, 0x02d8, 0x0141, \
+	0x00a4, 0x0104, 0x00a6, 0x00a7, \
+	0x00a8, 0x00a9, 0x015e, 0x00ab, \
+	0x00ac, 0x00ad, 0x00ae, 0x017b, \
+	0x00b0, 0x00b1, 0x02db, 0x0142, \
+	0x00b4, 0x00b5, 0x00b6, 0x00b7, \
+	0x00b8, 0x0105, 0x015f, 0x00bb, \
+	0x013d, 0x02dd, 0x013e, 0x017c, \
+	0x0154, 0x00c1, 0x00c2, 0x0102, \
+	0x00c4, 0x0139, 0x0106, 0x00c7, \
+	0x010c, 0x00c9, 0x0118, 0x00cb, \
+	0x011a, 0x00cd, 0x00ce, 0x010e, \
+	0x0110, 0x0143, 0x0147, 0x00d3, \
+	0x00d4, 0x0150, 0x00d6, 0x00d7, \
+	0x0158, 0x016e, 0x00da, 0x0170, \
+	0x00dc, 0x00dd, 0x0162, 0x00df, \
+	0x0155, 0x00e1, 0x00e2, 0x0103, \
+	0x00e4, 0x013a, 0x0107, 0x00e7, \
+	0x010d, 0x00e9, 0x0119, 0x00eb, \
+	0x011b, 0x00ed, 0x00ee, 0x010f, \
+	0x0111, 0x0144, 0x0148, 0x00f3, \
+	0x00f4, 0x0151, 0x00f6, 0x00f7, \
+	0x0159, 0x016f, 0x00fa, 0x0171, \
+	0x00fc, 0x00fd, 0x0163, 0x02d9, \
+}
include/cp437.h new file +40 -0
new file mode 100644
index 0000000000..0b2b97132e
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * Constant CP437 contains the Unicode code points for characters 0x80 - 0xff
+ * of the code page 437.
+ */
+#define CP437 { \
+	0x00c7, 0x00fc, 0x00e9, 0x00e2, \
+	0x00e4, 0x00e0, 0x00e5, 0x00e7, \
+	0x00ea, 0x00eb, 0x00e8, 0x00ef, \
+	0x00ee, 0x00ec, 0x00c4, 0x00c5, \
+	0x00c9, 0x00e6, 0x00c6, 0x00f4, \
+	0x00f6, 0x00f2, 0x00fb, 0x00f9, \
+	0x00ff, 0x00d6, 0x00dc, 0x00a2, \
+	0x00a3, 0x00a5, 0x20a7, 0x0192, \
+	0x00e1, 0x00ed, 0x00f3, 0x00fa, \
+	0x00f1, 0x00d1, 0x00aa, 0x00ba, \
+	0x00bf, 0x2310, 0x00ac, 0x00bd, \
+	0x00bc, 0x00a1, 0x00ab, 0x00bb, \
+	0x2591, 0x2592, 0x2593, 0x2502, \
+	0x2524, 0x2561, 0x2562, 0x2556, \
+	0x2555, 0x2563, 0x2551, 0x2557, \
+	0x255d, 0x255c, 0x255b, 0x2510, \
+	0x2514, 0x2534, 0x252c, 0x251c, \
+	0x2500, 0x253c, 0x255e, 0x255f, \
+	0x255a, 0x2554, 0x2569, 0x2566, \
+	0x2560, 0x2550, 0x256c, 0x2567, \
+	0x2568, 0x2564, 0x2565, 0x2559, \
+	0x2558, 0x2552, 0x2553, 0x256b, \
+	0x256a, 0x2518, 0x250c, 0x2588, \
+	0x2584, 0x258c, 0x2590, 0x2580, \
+	0x03b1, 0x00df, 0x0393, 0x03c0, \
+	0x03a3, 0x03c3, 0x00b5, 0x03c4, \
+	0x03a6, 0x0398, 0x03a9, 0x03b4, \
+	0x221e, 0x03c6, 0x03b5, 0x2229, \
+	0x2261, 0x00b1, 0x2265, 0x2264, \
+	0x2320, 0x2321, 0x00f7, 0x2248, \
+	0x00b0, 0x2219, 0x00b7, 0x221a, \
+	0x207f, 0x00b2, 0x25a0, 0x00a0, \
+}
include/efi_api.h +21 -0
index ebf2a3bc18..1efc448184 100644
@@ -31,6 +31,7 @@ enum efi_timer_delay {
 	EFI_TIMER_RELATIVE = 2
 };
 
+#define efi_intn_t ssize_t
 #define efi_uintn_t size_t
 typedef uint16_t *efi_string_t;
 
@@ -958,4 +959,24 @@ struct efi_driver_binding_protocol {
 	efi_handle_t driver_binding_handle;
 };
 
+#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
+	EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
+		 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49)
+struct efi_unicode_collation_protocol {
+	efi_intn_t (EFIAPI *stri_coll)(
+		struct efi_unicode_collation_protocol *this, u16 *s1, u16 *s2);
+	bool (EFIAPI *metai_match)(struct efi_unicode_collation_protocol *this,
+				   const u16 *string, const u16 *patter);
+	void (EFIAPI *str_lwr)(struct efi_unicode_collation_protocol
+			       *this, u16 *string);
+	void (EFIAPI *str_upr)(struct efi_unicode_collation_protocol *this,
+			       u16 *string);
+	void (EFIAPI *fat_to_str)(struct efi_unicode_collation_protocol *this,
+				  efi_uintn_t fat_size, char *fat, u16 *string);
+	bool (EFIAPI *str_to_fat)(struct efi_unicode_collation_protocol *this,
+				  const u16 *string, efi_uintn_t fat_size,
+				  char *fat);
+	char *supported_languages;
+};
+
 #endif
include/efi_loader.h +5 -0
index f162adfff7..c5ae7c3c36 100644
@@ -98,6 +98,9 @@ extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
 /* implementation of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL */
 extern const struct efi_device_path_utilities_protocol
 					efi_device_path_utilities;
+/* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */
+extern const struct efi_unicode_collation_protocol
+					efi_unicode_collation_protocol;
 
 uint16_t *efi_dp_str(struct efi_device_path *dp);
 
@@ -127,6 +130,8 @@ extern const efi_guid_t efi_file_info_guid;
 /* GUID for file system information */
 extern const efi_guid_t efi_file_system_info_guid;
 extern const efi_guid_t efi_guid_device_path_utilities_protocol;
+/* GUID of the Unicode collation protocol */
+extern const efi_guid_t efi_guid_unicode_collation_protocol;
 
 extern unsigned int __efi_runtime_start, __efi_runtime_stop;
 extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
lib/efi_loader/Makefile +14 -4
index 1ffbf52a89..0769df20f7 100644
@@ -17,10 +17,20 @@ always += helloworld.efi
 endif
 
 obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
-obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
-obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
-obj-y += efi_device_path_utilities.o efi_file.o efi_variable.o efi_bootmgr.o
-obj-y += efi_watchdog.o
+obj-y += \
+efi_bootmgr.o \
+efi_boottime.o \
+efi_console.o \
+efi_device_path.o \
+efi_device_path_to_text.o \
+efi_device_path_utilities.o \
+efi_file.o \
+efi_image_loader.o \
+efi_memory.o \
+efi_runtime.o \
+efi_unicode_collation.o \
+efi_variable.o \
+efi_watchdog.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
 obj-$(CONFIG_PARTITIONS) += efi_disk.o
lib/efi_loader/efi_boottime.c +6 -0
index 618e8a8d8c..8a0701e828 100644
@@ -1525,6 +1525,12 @@ efi_status_t efi_setup_loaded_image(
 	if (ret != EFI_SUCCESS)
 		goto failure;
 
+	ret = efi_add_protocol(obj->handle,
+			       &efi_guid_unicode_collation_protocol,
+			       (void *)&efi_unicode_collation_protocol);
+	if (ret != EFI_SUCCESS)
+		goto failure;
+
 	return ret;
 failure:
 	printf("ERROR: Failure to install protocols for loaded image\n");
lib/efi_loader/efi_unicode_collation.c new file +218 -0

218 lines not on this page · raw message

Signature · 1 line
2.18.0
#43 lore raw

PATCH 15/15 efi_selftest: EFI_UNICODE_COLLATION_PROTOCOL

In reply to Heinrich Schuchardt

Provide a unit test for the EFI_UNICODE_COLLATION_PROTOCOL.

---
 lib/efi_selftest/Makefile                     |   1 +
 .../efi_selftest_unicode_collation.c          | 257 ++++++++++++++++++
 2 files changed, 258 insertions(+)
 create mode 100644 lib/efi_selftest/efi_selftest_unicode_collation.c
lib/efi_selftest/Makefile +1 -0
index 590f90b16d..7ff879742f 100644
@@ -30,6 +30,7 @@ efi_selftest_snp.o \
 efi_selftest_textinput.o \
 efi_selftest_textoutput.o \
 efi_selftest_tpl.o \
+efi_selftest_unicode_collation.o \
 efi_selftest_util.o \
 efi_selftest_variables.o \
 efi_selftest_watchdog.o
lib/efi_selftest/efi_selftest_unicode_collation.c new file +257 -0

257 lines not on this page · raw message

Signature · 1 line
2.18.0