aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Protsenko2024-03-29 19:55:53 -0500
committerTom Rini2024-04-12 08:53:31 -0600
commit16b80c93e2d16d9b18f1bb1d884254281dc4bec2 (patch)
tree25e1b5d5bb527d5fb8172250a4143d5d6ef3913c
parentd2e4b2fa04cfeb71b821f9d0100d886b7f9e166c (diff)
fdt: Fix fdt_pack_reg() on 64-bit platforms
When "memory" node is being processed in fdt_pack_reg() on ARM64 platforms, an unaligned bus access might happen, which leads to "synchronous abort" CPU exception. Consider next dts example: / { #address-cells = <2>; #size-cells = <1>; memory@80000000 { device_type = "memory"; reg = <0x0 0x80000000 0x3ab00000>, <0x0 0xc0000000 0x40000000>, <0x8 0x80000000 0x80000000>; }; }; After fdt_pack_reg() reads the first addr/size entry from such memory node, the "p" pointer becomes 12 bytes shifted from its original value (8 bytes for two address cells + 4 bytes for one size cell). So now it's not 64-bit aligned, and an attempt to do 64-bit bus access to that address will cause an abort like this: "Synchronous Abort" handler, esr 0x96000021, far 0xba235efc This issue was originally reported by David Virag [1] who observed it happening on Samsung Exynos7885 SoC (ARM64), and later the same issue was observed on Samsung Exynos850 (ARM64). Fix the issue by using put_unaligned_be64() helper, which takes care of possible unaligned 64-bit accesses. That solution was proposed by Simon Glass in the original thread [1]. [1] https://lists.denx.de/pipermail/u-boot/2023-July/522074.html Fixes: 739a01ed8e02 ("fdt_support: fix an endian bug of fdt_fixup_memory_banks") Suggested-by: Simon Glass <sjg@google.com> Reported-by: David Virag <virag.david003@gmail.com> Closes: https://lists.denx.de/pipermail/u-boot/2023-July/522074.html Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
-rw-r--r--boot/fdt_support.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/boot/fdt_support.c b/boot/fdt_support.c
index 090d82ee80a..9844c70be80 100644
--- a/boot/fdt_support.c
+++ b/boot/fdt_support.c
@@ -17,6 +17,7 @@
#include <linux/ctype.h>
#include <linux/types.h>
#include <asm/global_data.h>
+#include <asm/unaligned.h>
#include <linux/libfdt.h>
#include <fdt_support.h>
#include <exports.h>
@@ -421,13 +422,13 @@ static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size,
for (i = 0; i < n; i++) {
if (address_cells == 2)
- *(fdt64_t *)p = cpu_to_fdt64(address[i]);
+ put_unaligned_be64(address[i], p);
else
*(fdt32_t *)p = cpu_to_fdt32(address[i]);
p += 4 * address_cells;
if (size_cells == 2)
- *(fdt64_t *)p = cpu_to_fdt64(size[i]);
+ put_unaligned_be64(size[i], p);
else
*(fdt32_t *)p = cpu_to_fdt32(size[i]);
p += 4 * size_cells;