RAM FIT loading currently assumes a configured image address. Downloaded
images need the same loader with a caller-provided buffer and length so
reads cannot run beyond the received data.

Expose a reusable RAM FIT loader with header validation, bounded reads
and overlap-safe copying. Keep preloaded images working when their buffer
size is unknown. Add tests for embedded and external FIT data.

Signed-off-by: Carlo Caione <[email protected]>
---
 MAINTAINERS           |  1 +
 common/spl/spl_ram.c  | 49 +++++++++++++++++++++++++++----------------------
 include/spl.h         |  9 +++++++++
 test/image/Kconfig    |  9 +++++++++
 test/image/Makefile   |  1 +
 test/image/spl_load.c |  4 +++-
 test/image/spl_ram.c  | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 98 insertions(+), 23 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index d1f51d9197d..f464e0bd2bc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1923,5 +1923,6 @@ Q:        http://patchwork.ozlabs.org/project/uboot/list/
 S:     Maintained
 T:     git https://git.u-boot-project.org/u-boot/u-boot.git
 F:     configs/tools-only_defconfig
+F:     test/image/spl_ram.c
 F:     *
 F:     */
diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c
index 0c501cf02f2..ee588ef4718 100644
--- a/common/spl/spl_ram.c
+++ b/common/spl/spl_ram.c
@@ -16,32 +16,39 @@
 #include <spl.h>
 #include <linux/libfdt.h>
 
-static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
+struct spl_ram_image {
+       const void *data;
+       size_t size;
+};
+
+static ulong spl_ram_load_read(struct spl_load_info *load, ulong offset,
                               ulong count, void *buf)
 {
-       ulong addr = 0;
-
-       debug("%s: sector %lx, count %lx, buf %lx\n",
-             __func__, sector, count, (ulong)buf);
+       struct spl_ram_image *image = load->priv;
 
-       if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
-               addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
-                                     CONFIG_SPL_LOAD_FIT_ADDRESS);
+       if (offset >= image->size)
+               return 0;
+       count = min_t(ulong, count, image->size - offset);
+       memmove(buf, image->data + offset, count);
+       return count;
+}
 
-#ifdef CONFIG_SPL_PCI_DFU
-               if (spl_boot_device() == BOOT_DEVICE_PCIE)
-                       addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
-#endif
-       }
-       addr += sector;
-       if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD))
-               addr += image_load_offset;
+int spl_ram_load_fit(struct spl_image_info *spl_image, void *fit, size_t size)
+{
+       struct spl_ram_image image = { .data = fit, .size = size };
+       struct spl_load_info load;
 
-       memcpy(buf, (void *)addr, count);
+       if (!CONFIG_IS_ENABLED(LOAD_FIT))
+               return -EOPNOTSUPP;
+       if (size < sizeof(struct fdt_header) || fdt_check_header(fit) ||
+           fdt_totalsize(fit) > size)
+               return -EINVAL;
 
-       return count;
+       spl_load_init(&load, spl_ram_load_read, &image, 1);
+       return spl_load_simple_fit(spl_image, &load, 0, fit);
 }
 
+#if CONFIG_IS_ENABLED(RAM_SUPPORT)
 static int spl_ram_load_image(struct spl_image_info *spl_image,
                              struct spl_boot_device *bootdev)
 {
@@ -81,11 +88,8 @@ static int spl_ram_load_image(struct spl_image_info 
*spl_image,
 
        if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
            image_get_magic(header) == FDT_MAGIC) {
-               struct spl_load_info load;
-
                debug("Found FIT\n");
-               spl_load_init(&load, spl_ram_load_read, NULL, 1);
-               ret = spl_load_simple_fit(spl_image, &load, 0, header);
+               ret = spl_ram_load_fit(spl_image, header, SIZE_MAX);
        } else {
                ulong u_boot_pos = spl_get_image_pos();
 
@@ -120,3 +124,4 @@ SPL_LOAD_IMAGE_METHOD("DFU", 0, BOOT_DEVICE_DFU, 
spl_ram_load_image);
 #if CONFIG_IS_ENABLED(PCI_DFU)
 SPL_LOAD_IMAGE_METHOD("PCIE", 0, BOOT_DEVICE_PCIE, spl_ram_load_image);
 #endif
+#endif
diff --git a/include/spl.h b/include/spl.h
index 390d18fd9d5..f884c24b85e 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -989,6 +989,15 @@ bool spl_was_boot_source(void);
  */
 int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char 
*devstr);
 
+/**
+ * spl_ram_load_fit() - Load a FIT from a RAM buffer
+ * @spl_image: Receives the loaded image information
+ * @fit: FIT image, including any external data
+ * @size: Buffer size, or SIZE_MAX for a preloaded image of unknown size
+ * Return: 0 on success, or a negative error code
+ */
+int spl_ram_load_fit(struct spl_image_info *spl_image, void *fit, size_t size);
+
 /**
  * spl_mmc_clear_cache() - Clear cached MMC devices
  *
diff --git a/test/image/Kconfig b/test/image/Kconfig
index 45b6e8c52e6..1cb8337e0f4 100644
--- a/test/image/Kconfig
+++ b/test/image/Kconfig
@@ -41,6 +41,15 @@ config SPL_UT_LOAD_NET
        help
          Test loading images over TFTP using the NET image load method.
 
+config SPL_UT_LOAD_RAM
+       bool "Test loading images from RAM"
+       depends on SANDBOX && SPL_LOAD_FIT
+       select SPL_RAM_SUPPORT
+       default y
+       help
+         Test loading FIT images from a RAM buffer, including images with
+         embedded and external payloads.
+
 config SPL_UT_LOAD_SPI
        bool "Test loading from SPI Flash"
        depends on SANDBOX && SPL_OF_REAL
diff --git a/test/image/Makefile b/test/image/Makefile
index 11ed25734e8..feca0611fcf 100644
--- a/test/image/Makefile
+++ b/test/image/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_SPL_UT_LOAD_FS) += spl_load_fs.o
 obj-$(CONFIG_SPL_UT_LOAD_NAND) += spl_load_nand.o
 obj-$(CONFIG_SPL_UT_LOAD_NET) += spl_load_net.o
 obj-$(CONFIG_SPL_NOR_SUPPORT) += spl_load_nor.o
+obj-$(CONFIG_SPL_UT_LOAD_RAM) += spl_ram.o
 obj-$(CONFIG_SPL_UT_LOAD_OS) += spl_load_os.o
 obj-$(CONFIG_SPL_UT_LOAD_SPI) += spl_load_spi.o
diff --git a/test/image/spl_load.c b/test/image/spl_load.c
index 166cf331194..0e3bc0d6caa 100644
--- a/test/image/spl_load.c
+++ b/test/image/spl_load.c
@@ -163,7 +163,9 @@ static size_t start_fit(void *dst, size_t fit_size, size_t 
data_size,
 static size_t create_fit(void *dst, struct spl_image_info *spl_image,
                         size_t *data_offset, bool external)
 {
-       size_t prop_size = 596, total_size = prop_size + spl_image->size;
+       /* Both the image and configuration have a description. */
+       size_t prop_size = ALIGN(596 + 2 * (strlen(spl_image->name) + 1), 4);
+       size_t total_size = prop_size + spl_image->size;
        size_t off, size;
 
        if (external) {
diff --git a/test/image/spl_ram.c b/test/image/spl_ram.c
new file mode 100644
index 00000000000..5874ac02a3a
--- /dev/null
+++ b/test/image/spl_ram.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Carlo Caione <[email protected]> */
+
+#include <image.h>
+#include <mapmem.h>
+#include <spl.h>
+#include <test/spl.h>
+#include <test/ut.h>
+
+static int check_ram_image(struct unit_test_state *uts, void *image, size_t 
size,
+                          struct spl_image_info *expected, const void *data)
+{
+       struct spl_image_info loaded = {};
+
+       ut_assertok(spl_ram_load_fit(&loaded, image, size));
+       ut_assertok(check_image_info(uts, expected, &loaded));
+       ut_asserteq_mem(data, map_sysmem(loaded.load_addr, loaded.size), 
loaded.size);
+       return 0;
+}
+
+static int spl_test_ram(struct unit_test_state *uts, const char *name,
+                       enum spl_test_image type)
+{
+       struct spl_image_info info = { .name = name, .size = SPL_TEST_DATA_SIZE 
};
+       size_t size, offset;
+       void *image;
+       int ret;
+
+       size = create_image(NULL, type, &info, &offset);
+       ut_assert(size);
+       image = calloc(1, size);
+       ut_assertnonnull(image);
+       generate_data(image + offset, info.size, name);
+       if (create_image(image, type, &info, NULL) != size) {
+               free(image);
+               return -EINVAL;
+       }
+       if (type == FIT_INTERNAL)
+               size = fdt_totalsize(image);
+       ret = check_ram_image(uts, image, size, &info, image + offset);
+       if (!ret)
+               ret = check_ram_image(uts, image, SIZE_MAX, &info, image + 
offset);
+       free(image);
+       return ret;
+}
+
+SPL_IMG_TEST(spl_test_ram, FIT_INTERNAL, 0);
+SPL_IMG_TEST(spl_test_ram, FIT_EXTERNAL, 0);

-- 
2.56.0

Reply via email to