[PATCH 07/18] lib/charset & efi: Fix possible unaligned accesses

Jiaxun Yang jiaxun.yang at flygoat.com
Wed Jul 17 16:29:18 CEST 2024


As per armv7 arch spec, for A-profile CPU if translation is disabled,
then the default memory type is Device(-nGnRnE) instead of Normal,
which requires that alignment be enforced.

This means in some cases we can't perform unaligned access even after
allow_unaligned is called.

We do have many platforms that didn't have translation enabled in U-Boot,
and QEMU started to enforce this since 9.0.

Fix by using unaligned access helper for UTF-16 memory read/write to
ensure we don't do any unaligned access in U-Boot.

Signed-off-by: Jiaxun Yang <jiaxun.yang at flygoat.com>
---
 lib/charset.c                    | 21 ++++++++++++---------
 lib/efi_loader/efi_device_path.c | 11 ++---------
 2 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/lib/charset.c b/lib/charset.c
index 182c92a50c48..af5f3ad16d9b 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -11,6 +11,7 @@
 #include <efi_loader.h>
 #include <errno.h>
 #include <malloc.h>
+#include <asm/unaligned.h>
 
 /**
  * codepage_437 - Unicode to codepage 437 translation table
@@ -215,7 +216,7 @@ s32 utf16_get(const u16 **src)
 		return -1;
 	if (!**src)
 		return 0;
-	code = **src;
+	code = get_unaligned_le16(*src);
 	++*src;
 	if (code >= 0xDC00 && code <= 0xDFFF)
 		return -1;
@@ -242,12 +243,12 @@ int utf16_put(s32 code, u16 **dst)
 	if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
 		return -1;
 	if (code < 0x10000) {
-		**dst = code;
+		put_unaligned_le16(code, *dst);
 	} else {
 		code -= 0x10000;
-		**dst = code >> 10 | 0xD800;
+		put_unaligned_le16(code >> 10 | 0xD800, *dst);
 		++*dst;
-		**dst = (code & 0x3ff) | 0xDC00;
+		put_unaligned_le16((code & 0x3ff) | 0xDC00, *dst);
 	}
 	++*dst;
 	return 0;
@@ -392,7 +393,7 @@ int __efi_runtime u16_strncmp(const u16 *s1, const u16 *s2, size_t n)
 	int ret = 0;
 
 	for (; n; --n, ++s1, ++s2) {
-		ret = *s1 - *s2;
+		ret = get_unaligned_le16(s1) - get_unaligned_le16(s2);
 		if (ret || !*s1)
 			break;
 	}
@@ -403,7 +404,7 @@ int __efi_runtime u16_strncmp(const u16 *s1, const u16 *s2, size_t n)
 size_t __efi_runtime u16_strnlen(const u16 *in, size_t count)
 {
 	size_t i;
-	for (i = 0; count-- && in[i]; i++);
+	for (i = 0; count-- && get_unaligned_le16(in + i); i++);
 	return i;
 }
 
@@ -417,8 +418,10 @@ u16 *u16_strcpy(u16 *dest, const u16 *src)
 	u16 *tmp = dest;
 
 	for (;; dest++, src++) {
-		*dest = *src;
-		if (!*src)
+		u16 code = get_unaligned_le16(src);
+
+		put_unaligned_le16(code, dest);
+		if (!code)
 			break;
 	}
 
@@ -463,7 +466,7 @@ uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
 	uint32_t code_high = 0;
 
 	while (size--) {
-		uint32_t code = *src++;
+		uint32_t code = get_unaligned_le16(src++);
 
 		if (code_high) {
 			if (code >= 0xDC00 && code <= 0xDFFF) {
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 0f684590f22a..97a3200574a1 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -18,7 +18,7 @@
 #include <efi_loader.h>
 #include <part.h>
 #include <uuid.h>
-#include <asm-generic/unaligned.h>
+#include <asm/unaligned.h>
 #include <linux/compat.h> /* U16_MAX */
 
 /* template END node: */
@@ -873,13 +873,6 @@ static void path_to_uefi(void *uefi, const char *src)
 {
 	u16 *pos = uefi;
 
-	/*
-	 * efi_set_bootdev() calls this routine indirectly before the UEFI
-	 * subsystem is initialized. So we cannot assume unaligned access to be
-	 * enabled.
-	 */
-	allow_unaligned();
-
 	while (*src) {
 		s32 code = utf8_get(&src);
 
@@ -889,7 +882,7 @@ static void path_to_uefi(void *uefi, const char *src)
 			code = '\\';
 		utf16_put(code, &pos);
 	}
-	*pos = 0;
+	put_unaligned_le16(0, pos);
 }
 
 /**

-- 
2.45.2



More information about the U-Boot mailing list