[PATCH] uboot-lantiq: fix out of bounds cache invalidate
Mathias Kresin
dev at kresin.me
Wed Nov 10 12:59:55 PST 2021
11/3/21 2:43 PM, Daniel Schwierzeck:
> Am Dienstag, dem 02.11.2021 um 23:35 +0100 schrieb Mathias Kresin:
>> If u-boot is compiled with gcc 10+ the relevant part of the memory is
>> used as following:
>>
>> variable BootFile is at address: 0x83ffe4ec
>> variable data is at address: 0x83ffdee2
>> variable data has len: 0x600
>>
>> Within invalidate_dcache_range() the cache covering the data variable
>> should be invalidated (0x83ffdee2 till 0x83ffdef2).
>>
>> Due to dcache line size of 32 and some alignment correction, the
>> actual
>> memory range for which the cache is invalidated is from 0x83ffdee0
>> till
>> 0x83ffe500, which includes the location of the BootFile variable as
>> well.
>>
>> Afterwards the BootFile variable is 0. The issue can be observed by
>> using tftpboot, which always uses the default/generated filename
>> instead
>> of the specified one.
>>
>> To fix the issue, align the memory addresses properly before passing
>> them to invalidate_dcache_range(). The misalignment can be observed
>> with
>> older gcc versions as well but the BootFile variable is placed more
>> than
>> 0x1000 bytes after the data variable and doesn't get null'ed.
>>
>> Fixes: FS#4113
>>
>> Signed-off-by: Mathias Kresin <dev at kresin.me>
>> ---
>> ...q-fix-out-of-bounds-cache-invalidate.patch | 48
>> +++++++++++++++++++
>> 1 file changed, 48 insertions(+)
>> create mode 100644 package/boot/uboot-lantiq/patches/0031-dma-
>> lantiq-fix-out-of-bounds-cache-invalidate.patch
>>
>> diff --git a/package/boot/uboot-lantiq/patches/0031-dma-lantiq-fix-
>> out-of-bounds-cache-invalidate.patch b/package/boot/uboot-
>> lantiq/patches/0031-dma-lantiq-fix-out-of-bounds-cache-
>> invalidate.patch
>> new file mode 100644
>> index 0000000000..5a2bf39441
>> --- /dev/null
>> +++ b/package/boot/uboot-lantiq/patches/0031-dma-lantiq-fix-out-of-
>> bounds-cache-invalidate.patch
>> @@ -0,0 +1,48 @@
>> +From f10ffb65865d5bfa5679293b13e027e0474df1fe Mon Sep 17 00:00:00
>> 2001
>> +From: Mathias Kresin <dev at kresin.me>
>> +Date: Tue, 2 Nov 2021 21:24:29 +0100
>> +Subject: [PATCH] dma: lantiq: fix out of bounds cache invalidate
>> +
>> +If u-boot is compiled with gcc 10+ the relevant part of the memory
>> is
>> +used as following:
>> +
>> +variable BootFile is at address: 0x83ffe4ec
>> +variable data is at address: 0x83ffdee2
>> +variable data has len: 0x600
>> +
>> +Within invalidate_dcache_range() the cache covering the data
>> variable
>> +should be invalidated (0x83ffdee2 till 0x83ffdef2).
>> +
>> +Due to dcache line size of 32 and some alignment correction, the
>> actual
>> +memory range for which the cache is invalidated is from 0x83ffdee0
>> till
>> +0x83ffe500, which includes the location of the BootFile variable as
>> +well.
>> +
>> +Afterwards the BootFile variable is 0. The issue can be observed by
>> +using tftpboot, which always uses the default/generated filename
>> instead
>> +of the specified one.
>> +
>> +To fix the issue, align the memory addresses properly before passing
>> +them to invalidate_dcache_range(). The misalignment can be observed
>> with
>> +older gcc versions as well but the BootFile variable is placed more
>> than
>> +0x1000 bytes after the data variable and doesn't get null'ed.
>> +
>> +Signed-off-by: Mathias Kresin <dev at kresin.me>
>> +---
>> + drivers/dma/lantiq_dma.c | 4 ++--
>> + 1 file changed, 2 insertions(+), 2 deletions(-)
>> +
>> +--- a/drivers/dma/lantiq_dma.c
>> ++++ b/drivers/dma/lantiq_dma.c
>> +@@ -122,9 +122,9 @@ static inline void ltq_dma_dcache_wb_inv
>> +
>> + static inline void ltq_dma_dcache_inv(const void *ptr, size_t size)
>> + {
>> +- unsigned long addr = (unsigned long) ptr;
>> ++ unsigned long addr = (unsigned long) ptr & ~(ARCH_DMA_MINALIGN
>> - 1);
>> +
>> +- invalidate_dcache_range(addr, addr + size);
>> ++ invalidate_dcache_range(addr, ALIGN(addr + size,
>> ARCH_DMA_MINALIGN));
>> + }
>
> actually invalidate_dcache_range() already aligns start and end address
> to CONFIG_SYS_CACHELINE_SIZE which is the same as ARCH_DMA_MINALIGN.
>
> In mainline we fixed the cache functions to always issue a sync() after
> the cache ops to wait for all HW transactions to be complete. The
> Lantiq DMA driver only does this in ltq_dma_dcache_wb_inv() but not
> in ltq_dma_dcache_inv(). Maybe adding a ltq_dma_sync() there would also
> fix your problem?
>
>> +
>> + void ltq_dma_init(void)
Hey Daniel,
a had an even closer look at what is going on here. It all starts in the
soc netdev driver (here lantiq_danube_etop.c).
NetRxPackets[] points to cache line size aligned addresses. In
ltq_eth_rx_packet_align() the address NetRxPackets[] points to is
increased by LTQ_ETH_IP_ALIGN and the resulting not cache aligned
address is used further on. While doing so, the len/size is never updated.
The "not cache aligned address" + len/size for a cache aligned address
is passed to invalidate_dcache_range(). Hence, invalidate_dcache_range()
invalidates the next 32 bit as well, which causes the issue.
variable BootFile is at address: 0x83ffe12c
NetRxPackets[] points to 0x83ffdb20 (len is 0x600)
data points to: 0x83ffdb22 (len is 0x600)
ltq_dma_dcache_inv: 0x83ffdb22 (for len 0x600)
invalidate_dcache_range: 0x83ffdb20 to 0x83ffe120 (size: 32)
invalidate_dcache_range: 0x83ffdb20 to 0x83ffdb40 (Bootfile: a.bin)
...
invalidate_dcache_range: 0x83ffe100 to 0x83ffe120 (Bootfile: a.bin)
invalidate_dcache_range: 0x83ffe120 to 0x83ffe140 (Bootfile: )
I see two possible approaches to fix the issue.
1. Do not move the pointer by LTQ_ETH_IP_ALIGN:
To my own surprise Ethernet still works. But I've no idea why the
pointer has to be moved by LTQ_ETH_IP_ALIGN nor why it still works if
the pointer isn't moved. I'm quite sure the pointer is moved for a
reason, which I do not get yet.
2. fix the alignment in ltq_dma_dcache_inv() as in my proposed change
In the end, the pointer/startaddress gets corrected to the value it
should be (0x83ffdb22 => 0x83ffdb20), the size matches again and only
the expected cache range gets invalidated.
Any recommendation which approach is the more sane one? Since I don't
understand the purpose of LTQ_ETH_IP_ALIGN, I tend to go with 2., but
with an updated commit message.
Mathias
More information about the openwrt-devel
mailing list