11/3/21 2:25 PM, Daniel Schwierzeck:
Am Dienstag, dem 02.11.2021 um 23:35 +0100 schrieb Mathias Kresin:
At least since gcc 7.3.0 (OpenWrt 18.06) lwr/lwl are used in the
assembly  of LzmaProps_Decode. The instructions are using unaligned
access, which locks up danube boards using memory mapped NOR flash.

It isn't clear whether it is a limitation of the flash chip or a
limitation of the EBU.

Moving the pointer to the next int position and accessing accessing
just
the first byte, let gcc use sll instead of lwr/lwl and prevents the
unaligned access.

Signed-off-by: Mathias Kresin <d...@kresin.me>
---
  .../0030-lzma-fix-unaligned-access.patch      | 32
+++++++++++++++++++
  1 file changed, 32 insertions(+)
  create mode 100644 package/boot/uboot-lantiq/patches/0030-lzma-fix-
unaligned-access.patch

diff --git a/package/boot/uboot-lantiq/patches/0030-lzma-fix-
unaligned-access.patch b/package/boot/uboot-lantiq/patches/0030-lzma-
fix-unaligned-access.patch
new file mode 100644
index 0000000000..de9afe0bf5
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0030-lzma-fix-unaligned-
access.patch
@@ -0,0 +1,32 @@
+From a335c4c0532cf0d09b31e73f8461d3b4d0ce6f9a Mon Sep 17 00:00:00
2001
+From: Mathias Kresin <d...@kresin.me>
+Date: Sun, 31 Oct 2021 23:04:54 +0100
+Subject: [PATCH] lzma: fix unaligned access
+
+At least since gcc 7.3.0 (OpenWrt 18.06) lwr/lwl are used in the
+assembly  of LzmaProps_Decode. The instructions are using unaligned
+access, which locks up danube boards using memory mapped NOR flash.
+
+It isn't clear whether it is a limitation of the flash chip or a
+limitation of the EBU.

I think the problem is not the unaligned access but the 32bit read
operation. The internal EBU data bus has a 16 bit width and can access
8bit or 16bit flash devices. So 8bit read operations at odd addresses
shouldn't be a problem. I'm not sure what happens exactly at 32bit
reads but this maybe involves multiple reads from flash and also some
internal endianess swapping.

I've done more testing and the behaviour can be only described as strange. The system only hangs if the offset is 1.

  lwl s0,0(a1) - 0x6d000080
  lwl s0,1(a1) - hangs
  lwl s0,2(a1) - 0x0080xxxx
  lwl s0,3(a1) - 0x80xxxxxx

Looks like 32bit reads via the EBU on a flash device are working fine with exception to offset 1. So, it doesn't look like a 32bit read issue and obviously it isn't an issue with unaligned access...

Maybe a more robust solution would be to use readb(data[n] to always
force 8bit reads.

It isn't just more robust, it's the only reliable way.

While checking the generated assembler code, I spotted that with my change the read to offset 4 is completely gone. No idea what the compiler is doing here. It only worked by accident.


+
+Moving the pointer to the next int position and accessing accessing
just
+the first byte, let gcc use sll instead of lwr/lwl and prevents the
+unaligned access.
+
+Signed-off-by: Mathias Kresin <d...@kresin.me>
+---
+ lib/lzma/LzmaDec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/lib/lzma/LzmaDec.c
++++ b/lib/lzma/LzmaDec.c
+@@ -929,7 +929,7 @@ SRes LzmaProps_Decode(CLzmaProps *p, con
+   if (size < LZMA_PROPS_SIZE)
+     return SZ_ERROR_UNSUPPORTED;
+   else
+-    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3]
<< 16) | ((UInt32)data[4] << 24);
++    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3]
<< 16) | ((UInt32)(data+1)[0] << 24);
+
+   if (dicSize < LZMA_DIC_MIN)
+     dicSize = LZMA_DIC_MIN;


_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to