versal_align_dma_buffer() rounds a misaligned pointer up with
ALIGN() and memmove()s the full payload there, writing up to
ARCH_DMA_MINALIGN-1 bytes past the end of the caller's buffer.

Allocate a separate cache-aligned bounce buffer via
malloc_cache_aligned() and memcpy() into it instead, propagating
-ENOMEM on allocation failure and freeing it after use.

A misaligned buffer larger than the available malloc pool now fails
cleanly with -ENOMEM instead of silently corrupting adjacent memory
as before an explicit, diagnosable failure is strictly preferable
to undefined behavior that previously went unnoticed only because the
caller's buffer happened to have trailing slack.

Fixes: 26e054c943a7 ("arm64: versal: fpga: Add PL bit stream load support")
Signed-off-by: Prasad Kummari <[email protected]>
---
CR: CR-1278219
Branch: master-next-test

DJ:
http://sswregress.amd.com/job/GITHUB_EMU/job/REGRESSIONS/job/U-BOOT_REGRESSIONS/912/

Note:

Hardware validation was completed on VEK385 and VCK190
 - Aligned buffer, existing fast path remains unchanged no bounce
   buffer is allocated.
 - Misaligned buffer with a small payloa, A cache-line-aligned bounce buffer 
   is allocated, used, and freed correctly, with no memory leaks observed.
 - Misaligned buffer with a payload larger than CONFIG_SYS_MALLOC_LEN
   (VCK190, +72.7 MiB request against a 64 MiB heap): The operation
   fails cleanly with -ENOMEM, without crashes or memory corruption.


┌────────────┬───────────────────────┐
│  Platform  │ CONFIG_SYS_MALLOC_LEN │
├────────────┼───────────────────────┤
│ Versal     │ 64 MB                 │
├────────────┼───────────────────────┤
│ Versal2    │ 64 MB                 │
├────────────┼───────────────────────┤
│ Versal Net │ 32 MB                 │
├────────────┼───────────────────────┤

 drivers/fpga/versalpl.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c
index 29d2a389fd9..1c121919db7 100644
--- a/drivers/fpga/versalpl.c
+++ b/drivers/fpga/versalpl.c
@@ -17,8 +17,18 @@ static ulong versal_align_dma_buffer(ulong *buf, u32 len)
        ulong *new_buf;
 
        if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) {
-               new_buf = (ulong *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN);
-               memmove(new_buf, buf, len);
+               /*
+                * ALIGN() rounds up, so an in-place forward memmove() would
+                * write past the end of the caller's buffer. Copy into a
+                * separately allocated, cache-aligned bounce buffer instead.
+                */
+               new_buf = malloc_cache_aligned(len);
+               if (!new_buf) {
+                       printf("%s: Failed to allocate aligned buffer\n",
+                              __func__);
+                       return 0;
+               }
+               memcpy(new_buf, buf, len);
                buf = new_buf;
        }
 
@@ -37,6 +47,8 @@ static int versal_load(xilinx_desc *desc, const void *buf, 
size_t bsize,
        int ret;
 
        bin_buf = versal_align_dma_buffer((ulong *)buf, bsize);
+       if (!bin_buf)
+               return -ENOMEM;
 
        debug("%s called!\n", __func__);
        flush_dcache_range(bin_buf, bin_buf + bsize);
@@ -45,6 +57,9 @@ static int versal_load(xilinx_desc *desc, const void *buf, 
size_t bsize,
        if (ret)
                printf("PL FPGA LOAD failed with err: 0x%08x\n", ret);
 
+       if (bin_buf != (ulong)buf)
+               free((void *)bin_buf);
+
        return ret;
 }
 
-- 
2.43.0

Reply via email to