[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