[PATCH] uboot-lantiq: danube: fix hanging lzma kernel uncompression
dev at kresin.me
Wed Nov 3 16:07:10 PDT 2021
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
>> the first byte, let gcc use sll instead of lwr/lwl and prevents the
>> unaligned access.
>> Signed-off-by: Mathias Kresin <dev at 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-
>> diff --git a/package/boot/uboot-lantiq/patches/0030-lzma-fix-
>> unaligned-access.patch b/package/boot/uboot-lantiq/patches/0030-lzma-
>> new file mode 100644
>> index 0000000000..de9afe0bf5
>> --- /dev/null
>> +++ b/package/boot/uboot-lantiq/patches/0030-lzma-fix-unaligned-
>> @@ -0,0 +1,32 @@
>> +From a335c4c0532cf0d09b31e73f8461d3b4d0ce6f9a Mon Sep 17 00:00:00
>> +From: Mathias Kresin <dev at 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
>> +the first byte, let gcc use sll instead of lwr/lwl and prevents the
>> +unaligned access.
>> +Signed-off-by: Mathias Kresin <dev at 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 | ((UInt32)data << 8) | ((UInt32)data
>> << 16) | ((UInt32)data << 24);
>> ++ dicSize = data | ((UInt32)data << 8) | ((UInt32)data
>> << 16) | ((UInt32)(data+1) << 24);
>> + if (dicSize < LZMA_DIC_MIN)
>> + dicSize = LZMA_DIC_MIN;
More information about the openwrt-devel