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
