[PATCH v2 00/29] test: spl: Test some load methods

This series adds some tests for various SPL load methods, with the intent of helping debug v6 of [1]. With that in mind, notable omissions include NAND and ROMAPI, which both lack sandbox implementations, and OS_BOOT, which I have deferred due to its complexity. Semihosting is also omitted, but I think we can test that with qemu.
In order to test all of these methods, we must first generate suitable images, possibly on filesystems. While other tests have historically generated these images using external tools (e.g. mkimage, mkfs, etc.), I have chosen to generate them on the fly. This is for a few reasons:
- By removing external dependencies on pytest to create certain files, the tests become self-contained. This makes them easier to iterate on and debug. - By generating tests at runtime, we can dynamically vary the content. This helps detect test failures, as even if tests are loaded to the same location, the expected content will be different. - We are not testing the image parsers themselves (e.g. spl_load_simple_fit or fs_read) but rather the load methods (e.g. spl_mmc_load_image). It is unnecessary to exercise full functionality or generate 100% correct images. - By reducing functionality to only what is necessary, the complexity of various formats can often be greatly reduced.
This series depends on [2-3], which are small fixes identified through this patch set. The organization of patches in this series is as follows:
- General fixes for bugs which are unlikely to be triggered outside of this series - Changes to IMX8 container images to facilitate testing - General prep. work, particularly regarding linker issues - The tests themselves
Passing CI at [4].
[1] https://lore.kernel.org/all/20230731224304.111081-1-sean.anderson@seco.com/ [2] https://lore.kernel.org/all/20230930204246.515254-1-seanga2@gmail.com/ [3] https://lore.kernel.org/all/20231008014748.1987840-1-seanga2@gmail.com/ [4] https://source.denx.de/u-boot/custodians/u-boot-clk/-/pipelines/18128
Changes in v2: - Use "address of" to describe the "&" operator - Remove check for zero entry point in spl_load_fit_image - Use log_err for errors in read_auth_container - Clarify commit message for patch "Check header before calling spl_load_imx_container" - Hide SPL_OF_REAL unless SANDBOX is enabled - Disable sandbox filesystem in SPL instead of compiling it in - Split ext4 defines into their own commit - Use SPL_TPL_ for compiling fastboot functions - Use callbacks to invalidate SPL caches instead of disabling them entirely - Split off -T support into its own commit - Compare to PHASE_SPL in sandbox_cmdline_cb_test_fdt for clarity - Remove redundant condition on CONFIG_SPL_UT_LOAD in test/image/Makefile - Remove unused mapmem.h include in spl_load_os.c - Fix size not being updated in board_spl_fit_buffer_addr - Fix return value documentation for check_image_info - Explicitly invalidate FAT block device cache before testing - Remove unused dm.h include in spl_load.c - Add note about why we enable SPL_TIMER - Explicitly invalidate FAT block device cache before testing - Correct return value documentation for do_spl_test_load - Explicitly invalidate FAT and MMC caches before testing - Add a comment about why we need to initialize bi_dram - Clarify generation process for LZMA data
Sean Anderson (29): spl: legacy: Fix referencing _image_binary_end spl: nor: Don't allocate header on stack spl: fit: Fix entry point for SPL_LOAD_FIT_FULL arm: imx: Fix i.MX8 container load address arm: imx: Add newlines after error messages arm: imx: Use log_err for errors in read_auth_container arm: imx: Add function to validate i.MX8 containers arm: imx: Check header before calling spl_load_imx_container Move i.MX8 container image loading support to common/spl spl: Allow enabling SPL_OF_REAL and SPL_OF_PLATDATA at the same time lib: acpi: Fix linking SPL when ACPIGEN is enabled fs: Disable sandbox filesystem in SPL fs: ext4: Fix building ext4 in SPL if write is enabled fs: ext4: Add some defines for testing net: Fix compiling SPL when fastboot is enabled net: bootp: Move port numbers to header net: bootp: Fall back to BOOTP from DHCP when unit testing spl: Add callbacks to invalidate cached devices spl: Use map_sysmem where appropriate sandbox: Support -T in spl test: spl: Split tests up and use some configs test: spl: Fix spl_test_load not failing if fname doesn't exist test: spl: Add functions to create images test: spl: Add functions to create filesystems test: spl: Add a test for spl_blk_load_image test: spl: Add a test for the MMC load method test: spl: Add a test for the NET load method test: spl: Add a test for the NOR load method test: spl: Add a test for the SPI load method
.azure-pipelines.yml | 4 + .gitlab-ci.yml | 7 + MAINTAINERS | 2 + arch/arm/include/asm/mach-imx/ahab.h | 2 +- arch/arm/mach-imx/Kconfig | 13 - arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/cmd_dek.c | 4 +- arch/arm/mach-imx/ele_ahab.c | 4 +- arch/arm/mach-imx/image-container.c | 4 +- arch/arm/mach-imx/imx8/ahab.c | 4 +- arch/arm/mach-imx/spl_imx_romapi.c | 8 +- arch/sandbox/cpu/spl.c | 4 + arch/sandbox/cpu/start.c | 9 +- arch/sandbox/cpu/u-boot-spl.lds | 2 + arch/sandbox/include/asm/spl.h | 3 + common/spl/Kconfig | 15 + common/spl/Makefile | 1 + common/spl/spl.c | 4 +- common/spl/spl_blk_fs.c | 6 +- common/spl/spl_ext.c | 4 +- common/spl/spl_fat.c | 16 +- common/spl/spl_fit.c | 39 +- .../spl/spl_imx_container.c | 13 +- common/spl/spl_legacy.c | 8 +- common/spl/spl_mmc.c | 16 +- common/spl/spl_nand.c | 4 +- common/spl/spl_net.c | 10 +- common/spl/spl_nor.c | 18 +- common/spl/spl_spi.c | 18 +- configs/deneb_defconfig | 2 + configs/giedi_defconfig | 2 + configs/imx8qm_mek_defconfig | 2 + configs/imx8qxp_mek_defconfig | 2 + configs/sandbox_noinst_defconfig | 31 +- configs/sandbox_spl_defconfig | 8 + configs/sandbox_vpl_defconfig | 1 + drivers/core/Makefile | 1 + drivers/core/root.c | 2 +- drivers/i2c/Makefile | 2 +- drivers/i2c/i2c-emul-uclass.c | 2 +- drivers/serial/sandbox.c | 2 +- drivers/sysreset/sysreset_sandbox.c | 2 +- drivers/usb/gadget/f_sdp.c | 4 +- dts/Kconfig | 8 +- fs/fs.c | 2 +- include/configs/sandbox.h | 3 + include/ext4fs.h | 1 + include/ext_common.h | 14 + .../image.h => include/imx_container.h | 9 + include/spl.h | 36 + include/test/spl.h | 155 ++++ lib/Kconfig | 6 + lib/Makefile | 1 + net/Makefile | 4 +- net/bootp.c | 9 +- net/bootp.h | 3 + net/net.c | 4 +- test/Kconfig | 1 + test/Makefile | 5 +- test/image/Kconfig | 50 ++ test/image/Makefile | 7 +- test/image/spl_load.c | 690 ++++++++++++++++-- test/image/spl_load_fs.c | 428 +++++++++++ test/image/spl_load_net.c | 252 +++++++ test/image/spl_load_nor.c | 39 + test/image/spl_load_os.c | 76 ++ test/image/spl_load_spi.c | 41 ++ test/py/tests/test_spl.py | 10 + test/test-main.c | 2 +- 69 files changed, 2000 insertions(+), 163 deletions(-) rename arch/arm/mach-imx/parse-container.c => common/spl/spl_imx_container.c (91%) rename arch/arm/include/asm/mach-imx/image.h => include/imx_container.h (82%) create mode 100644 include/test/spl.h create mode 100644 test/image/Kconfig create mode 100644 test/image/spl_load_fs.c create mode 100644 test/image/spl_load_net.c create mode 100644 test/image/spl_load_nor.c create mode 100644 test/image/spl_load_os.c create mode 100644 test/image/spl_load_spi.c

On non-arm architectures, _image_binary_end is defined as a ulong and not a char[]. Take the address of it when accessing it, which is correct for both.
Fixes: 1b8a1be1a1f ("spl: spl_legacy: Fix spl_end address") Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Use "address of" to describe the "&" operator
common/spl/spl_legacy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/spl/spl_legacy.c b/common/spl/spl_legacy.c index 095443c63d8..e9564e5c2a5 100644 --- a/common/spl/spl_legacy.c +++ b/common/spl/spl_legacy.c @@ -19,7 +19,7 @@ static void spl_parse_legacy_validate(uintptr_t start, uintptr_t size) { uintptr_t spl_start = (uintptr_t)_start; - uintptr_t spl_end = (uintptr_t)_image_binary_end; + uintptr_t spl_end = (uintptr_t)&_image_binary_end; uintptr_t end = start + size;
if ((start >= spl_start && start < spl_end) ||

spl_image_info.name contains a reference to legacy_img_hdr. If we allocate the latter on the stack, it will be clobbered after we return. This was addressed for NAND back in 06377c5a1fc ("spl: spl_legacy: Fix NAND boot on OMAP3 BeagleBoard"), but that commit didn't fix NOR.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Michael Trimarchi michael@amarulasolutions.com ---
(no changes since v1)
common/spl/spl_nor.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/common/spl/spl_nor.c b/common/spl/spl_nor.c index 79d4f1d7aa8..c141a9ae629 100644 --- a/common/spl/spl_nor.c +++ b/common/spl/spl_nor.c @@ -26,7 +26,7 @@ unsigned long __weak spl_nor_get_uboot_base(void) static int spl_nor_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { - __maybe_unused const struct legacy_img_hdr *header; + struct legacy_img_hdr *header; __maybe_unused struct spl_load_info load;
/* @@ -41,7 +41,7 @@ static int spl_nor_load_image(struct spl_image_info *spl_image, * Load Linux from its location in NOR flash to its defined * location in SDRAM */ - header = (const struct legacy_img_hdr *)CONFIG_SYS_OS_BASE; + header = (void *)CONFIG_SYS_OS_BASE; #ifdef CONFIG_SPL_LOAD_FIT if (image_get_magic(header) == FDT_MAGIC) { int ret; @@ -91,8 +91,8 @@ static int spl_nor_load_image(struct spl_image_info *spl_image, * Load real U-Boot from its location in NOR flash to its * defined location in SDRAM */ -#ifdef CONFIG_SPL_LOAD_FIT header = (const struct legacy_img_hdr *)spl_nor_get_uboot_base(); +#ifdef CONFIG_SPL_LOAD_FIT if (image_get_magic(header) == FDT_MAGIC) { debug("Found FIT format U-Boot\n"); load.bl_len = 1; @@ -111,14 +111,11 @@ static int spl_nor_load_image(struct spl_image_info *spl_image,
/* Legacy image handling */ if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_FORMAT)) { - struct legacy_img_hdr hdr; - load.bl_len = 1; load.read = spl_nor_load_read; - spl_nor_load_read(&load, spl_nor_get_uboot_base(), sizeof(hdr), &hdr); return spl_load_legacy_img(spl_image, bootdev, &load, spl_nor_get_uboot_base(), - &hdr); + header); }
return -EINVAL;

The entry point is not always the same as the load address. Use the value of the entry property if it exists.
Fixes: 8a9dc16e4d0 ("spl: Add full fitImage support") Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Remove check for zero entry point in spl_load_fit_image
common/spl/spl_fit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index ce6b8aa370a..4f8b951efe2 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -884,8 +884,9 @@ int spl_load_fit_image(struct spl_image_info *spl_image, return ret;
spl_image->size = fw_len; - spl_image->entry_point = fw_data; spl_image->load_addr = fw_data; + if (fit_image_get_entry(header, ret, &spl_image->entry_point)) + spl_image->entry_point = fw_data; if (fit_image_get_os(header, ret, &spl_image->os)) spl_image->os = IH_OS_INVALID; spl_image->name = genimg_get_os_name(spl_image->os);

We should load images to their destination, not their entry point.
Fixes: 7b86cd4274e ("imx8: support parsing i.MX8 Container file") Signed-off-by: Sean Anderson seanga2@gmail.com ---
(no changes since v1)
arch/arm/mach-imx/parse-container.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-imx/parse-container.c b/arch/arm/mach-imx/parse-container.c index e2a9e2b2732..d7275a58c17 100644 --- a/arch/arm/mach-imx/parse-container.c +++ b/arch/arm/mach-imx/parse-container.c @@ -45,7 +45,7 @@ static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image, debug("%s: container: %p sector: %lu sectors: %u\n", __func__, container, sector, sectors); if (info->read(info, sector, sectors, - (void *)images[image_index].entry) != sectors) { + (void *)images[image_index].dst) != sectors) { printf("%s wrong\n", __func__); return NULL; }

These error messages are missing newlines. Add them.
Fixes: 6e81ca220e0 ("imx: parse-container: Use malloc for container processing") Signed-off-by: Sean Anderson seanga2@gmail.com ---
(no changes since v1)
arch/arm/mach-imx/parse-container.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-imx/parse-container.c b/arch/arm/mach-imx/parse-container.c index d7275a58c17..c5df78d1c58 100644 --- a/arch/arm/mach-imx/parse-container.c +++ b/arch/arm/mach-imx/parse-container.c @@ -85,13 +85,13 @@ static int read_auth_container(struct spl_image_info *spl_image, }
if (container->tag != 0x87 && container->version != 0x0) { - printf("Wrong container header"); + printf("Wrong container header\n"); ret = -ENOENT; goto end; }
if (!container->num_images) { - printf("Wrong container, no image found"); + printf("Wrong container, no image found\n"); ret = -ENOENT; goto end; }

To allow for more flexible handling of errors, use log_err instead of printf.
Signed-off-by: Sean Anderson seanga2@gmail.com ---
Changes in v2: - New
arch/arm/mach-imx/parse-container.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-imx/parse-container.c b/arch/arm/mach-imx/parse-container.c index c5df78d1c58..48cffb3ab4d 100644 --- a/arch/arm/mach-imx/parse-container.c +++ b/arch/arm/mach-imx/parse-container.c @@ -3,6 +3,7 @@ * Copyright 2018-2021 NXP */
+#define LOG_CATEGORY LOGC_ARCH #include <common.h> #include <stdlib.h> #include <errno.h> @@ -85,13 +86,13 @@ static int read_auth_container(struct spl_image_info *spl_image, }
if (container->tag != 0x87 && container->version != 0x0) { - printf("Wrong container header\n"); + log_err("Wrong container header\n"); ret = -ENOENT; goto end; }
if (!container->num_images) { - printf("Wrong container, no image found\n"); + log_err("Wrong container, no image found\n"); ret = -ENOENT; goto end; }

Add a function to abstract the common task of validating i.MX8 container image headers.
Signed-off-by: Sean Anderson seanga2@gmail.com ---
(no changes since v1)
arch/arm/include/asm/mach-imx/image.h | 9 +++++++++ arch/arm/mach-imx/ele_ahab.c | 2 +- arch/arm/mach-imx/image-container.c | 2 +- arch/arm/mach-imx/imx8/ahab.c | 2 +- arch/arm/mach-imx/parse-container.c | 2 +- arch/arm/mach-imx/spl_imx_romapi.c | 3 ++- 6 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/mach-imx/image.h b/arch/arm/include/asm/mach-imx/image.h index ee67ca96f4c..54cd684e35d 100644 --- a/arch/arm/include/asm/mach-imx/image.h +++ b/arch/arm/include/asm/mach-imx/image.h @@ -18,6 +18,9 @@ #define CONTAINER_HDR_QSPI_OFFSET SZ_4K #define CONTAINER_HDR_NAND_OFFSET SZ_128M
+#define CONTAINER_HDR_TAG 0x87 +#define CONTAINER_HDR_VERSION 0 + struct container_hdr { u8 version; u8 length_lsb; @@ -66,4 +69,10 @@ struct generate_key_blob_hdr { } __packed;
int get_container_size(ulong addr, u16 *header_length); + +static inline bool valid_container_hdr(struct container_hdr *container) +{ + return container->tag == CONTAINER_HDR_TAG && + container->version == CONTAINER_HDR_VERSION; +} #endif diff --git a/arch/arm/mach-imx/ele_ahab.c b/arch/arm/mach-imx/ele_ahab.c index 785b0d6ec3c..6a1ad198f89 100644 --- a/arch/arm/mach-imx/ele_ahab.c +++ b/arch/arm/mach-imx/ele_ahab.c @@ -343,7 +343,7 @@ int authenticate_os_container(ulong addr) }
phdr = (struct container_hdr *)addr; - if (phdr->tag != 0x87 || phdr->version != 0x0) { + if (!valid_container_hdr(phdr)) { printf("Error: Wrong container header\n"); return -EFAULT; } diff --git a/arch/arm/mach-imx/image-container.c b/arch/arm/mach-imx/image-container.c index 5f188ab32d1..eff9e0c4597 100644 --- a/arch/arm/mach-imx/image-container.c +++ b/arch/arm/mach-imx/image-container.c @@ -50,7 +50,7 @@ int get_container_size(ulong addr, u16 *header_length) u32 max_offset = 0, img_end;
phdr = (struct container_hdr *)addr; - if (phdr->tag != 0x87 || phdr->version != 0x0) { + if (!valid_container_hdr(phdr)) { debug("Wrong container header\n"); return -EFAULT; } diff --git a/arch/arm/mach-imx/imx8/ahab.c b/arch/arm/mach-imx/imx8/ahab.c index b58b14ca9b4..44ea63584aa 100644 --- a/arch/arm/mach-imx/imx8/ahab.c +++ b/arch/arm/mach-imx/imx8/ahab.c @@ -146,7 +146,7 @@ int authenticate_os_container(ulong addr) }
phdr = (struct container_hdr *)addr; - if (phdr->tag != 0x87 && phdr->version != 0x0) { + if (!valid_container_hdr(phdr)) { printf("Error: Wrong container header\n"); return -EFAULT; } diff --git a/arch/arm/mach-imx/parse-container.c b/arch/arm/mach-imx/parse-container.c index 48cffb3ab4d..d57f25df6dc 100644 --- a/arch/arm/mach-imx/parse-container.c +++ b/arch/arm/mach-imx/parse-container.c @@ -85,7 +85,7 @@ static int read_auth_container(struct spl_image_info *spl_image, goto end; }
- if (container->tag != 0x87 && container->version != 0x0) { + if (!valid_container_hdr(container)) { log_err("Wrong container header\n"); ret = -ENOENT; goto end; diff --git a/arch/arm/mach-imx/spl_imx_romapi.c b/arch/arm/mach-imx/spl_imx_romapi.c index 4af41699678..b51061b987b 100644 --- a/arch/arm/mach-imx/spl_imx_romapi.c +++ b/arch/arm/mach-imx/spl_imx_romapi.c @@ -184,7 +184,8 @@ static u8 *search_container_header(u8 *p, int size)
for (i = 0; i < size; i += 4) { hdr = p + i; - if (*(hdr + 3) == 0x87 && *hdr == 0 && (*(hdr + 1) != 0 || *(hdr + 2) != 0)) + if (valid_container_hdr((void *)hdr) && + (*(hdr + 1) != 0 || *(hdr + 2) != 0)) return p + i; }

Make sure we have an IMX header before calling spl_load_imx_container, since if we don't it will fail with -ENOENT. This allows us to fall back to legacy/raw images if they are also enabled.
This is a functional change, one which likely should have been in place from the start, but a functional change nonetheless. Previously, all non-IMX8 images (except FITs without FIT_FULL) would be optimized out if the only image load method enabled supported IMX8 images. With this change, support for other image types now has an effect.
There are seven boards with SPL_LOAD_IMX_CONTAINER enabled: three with SPL_BOOTROM_SUPPORT:
imx93_11x11_evk_ld imx93_11x11_evk imx8ulp_evk
and four with SPL_MMC:
deneb imx8qxp_mek giedi imx8qm_mek
All of these boards also have SPL_RAW_IMAGE_SUPPORT and SPL_LEGACY_IMAGE_FORMAT enabled as well. However, none have FIT support enabled. Of the six load methods affected by this patch, only SPL_MMC and SPL_BOOTROM_SUPPORT are enabled with SPL_LOAD_IMX_CONTAINER. spl_romapi_load_image_seekable does not support legacy or raw images, so there is no growth. However, mmc_load_image_raw_sector does support loading legacy/raw images. Since these images could not have been booted before, I have disabled support for legacy/raw images on these four boards. This reduces bloat from around 800 bytes to around 200.
There are no in-tree boards with SPL_LOAD_IMX_CONTAINER and AHAB_BOOT both enabled, so we do not need to worry about potentially falling back to legacy images in a secure boot scenario.
Future work could include merging imx_container.h with imx8image.h, since they appear to define mostly the same structures.
Signed-off-by: Sean Anderson seanga2@gmail.com ---
Changes in v2: - Clarify commit message
MAINTAINERS | 1 + arch/arm/include/asm/mach-imx/ahab.h | 2 +- arch/arm/mach-imx/cmd_dek.c | 4 ++-- arch/arm/mach-imx/ele_ahab.c | 2 +- arch/arm/mach-imx/image-container.c | 2 +- arch/arm/mach-imx/imx8/ahab.c | 2 +- arch/arm/mach-imx/parse-container.c | 2 +- arch/arm/mach-imx/spl_imx_romapi.c | 5 +++-- common/spl/spl_mmc.c | 4 +++- common/spl/spl_nand.c | 4 +++- common/spl/spl_nor.c | 4 +++- common/spl/spl_spi.c | 4 +++- configs/deneb_defconfig | 2 ++ configs/giedi_defconfig | 2 ++ configs/imx8qm_mek_defconfig | 2 ++ configs/imx8qxp_mek_defconfig | 2 ++ drivers/usb/gadget/f_sdp.c | 4 +++- .../include/asm/mach-imx/image.h => include/imx_container.h | 0 18 files changed, 34 insertions(+), 14 deletions(-) rename arch/arm/include/asm/mach-imx/image.h => include/imx_container.h (100%)
diff --git a/MAINTAINERS b/MAINTAINERS index 7d5d05320c0..35209e73af5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -300,6 +300,7 @@ F: arch/arm/include/asm/mach-imx/ F: board/freescale/*mx*/ F: board/freescale/common/ F: drivers/serial/serial_mxc.c +F: include/imx_container.h
ARM HISILICON M: Peter Griffin peter.griffin@linaro.org diff --git a/arch/arm/include/asm/mach-imx/ahab.h b/arch/arm/include/asm/mach-imx/ahab.h index 4222e3db278..4884f056251 100644 --- a/arch/arm/include/asm/mach-imx/ahab.h +++ b/arch/arm/include/asm/mach-imx/ahab.h @@ -6,7 +6,7 @@ #ifndef __IMX_AHAB_H__ #define __IMX_AHAB_H__
-#include <asm/mach-imx/image.h> +#include <imx_container.h>
int ahab_auth_cntr_hdr(struct container_hdr *container, u16 length); int ahab_auth_release(void); diff --git a/arch/arm/mach-imx/cmd_dek.c b/arch/arm/mach-imx/cmd_dek.c index 6fa5b41fcd3..2f389dbe8df 100644 --- a/arch/arm/mach-imx/cmd_dek.c +++ b/arch/arm/mach-imx/cmd_dek.c @@ -18,12 +18,12 @@ #include <mapmem.h> #include <tee.h> #ifdef CONFIG_IMX_SECO_DEK_ENCAP +#include <imx_container.h> #include <firmware/imx/sci/sci.h> -#include <asm/mach-imx/image.h> #endif #ifdef CONFIG_IMX_ELE_DEK_ENCAP +#include <imx_container.h> #include <asm/mach-imx/ele_api.h> -#include <asm/mach-imx/image.h> #endif
#include <cpu_func.h> diff --git a/arch/arm/mach-imx/ele_ahab.c b/arch/arm/mach-imx/ele_ahab.c index 6a1ad198f89..295c055ad0a 100644 --- a/arch/arm/mach-imx/ele_ahab.c +++ b/arch/arm/mach-imx/ele_ahab.c @@ -6,12 +6,12 @@ #include <common.h> #include <command.h> #include <errno.h> +#include <imx_container.h> #include <asm/io.h> #include <asm/mach-imx/ele_api.h> #include <asm/mach-imx/sys_proto.h> #include <asm/arch-imx/cpu.h> #include <asm/arch/sys_proto.h> -#include <asm/mach-imx/image.h> #include <console.h> #include <cpu_func.h> #include <asm/global_data.h> diff --git a/arch/arm/mach-imx/image-container.c b/arch/arm/mach-imx/image-container.c index eff9e0c4597..ebc8021d7cc 100644 --- a/arch/arm/mach-imx/image-container.c +++ b/arch/arm/mach-imx/image-container.c @@ -5,6 +5,7 @@
#include <common.h> #include <errno.h> +#include <imx_container.h> #include <log.h> #include <malloc.h> #include <asm/io.h> @@ -12,7 +13,6 @@ #include <spi_flash.h> #include <spl.h> #include <nand.h> -#include <asm/mach-imx/image.h> #include <asm/arch/sys_proto.h> #include <asm/mach-imx/boot_mode.h>
diff --git a/arch/arm/mach-imx/imx8/ahab.c b/arch/arm/mach-imx/imx8/ahab.c index 44ea63584aa..994becccefd 100644 --- a/arch/arm/mach-imx/imx8/ahab.c +++ b/arch/arm/mach-imx/imx8/ahab.c @@ -6,6 +6,7 @@ #include <common.h> #include <command.h> #include <errno.h> +#include <imx_container.h> #include <log.h> #include <asm/global_data.h> #include <asm/io.h> @@ -13,7 +14,6 @@ #include <asm/mach-imx/sys_proto.h> #include <asm/arch-imx/cpu.h> #include <asm/arch/sys_proto.h> -#include <asm/mach-imx/image.h> #include <console.h> #include <cpu_func.h> #include "u-boot/sha256.h" diff --git a/arch/arm/mach-imx/parse-container.c b/arch/arm/mach-imx/parse-container.c index d57f25df6dc..c29cb15f55e 100644 --- a/arch/arm/mach-imx/parse-container.c +++ b/arch/arm/mach-imx/parse-container.c @@ -7,9 +7,9 @@ #include <common.h> #include <stdlib.h> #include <errno.h> +#include <imx_container.h> #include <log.h> #include <spl.h> -#include <asm/mach-imx/image.h> #ifdef CONFIG_AHAB_BOOT #include <asm/mach-imx/ahab.h> #endif diff --git a/arch/arm/mach-imx/spl_imx_romapi.c b/arch/arm/mach-imx/spl_imx_romapi.c index b51061b987b..8816566b364 100644 --- a/arch/arm/mach-imx/spl_imx_romapi.c +++ b/arch/arm/mach-imx/spl_imx_romapi.c @@ -6,11 +6,11 @@ #include <common.h> #include <errno.h> #include <image.h> +#include <imx_container.h> #include <log.h> #include <asm/global_data.h> #include <linux/libfdt.h> #include <spl.h> -#include <asm/mach-imx/image.h> #include <asm/arch/sys_proto.h>
DECLARE_GLOBAL_DATA_PTR; @@ -111,7 +111,8 @@ static int spl_romapi_load_image_seekable(struct spl_image_info *spl_image, load.read = spl_romapi_read_seekable; load.priv = &pagesize; return spl_load_simple_fit(spl_image, &load, offset / pagesize, header); - } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { + } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) && + valid_container_hdr((void *)header)) { struct spl_load_info load;
memset(&load, 0, sizeof(load)); diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 02ad32a23e0..67c7ae34a58 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -16,6 +16,7 @@ #include <errno.h> #include <mmc.h> #include <image.h> +#include <imx_container.h>
static int mmc_load_legacy(struct spl_image_info *spl_image, struct spl_boot_device *bootdev, @@ -108,7 +109,8 @@ int mmc_load_image_raw_sector(struct spl_image_info *spl_image, load.bl_len = mmc->read_bl_len; load.read = h_spl_load_read; ret = spl_load_simple_fit(spl_image, &load, sector, header); - } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { + } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) && + valid_container_hdr((void *)header)) { struct spl_load_info load;
load.dev = mmc; diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 6cc34004f49..07916bedbb9 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -7,6 +7,7 @@ #include <config.h> #include <fdt_support.h> #include <image.h> +#include <imx_container.h> #include <log.h> #include <spl.h> #include <asm/io.h> @@ -99,7 +100,8 @@ static int spl_nand_load_element(struct spl_image_info *spl_image, load.bl_len = bl_len; load.read = spl_nand_fit_read; return spl_load_simple_fit(spl_image, &load, offset / bl_len, header); - } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { + } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) && + valid_container_hdr((void *)header)) { struct spl_load_info load;
load.dev = NULL; diff --git a/common/spl/spl_nor.c b/common/spl/spl_nor.c index c141a9ae629..dd447982071 100644 --- a/common/spl/spl_nor.c +++ b/common/spl/spl_nor.c @@ -5,6 +5,7 @@
#include <common.h> #include <image.h> +#include <imx_container.h> #include <log.h> #include <spl.h>
@@ -102,7 +103,8 @@ static int spl_nor_load_image(struct spl_image_info *spl_image, (void *)header); } #endif - if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { + if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) && + valid_container_hdr((void *)header)) { load.bl_len = 1; load.read = spl_nor_load_read; return spl_load_imx_container(spl_image, &load, diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index d69069a75bf..1427c9478c0 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -10,6 +10,7 @@
#include <common.h> #include <image.h> +#include <imx_container.h> #include <log.h> #include <spi.h> #include <spi_flash.h> @@ -153,7 +154,8 @@ static int spl_spi_load_image(struct spl_image_info *spl_image, err = spl_load_simple_fit(spl_image, &load, payload_offs, header); - } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { + } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) && + valid_container_hdr((void *)header)) { struct spl_load_info load;
load.dev = flash; diff --git a/configs/deneb_defconfig b/configs/deneb_defconfig index 82869e4e0f9..ee2478aa0bb 100644 --- a/configs/deneb_defconfig +++ b/configs/deneb_defconfig @@ -44,6 +44,8 @@ CONFIG_SPL_HAS_BSS_LINKER_SECTION=y CONFIG_SPL_BSS_START_ADDR=0x128000 CONFIG_SPL_BSS_MAX_SIZE=0x1000 CONFIG_SPL_BOARD_INIT=y +# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set +# CONFIG_SPL_LEGACY_IMAGE_FORMAT is not set CONFIG_SPL_SYS_MALLOC_SIMPLE=y # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set CONFIG_SPL_SYS_MALLOC=y diff --git a/configs/giedi_defconfig b/configs/giedi_defconfig index b56b736c436..5e403c90c8c 100644 --- a/configs/giedi_defconfig +++ b/configs/giedi_defconfig @@ -44,6 +44,8 @@ CONFIG_SPL_HAS_BSS_LINKER_SECTION=y CONFIG_SPL_BSS_START_ADDR=0x128000 CONFIG_SPL_BSS_MAX_SIZE=0x1000 CONFIG_SPL_BOARD_INIT=y +# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set +# CONFIG_SPL_LEGACY_IMAGE_FORMAT is not set CONFIG_SPL_SYS_MALLOC_SIMPLE=y # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set CONFIG_SPL_SYS_MALLOC=y diff --git a/configs/imx8qm_mek_defconfig b/configs/imx8qm_mek_defconfig index b9083b0453f..4c5206306ee 100644 --- a/configs/imx8qm_mek_defconfig +++ b/configs/imx8qm_mek_defconfig @@ -38,6 +38,8 @@ CONFIG_SPL_HAS_BSS_LINKER_SECTION=y CONFIG_SPL_BSS_START_ADDR=0x128000 CONFIG_SPL_BSS_MAX_SIZE=0x1000 CONFIG_SPL_BOARD_INIT=y +# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set +# CONFIG_SPL_LEGACY_IMAGE_FORMAT is not set CONFIG_SPL_SYS_MALLOC_SIMPLE=y # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set CONFIG_SPL_SYS_MALLOC=y diff --git a/configs/imx8qxp_mek_defconfig b/configs/imx8qxp_mek_defconfig index f516b0b5557..f312d3945fb 100644 --- a/configs/imx8qxp_mek_defconfig +++ b/configs/imx8qxp_mek_defconfig @@ -38,6 +38,8 @@ CONFIG_SPL_HAS_BSS_LINKER_SECTION=y CONFIG_SPL_BSS_START_ADDR=0x128000 CONFIG_SPL_BSS_MAX_SIZE=0x1000 CONFIG_SPL_BOARD_INIT=y +# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set +# CONFIG_SPL_LEGACY_IMAGE_FORMAT is not set CONFIG_SPL_SYS_MALLOC_SIMPLE=y # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set CONFIG_SPL_SYS_MALLOC=y diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index 2b3a9c5fd4c..ee9384fb37e 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -34,6 +34,7 @@ #include <spl.h> #include <image.h> #include <imximage.h> +#include <imx_container.h> #include <watchdog.h>
#define HID_REPORT_ID_MASK 0x000000ff @@ -852,7 +853,8 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image, return SDP_EXIT; } #endif - if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { + if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) && + valid_container_hdr((void *)header)) { struct spl_load_info load;
load.dev = header; diff --git a/arch/arm/include/asm/mach-imx/image.h b/include/imx_container.h similarity index 100% rename from arch/arm/include/asm/mach-imx/image.h rename to include/imx_container.h

To facilitate testing loading i.MX8 container images, move the parse-container code to common/spl.
Signed-off-by: Sean Anderson seanga2@gmail.com ---
(no changes since v1)
MAINTAINERS | 1 + arch/arm/mach-imx/Kconfig | 13 ------------- arch/arm/mach-imx/Makefile | 2 +- common/spl/Kconfig | 14 ++++++++++++++ common/spl/Makefile | 1 + .../spl/spl_imx_container.c | 0 6 files changed, 17 insertions(+), 14 deletions(-) rename arch/arm/mach-imx/parse-container.c => common/spl/spl_imx_container.c (100%)
diff --git a/MAINTAINERS b/MAINTAINERS index 35209e73af5..dd6bb558dc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -299,6 +299,7 @@ F: arch/arm/include/asm/arch-vf610/ F: arch/arm/include/asm/mach-imx/ F: board/freescale/*mx*/ F: board/freescale/common/ +F: common/spl/spl_imx_container.c F: drivers/serial/serial_mxc.c F: include/imx_container.h
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 266bb20df9d..08ab7069187 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -194,19 +194,6 @@ config IMX_DCD_ADDR This information is shared with the user via mkimage -l just so the image can be signed.
-config SPL_LOAD_IMX_CONTAINER - bool "Enable SPL loading U-Boot as a i.MX Container image" - depends on SPL - help - This is to let SPL could load i.MX Container image - -config IMX_CONTAINER_CFG - string "i.MX Container config file" - depends on SPL - help - This is to specific the cfg file for generating container - image which will be loaded by SPL. - config IOMUX_LPSR bool
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index aebfa6517bd..7c4e03278e3 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -79,7 +79,7 @@ obj-$(CONFIG_CMD_NANDBCB) += cmd_nandbcb.o endif
ifeq ($(CONFIG_SPL_BUILD),y) -obj-$(CONFIG_SPL_LOAD_IMX_CONTAINER) += image-container.o parse-container.o +obj-$(CONFIG_SPL_LOAD_IMX_CONTAINER) += image-container.o endif
ifeq ($(SOC),$(filter $(SOC),imx8ulp imx9)) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 46323597942..ad574a600e3 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -330,6 +330,20 @@ config SPL_LEGACY_IMAGE_CRC_CHECK If disabled, Legacy images are booted if the image magic and size are correct, without further integrity checks.
+config SPL_LOAD_IMX_CONTAINER + bool "Enable SPL loading and booting of i.MX8 Containers" + depends on SPL + help + Support booting U-Boot from an i.MX8 container image. If you are not + using i.MX8, say 'n'. + +config IMX_CONTAINER_CFG + string "i.MX8 Container config file" + depends on SPL && SPL_LOAD_IMX_CONTAINER + help + Specify the cfg file for generating the container image which will be + loaded by SPL. + config SPL_SYS_MALLOC_SIMPLE bool "Only use malloc_simple functions in the SPL" help diff --git a/common/spl/Makefile b/common/spl/Makefile index bad2bbf6cf1..4f8eb2ec0ca 100644 --- a/common/spl/Makefile +++ b/common/spl/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_$(SPL_TPL_)OPENSBI) += spl_opensbi.o obj-$(CONFIG_$(SPL_TPL_)USB_STORAGE) += spl_usb.o obj-$(CONFIG_$(SPL_TPL_)FS_FAT) += spl_fat.o obj-$(CONFIG_$(SPL_TPL_)FS_EXT4) += spl_ext.o +obj-$(CONFIG_$(SPL_TPL_)LOAD_IMX_CONTAINER) += spl_imx_container.o obj-$(CONFIG_$(SPL_TPL_)SATA) += spl_sata.o obj-$(CONFIG_$(SPL_TPL_)NVME) += spl_nvme.o obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += spl_semihosting.o diff --git a/arch/arm/mach-imx/parse-container.c b/common/spl/spl_imx_container.c similarity index 100% rename from arch/arm/mach-imx/parse-container.c rename to common/spl/spl_imx_container.c

Sandbox unit tests in U-Boot proper load a test device tree to have some devices to work with. In order to do the same in SPL, we must enable SPL_OF_REAL. However, we already have SPL_OF_PLATDATA enabled. When generating platdata from a devicetree, it is expected that we will not need devicetree access functions (even though SPL_OF_CONTROL is enabled). This expectation does not hold for sandbox, so allow user control of SPL_OF_REAL.
There are several places in the tree where conditions involving OF_PLATDATA or OF_REAL no longer function correctly when both of these options can be selected at the same time. Adjust these conditions accordingly.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Hide SPL_OF_REAL unless SANDBOX is enabled
drivers/core/Makefile | 1 + drivers/i2c/i2c-emul-uclass.c | 2 +- drivers/serial/sandbox.c | 2 +- drivers/sysreset/sysreset_sandbox.c | 2 +- dts/Kconfig | 8 +++++--- test/test-main.c | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index bce0a3f65cb..acbd2bf2cef 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)OF_LIVE) += of_access.o of_addr.o ifndef CONFIG_DM_DEV_READ_INLINE obj-$(CONFIG_OF_CONTROL) += read.o endif +obj-$(CONFIG_$(SPL_)OF_PLATDATA) += read.o obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o
ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c index 1107cf309fc..d421ddfcbe2 100644 --- a/drivers/i2c/i2c-emul-uclass.c +++ b/drivers/i2c/i2c-emul-uclass.c @@ -46,7 +46,7 @@ int i2c_emul_find(struct udevice *dev, struct udevice **emulp) struct udevice *emul; int ret;
- if (!CONFIG_IS_ENABLED(OF_PLATDATA)) { + if (CONFIG_IS_ENABLED(OF_REAL)) { ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev, "sandbox,emul", &emul); } else { diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index f4003811ee7..f6ac3d22852 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -280,7 +280,7 @@ U_BOOT_DRIVER(sandbox_serial) = { .flags = DM_FLAG_PRE_RELOC, };
-#if CONFIG_IS_ENABLED(OF_REAL) +#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA) static const struct sandbox_serial_plat platdata_non_fdt = { .colour = -1, }; diff --git a/drivers/sysreset/sysreset_sandbox.c b/drivers/sysreset/sysreset_sandbox.c index 3750c60b9b9..f485a135299 100644 --- a/drivers/sysreset/sysreset_sandbox.c +++ b/drivers/sysreset/sysreset_sandbox.c @@ -132,7 +132,7 @@ U_BOOT_DRIVER(warm_sysreset_sandbox) = { .ops = &sandbox_warm_sysreset_ops, };
-#if CONFIG_IS_ENABLED(OF_REAL) +#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA) /* This is here in case we don't have a device tree */ U_BOOT_DRVINFO(sysreset_sandbox_non_fdt) = { .name = "sysreset_sandbox", diff --git a/dts/Kconfig b/dts/Kconfig index 9152f5885e9..00c0aeff893 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -410,12 +410,14 @@ config SPL_OF_PLATDATA declarations for each node. See of-plat.txt for more information.
config SPL_OF_REAL - bool + bool "Support a real devicetree in SPL" if SANDBOX + depends on SPL_OF_CONTROL + select SPL_OF_LIBFDT help Indicates that a real devicetree is available which can be accessed at runtime. This means that dev_read_...() functions can be used to - read data from the devicetree for each device. This is true if - SPL_OF_CONTROL is enabled and not SPL_OF_PLATDATA + read data from the devicetree for each device. You do not need to + enable this option if you have enabled SPL_OF_PLATDATA.
if SPL_OF_PLATDATA
diff --git a/test/test-main.c b/test/test-main.c index edb20bc4b9c..b7015d9f38d 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -303,7 +303,7 @@ static int test_pre_run(struct unit_test_state *uts, struct unit_test *test) if (test->flags & UT_TESTF_PROBE_TEST) ut_assertok(do_autoprobe(uts));
- if (!CONFIG_IS_ENABLED(OF_PLATDATA) && + if (CONFIG_IS_ENABLED(OF_REAL) && (test->flags & UT_TESTF_SCAN_FDT)) { /* * only set this if we know the ethernet uclass will be created

lib/acpi/acpigen.o is only compiled into SPL when SPL_ACPIGEN is enabled. Update several files which reference these functions accordingly.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
drivers/core/root.c | 2 +- drivers/i2c/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/core/root.c b/drivers/core/root.c index 126b3140666..d4ae652bcfb 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -426,7 +426,7 @@ void dm_get_mem(struct dm_stats *stats) stats->tag_size; }
-#ifdef CONFIG_ACPIGEN +#if CONFIG_IS_ENABLED(ACPIGEN) static int root_acpi_get_name(const struct udevice *dev, char *out_name) { return acpi_copy_name(out_name, "\_SB"); diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index d5b85f398db..a96a8c7e955 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -3,7 +3,7 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. obj-$(CONFIG_$(SPL_)DM_I2C) += i2c-uclass.o -ifdef CONFIG_ACPIGEN +ifdef CONFIG_$(SPL_)ACPIGEN obj-$(CONFIG_$(SPL_)DM_I2C) += acpi_i2c.o endif obj-$(CONFIG_$(SPL_)DM_I2C_GPIO) += i2c-gpio.o

Don't bother compiling the sandbox filesystem in SPL for now, as it is not needed.
Signed-off-by: Sean Anderson seanga2@gmail.com ---
Changes in v2: - Disable sandbox filesystem in SPL instead of compiling it in
fs/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/fs.c b/fs/fs.c index cfc781bbb8d..4cb4310c9cc 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -237,7 +237,7 @@ static struct fstype_info fstypes[] = { .mkdir = fs_mkdir_unsupported, }, #endif -#ifdef CONFIG_SANDBOX +#if IS_ENABLED(CONFIG_SANDBOX) && !IS_ENABLED(CONFIG_SPL_BUILD) { .fstype = FS_TYPE_SANDBOX, .name = "sandbox",

Am 14. Oktober 2023 22:47:48 MESZ schrieb Sean Anderson seanga2@gmail.com:
Don't bother compiling the sandbox filesystem in SPL for now, as it is not needed.
Signed-off-by: Sean Anderson seanga2@gmail.com
Changes in v2:
- Disable sandbox filesystem in SPL instead of compiling it in
fs/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/fs.c b/fs/fs.c index cfc781bbb8d..4cb4310c9cc 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -237,7 +237,7 @@ static struct fstype_info fstypes[] = { .mkdir = fs_mkdir_unsupported, }, #endif -#ifdef CONFIG_SANDBOX +#if IS_ENABLED(CONFIG_SANDBOX) && !IS_ENABLED(CONFIG_SPL_BUILD)
Why do would you disable the sandbox file system in SPL for CONFIG_SANDBOX_SPL=y?
I cannot see that this is necessary to enable the unit tests you are striving for. Instead we should extend the SPL unit tests to sandbox_spl_defconfig in the long run.
Best regards
Heinrich
{ .fstype = FS_TYPE_SANDBOX, .name = "sandbox",

On 10/14/23 17:14, Heinrich Schuchardt wrote:
Am 14. Oktober 2023 22:47:48 MESZ schrieb Sean Anderson seanga2@gmail.com:
Don't bother compiling the sandbox filesystem in SPL for now, as it is not needed.
Signed-off-by: Sean Anderson seanga2@gmail.com
Changes in v2:
- Disable sandbox filesystem in SPL instead of compiling it in
fs/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/fs.c b/fs/fs.c index cfc781bbb8d..4cb4310c9cc 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -237,7 +237,7 @@ static struct fstype_info fstypes[] = { .mkdir = fs_mkdir_unsupported, }, #endif -#ifdef CONFIG_SANDBOX +#if IS_ENABLED(CONFIG_SANDBOX) && !IS_ENABLED(CONFIG_SPL_BUILD)
Why do would you disable the sandbox file system in SPL for CONFIG_SANDBOX_SPL=y?
It was never enabled in the first place, since we never had fs.c compiled in SPL before. This just fixes linking.
I cannot see that this is necessary to enable the unit tests you are striving for. Instead we should extend the SPL unit tests to sandbox_spl_defconfig in the long run.
The purpose of the sandbox filesystem is to test routines which use the filesystem API in U-Boot. However, there are very few which do so in SPL. SPL_FS_LOADER is the only one I know of off the top of my head. However, FS_LOADER is tested in U-Boot proper. I don't think there is a pressing need to enable the sandbox filesystem in SPL.
--Sean

On Sat, 14 Oct 2023 at 14:48, Sean Anderson seanga2@gmail.com wrote:
Don't bother compiling the sandbox filesystem in SPL for now, as it is not needed.
Signed-off-by: Sean Anderson seanga2@gmail.com
Changes in v2:
- Disable sandbox filesystem in SPL instead of compiling it in
fs/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

If EXT4_WRITE is enabled, write capabilities will be compiled into SPL, but not CRC16. Add an option to enable CRC16 to avoid linker errors.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
common/spl/Kconfig | 1 + lib/Kconfig | 6 ++++++ lib/Makefile | 1 + 3 files changed, 8 insertions(+)
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index ad574a600e3..6bc4066fad7 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -657,6 +657,7 @@ config SPL_ETH
config SPL_FS_EXT4 bool "Support EXT filesystems" + select SPL_CRC16 if EXT4_WRITE help Enable support for EXT2/3/4 filesystems with SPL. This permits U-Boot (or Linux in Falcon mode) to be loaded from an EXT diff --git a/lib/Kconfig b/lib/Kconfig index 79cf9ef0fa3..f6ca559897e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -687,6 +687,12 @@ config SPL_CRC8 checksum with feedback to produce an 8-bit result. The code is small and it does not require a lookup table (unlike CRC32).
+config SPL_CRC16 + bool "Support CRC16 in SPL" + depends on SPL + help + Enables CRC16 support in SPL. This is not normally required. + config CRC32 def_bool y help diff --git a/lib/Makefile b/lib/Makefile index 1c31ad9531e..2a76acf100d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_TPM_V2) += tpm-v2.o endif
obj-$(CONFIG_$(SPL_TPL_)CRC8) += crc8.o +obj-$(CONFIG_$(SPL_TPL_)CRC16) += crc16.o
obj-y += crypto/

Add various defines which are not necessary for reading/writing filesystems, but which are useful for creating them. These mostly come from Linux v6.5-rc2 (what I had checked out).
Signed-off-by: Sean Anderson seanga2@gmail.com ---
Changes in v2: - Split off from fs test
include/ext4fs.h | 1 + include/ext_common.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+)
diff --git a/include/ext4fs.h b/include/ext4fs.h index cb5d9cc0a5c..dd66d27f776 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -31,6 +31,7 @@ struct disk_partition;
#define EXT4_INDEX_FL 0x00001000 /* Inode uses hash tree index */ +#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ #define EXT4_EXT_MAGIC 0xf30a #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 diff --git a/include/ext_common.h b/include/ext_common.h index 30a0c248414..b09bbde116a 100644 --- a/include/ext_common.h +++ b/include/ext_common.h @@ -35,6 +35,16 @@ struct cmd_tbl; #define EXT2_PATH_MAX 4096 /* Maximum nesting of symlinks, used to prevent a loop. */ #define EXT2_MAX_SYMLINKCNT 8 +/* Maximum file name length */ +#define EXT2_NAME_LEN 255 + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_GOOD_OLD_INODE_SIZE 128
/* Filetype used in directory entry. */ #define FILETYPE_UNKNOWN 0 @@ -48,6 +58,10 @@ struct cmd_tbl; #define FILETYPE_INO_DIRECTORY 0040000 #define FILETYPE_INO_SYMLINK 0120000 #define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ + +/* First non-reserved inode for old ext2 filesystems */ +#define EXT2_GOOD_OLD_FIRST_INO 11
/* The size of an ext2 block in bytes. */ #define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data))

On Sat, 14 Oct 2023 at 14:48, Sean Anderson seanga2@gmail.com wrote:
Add various defines which are not necessary for reading/writing filesystems, but which are useful for creating them. These mostly come from Linux v6.5-rc2 (what I had checked out).
Signed-off-by: Sean Anderson seanga2@gmail.com
Changes in v2:
- Split off from fs test
include/ext4fs.h | 1 + include/ext_common.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

When fastboot is enabled in U-Boot proper and SPL_NET is enabled, we will try to (unsuccessfully) reference it in SPL. Fix these linker errors by conditioning on SPL_UDP/TCP_FUNCTION_FASTBOOT.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Tom Rini trini@konsulko.com ---
Changes in v2: - Use SPL_TPL_ for compiling fastboot functions
net/Makefile | 4 ++-- net/net.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/Makefile b/net/Makefile index 3e2d061338d..64ab7ec740a 100644 --- a/net/Makefile +++ b/net/Makefile @@ -27,8 +27,8 @@ obj-$(CONFIG_CMD_PCAP) += pcap.o obj-$(CONFIG_CMD_RARP) += rarp.o obj-$(CONFIG_CMD_SNTP) += sntp.o obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o -obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fastboot_udp.o -obj-$(CONFIG_TCP_FUNCTION_FASTBOOT) += fastboot_tcp.o +obj-$(CONFIG_$(SPL_TPL_)UDP_FUNCTION_FASTBOOT) += fastboot_udp.o +obj-$(CONFIG_$(SPL_TPL_)TCP_FUNCTION_FASTBOOT) += fastboot_tcp.o obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_PROT_UDP) += udp.o obj-$(CONFIG_PROT_TCP) += tcp.o diff --git a/net/net.c b/net/net.c index e6f61f0f8f6..8357f084101 100644 --- a/net/net.c +++ b/net/net.c @@ -511,12 +511,12 @@ restart: tftp_start_server(); break; #endif -#if defined(CONFIG_UDP_FUNCTION_FASTBOOT) +#if CONFIG_IS_ENABLED(UDP_FUNCTION_FASTBOOT) case FASTBOOT_UDP: fastboot_udp_start_server(); break; #endif -#if defined(CONFIG_TCP_FUNCTION_FASTBOOT) +#if CONFIG_IS_ENABLED(TCP_FUNCTION_FASTBOOT) case FASTBOOT_TCP: fastboot_tcp_start_server(); break;

These defines are useful when testing bootp.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de ---
(no changes since v1)
net/bootp.c | 3 --- net/bootp.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/bootp.c b/net/bootp.c index 8b1a4ae2ef8..2053cce88c6 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -41,9 +41,6 @@ */ #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000)
-#define PORT_BOOTPS 67 /* BOOTP server UDP port */ -#define PORT_BOOTPC 68 /* BOOTP client UDP port */ - #ifndef CFG_DHCP_MIN_EXT_LEN /* minimal length of extension list */ #define CFG_DHCP_MIN_EXT_LEN 64 #endif diff --git a/net/bootp.h b/net/bootp.h index 567340ec5d4..4e32b19d424 100644 --- a/net/bootp.h +++ b/net/bootp.h @@ -15,6 +15,9 @@
/**********************************************************************/
+#define PORT_BOOTPS 67 /* BOOTP server UDP port */ +#define PORT_BOOTPC 68 /* BOOTP client UDP port */ + /* * BOOTP header. */

Am 14. Oktober 2023 22:47:52 MESZ schrieb Sean Anderson seanga2@gmail.com:
These defines are useful when testing bootp.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
(no changes since v1)
net/bootp.c | 3 --- net/bootp.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/bootp.c b/net/bootp.c index 8b1a4ae2ef8..2053cce88c6 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -41,9 +41,6 @@ */ #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000)
-#define PORT_BOOTPS 67 /* BOOTP server UDP port */ -#define PORT_BOOTPC 68 /* BOOTP client UDP port */
#ifndef CFG_DHCP_MIN_EXT_LEN /* minimal length of extension list */ #define CFG_DHCP_MIN_EXT_LEN 64 #endif diff --git a/net/bootp.h b/net/bootp.h index 567340ec5d4..4e32b19d424 100644 --- a/net/bootp.h +++ b/net/bootp.h @@ -15,6 +15,9 @@
/**********************************************************************/
+#define PORT_BOOTPS 67 /* BOOTP server UDP port */
Reading code I would have a hard time to immediately see what this constant name stands for.
Shouldn't this be renamed BOOTP_SERVER_PORT to create readable code?
Regards Heinrich
+#define PORT_BOOTPC 68 /* BOOTP client UDP port */
/*
- BOOTP header.
*/

On Sat, Oct 14, 2023 at 11:20:31PM +0200, Heinrich Schuchardt wrote:
Am 14. Oktober 2023 22:47:52 MESZ schrieb Sean Anderson seanga2@gmail.com:
These defines are useful when testing bootp.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
(no changes since v1)
net/bootp.c | 3 --- net/bootp.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/bootp.c b/net/bootp.c index 8b1a4ae2ef8..2053cce88c6 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -41,9 +41,6 @@ */ #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000)
-#define PORT_BOOTPS 67 /* BOOTP server UDP port */ -#define PORT_BOOTPC 68 /* BOOTP client UDP port */
#ifndef CFG_DHCP_MIN_EXT_LEN /* minimal length of extension list */ #define CFG_DHCP_MIN_EXT_LEN 64 #endif diff --git a/net/bootp.h b/net/bootp.h index 567340ec5d4..4e32b19d424 100644 --- a/net/bootp.h +++ b/net/bootp.h @@ -15,6 +15,9 @@
/**********************************************************************/
+#define PORT_BOOTPS 67 /* BOOTP server UDP port */
Reading code I would have a hard time to immediately see what this constant name stands for.
Shouldn't this be renamed BOOTP_SERVER_PORT to create readable code?
We're just moving the code around for now, and this should get replaced by lwip in time.

If we sent a DHCP packet and get a BOOTP response from the server, we shouldn't try to send a DHCPREQUEST packet, since it won't be DHCPACKed. Transition straight to BIND. This is only enabled for UNIT_TEST to avoid bloat, since I suspect the number of BOOTP servers in the wild is vanishingly small.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
net/bootp.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/net/bootp.c b/net/bootp.c index 2053cce88c6..7b0f45e18a9 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -1073,6 +1073,11 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip, CONFIG_SYS_BOOTFILE_PREFIX, strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) { #endif /* CONFIG_SYS_BOOTFILE_PREFIX */ + if (CONFIG_IS_ENABLED(UNIT_TEST) && + dhcp_message_type((u8 *)bp->bp_vend) == -1) { + debug("got BOOTP response; transitioning to BOUND\n"); + goto dhcp_got_bootp; + } dhcp_packet_process_options(bp); if (CONFIG_IS_ENABLED(EFI_LOADER) && IS_ENABLED(CONFIG_NETDEVICES)) @@ -1099,6 +1104,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip, debug("DHCP State: REQUESTING\n");
if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK) { +dhcp_got_bootp: dhcp_packet_process_options(bp); /* Store net params from reply */ store_net_params(bp);

Am 14. Oktober 2023 22:47:53 MESZ schrieb Sean Anderson seanga2@gmail.com:
If we sent a DHCP packet and get a BOOTP response from the server, we shouldn't try to send a DHCPREQUEST packet, since it won't be DHCPACKed. Transition straight to BIND. This is only enabled for UNIT_TEST to avoid bloat, since I suspect the number of BOOTP servers in the wild is vanishingly small.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
net/bootp.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/net/bootp.c b/net/bootp.c index 2053cce88c6..7b0f45e18a9 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -1073,6 +1073,11 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip, CONFIG_SYS_BOOTFILE_PREFIX, strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) { #endif /* CONFIG_SYS_BOOTFILE_PREFIX */
if (CONFIG_IS_ENABLED(UNIT_TEST) &&
dhcp_message_type((u8 *)bp->bp_vend) == -1) {
As written before, please, do not add unit test specific code paths.
Best regards
Heinrich
debug("got BOOTP response; transitioning to BOUND\n");
goto dhcp_got_bootp;
} dhcp_packet_process_options(bp); if (CONFIG_IS_ENABLED(EFI_LOADER) && IS_ENABLED(CONFIG_NETDEVICES))
@@ -1099,6 +1104,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip, debug("DHCP State: REQUESTING\n");
if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK) {
+dhcp_got_bootp: dhcp_packet_process_options(bp); /* Store net params from reply */ store_net_params(bp);

On 10/14/23 17:22, Heinrich Schuchardt wrote:
Am 14. Oktober 2023 22:47:53 MESZ schrieb Sean Anderson seanga2@gmail.com:
If we sent a DHCP packet and get a BOOTP response from the server, we shouldn't try to send a DHCPREQUEST packet, since it won't be DHCPACKed. Transition straight to BIND. This is only enabled for UNIT_TEST to avoid bloat, since I suspect the number of BOOTP servers in the wild is vanishingly small.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
net/bootp.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/net/bootp.c b/net/bootp.c index 2053cce88c6..7b0f45e18a9 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -1073,6 +1073,11 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip, CONFIG_SYS_BOOTFILE_PREFIX, strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) { #endif /* CONFIG_SYS_BOOTFILE_PREFIX */
if (CONFIG_IS_ENABLED(UNIT_TEST) &&
dhcp_message_type((u8 *)bp->bp_vend) == -1) {
As written before, please, do not add unit test specific code paths.
While it is convenient for tests to implement a BOOTP server, there are effectively no BOOTP servers in the wild. However, BOOTP is commonly enabled in U-Boot. In an effort to avoid growing most U-Boots for testing purposes, I enabled this path just for unit tests. That said, only 6 boards enable SPL_ETH, so maybe it is not too bad.
--Sean

Hi Sean,
On Sat, 14 Oct 2023 at 15:27, Sean Anderson seanga2@gmail.com wrote:
On 10/14/23 17:22, Heinrich Schuchardt wrote:
Am 14. Oktober 2023 22:47:53 MESZ schrieb Sean Anderson seanga2@gmail.com:
If we sent a DHCP packet and get a BOOTP response from the server, we shouldn't try to send a DHCPREQUEST packet, since it won't be DHCPACKed. Transition straight to BIND. This is only enabled for UNIT_TEST to avoid bloat, since I suspect the number of BOOTP servers in the wild is vanishingly small.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
net/bootp.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/net/bootp.c b/net/bootp.c index 2053cce88c6..7b0f45e18a9 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -1073,6 +1073,11 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip, CONFIG_SYS_BOOTFILE_PREFIX, strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) { #endif /* CONFIG_SYS_BOOTFILE_PREFIX */
if (CONFIG_IS_ENABLED(UNIT_TEST) &&
dhcp_message_type((u8 *)bp->bp_vend) == -1) {
As written before, please, do not add unit test specific code paths.
While it is convenient for tests to implement a BOOTP server, there are effectively no BOOTP servers in the wild. However, BOOTP is commonly enabled in U-Boot. In an effort to avoid growing most U-Boots for testing purposes, I enabled this path just for unit tests. That said, only 6 boards enable SPL_ETH, so maybe it is not too bad.
Yes, also if you are using networking in SPL, you can expect it to add quite a bit to code size.
Regards, Simon

On Sun, Oct 15, 2023 at 08:39:50AM -0600, Simon Glass wrote:
Hi Sean,
On Sat, 14 Oct 2023 at 15:27, Sean Anderson seanga2@gmail.com wrote:
On 10/14/23 17:22, Heinrich Schuchardt wrote:
Am 14. Oktober 2023 22:47:53 MESZ schrieb Sean Anderson seanga2@gmail.com:
If we sent a DHCP packet and get a BOOTP response from the server, we shouldn't try to send a DHCPREQUEST packet, since it won't be DHCPACKed. Transition straight to BIND. This is only enabled for UNIT_TEST to avoid bloat, since I suspect the number of BOOTP servers in the wild is vanishingly small.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
net/bootp.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/net/bootp.c b/net/bootp.c index 2053cce88c6..7b0f45e18a9 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -1073,6 +1073,11 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip, CONFIG_SYS_BOOTFILE_PREFIX, strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) { #endif /* CONFIG_SYS_BOOTFILE_PREFIX */
if (CONFIG_IS_ENABLED(UNIT_TEST) &&
dhcp_message_type((u8 *)bp->bp_vend) == -1) {
As written before, please, do not add unit test specific code paths.
While it is convenient for tests to implement a BOOTP server, there are effectively no BOOTP servers in the wild. However, BOOTP is commonly enabled in U-Boot. In an effort to avoid growing most U-Boots for testing purposes, I enabled this path just for unit tests. That said, only 6 boards enable SPL_ETH, so maybe it is not too bad.
Yes, also if you are using networking in SPL, you can expect it to add quite a bit to code size.
And so long as this doesn't lead to overflowing them, OK. But size is not infinite there, am335x_evm and am43xx_hs_evm are both a bit constrained.

Several SPL functions try to avoid performing initialization twice by caching devices. This is fine for regular boot, but does not work with UNIT_TEST, since all devices are torn down after each test. Add some functions to invalidate the caches which can be called before testing these load methods.
Signed-off-by: Sean Anderson seanga2@gmail.com ---
Changes in v2: - Use callbacks to invalidate SPL caches instead of disabling them entirely
common/spl/spl_fat.c | 5 +++++ common/spl/spl_mmc.c | 8 +++++++- include/spl.h | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/common/spl/spl_fat.c b/common/spl/spl_fat.c index c6e2526ade1..b7b6a7794fd 100644 --- a/common/spl/spl_fat.c +++ b/common/spl/spl_fat.c @@ -20,6 +20,11 @@
static int fat_registered;
+void spl_fat_force_reregister(void) +{ + fat_registered = 0; +} + static int spl_register_fat_device(struct blk_desc *block_dev, int partition) { int err = 0; diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 67c7ae34a58..03a081fa47e 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -403,13 +403,19 @@ static int spl_mmc_get_mmc_devnum(struct mmc *mmc) return block_dev->devnum; }
+static struct mmc *mmc; + +void spl_mmc_clear_cache(void) +{ + mmc = NULL; +} + int spl_mmc_load(struct spl_image_info *spl_image, struct spl_boot_device *bootdev, const char *filename, int raw_part, unsigned long raw_sect) { - static struct mmc *mmc; u32 boot_mode; int err = 0; __maybe_unused int part = 0; diff --git a/include/spl.h b/include/spl.h index 7d30fb57dac..5b051ef2aae 100644 --- a/include/spl.h +++ b/include/spl.h @@ -674,6 +674,18 @@ static inline const char *spl_loader_name(const struct spl_image_loader *loader) #endif
/* SPL FAT image functions */ + +/** + * spl_fat_force_reregister() - Force reregistration of FAT block devices + * + * To avoid repeatedly looking up block devices, spl_load_image_fat keeps track + * of whether it has already registered a block device. This is fine for most + * cases, but when running unit tests all devices are removed and recreated + * in-between tests. This function will force re-registration of any block + * devices, ensuring that we don't try to use an invalid block device. + */ +void spl_fat_force_reregister(void); + int spl_load_image_fat(struct spl_image_info *spl_image, struct spl_boot_device *bootdev, struct blk_desc *block_dev, int partition, @@ -753,6 +765,16 @@ bool spl_was_boot_source(void); */ int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr);
+/** + * spl_mmc_clear_cache() - Clear cached MMC devices + * + * To avoid reinitializing MMCs, spl_mmc_load caches the most-recently-used MMC + * device. This is fine for most cases, but when running unit tests all devices + * are removed and recreated in-between tests. This function will clear any + * cached state, ensuring that we don't try to use an invalid MMC. + */ +void spl_mmc_clear_cache(void); + int spl_mmc_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev);

All "physical" addresses in SPL must be converted to virtual addresses before access in order for sandbox to work. Add some calls to map_sysmem in appropriate places. We do not generally call unmap_sysmem, since we need the image memory to still be mapped when we jump to the image. This doesn't matter at the moment since unmap_sysmem is a no-op.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
common/spl/spl.c | 4 +++- common/spl/spl_blk_fs.c | 6 ++++-- common/spl/spl_ext.c | 4 +++- common/spl/spl_fat.c | 11 +++++++---- common/spl/spl_fit.c | 36 +++++++++++++++++++++------------- common/spl/spl_imx_container.c | 4 +++- common/spl/spl_legacy.c | 6 ++++-- common/spl/spl_mmc.c | 4 +++- common/spl/spl_net.c | 10 +++++++--- common/spl/spl_nor.c | 5 +++-- common/spl/spl_spi.c | 14 +++++++++---- 11 files changed, 69 insertions(+), 35 deletions(-)
diff --git a/common/spl/spl.c b/common/spl/spl.c index 66eeea41a34..732d90d39e6 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -653,7 +653,9 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_set_bd();
if (IS_ENABLED(CONFIG_SPL_SYS_MALLOC)) { - mem_malloc_init(SPL_SYS_MALLOC_START, SPL_SYS_MALLOC_SIZE); + mem_malloc_init((ulong)map_sysmem(SPL_SYS_MALLOC_START, + SPL_SYS_MALLOC_SIZE), + SPL_SYS_MALLOC_SIZE); gd->flags |= GD_FLG_FULL_MALLOC_INIT; } if (!(gd->flags & GD_FLG_SPL_INIT)) { diff --git a/common/spl/spl_blk_fs.c b/common/spl/spl_blk_fs.c index ea5d1a51d9f..63825d620d1 100644 --- a/common/spl/spl_blk_fs.c +++ b/common/spl/spl_blk_fs.c @@ -9,6 +9,7 @@ #include <spl.h> #include <image.h> #include <fs.h> +#include <asm/io.h>
struct blk_dev { const char *ifname; @@ -29,7 +30,8 @@ static ulong spl_fit_read(struct spl_load_info *load, ulong file_offset, return ret; }
- ret = fs_read(load->filename, (ulong)buf, file_offset, size, &actlen); + ret = fs_read(load->filename, virt_to_phys(buf), file_offset, size, + &actlen); if (ret < 0) { printf("spl: error reading image %s. Err - %d\n", load->filename, ret); @@ -69,7 +71,7 @@ int spl_blk_load_image(struct spl_image_info *spl_image, goto out; }
- ret = fs_read(filename, (ulong)header, 0, + ret = fs_read(filename, virt_to_phys(header), 0, sizeof(struct legacy_img_hdr), &actlen); if (ret) { printf("spl: unable to read file %s. Err - %d\n", filename, diff --git a/common/spl/spl_ext.c b/common/spl/spl_ext.c index 902564a6077..af836ca15b8 100644 --- a/common/spl/spl_ext.c +++ b/common/spl/spl_ext.c @@ -2,6 +2,7 @@
#include <common.h> #include <env.h> +#include <mapmem.h> #include <part.h> #include <spl.h> #include <asm/u-boot.h> @@ -53,7 +54,8 @@ int spl_load_image_ext(struct spl_image_info *spl_image, goto end; }
- err = ext4fs_read((char *)spl_image->load_addr, 0, filelen, &actlen); + err = ext4fs_read(map_sysmem(spl_image->load_addr, filelen), 0, filelen, + &actlen);
end: #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT diff --git a/common/spl/spl_fat.c b/common/spl/spl_fat.c index b7b6a7794fd..014074f85be 100644 --- a/common/spl/spl_fat.c +++ b/common/spl/spl_fat.c @@ -11,6 +11,7 @@ #include <common.h> #include <env.h> #include <log.h> +#include <mapmem.h> #include <spl.h> #include <asm/u-boot.h> #include <fat.h> @@ -79,11 +80,13 @@ int spl_load_image_fat(struct spl_image_info *spl_image,
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) && image_get_magic(header) == FDT_MAGIC) { - err = file_fat_read(filename, (void *)CONFIG_SYS_LOAD_ADDR, 0); + err = file_fat_read(filename, + map_sysmem(CONFIG_SYS_LOAD_ADDR, 0), 0); if (err <= 0) goto end; err = spl_parse_image_header(spl_image, bootdev, - (struct legacy_img_hdr *)CONFIG_SYS_LOAD_ADDR); + map_sysmem(CONFIG_SYS_LOAD_ADDR, + err)); if (err == -EAGAIN) return err; if (err == 0) @@ -104,8 +107,8 @@ int spl_load_image_fat(struct spl_image_info *spl_image, if (err) goto end;
- err = file_fat_read(filename, - (u8 *)(uintptr_t)spl_image->load_addr, 0); + err = file_fat_read(filename, map_sysmem(spl_image->load_addr, + spl_image->size), 0); }
end: diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 4f8b951efe2..c3b493cdb92 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -16,6 +16,7 @@ #include <sysinfo.h> #include <asm/cache.h> #include <asm/global_data.h> +#include <asm/io.h> #include <linux/libfdt.h> #include <linux/printk.h>
@@ -388,25 +389,32 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image, /* Figure out which device tree the board wants to use */ node = spl_fit_get_image_node(ctx, FIT_FDT_PROP, index++); if (node < 0) { + size_t size; + debug("%s: cannot find FDT node\n", __func__);
/* * U-Boot did not find a device tree inside the FIT image. Use * the U-Boot device tree instead. */ - if (gd->fdt_blob) - memcpy((void *)image_info.load_addr, gd->fdt_blob, - fdt_totalsize(gd->fdt_blob)); - else + if (!gd->fdt_blob) return node; + + /* + * Make the load-address of the FDT available for the SPL + * framework + */ + size = fdt_totalsize(gd->fdt_blob); + spl_image->fdt_addr = map_sysmem(image_info.load_addr, size); + memcpy(spl_image->fdt_addr, gd->fdt_blob, size); } else { ret = load_simple_fit(info, sector, ctx, node, &image_info); if (ret < 0) return ret; + + spl_image->fdt_addr = phys_to_virt(image_info.load_addr); }
- /* Make the load-address of the FDT available for the SPL framework */ - spl_image->fdt_addr = map_sysmem(image_info.load_addr, 0); if (CONFIG_IS_ENABLED(FIT_IMAGE_TINY)) return 0;
@@ -859,7 +867,7 @@ int spl_load_fit_image(struct spl_image_info *spl_image, #ifdef CONFIG_SPL_FIT_SIGNATURE images.verify = 1; #endif - ret = fit_image_load(&images, (ulong)header, + ret = fit_image_load(&images, virt_to_phys((void *)header), NULL, &fit_uname_config, IH_ARCH_DEFAULT, IH_TYPE_STANDALONE, -1, FIT_LOAD_OPTIONAL, &fw_data, &fw_len); @@ -867,15 +875,15 @@ int spl_load_fit_image(struct spl_image_info *spl_image, printf("DEPRECATED: 'standalone = ' property."); printf("Please use either 'firmware =' or 'kernel ='\n"); } else { - ret = fit_image_load(&images, (ulong)header, NULL, - &fit_uname_config, IH_ARCH_DEFAULT, + ret = fit_image_load(&images, virt_to_phys((void *)header), + NULL, &fit_uname_config, IH_ARCH_DEFAULT, IH_TYPE_FIRMWARE, -1, FIT_LOAD_OPTIONAL, &fw_data, &fw_len); }
if (ret < 0) { - ret = fit_image_load(&images, (ulong)header, NULL, - &fit_uname_config, IH_ARCH_DEFAULT, + ret = fit_image_load(&images, virt_to_phys((void *)header), + NULL, &fit_uname_config, IH_ARCH_DEFAULT, IH_TYPE_KERNEL, -1, FIT_LOAD_OPTIONAL, &fw_data, &fw_len); } @@ -897,9 +905,9 @@ int spl_load_fit_image(struct spl_image_info *spl_image, #ifdef CONFIG_SPL_FIT_SIGNATURE images.verify = 1; #endif - ret = fit_image_load(&images, (ulong)header, NULL, &fit_uname_config, - IH_ARCH_DEFAULT, IH_TYPE_FLATDT, -1, - FIT_LOAD_OPTIONAL, &dt_data, &dt_len); + ret = fit_image_load(&images, virt_to_phys((void *)header), NULL, + &fit_uname_config, IH_ARCH_DEFAULT, IH_TYPE_FLATDT, + -1, FIT_LOAD_OPTIONAL, &dt_data, &dt_len); if (ret >= 0) { spl_image->fdt_addr = (void *)dt_data;
diff --git a/common/spl/spl_imx_container.c b/common/spl/spl_imx_container.c index c29cb15f55e..127802f5cb7 100644 --- a/common/spl/spl_imx_container.c +++ b/common/spl/spl_imx_container.c @@ -9,6 +9,7 @@ #include <errno.h> #include <imx_container.h> #include <log.h> +#include <mapmem.h> #include <spl.h> #ifdef CONFIG_AHAB_BOOT #include <asm/mach-imx/ahab.h> @@ -46,7 +47,8 @@ static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image, debug("%s: container: %p sector: %lu sectors: %u\n", __func__, container, sector, sectors); if (info->read(info, sector, sectors, - (void *)images[image_index].dst) != sectors) { + map_sysmem(images[image_index].dst, + images[image_index].size)) != sectors) { printf("%s wrong\n", __func__); return NULL; } diff --git a/common/spl/spl_legacy.c b/common/spl/spl_legacy.c index e9564e5c2a5..51656fb9617 100644 --- a/common/spl/spl_legacy.c +++ b/common/spl/spl_legacy.c @@ -7,6 +7,7 @@ #include <image.h> #include <log.h> #include <malloc.h> +#include <mapmem.h> #include <asm/sections.h> #include <spl.h>
@@ -129,7 +130,7 @@ int spl_load_legacy_img(struct spl_image_info *spl_image, dataptr += sizeof(*hdr);
load->read(load, dataptr, spl_image->size, - (void *)(unsigned long)spl_image->load_addr); + map_sysmem(spl_image->load_addr, spl_image->size)); break;
case IH_COMP_LZMA: @@ -148,7 +149,8 @@ int spl_load_legacy_img(struct spl_image_info *spl_image, }
load->read(load, dataptr, spl_image->size, src); - ret = lzmaBuffToBuffDecompress((void *)spl_image->load_addr, + ret = lzmaBuffToBuffDecompress(map_sysmem(spl_image->load_addr, + spl_image->size), &lzma_len, src, spl_image->size); if (ret) { printf("LZMA decompression error: %d\n", ret); diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 03a081fa47e..0b01368d9de 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -8,6 +8,7 @@ #include <common.h> #include <dm.h> #include <log.h> +#include <mapmem.h> #include <part.h> #include <spl.h> #include <linux/compiler.h> @@ -46,7 +47,8 @@ static int mmc_load_legacy(struct spl_image_info *spl_image, count = blk_dread(mmc_get_blk_desc(mmc), sector + image_offset_sectors, image_size_sectors, - (void *)(ulong)spl_image->load_addr); + map_sysmem(spl_image->load_addr, + image_size_sectors * mmc->read_bl_len)); debug("read %x sectors to %lx\n", image_size_sectors, spl_image->load_addr); if (count != image_size_sectors) diff --git a/common/spl/spl_net.c b/common/spl/spl_net.c index b2c901b554b..f01d4df8bc6 100644 --- a/common/spl/spl_net.c +++ b/common/spl/spl_net.c @@ -11,6 +11,7 @@ #include <errno.h> #include <image.h> #include <log.h> +#include <mapmem.h> #include <spl.h> #include <net.h> #include <linux/libfdt.h> @@ -21,14 +22,15 @@ static ulong spl_net_load_read(struct spl_load_info *load, ulong sector, { debug("%s: sector %lx, count %lx, buf %lx\n", __func__, sector, count, (ulong)buf); - memcpy(buf, (void *)(image_load_addr + sector), count); + memcpy(buf, map_sysmem(image_load_addr + sector, count), count); return count; }
static int spl_net_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { - struct legacy_img_hdr *header = (struct legacy_img_hdr *)image_load_addr; + struct legacy_img_hdr *header = map_sysmem(image_load_addr, + sizeof(*header)); int rv;
env_init(); @@ -62,7 +64,9 @@ static int spl_net_load_image(struct spl_image_info *spl_image, if (rv) return rv;
- memcpy((void *)spl_image->load_addr, header, spl_image->size); + memcpy(map_sysmem(spl_image->load_addr, spl_image->size), + map_sysmem(image_load_addr, spl_image->size), + spl_image->size); }
return rv; diff --git a/common/spl/spl_nor.c b/common/spl/spl_nor.c index dd447982071..236b0718283 100644 --- a/common/spl/spl_nor.c +++ b/common/spl/spl_nor.c @@ -7,6 +7,7 @@ #include <image.h> #include <imx_container.h> #include <log.h> +#include <mapmem.h> #include <spl.h>
static ulong spl_nor_load_read(struct spl_load_info *load, ulong sector, @@ -14,7 +15,7 @@ static ulong spl_nor_load_read(struct spl_load_info *load, ulong sector, { debug("%s: sector %lx, count %lx, buf %p\n", __func__, sector, count, buf); - memcpy(buf, (void *)sector, count); + memcpy(buf, map_sysmem(sector, count), count);
return count; } @@ -92,7 +93,7 @@ static int spl_nor_load_image(struct spl_image_info *spl_image, * Load real U-Boot from its location in NOR flash to its * defined location in SDRAM */ - header = (const struct legacy_img_hdr *)spl_nor_get_uboot_base(); + header = map_sysmem(spl_nor_get_uboot_base(), sizeof(*header)); #ifdef CONFIG_SPL_LOAD_FIT if (image_get_magic(header) == FDT_MAGIC) { debug("Found FIT format U-Boot\n"); diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index 1427c9478c0..3ac4b1b5091 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -12,11 +12,13 @@ #include <image.h> #include <imx_container.h> #include <log.h> +#include <mapmem.h> #include <spi.h> #include <spi_flash.h> #include <errno.h> #include <spl.h> #include <asm/global_data.h> +#include <asm/io.h> #include <dm/ofnode.h>
#if CONFIG_IS_ENABLED(OS_BOOT) @@ -134,13 +136,16 @@ static int spl_spi_load_image(struct spl_image_info *spl_image,
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) && image_get_magic(header) == FDT_MAGIC) { + u32 size = roundup(fdt_totalsize(header), 4); + err = spi_flash_read(flash, payload_offs, - roundup(fdt_totalsize(header), 4), - (void *)CONFIG_SYS_LOAD_ADDR); + size, + map_sysmem(CONFIG_SYS_LOAD_ADDR, + size)); if (err) return err; err = spl_parse_image_header(spl_image, bootdev, - (struct legacy_img_hdr *)CONFIG_SYS_LOAD_ADDR); + phys_to_virt(CONFIG_SYS_LOAD_ADDR)); } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && image_get_magic(header) == FDT_MAGIC) { struct spl_load_info load; @@ -172,7 +177,8 @@ static int spl_spi_load_image(struct spl_image_info *spl_image, return err; err = spi_flash_read(flash, payload_offs + spl_image->offset, spl_image->size, - (void *)spl_image->load_addr); + map_sysmem(spl_image->load_addr, + spl_image->size)); } if (IS_ENABLED(CONFIG_SPI_FLASH_SOFT_RESET)) { err = spi_nor_remove(flash);

The test devicetree is only compiled for U-Boot proper. When accessing it in SPL we need to go up one directory.
Signed-off-by: Sean Anderson seanga2@gmail.com ---
Changes in v2: - Compare to PHASE_SPL in sandbox_cmdline_cb_test_fdt for clarity - Split off from fs test
arch/sandbox/cpu/start.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 2c8a72590b5..2589c2eba73 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -13,6 +13,7 @@ #include <log.h> #include <os.h> #include <sort.h> +#include <spl.h> #include <asm/getopt.h> #include <asm/global_data.h> #include <asm/io.h> @@ -202,10 +203,14 @@ static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state, { char buf[256]; char *fname; + char *relname; int len;
- len = state_get_rel_filename("arch/sandbox/dts/test.dtb", buf, - sizeof(buf)); + if (spl_phase() <= PHASE_SPL) + relname = "../arch/sandbox/dts/test.dtb"; + else + relname = "arch/sandbox/dts/test.dtb"; + len = state_get_rel_filename(relname, buf, sizeof(buf)); if (len < 0) return len;

On Sat, 14 Oct 2023 at 14:48, Sean Anderson seanga2@gmail.com wrote:
The test devicetree is only compiled for U-Boot proper. When accessing it in SPL we need to go up one directory.
Signed-off-by: Sean Anderson seanga2@gmail.com
Changes in v2:
- Compare to PHASE_SPL in sandbox_cmdline_cb_test_fdt for clarity
- Split off from fs test
arch/sandbox/cpu/start.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
BTW that function is in mainline now - spl_in_proper()
This is fine though

In order to make adding new spl unit tests easier, especially when they may have many dependencies, add some Kconfigs for the existing image test. Split it into the parts which are generic (such as callbacks) and the test-specific parts.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Remove redundant condition on CONFIG_SPL_UT_LOAD in test/image/Makefile - Remove unused mapmem.h include in spl_load_os.c
test/Kconfig | 1 + test/Makefile | 5 +-- test/image/Kconfig | 20 ++++++++++ test/image/Makefile | 3 +- test/image/spl_load.c | 76 +------------------------------------- test/image/spl_load_os.c | 80 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 79 deletions(-) create mode 100644 test/image/Kconfig create mode 100644 test/image/spl_load_os.c
diff --git a/test/Kconfig b/test/Kconfig index 830245b6f9a..ca648d23376 100644 --- a/test/Kconfig +++ b/test/Kconfig @@ -101,6 +101,7 @@ config UT_UNICODE
source "test/dm/Kconfig" source "test/env/Kconfig" +source "test/image/Kconfig" source "test/lib/Kconfig" source "test/optee/Kconfig" source "test/overlay/Kconfig" diff --git a/test/Makefile b/test/Makefile index 178773647a8..8e1fed2c28b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,9 +3,6 @@ # (C) Copyright 2012 The Chromium Authors
obj-y += test-main.o -ifdef CONFIG_SPL_LOAD_FIT -obj-$(CONFIG_SANDBOX) += image/ -endif
ifneq ($(CONFIG_$(SPL_)BLOBLIST),) obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o @@ -30,4 +27,6 @@ obj-$(CONFIG_UNIT_TEST) += boot/ obj-$(CONFIG_UNIT_TEST) += common/ obj-y += log/ obj-$(CONFIG_$(SPL_)UT_UNICODE) += unicode_ut.o +else +obj-$(CONFIG_SPL_UT_LOAD) += image/ endif diff --git a/test/image/Kconfig b/test/image/Kconfig new file mode 100644 index 00000000000..70ffe0ff276 --- /dev/null +++ b/test/image/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2023 Sean Anderson seanga2@gmail.com + +config SPL_UT_LOAD + bool "Unit tests for SPL load methods" + depends on SPL_UNIT_TEST + default y if SANDBOX + help + Test various SPL load methods. + +if SPL_UT_LOAD + +config SPL_UT_LOAD_OS + bool "Test loading from the host OS" + depends on SANDBOX && SPL_LOAD_FIT + default y + help + Smoke test to ensure that loading U-boot works in sandbox. + +endif diff --git a/test/image/Makefile b/test/image/Makefile index c4039df707f..f7ae996bc86 100644 --- a/test/image/Makefile +++ b/test/image/Makefile @@ -2,4 +2,5 @@ # # Copyright 2021 Google LLC
-obj-$(CONFIG_SPL_BUILD) += spl_load.o +obj-y += spl_load.o +obj-$(CONFIG_SPL_UT_LOAD_OS) += spl_load_os.o diff --git a/test/image/spl_load.c b/test/image/spl_load.c index 4e27ff460ab..1a57bf846d2 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -1,48 +1,10 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2021 Google LLC - * Written by Simon Glass sjg@chromium.org + * Copyright (C) 2023 Sean Anderson seanga2@gmail.com */
#include <common.h> -#include <image.h> #include <mapmem.h> -#include <os.h> -#include <spl.h> -#include <test/ut.h> - -/* Declare a new SPL test */ -#define SPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, spl_test) - -/* Context used for this test */ -struct text_ctx { - int fd; -}; - -static ulong read_fit_image(struct spl_load_info *load, ulong sector, - ulong count, void *buf) -{ - struct text_ctx *text_ctx = load->priv; - off_t offset, ret; - ssize_t res; - - offset = sector * load->bl_len; - ret = os_lseek(text_ctx->fd, offset, OS_SEEK_SET); - if (ret != offset) { - printf("Failed to seek to %zx, got %zx (errno=%d)\n", offset, - ret, errno); - return 0; - } - - res = os_read(text_ctx->fd, buf, count * load->bl_len); - if (res == -1) { - printf("Failed to read %lx bytes, got %ld (errno=%d)\n", - count * load->bl_len, res, errno); - return 0; - } - - return count; -}
int board_fit_config_name_match(const char *name) { @@ -53,39 +15,3 @@ struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) { return map_sysmem(0x100000, 0); } - -static int spl_test_load(struct unit_test_state *uts) -{ - struct spl_image_info image; - struct legacy_img_hdr *header; - struct text_ctx text_ctx; - struct spl_load_info load; - char fname[256]; - int ret; - int fd; - - memset(&load, '\0', sizeof(load)); - load.bl_len = 512; - load.read = read_fit_image; - - ret = sandbox_find_next_phase(fname, sizeof(fname), true); - if (ret) { - printf("(%s not found, error %d)\n", fname, ret); - return ret; - } - load.filename = fname; - - header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); - - fd = os_open(fname, OS_O_RDONLY); - ut_assert(fd >= 0); - ut_asserteq(512, os_read(fd, header, 512)); - text_ctx.fd = fd; - - load.priv = &text_ctx; - - ut_assertok(spl_load_simple_fit(&image, &load, 0, header)); - - return 0; -} -SPL_TEST(spl_test_load, 0); diff --git a/test/image/spl_load_os.c b/test/image/spl_load_os.c new file mode 100644 index 00000000000..bf374f2164d --- /dev/null +++ b/test/image/spl_load_os.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <image.h> +#include <os.h> +#include <spl.h> +#include <test/ut.h> + +/* Declare a new SPL test */ +#define SPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, spl_test) + +/* Context used for this test */ +struct text_ctx { + int fd; +}; + +static ulong read_fit_image(struct spl_load_info *load, ulong sector, + ulong count, void *buf) +{ + struct text_ctx *text_ctx = load->priv; + off_t offset, ret; + ssize_t res; + + offset = sector * load->bl_len; + ret = os_lseek(text_ctx->fd, offset, OS_SEEK_SET); + if (ret != offset) { + printf("Failed to seek to %zx, got %zx (errno=%d)\n", offset, + ret, errno); + return 0; + } + + res = os_read(text_ctx->fd, buf, count * load->bl_len); + if (res == -1) { + printf("Failed to read %lx bytes, got %ld (errno=%d)\n", + count * load->bl_len, res, errno); + return 0; + } + + return count; +} + +static int spl_test_load(struct unit_test_state *uts) +{ + struct spl_image_info image; + struct legacy_img_hdr *header; + struct text_ctx text_ctx; + struct spl_load_info load; + char fname[256]; + int ret; + int fd; + + memset(&load, '\0', sizeof(load)); + load.bl_len = 512; + load.read = read_fit_image; + + ret = sandbox_find_next_phase(fname, sizeof(fname), true); + if (ret) { + printf("(%s not found, error %d)\n", fname, ret); + return ret; + } + load.filename = fname; + + header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); + + fd = os_open(fname, OS_O_RDONLY); + ut_assert(fd >= 0); + ut_asserteq(512, os_read(fd, header, 512)); + text_ctx.fd = fd; + + load.priv = &text_ctx; + + ut_assertok(spl_load_simple_fit(&image, &load, 0, header)); + + return 0; +} +SPL_TEST(spl_test_load, 0);

Returning a negative value from a unit test doesn't automatically fail the test. We have to fail an assertion. Modify the test to do so.
This now causes the test to count as a failure on VPL. This is because the fname of SPL (and U-Boot) is generated with make_exec in os_jump_to_image. The original name of SPL is gone, and we can't determine the name of U-Boot from the generated name.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
configs/sandbox_vpl_defconfig | 1 + test/image/spl_load_os.c | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/configs/sandbox_vpl_defconfig b/configs/sandbox_vpl_defconfig index 8d76f19729b..5bd0281796d 100644 --- a/configs/sandbox_vpl_defconfig +++ b/configs/sandbox_vpl_defconfig @@ -262,3 +262,4 @@ CONFIG_UNIT_TEST=y CONFIG_SPL_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y +# CONFIG_SPL_UT_LOAD_OS is not set diff --git a/test/image/spl_load_os.c b/test/image/spl_load_os.c index bf374f2164d..3b2967d017a 100644 --- a/test/image/spl_load_os.c +++ b/test/image/spl_load_os.c @@ -58,10 +58,8 @@ static int spl_test_load(struct unit_test_state *uts) load.read = read_fit_image;
ret = sandbox_find_next_phase(fname, sizeof(fname), true); - if (ret) { - printf("(%s not found, error %d)\n", fname, ret); - return ret; - } + if (ret) + ut_assertf(0, "%s not found, error %d\n", fname, ret); load.filename = fname;
header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));

This add some basic functions to create images, and a test for said functions. This is not intended to be a test of the image parsing functions, but rather a framework for creating minimal images for testing load methods. That said, it does do an OK job at finding bugs in the image parsing directly.
Since we have two methods for loading/parsing FIT images, add LOAD_FIT_FULL as a separate CI run.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Fix size not being updated in board_spl_fit_buffer_addr - Fix return value documentation for check_image_info
.azure-pipelines.yml | 4 + .gitlab-ci.yml | 7 + arch/sandbox/cpu/u-boot-spl.lds | 2 + configs/sandbox_noinst_defconfig | 6 + configs/sandbox_spl_defconfig | 6 + include/test/spl.h | 117 +++++++++++ test/image/spl_load.c | 350 +++++++++++++++++++++++++++++++ test/image/spl_load_os.c | 4 +- 8 files changed, 493 insertions(+), 3 deletions(-) create mode 100644 include/test/spl.h
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 7985ff5523c..6f91553e861 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -299,6 +299,10 @@ stages: sandbox_noinst: TEST_PY_BD: "sandbox_noinst" TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" + sandbox_noinst_load_fit_full: + TEST_PY_BD: "sandbox_noinst" + TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" + OVERRIDE: "-a CONFIG_SPL_LOAD_FIT_FULL=y" sandbox_flattree: TEST_PY_BD: "sandbox_flattree" sandbox_trace: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 129234ba3db..6decdfdee33 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -293,6 +293,13 @@ sandbox_noinst_test.py: TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" <<: *buildman_and_testpy_dfn
+sandbox_noinst with LOAD_FIT_FULL test.py: + variables: + TEST_PY_BD: "sandbox_noinst" + TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" + OVERRIDE: "-a CONFIG_SPL_LOAD_FIT_FULL=y" + <<: *buildman_and_testpy_dfn + sandbox_vpl test.py: variables: TEST_PY_BD: "sandbox_vpl" diff --git a/arch/sandbox/cpu/u-boot-spl.lds b/arch/sandbox/cpu/u-boot-spl.lds index ef885fd0cb0..a81d66a6f2e 100644 --- a/arch/sandbox/cpu/u-boot-spl.lds +++ b/arch/sandbox/cpu/u-boot-spl.lds @@ -26,6 +26,8 @@ SECTIONS KEEP(*(_u_boot_sandbox_getopt)) *(_u_boot_sandbox_getopt_end) } + + _image_binary_end = .; }
INSERT AFTER .data; diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index d39e54f98d2..908155be8a3 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -32,6 +32,12 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_HANDOFF=y CONFIG_SPL_BOARD_INIT=y +CONFIG_SPL_LEGACY_IMAGE_FORMAT=y +CONFIG_SPL_LOAD_IMX_CONTAINER=y +CONFIG_SPL_SYS_MALLOC=y +CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y +CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0xa000000 +CONFIG_SPL_SYS_MALLOC_SIZE=0x4000000 CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_I2C=y CONFIG_SPL_RTC=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 4a67af2f088..b578cc8e443 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -32,6 +32,12 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_HANDOFF=y CONFIG_SPL_BOARD_INIT=y +CONFIG_SPL_LEGACY_IMAGE_FORMAT=y +CONFIG_SPL_LOAD_IMX_CONTAINER=y +CONFIG_SPL_SYS_MALLOC=y +CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y +CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0xa000000 +CONFIG_SPL_SYS_MALLOC_SIZE=0x4000000 CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_FPGA=y CONFIG_SPL_I2C=y diff --git a/include/test/spl.h b/include/test/spl.h new file mode 100644 index 00000000000..4c6b789e478 --- /dev/null +++ b/include/test/spl.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2023 Sean Anderson seanga2@gmail.com + */ + +#ifndef TEST_SPL_H +#define TEST_SPL_H + +struct unit_test_state; +struct spl_image_info; + +/* Declare a new SPL test */ +#define SPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, spl_test) + +/** + * generate_data() - Generate some test payload data + * @data: The location to fill + * @size: The size of @data + * @test_name: The seed for the data + * + * Fill @data with data. The upper nibbles will be an incrementing counter + * (0x00, 0x10, 0x20...) to make the data identifiable in a hex dump. The lower + * nibbles are random bits seeded with @test_name. + */ +void generate_data(char *data, size_t size, const char *test_name); + +/** + * enum spl_test_image - Image types for testing + * @LEGACY: "Legacy" uImages + * @IMX8: i.MX8 Container images + * @FIT_INTERNAL: FITs with internal data + * @FIT_EXTERNAL: FITs with external data + */ +enum spl_test_image { + LEGACY, + IMX8, + FIT_INTERNAL, + FIT_EXTERNAL, +}; + +/** + * create_image() - Create an image for testing + * @dst: The location to create the image at + * @type: The type of image to create + * @info: Image parameters + * @data_offset: Offset of payload data within the image + * + * Create a new image at @dst. @dst must be initialized to all zeros. @info + * should already have name and size filled in. All other parameters will be + * filled in by this function. @info can later be passed to check_image_info(). + * + * If @dst is %NULL, then no data is written. Otherwise, @dst must be + * initialized to zeros, except payload data which must already be present at + * @data_offset. @data_offset may be %NULL if unnecessary. + * + * Typically, this function will be called as follows: + * + * size = create_image(NULL, type, &info, &off); + * img = calloc(size, 1); + * generate_data(img + off, ...); + * create_image(img, type, &info, NULL); + * + * Return: The size of the image, or 0 on error + */ +size_t create_image(void *dst, enum spl_test_image type, + struct spl_image_info *info, size_t *data_offset); + +/** + * check_image_info() - Check image info after loading + * @uts: Current unit test state + * @info1: The base, known good info + * @info2: The info to check + * + * Check @info2 against @info1. This function is typically called after calling + * a function to load/parse an image. Image data is not checked. + * + * Return: 0 on success, or 1 on failure + */ +int check_image_info(struct unit_test_state *uts, struct spl_image_info *info1, + struct spl_image_info *info2); + +/** + * image_supported() - Determine whether an image type is supported + * @type: The image type to check + * + * Return: %true if supported and %false otherwise + */ +static inline bool image_supported(enum spl_test_image type) +{ + switch (type) { + case LEGACY: + return IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_FORMAT); + case IMX8: + return IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER); + case FIT_INTERNAL: + case FIT_EXTERNAL: + return IS_ENABLED(CONFIG_SPL_LOAD_FIT) || + IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL); + } + + return false; +} + +/* Declare an image test (skipped if the image type is unsupported) */ +#define SPL_IMG_TEST(func, type, flags) \ +static int func##_##type(struct unit_test_state *uts) \ +{ \ + if (!image_supported(type)) \ + return -EAGAIN; \ + return func(uts, __func__, type); \ +} \ +SPL_TEST(func##_##type, flags) + +/* More than a couple blocks, and will not be aligned to anything */ +#define SPL_TEST_DATA_SIZE 4099 + +#endif /* TEST_SPL_H */ diff --git a/test/image/spl_load.c b/test/image/spl_load.c index 1a57bf846d2..de2fddae359 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -4,7 +4,15 @@ */
#include <common.h> +#include <image.h> +#include <imx_container.h> #include <mapmem.h> +#include <memalign.h> +#include <rand.h> +#include <spl.h> +#include <test/spl.h> +#include <test/ut.h> +#include <u-boot/crc.h>
int board_fit_config_name_match(const char *name) { @@ -15,3 +23,345 @@ struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) { return map_sysmem(0x100000, 0); } + +/* Try to reuse the load buffer to conserve memory */ +void *board_spl_fit_buffer_addr(ulong fit_size, int sectors, int bl_len) +{ + static void *buf; + static size_t size; + + if (size < sectors * bl_len) { + free(buf); + size = sectors * bl_len; + buf = malloc_cache_aligned(size); + } + return buf; +} + +/* Local flags for spl_image; start from the "top" to avoid conflicts */ +#define SPL_IMX_CONTAINER 0x80000000 + +void generate_data(char *data, size_t size, const char *test_name) +{ + int i; + unsigned int seed = 1; + + while (*test_name) { + seed += *test_name++; + rand_r(&seed); + } + + for (i = 0; i < size; i++) + data[i] = (i & 0xf) << 4 | (rand_r(&seed) & 0xf); +} + +static size_t create_legacy(void *dst, struct spl_image_info *spl_image, + size_t *data_offset) +{ + struct legacy_img_hdr *hdr = dst; + void *data = dst + sizeof(*hdr); + + if (data_offset) + *data_offset = data - dst; + + if (!dst) + goto out; + + image_set_magic(hdr, IH_MAGIC); + image_set_time(hdr, 0); + image_set_size(hdr, spl_image->size); + image_set_load(hdr, spl_image->load_addr); + image_set_ep(hdr, spl_image->entry_point); + image_set_dcrc(hdr, crc32(0, data, spl_image->size)); + image_set_os(hdr, spl_image->os); + image_set_arch(hdr, IH_ARCH_DEFAULT); + image_set_type(hdr, IH_TYPE_FIRMWARE); + image_set_comp(hdr, IH_COMP_NONE); + image_set_name(hdr, spl_image->name); + image_set_hcrc(hdr, crc32(0, (void *)hdr, sizeof(*hdr))); + +out: + return sizeof(*hdr) + spl_image->size; +} + +static size_t create_imx8(void *dst, struct spl_image_info *spl_image, + size_t *data_offset) +{ + struct container_hdr *hdr = dst; + struct boot_img_t *img = dst + sizeof(*hdr); + size_t length = sizeof(*hdr) + sizeof(*img); + /* Align to MMC block size for now */ + void *data = dst + 512; + + if (data_offset) + *data_offset = data - dst; + + if (!dst) + goto out; + + hdr->version = CONTAINER_HDR_VERSION; + hdr->length_lsb = length & 0xff; + hdr->length_msb = length >> 8; + hdr->tag = CONTAINER_HDR_TAG; + hdr->num_images = 1; + + /* spl_load_imx_container doesn't handle endianness; whoops! */ + img->offset = data - dst; + img->size = spl_image->size; + img->dst = spl_image->load_addr; + img->entry = spl_image->entry_point; + +out: + return data - dst + spl_image->size; +} + +#define ADDRESS_CELLS (sizeof(uintptr_t) / sizeof(u32)) + +static inline int fdt_property_addr(void *fdt, const char *name, uintptr_t val) +{ + if (sizeof(uintptr_t) == sizeof(u32)) + return fdt_property_u32(fdt, name, val); + return fdt_property_u64(fdt, name, val); +} + +static size_t start_fit(void *dst, size_t fit_size, size_t data_size, + bool external) +{ + void *data; + + if (fdt_create(dst, fit_size)) + return 0; + if (fdt_finish_reservemap(dst)) + return 0; + if (fdt_begin_node(dst, "")) + return 0; + if (fdt_property_u32(dst, FIT_TIMESTAMP_PROP, 0)) + return 0; + if (fdt_property_u32(dst, "#address-cells", ADDRESS_CELLS)) + return 0; + if (fdt_property_string(dst, FIT_DESC_PROP, "")) + return 0; + + if (fdt_begin_node(dst, "images")) + return 0; + if (fdt_begin_node(dst, "u-boot")) + return 0; + + if (external) { + if (fdt_property_u32(dst, FIT_DATA_OFFSET_PROP, 0)) + return 0; + return fit_size; + } + + if (fdt_property_placeholder(dst, FIT_DATA_PROP, data_size, &data)) + return 0; + return data - dst; +} + +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; + size_t off, size; + + if (external) { + size = prop_size; + off = size; + } else { + char tmp[256]; + + size = total_size; + off = start_fit(tmp, sizeof(tmp), 0, false); + if (!off) + return 0; + } + + if (data_offset) + *data_offset = off; + + if (!dst) + goto out; + + if (start_fit(dst, size, spl_image->size, external) != off) + return 0; + + if (fdt_property_string(dst, FIT_DESC_PROP, spl_image->name)) + return 0; + if (fdt_property_string(dst, FIT_TYPE_PROP, "firmware")) + return 0; + if (fdt_property_string(dst, FIT_COMP_PROP, "none")) + return 0; + if (fdt_property_u32(dst, FIT_DATA_SIZE_PROP, spl_image->size)) + return 0; + if (fdt_property_string(dst, FIT_OS_PROP, + genimg_get_os_short_name(spl_image->os))) + return 0; + if (fdt_property_string(dst, FIT_ARCH_PROP, + genimg_get_arch_short_name(IH_ARCH_DEFAULT))) + return 0; + if (fdt_property_addr(dst, FIT_ENTRY_PROP, spl_image->entry_point)) + return 0; + if (fdt_property_addr(dst, FIT_LOAD_PROP, spl_image->load_addr)) + return 0; + if (fdt_end_node(dst)) /* u-boot */ + return 0; + if (fdt_end_node(dst)) /* images */ + return 0; + + if (fdt_begin_node(dst, "configurations")) + return 0; + if (fdt_property_string(dst, FIT_DEFAULT_PROP, "config-1")) + return 0; + if (fdt_begin_node(dst, "config-1")) + return 0; + if (fdt_property_string(dst, FIT_DESC_PROP, spl_image->name)) + return 0; + if (fdt_property_string(dst, FIT_FIRMWARE_PROP, "u-boot")) + return 0; + if (fdt_end_node(dst)) /* configurations */ + return 0; + if (fdt_end_node(dst)) /* config-1 */ + return 0; + + if (fdt_end_node(dst)) /* root */ + return 0; + if (fdt_finish(dst)) + return 0; + + if (external) { + if (fdt_totalsize(dst) > size) + return 0; + fdt_set_totalsize(dst, size); + } + +out: + return total_size; +} + +size_t create_image(void *dst, enum spl_test_image type, + struct spl_image_info *info, size_t *data_offset) +{ + bool external = false; + + info->os = IH_OS_U_BOOT; + info->load_addr = CONFIG_TEXT_BASE; + info->entry_point = CONFIG_TEXT_BASE + 0x100; + info->flags = 0; + + switch (type) { + case LEGACY: + return create_legacy(dst, info, data_offset); + case IMX8: + info->flags = SPL_IMX_CONTAINER; + return create_imx8(dst, info, data_offset); + case FIT_EXTERNAL: + /* + * spl_fit_append_fdt will clobber external images with U-Boot's + * FDT if the image doesn't have one. Just set the OS to + * something which doesn't take a devicetree. + */ + if (!IS_ENABLED(CONFIG_LOAD_FIT_FULL)) + info->os = IH_OS_TEE; + external = true; + case FIT_INTERNAL: + info->flags = SPL_FIT_FOUND; + return create_fit(dst, info, data_offset, external); + } + + return 0; +} + +int check_image_info(struct unit_test_state *uts, struct spl_image_info *info1, + struct spl_image_info *info2) +{ + if (info2->name) { + if (info1->flags & SPL_FIT_FOUND) + ut_asserteq_str(genimg_get_os_name(info1->os), + info2->name); + else + ut_asserteq_str(info1->name, info2->name); + } + + if (info1->flags & SPL_IMX_CONTAINER) + ut_asserteq(IH_OS_INVALID, info2->os); + else + ut_asserteq(info1->os, info2->os); + + ut_asserteq(info1->entry_point, info2->entry_point); + if (info1->flags & (SPL_FIT_FOUND | SPL_IMX_CONTAINER) || + info2->flags & SPL_COPY_PAYLOAD_ONLY) { + ut_asserteq(info1->load_addr, info2->load_addr); + if (info1->flags & SPL_IMX_CONTAINER) + ut_asserteq(0, info2->size); + else + ut_asserteq(info1->size, info2->size); + } else { + ut_asserteq(info1->load_addr - sizeof(struct legacy_img_hdr), + info2->load_addr); + ut_asserteq(info1->size + sizeof(struct legacy_img_hdr), + info2->size); + } + + return 0; +} + +static ulong spl_test_read(struct spl_load_info *load, ulong sector, + ulong count, void *buf) +{ + memcpy(buf, load->priv + sector, count); + return count; +} + +static int spl_test_image(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + size_t img_size, img_data, data_size = SPL_TEST_DATA_SIZE; + struct spl_image_info info_write = { + .name = test_name, + .size = data_size, + }, info_read = { }; + char *data; + void *img; + + img_size = create_image(NULL, type, &info_write, &img_data); + ut_assert(img_size); + img = calloc(img_size, 1); + ut_assertnonnull(img); + + data = img + img_data; + generate_data(data, data_size, test_name); + ut_asserteq(img_size, create_image(img, type, &info_write, NULL)); + + if (type == LEGACY) { + ut_assertok(spl_parse_image_header(&info_read, NULL, img)); + if (check_image_info(uts, &info_write, &info_read)) + return CMD_RET_FAILURE; + } else { + struct spl_load_info load = { + .bl_len = 1, + .priv = img, + .read = spl_test_read, + }; + + if (type == IMX8) + ut_assertok(spl_load_imx_container(&info_read, &load, + 0)); + else if (IS_ENABLED(CONFIG_SPL_FIT_FULL)) + ut_assertok(spl_parse_image_header(&info_read, NULL, + img)); + else + ut_assertok(spl_load_simple_fit(&info_read, &load, 0, + img)); + if (check_image_info(uts, &info_write, &info_read)) + return CMD_RET_FAILURE; + ut_asserteq_mem(data, phys_to_virt(info_write.load_addr), + data_size); + } + + free(img); + return 0; +} +SPL_IMG_TEST(spl_test_image, LEGACY, 0); +SPL_IMG_TEST(spl_test_image, IMX8, 0); +SPL_IMG_TEST(spl_test_image, FIT_INTERNAL, 0); +SPL_IMG_TEST(spl_test_image, FIT_EXTERNAL, 0); diff --git a/test/image/spl_load_os.c b/test/image/spl_load_os.c index 3b2967d017a..49edf152d78 100644 --- a/test/image/spl_load_os.c +++ b/test/image/spl_load_os.c @@ -8,11 +8,9 @@ #include <image.h> #include <os.h> #include <spl.h> +#include <test/spl.h> #include <test/ut.h>
-/* Declare a new SPL test */ -#define SPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, spl_test) - /* Context used for this test */ struct text_ctx { int fd;

Add some functions for creating fat/ext2 filesystems with a single file and a test for them. Filesystems require block devices, and it is easiest to just use MMC for this. To get an MMC, we must also pull in the test device tree. SPL_TIMER is necessary for SPL_MMC, perhaps because it uses a timeout.
Signed-off-by: Sean Anderson seanga2@gmail.com ---
Changes in v2: - Explicitly invalidate FAT block device cache before testing - Remove unused dm.h include in spl_load.c - Add note about why we enable SPL_TIMER - Split off ext/-T changes into their own commits
configs/sandbox_noinst_defconfig | 7 + include/test/spl.h | 3 + test/image/Kconfig | 11 ++ test/image/Makefile | 1 + test/image/spl_load_fs.c | 306 +++++++++++++++++++++++++++++++ 5 files changed, 328 insertions(+) create mode 100644 test/image/spl_load_fs.c
diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index 908155be8a3..0a542cfb6aa 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -6,10 +6,12 @@ CONFIG_NR_DRAM_BANKS=1 CONFIG_ENV_SIZE=0x2000 CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_DM_RESET=y +CONFIG_SPL_MMC=y CONFIG_SPL_SERIAL=y CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y +CONFIG_SPL_FS_FAT=y CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y CONFIG_SANDBOX_SPL=y @@ -39,7 +41,9 @@ CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0xa000000 CONFIG_SPL_SYS_MALLOC_SIZE=0x4000000 CONFIG_SPL_ENV_SUPPORT=y +CONFIG_SPL_FS_EXT4=y CONFIG_SPL_I2C=y +CONFIG_SPL_MMC_WRITE=y CONFIG_SPL_RTC=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y @@ -97,6 +101,7 @@ CONFIG_AMIGA_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y CONFIG_SPL_OF_PLATDATA=y +CONFIG_SPL_OF_REAL=y CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y CONFIG_ENV_EXT4_INTERFACE="host" @@ -159,6 +164,7 @@ CONFIG_CROS_EC_SPI=y CONFIG_P2SB=y CONFIG_PWRSEQ=y CONFIG_SPL_PWRSEQ=y +CONFIG_FS_LOADER=y CONFIG_MMC_SANDBOX=y CONFIG_SPI_FLASH_SANDBOX=y CONFIG_SPI_FLASH_ATMEL=y @@ -220,6 +226,7 @@ CONFIG_SYSRESET=y CONFIG_SPL_SYSRESET=y CONFIG_DM_THERMAL=y CONFIG_TIMER=y +CONFIG_SPL_TIMER=y CONFIG_TIMER_EARLY=y CONFIG_SANDBOX_TIMER=y CONFIG_USB=y diff --git a/include/test/spl.h b/include/test/spl.h index 4c6b789e478..7dba3f03d07 100644 --- a/include/test/spl.h +++ b/include/test/spl.h @@ -114,4 +114,7 @@ SPL_TEST(func##_##type, flags) /* More than a couple blocks, and will not be aligned to anything */ #define SPL_TEST_DATA_SIZE 4099
+/* Flags necessary for accessing DM devices */ +#define DM_FLAGS (UT_TESTF_DM | UT_TESTF_SCAN_FDT) + #endif /* TEST_SPL_H */ diff --git a/test/image/Kconfig b/test/image/Kconfig index 70ffe0ff276..963c86cc290 100644 --- a/test/image/Kconfig +++ b/test/image/Kconfig @@ -10,6 +10,17 @@ config SPL_UT_LOAD
if SPL_UT_LOAD
+config SPL_UT_LOAD_FS + bool "Unit tests for filesystems" + depends on SANDBOX && SPL_OF_REAL + depends on FS_LOADER + depends on SPL_FS_FAT + depends on SPL_FS_EXT4 + depends on SPL_MMC_WRITE + default y + help + Test filesystems in SPL. + config SPL_UT_LOAD_OS bool "Test loading from the host OS" depends on SANDBOX && SPL_LOAD_FIT diff --git a/test/image/Makefile b/test/image/Makefile index f7ae996bc86..6bd77bf0aab 100644 --- a/test/image/Makefile +++ b/test/image/Makefile @@ -3,4 +3,5 @@ # Copyright 2021 Google LLC
obj-y += spl_load.o +obj-$(CONFIG_SPL_UT_LOAD_FS) += spl_load_fs.o obj-$(CONFIG_SPL_UT_LOAD_OS) += spl_load_os.o diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c new file mode 100644 index 00000000000..0ee1ede134a --- /dev/null +++ b/test/image/spl_load_fs.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson seanga2@gmail.com + */ + +#include <common.h> +#include <blk.h> +#include <ext_common.h> +#include <ext4fs.h> +#include <fat.h> +#include <fs.h> +#include <memalign.h> +#include <asm/io.h> +#include <linux/stat.h> +#include <test/spl.h> +#include <test/ut.h> + +/** + * create_ext2() - Create an "ext2" filesystem with a single file + * @dst: The location of the new filesystem; MUST be zeroed + * @size: The size of the file + * @filename: The name of the file + * @data_offset: Filled with the offset of the file data from @dst + * + * Budget mke2fs. We use 1k blocks (to reduce overhead) with a single block + * group, which limits us to 8M of data. Almost every feature which increases + * complexity (checksums, hash tree directories, etc.) is disabled. We do cheat + * a little and use extents from ext4 to save having to deal with indirects, but + * U-Boot doesn't care. + * + * If @dst is %NULL, nothing is copied. + * + * Return: The size of the filesystem in bytes + */ +static size_t create_ext2(void *dst, size_t size, const char *filename, + size_t *data_offset) +{ + u32 super_block = 1; + u32 group_block = 2; + u32 block_bitmap_block = 3; + u32 inode_bitmap_block = 4; + u32 inode_table_block = 5; + u32 root_block = 6; + u32 file_block = 7; + + u32 root_ino = EXT2_ROOT_INO; + u32 file_ino = EXT2_BOOT_LOADER_INO; + + u32 block_size = EXT2_MIN_BLOCK_SIZE; + u32 inode_size = sizeof(struct ext2_inode); + + u32 file_blocks = (size + block_size - 1) / block_size; + u32 blocks = file_block + file_blocks; + u32 inodes = block_size / inode_size; + u32 filename_len = strlen(filename); + u32 dirent_len = ALIGN(filename_len, sizeof(struct ext2_dirent)) + + sizeof(struct ext2_dirent); + + struct ext2_sblock *sblock = dst + super_block * block_size; + struct ext2_block_group *bg = dst + group_block * block_size; + struct ext2_inode *inode_table = dst + inode_table_block * block_size; + struct ext2_inode *root_inode = &inode_table[root_ino - 1]; + struct ext2_inode *file_inode = &inode_table[file_ino - 1]; + struct ext4_extent_header *ext_block = (void *)&file_inode->b; + struct ext4_extent *extent = (void *)(ext_block + 1); + struct ext2_dirent *dot = dst + root_block * block_size; + struct ext2_dirent *dotdot = dot + 2; + struct ext2_dirent *dirent = dotdot + 2; + struct ext2_dirent *last = ((void *)dirent) + dirent_len; + + /* Make sure we fit in one block group */ + if (blocks > block_size * 8) + return 0; + + if (filename_len > EXT2_NAME_LEN) + return 0; + + if (data_offset) + *data_offset = file_block * block_size; + + if (!dst) + goto out; + + sblock->total_inodes = cpu_to_le32(inodes); + sblock->total_blocks = cpu_to_le32(blocks); + sblock->first_data_block = cpu_to_le32(super_block); + sblock->blocks_per_group = cpu_to_le32(blocks); + sblock->fragments_per_group = cpu_to_le32(blocks); + sblock->inodes_per_group = cpu_to_le32(inodes); + sblock->magic = cpu_to_le16(EXT2_MAGIC); + /* Done mostly so we can pretend to be (in)compatible */ + sblock->revision_level = cpu_to_le32(EXT2_DYNAMIC_REV); + /* Not really accurate but it doesn't matter */ + sblock->first_inode = cpu_to_le32(EXT2_GOOD_OLD_FIRST_INO); + sblock->inode_size = cpu_to_le32(inode_size); + sblock->feature_incompat = cpu_to_le32(EXT4_FEATURE_INCOMPAT_EXTENTS); + + bg->block_id = cpu_to_le32(block_bitmap_block); + bg->inode_id = cpu_to_le32(inode_bitmap_block); + bg->inode_table_id = cpu_to_le32(inode_table_block); + + /* + * All blocks/inodes are in-use. I don't want to have to deal with + * endianness, so just fill everything in. + */ + memset(dst + block_bitmap_block * block_size, 0xff, block_size * 2); + + root_inode->mode = cpu_to_le16(S_IFDIR | 0755); + root_inode->size = cpu_to_le32(block_size); + root_inode->nlinks = cpu_to_le16(3); + root_inode->blockcnt = cpu_to_le32(1); + root_inode->flags = cpu_to_le32(EXT4_TOPDIR_FL); + root_inode->b.blocks.dir_blocks[0] = root_block; + + file_inode->mode = cpu_to_le16(S_IFREG | 0644); + file_inode->size = cpu_to_le32(size); + file_inode->nlinks = cpu_to_le16(1); + file_inode->blockcnt = cpu_to_le32(file_blocks); + file_inode->flags = cpu_to_le32(EXT4_EXTENTS_FL); + ext_block->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC); + ext_block->eh_entries = cpu_to_le16(1); + ext_block->eh_max = cpu_to_le16(sizeof(file_inode->b) / + sizeof(*ext_block) - 1); + extent->ee_len = cpu_to_le16(file_blocks); + extent->ee_start_lo = cpu_to_le16(file_block); + + /* I'm not sure we need these, but it can't hurt */ + dot->inode = cpu_to_le32(root_ino); + dot->direntlen = cpu_to_le16(2 * sizeof(*dot)); + dot->namelen = 1; + dot->filetype = FILETYPE_DIRECTORY; + memcpy(dot + 1, ".", dot->namelen); + + dotdot->inode = cpu_to_le32(root_ino); + dotdot->direntlen = cpu_to_le16(2 * sizeof(*dotdot)); + dotdot->namelen = 2; + dotdot->filetype = FILETYPE_DIRECTORY; + memcpy(dotdot + 1, "..", dotdot->namelen); + + dirent->inode = cpu_to_le32(file_ino); + dirent->direntlen = cpu_to_le16(dirent_len); + dirent->namelen = filename_len; + dirent->filetype = FILETYPE_REG; + memcpy(dirent + 1, filename, filename_len); + + last->direntlen = block_size - dirent_len; + +out: + return (size_t)blocks * block_size; +} + +/** + * create_fat() - Create a FAT32 filesystem with a single file + * @dst: The location of the new filesystem; MUST be zeroed + * @size: The size of the file + * @filename: The name of the file + * @data_offset: Filled with the offset of the file data from @dst + * + * Budget mkfs.fat. We use FAT32 (so I don't have to deal with FAT12) with no + * info sector, and a single one-sector FAT. This limits us to 64k of data + * (enough for anyone). The filename must fit in 8.3. + * + * If @dst is %NULL, nothing is copied. + * + * Return: The size of the filesystem in bytes + */ +static size_t create_fat(void *dst, size_t size, const char *filename, + size_t *data_offset) +{ + u16 boot_sector = 0; + u16 fat_sector = 1; + u32 root_sector = 2; + u32 file_sector = 3; + + u16 sector_size = 512; + u32 file_sectors = (size + sector_size - 1) / sector_size; + u32 sectors = file_sector + file_sectors; + + char *ext; + size_t filename_len, ext_len; + int i; + + struct boot_sector *bs = dst + boot_sector * sector_size; + struct volume_info *vi = (void *)(bs + 1); + __le32 *fat = dst + fat_sector * sector_size; + struct dir_entry *dirent = dst + root_sector * sector_size; + + /* Make sure we fit in the FAT */ + if (sectors > sector_size / sizeof(u32)) + return 0; + + ext = strchr(filename, '.'); + if (ext) { + filename_len = ext - filename; + ext++; + ext_len = strlen(ext); + } else { + filename_len = strlen(filename); + ext_len = 0; + } + + if (filename_len > 8 || ext_len > 3) + return 0; + + if (data_offset) + *data_offset = file_sector * sector_size; + + if (!dst) + goto out; + + bs->sector_size[0] = sector_size & 0xff; + bs->sector_size[1] = sector_size >> 8; + bs->cluster_size = 1; + bs->reserved = cpu_to_le16(fat_sector); + bs->fats = 1; + bs->media = 0xf8; + bs->total_sect = cpu_to_le32(sectors); + bs->fat32_length = cpu_to_le32(1); + bs->root_cluster = cpu_to_le32(root_sector); + + vi->ext_boot_sign = 0x29; + memcpy(vi->fs_type, FAT32_SIGN, sizeof(vi->fs_type)); + + memcpy(dst + 0x1fe, "\x55\xAA", 2); + + fat[0] = cpu_to_le32(0x0ffffff8); + fat[1] = cpu_to_le32(0x0fffffff); + fat[2] = cpu_to_le32(0x0ffffff8); + for (i = file_sector; file_sectors > 1; file_sectors--, i++) + fat[i] = cpu_to_le32(i + 1); + fat[i] = cpu_to_le32(0x0ffffff8); + + for (i = 0; i < sizeof(dirent->nameext.name); i++) { + if (i < filename_len) + dirent->nameext.name[i] = toupper(filename[i]); + else + dirent->nameext.name[i] = ' '; + } + + for (i = 0; i < sizeof(dirent->nameext.ext); i++) { + if (i < ext_len) + dirent->nameext.ext[i] = toupper(ext[i]); + else + dirent->nameext.ext[i] = ' '; + } + + dirent->start = cpu_to_le16(file_sector); + dirent->size = cpu_to_le32(size); + +out: + return sectors * sector_size; +} + +typedef size_t (*create_fs_t)(void *, size_t, const char *, size_t *); + +static int spl_test_fs(struct unit_test_state *uts, const char *test_name, + create_fs_t create) +{ + const char *filename = CONFIG_SPL_FS_LOAD_PAYLOAD_NAME; + struct blk_desc *dev_desc; + char *data_write, *data_read; + void *fs; + size_t fs_size, fs_data, fs_blocks, data_size = SPL_TEST_DATA_SIZE; + loff_t actread; + + fs_size = create(NULL, data_size, filename, &fs_data); + ut_assert(fs_size); + fs = calloc(fs_size, 1); + ut_assertnonnull(fs); + + data_write = fs + fs_data; + generate_data(data_write, data_size, test_name); + ut_asserteq(fs_size, create(fs, data_size, filename, NULL)); + + dev_desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0); + ut_assertnonnull(dev_desc); + ut_asserteq(512, dev_desc->blksz); + fs_blocks = fs_size / dev_desc->blksz; + ut_asserteq(fs_blocks, blk_dwrite(dev_desc, 0, fs_blocks, fs)); + + /* We have to use malloc so we can call virt_to_phys */ + data_read = malloc_cache_aligned(data_size); + ut_assertnonnull(data_read); + ut_assertok(fs_set_blk_dev_with_part(dev_desc, 0)); + ut_assertok(fs_read("/" CONFIG_SPL_FS_LOAD_PAYLOAD_NAME, + virt_to_phys(data_read), 0, data_size, &actread)); + ut_asserteq(data_size, actread); + ut_asserteq_mem(data_write, data_read, data_size); + + free(data_read); + free(fs); + return 0; +} + +static int spl_test_ext(struct unit_test_state *uts) +{ + return spl_test_fs(uts, __func__, create_ext2); +} +SPL_TEST(spl_test_ext, DM_FLAGS); + +static int spl_test_fat(struct unit_test_state *uts) +{ + spl_fat_force_reregister(); + return spl_test_fs(uts, __func__, create_fat); +} +SPL_TEST(spl_test_fat, DM_FLAGS);

On Sat, 14 Oct 2023 at 14:48, Sean Anderson seanga2@gmail.com wrote:
Add some functions for creating fat/ext2 filesystems with a single file and a test for them. Filesystems require block devices, and it is easiest to just use MMC for this. To get an MMC, we must also pull in the test device tree. SPL_TIMER is necessary for SPL_MMC, perhaps because it uses a timeout.
Signed-off-by: Sean Anderson seanga2@gmail.com
Changes in v2:
- Explicitly invalidate FAT block device cache before testing
- Remove unused dm.h include in spl_load.c
- Add note about why we enable SPL_TIMER
- Split off ext/-T changes into their own commits
configs/sandbox_noinst_defconfig | 7 + include/test/spl.h | 3 + test/image/Kconfig | 11 ++ test/image/Makefile | 1 + test/image/spl_load_fs.c | 306 +++++++++++++++++++++++++++++++ 5 files changed, 328 insertions(+) create mode 100644 test/image/spl_load_fs.c
Reviewed-by: Simon Glass sjg@chromium.org

Add a test for spl_blk_load_image, currently used only by NVMe. Because there is no sandbox NVMe driver, just use MMC instead. Avoid falling back to raw images to make failures more obvious.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Explicitly invalidate FAT block device cache before testing
configs/sandbox_noinst_defconfig | 2 + test/image/Kconfig | 3 +- test/image/spl_load_fs.c | 63 ++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index 0a542cfb6aa..11be2dccf7d 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -34,6 +34,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_HANDOFF=y CONFIG_SPL_BOARD_INIT=y +# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set CONFIG_SPL_LEGACY_IMAGE_FORMAT=y CONFIG_SPL_LOAD_IMX_CONTAINER=y CONFIG_SPL_SYS_MALLOC=y @@ -123,6 +124,7 @@ CONFIG_ADC=y CONFIG_ADC_SANDBOX=y CONFIG_AXI=y CONFIG_AXI_SANDBOX=y +CONFIG_SPL_BLK_FS=y CONFIG_SYS_IDE_MAXBUS=1 CONFIG_SYS_ATA_BASE_ADDR=0x100 CONFIG_SYS_ATA_STRIDE=4 diff --git a/test/image/Kconfig b/test/image/Kconfig index 963c86cc290..a52766b77d4 100644 --- a/test/image/Kconfig +++ b/test/image/Kconfig @@ -14,12 +14,13 @@ config SPL_UT_LOAD_FS bool "Unit tests for filesystems" depends on SANDBOX && SPL_OF_REAL depends on FS_LOADER + depends on SPL_BLK_FS depends on SPL_FS_FAT depends on SPL_FS_EXT4 depends on SPL_MMC_WRITE default y help - Test filesystems in SPL. + Test filesystems and the various load methods which use them.
config SPL_UT_LOAD_OS bool "Test loading from the host OS" diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c index 0ee1ede134a..a8b45bdbc49 100644 --- a/test/image/spl_load_fs.c +++ b/test/image/spl_load_fs.c @@ -10,6 +10,7 @@ #include <fat.h> #include <fs.h> #include <memalign.h> +#include <spl.h> #include <asm/io.h> #include <linux/stat.h> #include <test/spl.h> @@ -304,3 +305,65 @@ static int spl_test_fat(struct unit_test_state *uts) return spl_test_fs(uts, __func__, create_fat); } SPL_TEST(spl_test_fat, DM_FLAGS); + +static int spl_test_mmc_fs(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type, create_fs_t create_fs) +{ + const char *filename = CONFIG_SPL_FS_LOAD_PAYLOAD_NAME; + struct blk_desc *dev_desc; + size_t fs_size, fs_data, img_size, img_data, + data_size = SPL_TEST_DATA_SIZE; + struct spl_image_info info_write = { + .name = test_name, + .size = data_size, + }, info_read = { }; + struct disk_partition part = { + .start = 1, + .sys_ind = 0x83, + }; + struct spl_boot_device bootdev = { }; + void *fs; + char *data; + + img_size = create_image(NULL, type, &info_write, &img_data); + ut_assert(img_size); + fs_size = create_fs(NULL, img_size, filename, &fs_data); + ut_assert(fs_size); + fs = calloc(fs_size, 1); + ut_assertnonnull(fs); + + data = fs + fs_data + img_data; + generate_data(data, data_size, test_name); + ut_asserteq(img_size, create_image(fs + fs_data, type, &info_write, + NULL)); + ut_asserteq(fs_size, create_fs(fs, img_size, filename, NULL)); + + dev_desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0); + ut_assertnonnull(dev_desc); + + ut_asserteq(512, dev_desc->blksz); + part.size = fs_size / dev_desc->blksz; + ut_assertok(write_mbr_partitions(dev_desc, &part, 1, 0)); + ut_asserteq(part.size, blk_dwrite(dev_desc, part.start, part.size, fs)); + + ut_assertok(spl_blk_load_image(&info_read, &bootdev, UCLASS_MMC, 0, 1)); + if (check_image_info(uts, &info_write, &info_read)) + return CMD_RET_FAILURE; + ut_asserteq_mem(data, phys_to_virt(info_write.load_addr), data_size); + + free(fs); + return 0; +} + +static int spl_test_blk(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + spl_fat_force_reregister(); + if (spl_test_mmc_fs(uts, test_name, type, create_fat)) + return CMD_RET_FAILURE; + + return spl_test_mmc_fs(uts, test_name, type, create_ext2); +} +SPL_IMG_TEST(spl_test_blk, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_blk, FIT_EXTERNAL, DM_FLAGS); +SPL_IMG_TEST(spl_test_blk, FIT_INTERNAL, DM_FLAGS);

Add a test for the MMC load method. This shows the general shape of tests to come: The main test function calls do_spl_test_load with an appropriate callback to write the image to the medium.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Correct return value documentation for do_spl_test_load - Explicitly invalidate FAT and MMC caches before testing
configs/sandbox_noinst_defconfig | 2 + include/spl.h | 4 ++ include/test/spl.h | 30 ++++++++++++++ test/image/Kconfig | 1 + test/image/spl_load.c | 36 +++++++++++++++++ test/image/spl_load_fs.c | 69 +++++++++++++++++++++++++++++--- 6 files changed, 137 insertions(+), 5 deletions(-)
diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index 11be2dccf7d..4f16d9860d2 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -41,6 +41,8 @@ CONFIG_SPL_SYS_MALLOC=y CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0xa000000 CONFIG_SPL_SYS_MALLOC_SIZE=0x4000000 +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x0 CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_FS_EXT4=y CONFIG_SPL_I2C=y diff --git a/include/spl.h b/include/spl.h index 5b051ef2aae..708b15a0c7f 100644 --- a/include/spl.h +++ b/include/spl.h @@ -673,6 +673,10 @@ static inline const char *spl_loader_name(const struct spl_image_loader *loader) } #endif
+#define SPL_LOAD_IMAGE_GET(_priority, _boot_device, _method) \ + ll_entry_get(struct spl_image_loader, \ + _boot_device ## _priority ## _method, spl_image_loader) + /* SPL FAT image functions */
/** diff --git a/include/test/spl.h b/include/test/spl.h index 7dba3f03d07..009c6b35462 100644 --- a/include/test/spl.h +++ b/include/test/spl.h @@ -79,6 +79,36 @@ size_t create_image(void *dst, enum spl_test_image type, int check_image_info(struct unit_test_state *uts, struct spl_image_info *info1, struct spl_image_info *info2);
+/** + * typedef write_image_t - Callback for writing an image + * @uts: Current unit test state + * @img: Image to write + * @size: Size of @img + * + * Write @img to a location which will be read by a &struct spl_image_loader. + * + * Return: 0 on success or 1 on failure + */ +typedef int write_image_t(struct unit_test_state *its, void *img, size_t size); + +/** + * do_spl_test_load() - Test loading with an SPL image loader + * @uts: Current unit test state + * @test_name: Name of the current test + * @type: Type of image to try loading + * @loader: The loader to test + * @write_image: Callback to write the image to the backing storage + * + * Test @loader, performing the common tasks of setting up the image and + * checking it was loaded correctly. The caller must supply a @write_image + * callback to write the image to a location which will be read by @loader. + * + * Return: 0 on success or 1 on failure + */ +int do_spl_test_load(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type, struct spl_image_loader *loader, + write_image_t write_image); + /** * image_supported() - Determine whether an image type is supported * @type: The image type to check diff --git a/test/image/Kconfig b/test/image/Kconfig index a52766b77d4..e6be1b829f3 100644 --- a/test/image/Kconfig +++ b/test/image/Kconfig @@ -18,6 +18,7 @@ config SPL_UT_LOAD_FS depends on SPL_FS_FAT depends on SPL_FS_EXT4 depends on SPL_MMC_WRITE + depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR default y help Test filesystems and the various load methods which use them. diff --git a/test/image/spl_load.c b/test/image/spl_load.c index de2fddae359..d2ce66071bc 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -365,3 +365,39 @@ SPL_IMG_TEST(spl_test_image, LEGACY, 0); SPL_IMG_TEST(spl_test_image, IMX8, 0); SPL_IMG_TEST(spl_test_image, FIT_INTERNAL, 0); SPL_IMG_TEST(spl_test_image, FIT_EXTERNAL, 0); + +int do_spl_test_load(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type, struct spl_image_loader *loader, + int (*write_image)(struct unit_test_state *, void *, size_t)) +{ + size_t img_size, img_data, plain_size = SPL_TEST_DATA_SIZE; + struct spl_image_info info_write = { + .name = test_name, + .size = plain_size, + }, info_read = { }; + struct spl_boot_device bootdev = { + .boot_device = loader->boot_device, + }; + char *plain; + void *img; + + img_size = create_image(NULL, type, &info_write, &img_data); + ut_assert(img_size); + img = calloc(img_size, 1); + ut_assertnonnull(img); + + plain = img + img_data; + generate_data(plain, plain_size, test_name); + ut_asserteq(img_size, create_image(img, type, &info_write, NULL)); + + if (write_image(uts, img, img_size)) + return CMD_RET_FAILURE; + + ut_assertok(loader->load_image(&info_read, &bootdev)); + if (check_image_info(uts, &info_write, &info_read)) + return CMD_RET_FAILURE; + ut_asserteq_mem(plain, phys_to_virt(info_write.load_addr), plain_size); + + free(img); + return 0; +} diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c index a8b45bdbc49..297ab08a820 100644 --- a/test/image/spl_load_fs.c +++ b/test/image/spl_load_fs.c @@ -306,8 +306,16 @@ static int spl_test_fat(struct unit_test_state *uts) } SPL_TEST(spl_test_fat, DM_FLAGS);
+static bool spl_mmc_raw; + +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) +{ + return spl_mmc_raw ? MMCSD_MODE_RAW : MMCSD_MODE_FS; +} + static int spl_test_mmc_fs(struct unit_test_state *uts, const char *test_name, - enum spl_test_image type, create_fs_t create_fs) + enum spl_test_image type, create_fs_t create_fs, + bool blk_mode) { const char *filename = CONFIG_SPL_FS_LOAD_PAYLOAD_NAME; struct blk_desc *dev_desc; @@ -321,7 +329,11 @@ static int spl_test_mmc_fs(struct unit_test_state *uts, const char *test_name, .start = 1, .sys_ind = 0x83, }; - struct spl_boot_device bootdev = { }; + struct spl_image_loader *loader = + SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_MMC1, spl_mmc_load_image); + struct spl_boot_device bootdev = { + .boot_device = loader->boot_device, + }; void *fs; char *data;
@@ -346,7 +358,12 @@ static int spl_test_mmc_fs(struct unit_test_state *uts, const char *test_name, ut_assertok(write_mbr_partitions(dev_desc, &part, 1, 0)); ut_asserteq(part.size, blk_dwrite(dev_desc, part.start, part.size, fs));
- ut_assertok(spl_blk_load_image(&info_read, &bootdev, UCLASS_MMC, 0, 1)); + spl_mmc_raw = false; + if (blk_mode) + ut_assertok(spl_blk_load_image(&info_read, &bootdev, UCLASS_MMC, + 0, 1)); + else + ut_assertok(loader->load_image(&info_read, &bootdev)); if (check_image_info(uts, &info_write, &info_read)) return CMD_RET_FAILURE; ut_asserteq_mem(data, phys_to_virt(info_write.load_addr), data_size); @@ -359,11 +376,53 @@ static int spl_test_blk(struct unit_test_state *uts, const char *test_name, enum spl_test_image type) { spl_fat_force_reregister(); - if (spl_test_mmc_fs(uts, test_name, type, create_fat)) + if (spl_test_mmc_fs(uts, test_name, type, create_fat, true)) return CMD_RET_FAILURE;
- return spl_test_mmc_fs(uts, test_name, type, create_ext2); + return spl_test_mmc_fs(uts, test_name, type, create_ext2, true); } SPL_IMG_TEST(spl_test_blk, LEGACY, DM_FLAGS); SPL_IMG_TEST(spl_test_blk, FIT_EXTERNAL, DM_FLAGS); SPL_IMG_TEST(spl_test_blk, FIT_INTERNAL, DM_FLAGS); + +static int spl_test_mmc_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + struct blk_desc *dev_desc; + size_t img_blocks; + + dev_desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0); + ut_assertnonnull(dev_desc); + + img_blocks = DIV_ROUND_UP(img_size, dev_desc->blksz); + ut_asserteq(img_blocks, blk_dwrite(dev_desc, + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, + img_blocks, img)); + + spl_mmc_raw = true; + return 0; +} + +static int spl_test_mmc(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + spl_mmc_clear_cache(); + spl_fat_force_reregister(); + + if (type == LEGACY && + spl_test_mmc_fs(uts, test_name, type, create_ext2, false)) + return CMD_RET_FAILURE; + + if (type != IMX8 && + spl_test_mmc_fs(uts, test_name, type, create_fat, false)) + return CMD_RET_FAILURE; + + return do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_MMC1, + spl_mmc_load_image), + spl_test_mmc_write_image); +} +SPL_IMG_TEST(spl_test_mmc, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_mmc, IMX8, DM_FLAGS); +SPL_IMG_TEST(spl_test_mmc, FIT_EXTERNAL, DM_FLAGS); +SPL_IMG_TEST(spl_test_mmc, FIT_INTERNAL, DM_FLAGS);

Add a test for loading U-Boot over TFTP. As with other sandbox net routines, we need to initialize our packets manually since things like net_set_ether and net_set_udp_header always use "our" addresses. We use BOOTP instead of DHCP, since DHCP has a tag/length-based format which is harder to parse. Our TFTP implementation doesn't define as many constants as I'd like, so I create some here. Note that the TFTP block size is one-based, but offsets are zero-based.
In order to avoid address errors, we need to set up/define some additional address information settings. dram_init_banksize would be a good candidate for settig up bi_dram, but it gets called too late in board_init_r.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a comment about why we need to initialize bi_dram
arch/sandbox/cpu/spl.c | 4 + arch/sandbox/include/asm/spl.h | 1 + configs/sandbox_noinst_defconfig | 6 +- test/image/Kconfig | 9 ++ test/image/Makefile | 1 + test/image/spl_load_net.c | 252 +++++++++++++++++++++++++++++++ 6 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 test/image/spl_load_net.c
diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 09e3d10d6a5..e8a75e73d24 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -126,6 +126,10 @@ void spl_board_init(void) { struct sandbox_state *state = state_get_current();
+ /* These are necessary so TFTP can use LMBs to check its load address */ + gd->bd->bi_dram[0].start = gd->ram_base; + gd->bd->bi_dram[0].size = get_effective_memsize(); + if (state->run_unittests) { struct unit_test *tests = UNIT_TEST_ALL_START(); const int count = UNIT_TEST_ALL_COUNT(); diff --git a/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h index 2f8b5fcfcfe..ab9475567e0 100644 --- a/arch/sandbox/include/asm/spl.h +++ b/arch/sandbox/include/asm/spl.h @@ -12,6 +12,7 @@ enum { BOOT_DEVICE_MMC2_2, BOOT_DEVICE_BOARD, BOOT_DEVICE_VBE, + BOOT_DEVICE_CPGMAC, };
/** diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index 4f16d9860d2..57cbadedb7d 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -12,7 +12,7 @@ CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y CONFIG_SPL_FS_FAT=y -CONFIG_SYS_LOAD_ADDR=0x0 +CONFIG_SYS_LOAD_ADDR=0x1000000 CONFIG_PCI=y CONFIG_SANDBOX_SPL=y CONFIG_DEBUG_UART=y @@ -44,9 +44,11 @@ CONFIG_SPL_SYS_MALLOC_SIZE=0x4000000 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x0 CONFIG_SPL_ENV_SUPPORT=y +CONFIG_SPL_ETH=y CONFIG_SPL_FS_EXT4=y CONFIG_SPL_I2C=y CONFIG_SPL_MMC_WRITE=y +CONFIG_SPL_NET=y CONFIG_SPL_RTC=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y @@ -109,6 +111,8 @@ CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y CONFIG_ENV_EXT4_INTERFACE="host" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" +CONFIG_USE_BOOTFILE=y +CONFIG_BOOTFILE="uImage" CONFIG_BOOTP_SEND_HOSTNAME=y CONFIG_NETCONSOLE=y CONFIG_IP_DEFRAG=y diff --git a/test/image/Kconfig b/test/image/Kconfig index e6be1b829f3..99c50787816 100644 --- a/test/image/Kconfig +++ b/test/image/Kconfig @@ -23,6 +23,15 @@ config SPL_UT_LOAD_FS help Test filesystems and the various load methods which use them.
+config SPL_UT_LOAD_NET + bool "Test loading over TFTP" + depends on SANDBOX && SPL_OF_REAL + depends on SPL_ETH + depends on USE_BOOTFILE + default y + help + Test loading images over TFTP using the NET image load method. + config SPL_UT_LOAD_OS bool "Test loading from the host OS" depends on SANDBOX && SPL_LOAD_FIT diff --git a/test/image/Makefile b/test/image/Makefile index 6bd77bf0aab..245672f8d83 100644 --- a/test/image/Makefile +++ b/test/image/Makefile @@ -4,4 +4,5 @@
obj-y += spl_load.o obj-$(CONFIG_SPL_UT_LOAD_FS) += spl_load_fs.o +obj-$(CONFIG_SPL_UT_LOAD_NET) += spl_load_net.o obj-$(CONFIG_SPL_UT_LOAD_OS) += spl_load_os.o diff --git a/test/image/spl_load_net.c b/test/image/spl_load_net.c new file mode 100644 index 00000000000..f570cef163f --- /dev/null +++ b/test/image/spl_load_net.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson seanga2@gmail.com + */ + +#include <common.h> +#include <dm.h> +#include <spl.h> +#include <test/spl.h> +#include <asm/eth.h> +#include <test/ut.h> +#include "../../net/bootp.h" + +/* + * sandbox_eth_bootp_req_to_reply() + * + * Check if a BOOTP request was sent. If so, inject a reply + * + * returns 0 if injected, -EAGAIN if not + */ +static int sandbox_eth_bootp_req_to_reply(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct ip_udp_hdr *ip; + struct bootp_hdr *bp; + struct ethernet_hdr *eth_recv; + struct ip_udp_hdr *ipr; + struct bootp_hdr *bpr; + + if (ntohs(eth->et_protlen) != PROT_IP) + return -EAGAIN; + + ip = packet + ETHER_HDR_SIZE; + if (ip->ip_p != IPPROTO_UDP) + return -EAGAIN; + + if (ntohs(ip->udp_dst) != PORT_BOOTPS) + return -EAGAIN; + + bp = (void *)ip + IP_UDP_HDR_SIZE; + if (bp->bp_op != OP_BOOTREQUEST) + return -EAGAIN; + + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return 0; + + /* reply to the request */ + eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets]; + memcpy(eth_recv, packet, len); + ipr = (void *)eth_recv + ETHER_HDR_SIZE; + bpr = (void *)ipr + IP_UDP_HDR_SIZE; + memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); + ipr->ip_sum = 0; + ipr->ip_off = 0; + net_write_ip(&ipr->ip_dst, net_ip); + net_write_ip(&ipr->ip_src, priv->fake_host_ipaddr); + ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE); + ipr->udp_src = ip->udp_dst; + ipr->udp_dst = ip->udp_src; + + bpr->bp_op = OP_BOOTREPLY; + net_write_ip(&bpr->bp_yiaddr, net_ip); + net_write_ip(&bpr->bp_siaddr, priv->fake_host_ipaddr); + copy_filename(bpr->bp_file, CONFIG_BOOTFILE, sizeof(CONFIG_BOOTFILE)); + memset(&bpr->bp_vend, 0, sizeof(bpr->bp_vend)); + + priv->recv_packet_length[priv->recv_packets] = len; + ++priv->recv_packets; + + return 0; +} + +struct spl_test_net_priv { + struct unit_test_state *uts; + void *img; + size_t img_size; + u16 port; +}; + +/* Well known TFTP port # */ +#define TFTP_PORT 69 +/* Transaction ID, chosen at random */ +#define TFTP_TID 21313 + +/* + * TFTP operations. + */ +#define TFTP_RRQ 1 +#define TFTP_DATA 3 +#define TFTP_ACK 4 + +/* default TFTP block size */ +#define TFTP_BLOCK_SIZE 512 + +struct tftp_hdr { + u16 opcode; + u16 block; +}; + +#define TFTP_HDR_SIZE sizeof(struct tftp_hdr) + +/* + * sandbox_eth_tftp_req_to_reply() + * + * Check if a TFTP request was sent. If so, inject a reply. We don't support + * options, and we don't check for rollover, so we are limited files of less + * than 32M. + * + * returns 0 if injected, -EAGAIN if not + */ +static int sandbox_eth_tftp_req_to_reply(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct spl_test_net_priv *test_priv = priv->priv; + struct ethernet_hdr *eth = packet; + struct ip_udp_hdr *ip; + struct tftp_hdr *tftp; + struct ethernet_hdr *eth_recv; + struct ip_udp_hdr *ipr; + struct tftp_hdr *tftpr; + size_t size; + u16 block; + + if (ntohs(eth->et_protlen) != PROT_IP) + return -EAGAIN; + + ip = packet + ETHER_HDR_SIZE; + if (ip->ip_p != IPPROTO_UDP) + return -EAGAIN; + + if (ntohs(ip->udp_dst) == TFTP_PORT) { + tftp = (void *)ip + IP_UDP_HDR_SIZE; + if (htons(tftp->opcode) != TFTP_RRQ) + return -EAGAIN; + + block = 0; + } else if (ntohs(ip->udp_dst) == TFTP_TID) { + tftp = (void *)ip + IP_UDP_HDR_SIZE; + if (htons(tftp->opcode) != TFTP_ACK) + return -EAGAIN; + + block = htons(tftp->block); + } else { + return -EAGAIN; + } + + if (block * TFTP_BLOCK_SIZE > test_priv->img_size) + return 0; + + size = min(test_priv->img_size - block * TFTP_BLOCK_SIZE, + (size_t)TFTP_BLOCK_SIZE); + + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return 0; + + /* reply to the request */ + eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets]; + memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); + eth_recv->et_protlen = htons(PROT_IP); + + ipr = (void *)eth_recv + ETHER_HDR_SIZE; + ipr->ip_hl_v = 0x45; + ipr->ip_len = htons(IP_UDP_HDR_SIZE + TFTP_HDR_SIZE + size); + ipr->ip_off = htons(IP_FLAGS_DFRAG); + ipr->ip_ttl = 255; + ipr->ip_p = IPPROTO_UDP; + ipr->ip_sum = 0; + net_copy_ip(&ipr->ip_dst, &ip->ip_src); + net_copy_ip(&ipr->ip_src, &ip->ip_dst); + ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE); + + ipr->udp_src = htons(TFTP_TID); + ipr->udp_dst = ip->udp_src; + ipr->udp_len = htons(UDP_HDR_SIZE + TFTP_HDR_SIZE + size); + ipr->udp_xsum = 0; + + tftpr = (void *)ipr + IP_UDP_HDR_SIZE; + tftpr->opcode = htons(TFTP_DATA); + tftpr->block = htons(block + 1); + memcpy((void *)tftpr + TFTP_HDR_SIZE, + test_priv->img + block * TFTP_BLOCK_SIZE, size); + + priv->recv_packet_length[priv->recv_packets] = + ETHER_HDR_SIZE + IP_UDP_HDR_SIZE + TFTP_HDR_SIZE + size; + ++priv->recv_packets; + + return 0; +} + +static int spl_net_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + int old_packets = priv->recv_packets; + + priv->fake_host_ipaddr = string_to_ip("1.1.2.4"); + net_ip = string_to_ip("1.1.2.2"); + + sandbox_eth_arp_req_to_reply(dev, packet, len); + sandbox_eth_bootp_req_to_reply(dev, packet, len); + sandbox_eth_tftp_req_to_reply(dev, packet, len); + + if (old_packets == priv->recv_packets) + return 0; + + return 0; +} + +static int spl_test_net_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + struct spl_test_net_priv *test_priv = malloc(sizeof(*test_priv)); + + ut_assertnonnull(test_priv); + test_priv->uts = uts; + test_priv->img = img; + test_priv->img_size = img_size; + + sandbox_eth_set_tx_handler(0, spl_net_handler); + sandbox_eth_set_priv(0, test_priv); + return 0; +} + +static int spl_test_net(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + struct eth_sandbox_priv *priv; + struct udevice *dev; + int ret; + + net_server_ip = string_to_ip("1.1.2.4"); + ret = do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_CPGMAC, + spl_net_load_image_cpgmac), + spl_test_net_write_image); + + sandbox_eth_set_tx_handler(0, NULL); + ut_assertok(uclass_get_device(UCLASS_ETH, 0, &dev)); + priv = dev_get_priv(dev); + free(priv->priv); + return ret; +} +SPL_IMG_TEST(spl_test_net, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_net, FIT_INTERNAL, DM_FLAGS); +SPL_IMG_TEST(spl_test_net, FIT_EXTERNAL, DM_FLAGS);

Add a test for the NOR load method. Since NOR is memory-mapped we can substitute a buffer instead. The only major complication is testing LZMA decompression. It's too complex to implement LZMA compression in a test, and we have no in-tree compressor, so we just include some pre-compressed data. This data was generated through something like
generate_data(plain, plain_size, "lzma") cat plain.dat | lzma | hexdump -C
and was cleaned up further in my editor.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Clarify generation process for LZMA data
arch/sandbox/include/asm/spl.h | 1 + configs/sandbox_noinst_defconfig | 2 + configs/sandbox_spl_defconfig | 2 + include/configs/sandbox.h | 3 + include/test/spl.h | 5 + test/image/Makefile | 1 + test/image/spl_load.c | 269 ++++++++++++++++++++++++++++++- test/image/spl_load_nor.c | 39 +++++ 8 files changed, 316 insertions(+), 6 deletions(-) create mode 100644 test/image/spl_load_nor.c
diff --git a/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h index ab9475567e0..cf16af5278a 100644 --- a/arch/sandbox/include/asm/spl.h +++ b/arch/sandbox/include/asm/spl.h @@ -13,6 +13,7 @@ enum { BOOT_DEVICE_BOARD, BOOT_DEVICE_VBE, BOOT_DEVICE_CPGMAC, + BOOT_DEVICE_NOR, };
/** diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index 57cbadedb7d..085cc30c1e2 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -49,6 +49,7 @@ CONFIG_SPL_FS_EXT4=y CONFIG_SPL_I2C=y CONFIG_SPL_MMC_WRITE=y CONFIG_SPL_NET=y +CONFIG_SPL_NOR_SUPPORT=y CONFIG_SPL_RTC=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y @@ -257,6 +258,7 @@ CONFIG_RSA_VERIFY_WITH_PKEY=y CONFIG_TPM=y CONFIG_LZ4=y CONFIG_ZSTD=y +CONFIG_SPL_LZMA=y CONFIG_ERRNO_STR=y CONFIG_EFI_CAPSULE_ON_DISK=y CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index b578cc8e443..56072b15ad2 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -41,6 +41,7 @@ CONFIG_SPL_SYS_MALLOC_SIZE=0x4000000 CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_FPGA=y CONFIG_SPL_I2C=y +CONFIG_SPL_NOR_SUPPORT=y CONFIG_SPL_RTC=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y @@ -249,6 +250,7 @@ CONFIG_TPM=y CONFIG_SPL_CRC8=y CONFIG_LZ4=y CONFIG_ZSTD=y +CONFIG_SPL_LZMA=y CONFIG_ERRNO_STR=y CONFIG_SPL_HEXDUMP=y CONFIG_EFI_CAPSULE_ON_DISK=y diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 4e5653dc886..2372485c84e 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -18,4 +18,7 @@ #define CFG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600,\ 115200}
+/* Unused but necessary to build */ +#define CFG_SYS_UBOOT_BASE CONFIG_TEXT_BASE + #endif diff --git a/include/test/spl.h b/include/test/spl.h index 009c6b35462..c1f64658502 100644 --- a/include/test/spl.h +++ b/include/test/spl.h @@ -27,12 +27,14 @@ void generate_data(char *data, size_t size, const char *test_name); /** * enum spl_test_image - Image types for testing * @LEGACY: "Legacy" uImages + * @LEGACY_LZMA: "Legacy" uImages, LZMA compressed * @IMX8: i.MX8 Container images * @FIT_INTERNAL: FITs with internal data * @FIT_EXTERNAL: FITs with external data */ enum spl_test_image { LEGACY, + LEGACY_LZMA, IMX8, FIT_INTERNAL, FIT_EXTERNAL, @@ -118,6 +120,9 @@ int do_spl_test_load(struct unit_test_state *uts, const char *test_name, static inline bool image_supported(enum spl_test_image type) { switch (type) { + case LEGACY_LZMA: + if (!IS_ENABLED(CONFIG_SPL_LZMA)) + return false; case LEGACY: return IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_FORMAT); case IMX8: diff --git a/test/image/Makefile b/test/image/Makefile index 245672f8d83..a82aa40449d 100644 --- a/test/image/Makefile +++ b/test/image/Makefile @@ -5,4 +5,5 @@ obj-y += spl_load.o obj-$(CONFIG_SPL_UT_LOAD_FS) += spl_load_fs.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_OS) += spl_load_os.o diff --git a/test/image/spl_load.c b/test/image/spl_load.c index d2ce66071bc..07a986258d9 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -40,6 +40,7 @@ void *board_spl_fit_buffer_addr(ulong fit_size, int sectors, int bl_len)
/* Local flags for spl_image; start from the "top" to avoid conflicts */ #define SPL_IMX_CONTAINER 0x80000000 +#define SPL_COMP_LZMA 0x40000000
void generate_data(char *data, size_t size, const char *test_name) { @@ -76,7 +77,8 @@ static size_t create_legacy(void *dst, struct spl_image_info *spl_image, image_set_os(hdr, spl_image->os); image_set_arch(hdr, IH_ARCH_DEFAULT); image_set_type(hdr, IH_TYPE_FIRMWARE); - image_set_comp(hdr, IH_COMP_NONE); + image_set_comp(hdr, spl_image->flags & SPL_COMP_LZMA ? IH_COMP_LZMA : + IH_COMP_NONE); image_set_name(hdr, spl_image->name); image_set_hcrc(hdr, crc32(0, (void *)hdr, sizeof(*hdr)));
@@ -249,6 +251,8 @@ size_t create_image(void *dst, enum spl_test_image type, info->flags = 0;
switch (type) { + case LEGACY_LZMA: + info->flags = SPL_COMP_LZMA; case LEGACY: return create_legacy(dst, info, data_offset); case IMX8: @@ -293,7 +297,7 @@ int check_image_info(struct unit_test_state *uts, struct spl_image_info *info1, ut_asserteq(info1->load_addr, info2->load_addr); if (info1->flags & SPL_IMX_CONTAINER) ut_asserteq(0, info2->size); - else + else if (!(info1->flags & SPL_COMP_LZMA)) ut_asserteq(info1->size, info2->size); } else { ut_asserteq(info1->load_addr - sizeof(struct legacy_img_hdr), @@ -366,6 +370,246 @@ SPL_IMG_TEST(spl_test_image, IMX8, 0); SPL_IMG_TEST(spl_test_image, FIT_INTERNAL, 0); SPL_IMG_TEST(spl_test_image, FIT_EXTERNAL, 0);
+/* + * LZMA is too complex to generate on the fly, so let's use some data I put in + * the oven^H^H^H^H compressed earlier + */ +static const char lzma_compressed[] = { + 0x5d, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x02, 0x05, 0x55, 0x4e, 0x82, 0xbc, 0xc2, 0x42, 0xf6, 0x88, + 0x6c, 0x99, 0xd6, 0x82, 0x48, 0xa6, 0x06, 0x67, 0xf8, 0x46, 0x7c, 0xe9, + 0x41, 0x79, 0xfe, 0x90, 0x0b, 0x31, 0x7b, 0x79, 0x91, 0xb8, 0x5f, 0x33, + 0x11, 0x04, 0xc3, 0x4f, 0xf5, 0x71, 0xd1, 0xfb, 0x94, 0x6b, 0x5f, 0x78, + 0xe2, 0xfa, 0x6a, 0x21, 0xb6, 0x1d, 0x11, 0x0e, 0x5b, 0x56, 0x6a, 0x5b, + 0xe9, 0x56, 0x5f, 0x8b, 0x87, 0x61, 0x96, 0x6d, 0xce, 0x66, 0xbb, 0xb6, + 0xe7, 0x13, 0x5a, 0xd8, 0x84, 0x29, 0x60, 0xa0, 0x80, 0x43, 0xdd, 0x0f, + 0x4b, 0x85, 0xb0, 0x04, 0x9d, 0x9f, 0x28, 0x97, 0x0a, 0x1e, 0x16, 0xb0, + 0x45, 0x33, 0x5e, 0x79, 0x4f, 0xaa, 0xee, 0x79, 0x6e, 0xc3, 0x4e, 0x3d, + 0xe8, 0x67, 0x7c, 0xe0, 0xd0, 0xcc, 0x05, 0x40, 0xae, 0x6b, 0x97, 0x82, + 0x97, 0x02, 0x01, 0xe2, 0xe3, 0xbc, 0xe4, 0x9b, 0xb3, 0x28, 0xed, 0x5e, + 0x0d, 0x68, 0x6e, 0xe5, 0x17, 0x0a, 0x86, 0x5a, 0xcd, 0x8d, 0x46, 0x2d, + 0x06, 0x10, 0xa6, 0x90, 0x44, 0xa1, 0xfc, 0x66, 0x6d, 0x7c, 0x57, 0x57, + 0x07, 0xbc, 0x95, 0xb2, 0x8d, 0xf0, 0x9f, 0x4d, 0x90, 0x04, 0xaf, 0x0c, + 0x23, 0x51, 0x1b, 0x34, 0xd5, 0x5c, 0x5d, 0x87, 0x5e, 0x10, 0x2b, 0x71, + 0xc2, 0xcf, 0xc5, 0x9d, 0x4b, 0x89, 0x01, 0xc4, 0x97, 0xf2, 0xea, 0x83, + 0x97, 0xfa, 0xe0, 0x51, 0x96, 0x78, 0x4f, 0x44, 0xb8, 0xa8, 0x9d, 0x03, + 0x1c, 0x6e, 0xb7, 0xc6, 0xd7, 0xc5, 0x3e, 0x32, 0x65, 0xa7, 0x06, 0xab, + 0x86, 0xfb, 0xd2, 0x9b, 0xd7, 0x86, 0xa8, 0xfe, 0x46, 0x41, 0x2e, 0xc2, + 0x4e, 0xed, 0xa2, 0x9b, 0x79, 0x36, 0x37, 0x49, 0x90, 0xfc, 0xa6, 0x14, + 0x93, 0x17, 0x82, 0x62, 0x3f, 0x79, 0x6b, 0x86, 0xc2, 0xeb, 0x82, 0xfe, + 0x87, 0x49, 0xa5, 0x7e, 0x41, 0xe3, 0x59, 0x60, 0x15, 0x61, 0x4e, 0x3b, + 0x16, 0xcf, 0xdb, 0x49, 0x2c, 0x84, 0x92, 0x26, 0x40, 0x04, 0x78, 0xd3, + 0xd6, 0xa6, 0xed, 0x6e, 0x63, 0x49, 0xcb, 0xea, 0xfe, 0x43, 0x85, 0x21, + 0x1a, 0x28, 0x36, 0x0a, 0x3e, 0x2a, 0xad, 0xba, 0xfc, 0x8a, 0x37, 0x18, + 0xb4, 0x80, 0xbe, 0x6a, 0x36, 0x14, 0x03, 0xdd, 0xa3, 0x37, 0xbd, 0xc1, + 0x8a, 0xbb, 0x2d, 0xd4, 0x08, 0xd7, 0x4b, 0xc4, 0xe9, 0xb8, 0xb4, 0x65, + 0xdd, 0xf6, 0xe8, 0x17, 0x2c, 0x2c, 0x9b, 0x1e, 0x92, 0x0b, 0xcb, 0x22, + 0x7c, 0x1b, 0x74, 0x8d, 0x65, 0x11, 0x5f, 0xfe, 0xf5, 0x2a, 0xc2, 0xbe, + 0xea, 0xa2, 0xf1, 0x7b, 0xe8, 0xaf, 0x32, 0x5a, 0x0a, 0x5b, 0xd2, 0x5a, + 0x11, 0x22, 0x79, 0xfa, 0xae, 0x2d, 0xe8, 0xc6, 0x17, 0xba, 0x17, 0x81, + 0x6a, 0x63, 0xb5, 0x26, 0xd7, 0x8d, 0xd0, 0x66, 0x0c, 0x4a, 0x0c, 0x22, + 0x1b, 0x20, 0x9f, 0x3d, 0x0b, 0x1b, 0x59, 0x53, 0x89, 0x9b, 0x5e, 0xbd, + 0x3d, 0xd1, 0xdd, 0xff, 0xca, 0xb2, 0xb7, 0x12, 0x8d, 0x03, 0xaa, 0xc3, + 0x1d, 0x56, 0x76, 0x14, 0xf8, 0xee, 0xb3, 0xeb, 0x80, 0x38, 0xc1, 0xc1, + 0x1a, 0xef, 0x4a, 0xd5, 0x16, 0x1f, 0x5e, 0x21, 0x5d, 0x46, 0x01, 0xb3, + 0xa4, 0xf7, 0x99, 0x94, 0x05, 0xc6, 0xc8, 0x06, 0xd8, 0x1c, 0xac, 0x47, + 0x13, 0x54, 0x13, 0x1b, 0x1f, 0xb6, 0x23, 0x9c, 0x73, 0x2b, 0x57, 0x32, + 0x94, 0x92, 0xf1, 0x71, 0x44, 0x40, 0x02, 0xc3, 0x21, 0x4a, 0x2f, 0x36, + 0x5e, 0x8a, 0xd0, 0x4b, 0x02, 0xc7, 0x6e, 0xcf, 0xed, 0xa2, 0xdb, 0xce, + 0x0a, 0x0f, 0x66, 0x4f, 0xb2, 0x3d, 0xb6, 0xcc, 0x75, 0x45, 0x80, 0x0a, + 0x49, 0x4a, 0xe7, 0xe7, 0x24, 0x62, 0x65, 0xc7, 0x02, 0x22, 0x13, 0xbe, + 0x6c, 0xa9, 0x9a, 0x8b, 0xa9, 0x1b, 0x2b, 0x3a, 0xde, 0x5e, 0x37, 0xbd, + 0x7f, 0x85, 0xd1, 0x32, 0x1d, 0xbf, 0x03, 0x8a, 0x3b, 0xe5, 0xb3, 0xfd, + 0x01, 0xca, 0xde, 0x0d, 0x7a, 0x5b, 0x01, 0x05, 0x1d, 0x3c, 0x23, 0x00, + 0x60, 0xb7, 0x50, 0xfd, 0x0d, 0xd7, 0x63, 0x92, 0xd6, 0xb0, 0x48, 0x3a, + 0x2d, 0xa3, 0xf8, 0xf6, 0x44, 0xe1, 0xda, 0x3b, 0xf4, 0x39, 0x47, 0xc4, + 0x4d, 0x8f, 0x54, 0x78, 0xec, 0x27, 0x7b, 0xc6, 0xe4, 0x81, 0x3a, 0x3f, + 0xa5, 0x61, 0x9d, 0xcb, 0x71, 0x0b, 0x0d, 0x55, 0xea, 0x5b, 0xeb, 0x58, + 0xa5, 0x49, 0xb5, 0x44, 0x1b, 0xb0, 0x0d, 0x1f, 0x58, 0xfb, 0x7a, 0xd4, + 0x09, 0x1e, 0x9a, 0x7e, 0x21, 0xba, 0xb3, 0x36, 0xa6, 0x04, 0x74, 0xe1, + 0xd0, 0xca, 0x02, 0x11, 0x84, 0x93, 0x8f, 0x86, 0x3d, 0x79, 0xbf, 0xa8, + 0xec, 0x0a, 0x23, 0x5e, 0xde, 0xc4, 0xc6, 0xda, 0x45, 0xbd, 0x95, 0x74, + 0x7b, 0xbf, 0xc1, 0x80, 0x48, 0x3f, 0x10, 0xb6, 0xb9, 0x5c, 0x31, 0x52, + 0x06, 0x5a, 0xac, 0xec, 0x94, 0x21, 0x80, 0x51, 0xba, 0x64, 0xed, 0x9d, + 0x27, 0x72, 0x8d, 0x17, 0x43, 0x5f, 0xf1, 0x60, 0xfa, 0xb5, 0x65, 0xd4, + 0xb9, 0xf8, 0xfc, 0x48, 0x7b, 0xe3, 0xfe, 0xae, 0xe4, 0x71, 0x4a, 0x3d, + 0x8c, 0xf5, 0x72, 0x8b, 0xbf, 0x60, 0xd8, 0x6a, 0x8f, 0x51, 0x82, 0xae, + 0x98, 0xd0, 0x56, 0xf9, 0xa8, 0x3a, 0xad, 0x86, 0x26, 0xa8, 0x5a, 0xf8, + 0x63, 0x87, 0x2c, 0x74, 0xbf, 0xf9, 0x7d, 0x00, 0xa0, 0x2f, 0x17, 0x23, + 0xb7, 0x62, 0x94, 0x19, 0x47, 0x57, 0xf9, 0xa8, 0xe7, 0x4b, 0xe9, 0x2b, + 0xe8, 0xb4, 0x03, 0xbf, 0x23, 0x75, 0xfe, 0xc3, 0x94, 0xc0, 0xa9, 0x5b, + 0x07, 0xb5, 0x75, 0x87, 0xcc, 0xa5, 0xb5, 0x9b, 0x35, 0x29, 0xe4, 0xb1, + 0xaa, 0x04, 0x57, 0xe9, 0xa3, 0xd0, 0xa3, 0xe4, 0x11, 0xe1, 0xaa, 0x3b, + 0x67, 0x09, 0x60, 0x83, 0x23, 0x72, 0xa6, 0x7b, 0x73, 0x22, 0x5b, 0x4a, + 0xe0, 0xf0, 0xa3, 0xeb, 0x9c, 0x91, 0xda, 0xba, 0x8b, 0xc1, 0x32, 0xa9, + 0x24, 0x13, 0x51, 0xe4, 0x67, 0x49, 0x4a, 0xd9, 0x3d, 0xae, 0x80, 0xfd, + 0x0a, 0x0d, 0x56, 0x98, 0x66, 0xa2, 0x6d, 0x92, 0x54, 0x7f, 0x82, 0xe5, + 0x17, 0x39, 0xd3, 0xaa, 0xc4, 0x4e, 0x6f, 0xe1, 0x2e, 0xfe, 0x03, 0x44, + 0x8a, 0xdd, 0xeb, 0xc0, 0x74, 0x79, 0x63, 0x33, 0x2b, 0x4b, 0xb5, 0x62, + 0xdd, 0x47, 0xba, 0x6e, 0xfc, 0x91, 0x08, 0xa9, 0x17, 0x8c, 0x47, 0x61, + 0xd9, 0x32, 0xe9, 0xa0, 0xb3, 0xa2, 0x82, 0xc9, 0xa6, 0x32, 0xa1, 0xca, + 0x7c, 0x41, 0xa6, 0x5a, 0xe2, 0x46, 0xb6, 0x45, 0x53, 0x72, 0x55, 0x9e, + 0xdf, 0xac, 0x96, 0x68, 0xe5, 0xdc, 0x4e, 0x2d, 0xa8, 0x1e, 0x7a, 0x8e, + 0xff, 0x54, 0xe4, 0x0a, 0x33, 0x5d, 0x97, 0xdf, 0x4e, 0x36, 0x96, 0xba, + 0x52, 0xd9, 0xa9, 0xec, 0x52, 0xe5, 0x1d, 0x94, 0xfe, 0x1c, 0x46, 0x54, + 0xa6, 0x8e, 0x85, 0x47, 0xba, 0xeb, 0x4b, 0x8d, 0x57, 0xe4, 0x34, 0x24, + 0x9e, 0x80, 0xb5, 0xc9, 0xa9, 0x94, 0x1d, 0xe4, 0x18, 0xb6, 0x07, 0x1e, + 0xfa, 0xe0, 0x1c, 0x88, 0x06, 0x84, 0xaa, 0xcb, 0x5e, 0xfa, 0x15, 0x5a, + 0xdd, 0x10, 0x43, 0x81, 0xf2, 0x50, 0x3e, 0x93, 0x26, 0x77, 0x1c, 0x77, + 0xe9, 0x0c, 0xfc, 0x5f, 0xdd, 0x67, 0x31, 0x02, 0xc6, 0xdd, 0xf4, 0x30, + 0x76, 0x51, 0xce, 0x56, 0xba, 0x7f, 0x44, 0xbd, 0x42, 0x9f, 0x10, 0x8c, + 0x56, 0x49, 0x48, 0xa2, 0xcb, 0xc4, 0xdd, 0x29, 0xae, 0xf0, 0x33, 0x35, + 0x46, 0x69, 0x1d, 0xae, 0xde, 0xde, 0x98, 0x82, 0x79, 0xa6, 0x50, 0x28, + 0xb3, 0x5f, 0x10, 0x24, 0x63, 0xee, 0x9a, 0x22, 0xbe, 0xf8, 0x3a, 0xf4, + 0xab, 0x98, 0xfe, 0xdf, 0x30, 0x03, 0xe8, 0x45, 0x8c, 0xf4, 0x85, 0xc6, + 0x98, 0x7b, 0x35, 0xb8, 0x30, 0x9c, 0x15, 0xa6, 0x45, 0xbd, 0x39, 0x84, + 0xe7, 0x43, 0x4b, 0x05, 0xa4, 0x8f, 0x52, 0x8e, 0x4a, 0xe4, 0x87, 0xc1, + 0xdc, 0xdf, 0x25, 0x9c, 0x5c, 0x37, 0xd0, 0x66, 0x12, 0x41, 0x66, 0x8c, + 0x28, 0xd0, 0x3f, 0x5c, 0x7f, 0x15, 0x9b, 0xcf, 0xa0, 0xae, 0x29, 0x33, + 0xb0, 0xe4, 0xb7, 0x36, 0x2a, 0x45, 0x83, 0xff, 0x86, 0x75, 0xcf, 0xa7, + 0x4d, 0x5c, 0xa8, 0xcf, 0x3f, 0xf2, 0xc8, 0xde, 0xdd, 0xad, 0x42, 0x8f, + 0x0e, 0xd0, 0x11, 0x24, 0x42, 0x86, 0x51, 0x52, 0x76, 0x21, 0x68, 0xf1, + 0xa7, 0x8f, 0xdb, 0x5b, 0x78, 0xfa, 0x44, 0x5f, 0xee, 0x31, 0xda, 0x62, + 0x5f, 0xfe, 0x69, 0xae, 0x97, 0xc9, 0xb5, 0x04, 0x76, 0x79, 0x2e, 0xb9, + 0xd9, 0x1b, 0xdd, 0xb7, 0xc4, 0x12, 0x78, 0xb2, 0x4d, 0xab, 0xd2, 0x29, + 0x25, 0x8c, 0xd5, 0x52, 0x4a, 0xd7, 0x2e, 0x18, 0x9d, 0xa2, 0xee, 0x7b, + 0xa5, 0xe5, 0x35, 0x3c, 0xb5, 0x54, 0x1c, 0x7f, 0x87, 0x4b, 0xc0, 0xbb, + 0x1a, 0x85, 0x19, 0xc0, 0xa9, 0x2b, 0x4d, 0xed, 0x71, 0xc0, 0x15, 0xb3, + 0x49, 0x2c, 0x46, 0xfc, 0x37, 0x40, 0xc0, 0x60, 0xd0, 0x00, 0x96, 0xfa, + 0x7f, 0xbb, 0x30, 0x94, 0x6b, 0x81, 0x61, 0xc5, 0x13, 0x93, 0x95, 0xaa, + 0xf3, 0x8d, 0x1d, 0xac, 0xdb, 0xbd, 0xc3, 0x90, 0xf3, 0xd2, 0x5f, 0x3a, + 0x08, 0xb1, 0xc9, 0x3a, 0xe8, 0x25, 0x4d, 0x20, 0x2a, 0xe9, 0x4c, 0xaf, + 0x9b, 0x54, 0x7b, 0xaf, 0x89, 0x44, 0x3a, 0x60, 0x23, 0xd3, 0x02, 0xb1, + 0xb3, 0x9a, 0x3a, 0xb0, 0xa0, 0xdb, 0x61, 0x0b, 0xac, 0x55, 0xa1, 0x36, + 0x55, 0x5b, 0xc4, 0xc5, 0xbd, 0x2a, 0x16, 0xe9, 0xe7, 0x86, 0x7f, 0xdb, + 0xee, 0x90, 0xfa, 0xfd, 0x08, 0x7f, 0x1a, 0x43, 0xe0, 0xb8, 0x21, 0xb3, + 0xe3, 0xdf, 0x27, 0x56, 0x61, 0xc4, 0xe8, 0xd5, 0x60, 0xe9, 0x6d, 0x49, + 0xd9, 0xa8, 0xf5, 0xd9, 0xfc, 0x66, 0x82, 0xe9, 0x80, 0x5b, 0x85, 0x16, + 0x55, 0x2b, 0xef, 0x50, 0x90, 0x6c, 0x5d, 0x81, 0x00, 0x00, 0x88, 0x9b, + 0xb4, 0x62, 0x49, 0x46, 0x2e, 0x5d, 0x71, 0x95, 0xff, 0x63, 0xfb, 0x93, + 0x23, 0xf8, 0x9f, 0xa2, 0x55, 0x56, 0xd4, 0xd5, 0xf7, 0xae, 0xaf, 0xd3, + 0xf6, 0x82, 0xc8, 0xdd, 0x89, 0x0f, 0x7e, 0x89, 0x0d, 0x0d, 0x7f, 0x4f, + 0x84, 0xa7, 0x16, 0xe8, 0xaf, 0xf2, 0x95, 0xd7, 0xc3, 0x66, 0xd6, 0x85, + 0x5b, 0xa1, 0xbb, 0xea, 0x31, 0x02, 0xac, 0xa2, 0x7b, 0x50, 0xf4, 0x78, + 0x29, 0x49, 0x59, 0xf6, 0x41, 0x42, 0x52, 0xa8, 0x19, 0xfb, 0x3d, 0xda, + 0xa9, 0x8d, 0xac, 0xe1, 0x25, 0xd4, 0x12, 0x1e, 0x2b, 0x48, 0x44, 0xb0, + 0xf6, 0x29, 0xd0, 0x55, 0x22, 0xb4, 0xe7, 0xbc, 0x22, 0x97, 0x1f, 0xe2, + 0xe1, 0x73, 0x16, 0x13, 0x7a, 0x00, 0x62, 0x14, 0xcb, 0x25, 0x9b, 0x21, + 0x98, 0x9d, 0xb8, 0xd8, 0xf4, 0x65, 0xf6, 0x8f, 0x39, 0xe4, 0x76, 0xf7, + 0x30, 0xaf, 0xbc, 0x3a, 0xfe, 0x0e, 0xf1, 0x81, 0xa7, 0xff, 0x4d, 0xa7, + 0xff, 0xbf, 0x15, 0x60, 0x0b, 0xcd, 0x69, 0xd5, 0x77, 0xba, 0xcb, 0x7b, + 0x5a, 0xfb, 0x34, 0xc7, 0x5d, 0x13, 0x33, 0xd7, 0x86, 0x02, 0x43, 0x57, + 0x52, 0x2c, 0x74, 0x61, 0x21, 0xa3, 0x34, 0xf5, 0x89, 0x51, 0x44, 0x89, + 0xfc, 0xbb, 0x57, 0x5c, 0x6d, 0xb0, 0x2e, 0x8c, 0xff, 0x73, 0xe5, 0x09, + 0x13, 0x3b, 0x45, 0x5b, 0x27, 0x88, 0xee, 0x9b, 0xab, 0x57, 0x7c, 0x9b, + 0xb9, 0x78, 0x73, 0xd2, 0x2d, 0x98, 0x6f, 0xd2, 0x78, 0xb3, 0xeb, 0xaa, + 0x18, 0x44, 0x87, 0x6d, 0x51, 0x1e, 0x9b, 0x73, 0xaa, 0x91, 0x1a, 0x4f, + 0x69, 0x78, 0xef, 0x3f, 0xb1, 0x2d, 0x39, 0x3e, 0xda, 0x31, 0xfc, 0x99, + 0xf6, 0xa2, 0x8c, 0xe5, 0xfd, 0x97, 0x95, 0x77, 0x37, 0xef, 0xf5, 0xd1, + 0xc8, 0x74, 0x2c, 0x9a, 0x1f, 0x23, 0x8f, 0x72, 0x96, 0x3d, 0xb5, 0xad, + 0x28, 0xa0, 0x6c, 0x66, 0xe8, 0xee, 0xaa, 0x9d, 0xc2, 0x8a, 0x56, 0x54, + 0x89, 0x74, 0x56, 0xdc, 0x57, 0x49, 0xc3, 0x8e, 0xb9, 0x3a, 0x91, 0x34, + 0xc4, 0x5e, 0x0b, 0x13, 0x63, 0x5e, 0xeb, 0xc5, 0xef, 0xc7, 0xe9, 0x7f, + 0x27, 0xe8, 0xe7, 0xe5, 0x0d, 0x83, 0x95, 0x5f, 0x8a, 0xf2, 0xb2, 0x22, + 0x03, 0x8d, 0x71, 0x4f, 0x62, 0xb7, 0xf1, 0x87, 0xf5, 0x3f, 0xc4, 0x23, + 0x21, 0x40, 0x35, 0xcf, 0x79, 0x7a, 0x5b, 0x9d, 0x76, 0xb2, 0xdc, 0x6a, + 0xb5, 0x1d, 0x8b, 0xb6, 0x9a, 0x19, 0xe4, 0x87, 0xf5, 0xce, 0x38, 0xf3, + 0x70, 0xbf, 0x9e, 0x86, 0xa6, 0x07, 0x53, 0xdd, 0x5d, 0xc7, 0x72, 0x84, + 0x47, 0x38, 0xd0, 0xe2, 0xeb, 0x64, 0x4c, 0x3a, 0x1e, 0xf6, 0x56, 0x79, + 0x75, 0x75, 0x14, 0x5d, 0xe4, 0x1d, 0x9d, 0xbb, 0xe1, 0x35, 0x03, 0x5e, + 0x4f, 0x8f, 0xea, 0x95, 0xde, 0x19, 0x57, 0x98, 0xe9, 0x2c, 0x42, 0x22, + 0xcb, 0x0f, 0x15, 0x7a, 0x6b, 0x53, 0xc3, 0xec, 0xdc, 0xa0, 0x66, 0x26, + 0x91, 0x04, 0x83, 0x75, 0x09, 0x0c, 0x22, 0x05, 0xec, 0x3a, 0x2d, 0x39, + 0xea, 0x19, 0xf2, 0x1d, 0xdb, 0xba, 0x5c, 0x46, 0x47, 0xd4, 0x94, 0x6d, + 0x51, 0xdb, 0x68, 0xde, 0x0c, 0xa0, 0x36, 0x8f, 0xbc, 0xfd, 0x9b, 0x8f, + 0xfe, 0x04, 0x1f, 0xde, 0x1e, 0x77, 0xb5, 0x80, 0xb9, 0x9c, 0x1b, 0x24, + 0x61, 0xfc, 0x2b, 0xc0, 0x42, 0x2b, 0xc5, 0x90, 0x58, 0xa2, 0xb1, 0x38, + 0x58, 0xf2, 0x8b, 0x65, 0xbf, 0xe8, 0xe6, 0x79, 0xcf, 0x65, 0x35, 0xa5, + 0xe1, 0xb7, 0x8b, 0x95, 0x54, 0xd7, 0x1d, 0xf0, 0x91, 0x18, 0xc0, 0x5d, + 0x2c, 0xb5, 0xca, 0x1a, 0x7f, 0x8d, 0xfb, 0x9e, 0x57, 0x1c, 0x5c, 0xf0, + 0x94, 0x36, 0x51, 0x95, 0x27, 0x62, 0xca, 0x92, 0x96, 0xe5, 0x00, 0x2e, + 0xa4, 0x41, 0x97, 0xbf, 0x28, 0x3c, 0x6d, 0xc1, 0xb7, 0xe9, 0x1c, 0x2e, + 0x3e, 0xe0, 0x5e, 0x89, 0x0c, 0x78, 0x88, 0x80, 0xb8, 0x30, 0xd2, 0x22, + 0xf9, 0x71, 0xb4, 0xc8, 0xee, 0xe6, 0x80, 0x04, 0x04, 0x9a, 0xfb, 0x0c, + 0x36, 0xcb, 0xea, 0x66, 0xf9, 0x52, 0x8c, 0x66, 0xbf, 0x4c, 0x0f, 0xf4, + 0xf8, 0x1e, 0x7e, 0x39, 0x80, 0xe8, 0x82, 0x4b, 0x0e, 0x66, 0x1d, 0x51, + 0x16, 0xa9, 0x8d, 0xd6, 0xea, 0x33, 0xb0, 0x2c, 0x36, 0x25, 0xf5, 0x01, + 0x30, 0x7e, 0x03, 0x7f, 0xae, 0x8e, 0xd6, 0x25, 0x62, 0x6d, 0x99, 0x8c, + 0x1f, 0xc1, 0x22, 0xf0, 0x94, 0x80, 0xbf, 0x82, 0x51, 0xea, 0xc2, 0x5a, + 0x3c, 0x85, 0x2a, 0x5d, 0xbe, 0xae, 0xe1, 0xe3, 0x07, 0x92, 0xd2, 0x40, + 0x47, 0xe8, 0x0f, 0x1a, 0xa5, 0x73, 0x64, 0x26, 0xc4, 0xac, 0xca, 0xc2, + 0x83, 0x5a, 0x56, 0xbc, 0x81, 0x21, 0xcb, 0x72, 0xf3, 0xe7, 0x82, 0x1e, + 0xc8, 0x54, 0x18, 0x42, 0xfe, 0xd6, 0xfc, 0x96, 0x0e, 0x03, 0x29, 0x98, + 0x4f, 0xd1, 0xd2, 0x98, 0x7c, 0x9e, 0x4e, 0x1a, 0x0f, 0xd6, 0x4e, 0xa4, + 0x52, 0x1b, 0xd1, 0xd8, 0x36, 0xf7, 0x47, 0x5f, 0xce, 0xcb, 0x87, 0x36, + 0xc8, 0x9b, 0x44, 0xc6, 0x7a, 0xf3, 0x45, 0x28, 0xae, 0x96, 0x5a, 0x85, + 0x62, 0x8b, 0x10, 0xc2, 0x7b, 0x39, 0x51, 0xdf, 0xf4, 0x21, 0xc2, 0x6b, + 0x6f, 0x93, 0x27, 0xed, 0xf6, 0xea, 0xff, 0x2a, 0x21, 0x70, 0x84, 0x4e, + 0x21, 0xac, 0xbc, 0x06, 0x41, 0xd3, 0x59, 0xa0, 0xa1, 0x50, 0xa6, 0x87, + 0xa2, 0x48, 0xad, 0x94, 0x44, 0x8d, 0x2f, 0xa8, 0xc6, 0x10, 0xb5, 0xeb, + 0x66, 0x82, 0x94, 0x5f, 0xae, 0x6a, 0x56, 0xb4, 0x8d, 0xf4, 0x62, 0x80, + 0xe4, 0x42, 0xc4, 0xbc, 0xe7, 0xee, 0xa6, 0x96, 0x3b, 0xfd, 0xc0, 0x92, + 0x7d, 0xcd, 0xe7, 0x0c, 0x99, 0x9a, 0xb6, 0x83, 0xcf, 0x45, 0xe5, 0x74, + 0xb3, 0xbc, 0xc0, 0x40, 0xad, 0x4d, 0xfc, 0xa7, 0x92, 0x35, 0x13, 0x81, + 0x5c, 0x9c, 0x21, 0x00, 0xa4, 0x37, 0x07, 0x1d, 0x19, 0xfc, 0x88, 0x4d, + 0x71, 0x43, 0x7d, 0x94, 0xf7, 0x32, 0xb8, 0x4b, 0x8a, 0x54, 0xd6, 0xe4, + 0x37, 0x4f, 0x27, 0x1f, 0xfd, 0x45, 0x83, 0xb9, 0x14, 0x5a, 0xf7, 0x36, + 0xdc, 0x98, 0xad, 0x99, 0xb9, 0x38, 0x69, 0xac, 0x18, 0x7e, 0x47, 0xd0, + 0x63, 0x27, 0xba, 0xe7, 0xd5, 0x1d, 0x7b, 0x6e, 0xde, 0x28, 0x7b, 0xf1, + 0x84, 0x4d, 0x2d, 0x7c, 0x16, 0x38, 0x4b, 0x16, 0xa9, 0x10, 0x83, 0xfb, + 0xe0, 0xe0, 0x6f, 0xdd, 0x03, 0x0a, 0xb8, 0x81, 0xf5, 0x8c, 0x98, 0xc3, + 0xf4, 0xc8, 0x31, 0x3a, 0xed, 0x14, 0x83, 0x89, 0xc3, 0x0e, 0xf7, 0xba, + 0x84, 0xb0, 0x49, 0xdf, 0xc6, 0x6b, 0xed, 0xbe, 0xd4, 0xa3, 0x83, 0x3a, + 0xe6, 0x6d, 0xa3, 0x83, 0x17, 0x43, 0x5e, 0x3a, 0x83, 0xda, 0x81, 0xe3, + 0x26, 0x95, 0x6b, 0xe5, 0x30, 0x28, 0x6d, 0xec, 0xd7, 0xd7, 0x35, 0xfa, + 0x1a, 0xad, 0x86, 0x04, 0x05, 0x2c, 0x76, 0x3f, 0xb2, 0x83, 0x92, 0x4e, + 0xef, 0x05, 0xde, 0x13, 0x26, 0x68, 0x80, 0x57, 0xee, 0x92, 0x80, 0xa3, + 0x99, 0xb4, 0xac, 0x98, 0x31, 0xd4, 0xf3, 0xe2, 0x60, 0xd9, 0xb9, 0x8d, + 0x20, 0xf7, 0x97, 0x70, 0x10, 0xd6, 0xba, 0x86, 0xb8, 0x9c, 0xb8, 0xf8, + 0x49, 0x71, 0x28, 0x9d, 0x05, 0x38, 0x1f, 0x63, 0xba, 0xf7, 0x15, 0x60, + 0x96, 0x61, 0x84, 0x68, 0xeb, 0x5d, 0x28, 0x51, 0xe3, 0x51, 0xdd, 0x69, + 0x8a, 0xdd, 0xba, 0xec, 0xbd, 0xd3, 0xa1, 0x42, 0x83, 0x59, 0x77, 0x11, + 0x12, 0x86, 0x5b, 0x8d, 0x30, 0xcf, 0xdf, 0x6f, 0xea, 0x9d, 0x31, 0xa2, + 0x65, 0xa5, 0x61, 0xc0, 0xde, 0x52, 0x6c, 0x72, 0x71, 0x0b, 0x4c, 0x7a, + 0x4c, 0x9f, 0x75, 0x74, 0x38, 0xc8, 0xdd, 0x12, 0xba, 0x21, 0x57, 0x1b, + 0x45, 0xb3, 0x02, 0x1d, 0x67, 0x22, 0x66, 0x53, 0x18, 0x48, 0xed, 0x60, + 0x40, 0x55, 0xd1, 0x25, 0x3b, 0xbc, 0x08, 0x7b, 0x19, 0x8a, 0x30, 0x5b, + 0x02, 0x4f, 0x65, 0x42, 0xff, 0xce, 0x87, 0xe8, 0x97, 0x2b, 0xbb, 0xfe, + 0x52, 0x52, 0x72, 0xe8, 0xb5, 0x77, 0xb7, 0x8e, 0x94, 0x34, 0xbc, 0x46, + 0xf1, 0xe1, 0x94, 0x98, 0x19, 0xbe, 0x7c, 0x3f, 0xf6, 0x0e, 0xe4, 0xbb, + 0x88, 0x32, 0x07, 0x83, 0x64, 0xad, 0xd7, 0xd1, 0xe8, 0x35, 0x8d, 0x5d, + 0x70, 0x16, 0xc8, 0x11, 0x94, 0x39, 0xc9, 0xac, 0xd6, 0xed, 0x6b, 0xdf, + 0xc8, 0xf3, 0x1d, 0x5e, 0x37, 0xd8, 0xb5, 0x86, 0x9b, 0xc2, 0xdc, 0x3c, + 0x5c, 0x04, 0x52, 0x5c, 0x11, 0x88, 0x0a, 0x2b, 0x78, 0x48, 0x9e, 0x5e, + 0x98, 0x57, 0x5a, 0xd1, 0x77, 0x1c, 0x7d, 0x5f, 0x60, 0xbb, 0x61, 0x7e, + 0x7e, 0x2a, 0xaf, 0x44, 0x14, 0x88, 0xfc, 0xa5, 0x31, 0xb7, 0xd4, 0x44, + 0x48, 0xda, 0xb5, 0x71, 0xa8, 0xd8, 0x4f, 0x79, 0xcd, 0xe4, 0xbe, 0xb6, + 0x1a, 0x61, 0x74, 0x4b, 0xd8, 0xec, 0xd7, 0xbf, 0xad, 0x57, 0x00, 0x42, + 0x04, 0xe8, 0xb3, 0xec, 0x47, 0x1d, 0x2a, 0x0a, 0xde, 0x7c, 0x6e, 0x5e, + 0xf8, 0xaa, 0x44, 0x05, 0x10, 0xab, 0xe9, 0x4e, 0xd7, 0x44, 0x0b, 0x97, + 0x6f, 0x1a, 0xc1, 0x59, 0x2b, 0xe4, 0xe1, 0x8a, 0x13, 0x82, 0x65, 0xd8, + 0xae, 0x5f, 0x2b, 0xbc, 0xa6, 0x14, 0x39, 0xaf, 0x38, 0x41, 0x26, 0x74, + 0xdb, 0x55, 0x6b, 0xe2, 0x21, 0x80, 0x5d, 0x20, 0xc3, 0xf5, 0x82, 0xee, + 0xcc, 0x3c, 0xc9, 0xb4, 0xeb, 0x52, 0xe9, 0x13, 0x8a, 0xea, 0xc6, 0x19, + 0x70, 0x37, 0x1b, 0xb8, 0x2e, 0x86, 0xa2, 0xe9, 0x9d, 0xb6, 0xd5, 0xd6, + 0xf3, 0xa8, 0x31, 0xf3, 0x02, 0xaa, 0x10, 0x33, 0x3f, 0xba, 0xf8, 0xf9, + 0x46, 0x5b, 0xe1, 0xd7, 0x34, 0x9f, 0x94, 0xcb, 0xfb, 0xb1, 0x3d, 0x60, + 0x77, 0x85, 0x14, 0xd4, 0xcf, 0x55, 0x60, 0x5d, 0x47, 0x6c, 0x07, 0xb4, + 0xc7, 0x73, 0xbd, 0x49, 0xbd, 0xa5, 0x31, 0xa1, 0xfa, 0x34, 0x3a, 0x8b, + 0x77, 0x1b, 0xaa, 0xaf, 0xa5, 0x87, 0x12, 0x4e, 0x36, 0x06, 0x14, 0xe7, + 0xb3, 0xb8, 0x87, 0x6c, 0x4b, 0x50, 0xc9, 0x52, 0x1b, 0x19, 0x48, 0x69, + 0x5b, 0x7f, 0xd8, 0xc9, 0x14, 0xb8, 0x11, 0xa0, 0x51, 0x09, 0xbd, 0x42, + 0x5a, 0x50, 0x32, 0x57, 0x69, 0x39, 0x30, 0xdb, 0xbf, 0x8b, 0x93, 0x54, + 0x43, 0x80, 0x4e, 0xd0, 0xc6, 0xf2, 0x81, 0x15, 0x6d, 0xef, 0x5a, 0xb6, + 0x4d, 0x70, 0x93, 0x88, 0x8d, 0xce, 0x0d, 0xb8, 0xe9, 0xac, 0xa2, 0xcd, + 0xc7, 0x18, 0xa5, 0x95, 0xb7, 0xf6, 0x0c, 0x6f, 0xe1, 0x10, 0x7b, 0x22, + 0xf8, 0x81, 0x18, 0x42, 0x6a, 0x09, 0x75, 0x20, 0xb4, 0x2f, 0x67, 0x7a, + 0xda, 0x55, 0x28, 0xc3, 0x81, 0xf7, 0xc1, 0xf0, 0xe6, 0x1b, 0x29, 0x9c, + 0x72, 0x87, 0xe5, 0x4c, 0xa9, 0x5b, 0x5b, 0x62, 0xb5, 0xb7, 0x1e, 0x82, + 0xc3, 0x7b, 0xaf, 0xe9, 0x6f, 0x37, 0x31, 0x9f, 0x79, 0xe7, 0x4f, 0x06, + 0x1e, 0xff, 0xff, 0x80, 0x8e, 0x00, 0x00 +}; + int do_spl_test_load(struct unit_test_state *uts, const char *test_name, enum spl_test_image type, struct spl_image_loader *loader, int (*write_image)(struct unit_test_state *, void *, size_t)) @@ -373,12 +617,13 @@ int do_spl_test_load(struct unit_test_state *uts, const char *test_name, size_t img_size, img_data, plain_size = SPL_TEST_DATA_SIZE; struct spl_image_info info_write = { .name = test_name, - .size = plain_size, + .size = type == LEGACY_LZMA ? sizeof(lzma_compressed) : + plain_size, }, info_read = { }; struct spl_boot_device bootdev = { .boot_device = loader->boot_device, }; - char *plain; + char *data, *plain; void *img;
img_size = create_image(NULL, type, &info_write, &img_data); @@ -386,8 +631,16 @@ int do_spl_test_load(struct unit_test_state *uts, const char *test_name, img = calloc(img_size, 1); ut_assertnonnull(img);
- plain = img + img_data; - generate_data(plain, plain_size, test_name); + data = img + img_data; + if (type == LEGACY_LZMA) { + plain = malloc(plain_size); + ut_assertnonnull(plain); + generate_data(plain, plain_size, "lzma"); + memcpy(data, lzma_compressed, sizeof(lzma_compressed)); + } else { + plain = data; + generate_data(plain, plain_size, test_name); + } ut_asserteq(img_size, create_image(img, type, &info_write, NULL));
if (write_image(uts, img, img_size)) @@ -396,8 +649,12 @@ int do_spl_test_load(struct unit_test_state *uts, const char *test_name, ut_assertok(loader->load_image(&info_read, &bootdev)); if (check_image_info(uts, &info_write, &info_read)) return CMD_RET_FAILURE; + if (type == LEGACY_LZMA) + ut_asserteq(plain_size, info_read.size); ut_asserteq_mem(plain, phys_to_virt(info_write.load_addr), plain_size);
+ if (type == LEGACY_LZMA) + free(plain); free(img); return 0; } diff --git a/test/image/spl_load_nor.c b/test/image/spl_load_nor.c new file mode 100644 index 00000000000..a62bb60d253 --- /dev/null +++ b/test/image/spl_load_nor.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson seanga2@gmail.com + */ + +#include <common.h> +#include <dm.h> +#include <spl.h> +#include <asm/io.h> +#include <test/spl.h> +#include <test/ut.h> + +static void *spl_test_nor_base; + +unsigned long spl_nor_get_uboot_base(void) +{ + return virt_to_phys(spl_test_nor_base); +} + +static int spl_test_nor_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + spl_test_nor_base = img; + return 0; +} + +static int spl_test_nor(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + return do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_NOR, + spl_nor_load_image), + spl_test_nor_write_image); +} +SPL_IMG_TEST(spl_test_nor, LEGACY, 0); +SPL_IMG_TEST(spl_test_nor, LEGACY_LZMA, 0); +SPL_IMG_TEST(spl_test_nor, IMX8, 0); +SPL_IMG_TEST(spl_test_nor, FIT_INTERNAL, 0); +SPL_IMG_TEST(spl_test_nor, FIT_EXTERNAL, 0);

Add test for the SPI load method. This one is pretty straightforward. We can't enable FIT_EXTERNAL with LOAD_FIT_FULL because spl_spi_load_image doesn't know the total image size and has to guess from fdt_totalsize. This doesn't include external data, so loading it will fail.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
arch/sandbox/include/asm/spl.h | 1 + configs/sandbox_noinst_defconfig | 6 +++++ include/spl.h | 10 ++++++++ test/image/Kconfig | 8 +++++++ test/image/Makefile | 1 + test/image/spl_load.c | 1 + test/image/spl_load_spi.c | 41 ++++++++++++++++++++++++++++++++ test/py/tests/test_spl.py | 10 ++++++++ 8 files changed, 78 insertions(+) create mode 100644 test/image/spl_load_spi.c
diff --git a/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h index cf16af5278a..f349ea19971 100644 --- a/arch/sandbox/include/asm/spl.h +++ b/arch/sandbox/include/asm/spl.h @@ -14,6 +14,7 @@ enum { BOOT_DEVICE_VBE, BOOT_DEVICE_CPGMAC, BOOT_DEVICE_NOR, + BOOT_DEVICE_SPI, };
/** diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index 085cc30c1e2..db05e630832 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -4,6 +4,7 @@ CONFIG_SPL_LIBCOMMON_SUPPORT=y CONFIG_SPL_LIBGENERIC_SUPPORT=y CONFIG_NR_DRAM_BANKS=1 CONFIG_ENV_SIZE=0x2000 +CONFIG_SPL_DM_SPI=y CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_DM_RESET=y CONFIG_SPL_MMC=y @@ -12,6 +13,8 @@ CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y CONFIG_SPL_FS_FAT=y +CONFIG_SPL_SPI_FLASH_SUPPORT=y +CONFIG_SPL_SPI=y CONFIG_SYS_LOAD_ADDR=0x1000000 CONFIG_PCI=y CONFIG_SANDBOX_SPL=y @@ -48,9 +51,12 @@ CONFIG_SPL_ETH=y CONFIG_SPL_FS_EXT4=y CONFIG_SPL_I2C=y CONFIG_SPL_MMC_WRITE=y +CONFIG_SPL_DM_SPI_FLASH=y CONFIG_SPL_NET=y CONFIG_SPL_NOR_SUPPORT=y CONFIG_SPL_RTC=y +# CONFIG_SPL_SPI_FLASH_TINY is not set +CONFIG_SPL_SPI_LOAD=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y CONFIG_CMD_BOOTZ=y diff --git a/include/spl.h b/include/spl.h index 708b15a0c7f..2c32e37e6b0 100644 --- a/include/spl.h +++ b/include/spl.h @@ -416,6 +416,16 @@ int spl_load_imx_container(struct spl_image_info *spl_image, void preloader_console_init(void); u32 spl_boot_device(void);
+struct spi_flash; + +/** + * spl_spi_get_uboot_offs() - Lookup function for the SPI boot offset + * @flash: The spi flash to boot from + * + * Return: The offset of U-Boot within the SPI flash + */ +unsigned int spl_spi_get_uboot_offs(struct spi_flash *flash); + /** * spl_spi_boot_bus() - Lookup function for the SPI boot bus source. * diff --git a/test/image/Kconfig b/test/image/Kconfig index 99c50787816..8f9e6ae036b 100644 --- a/test/image/Kconfig +++ b/test/image/Kconfig @@ -32,6 +32,14 @@ config SPL_UT_LOAD_NET help Test loading images over TFTP using the NET image load method.
+config SPL_UT_LOAD_SPI + bool "Test loading from SPI Flash" + depends on SANDBOX && SPL_OF_REAL + depends on SPL_SPI_LOAD + default y + help + Test the SPI flash image load metod. + config SPL_UT_LOAD_OS bool "Test loading from the host OS" depends on SANDBOX && SPL_LOAD_FIT diff --git a/test/image/Makefile b/test/image/Makefile index a82aa40449d..b30210106a4 100644 --- a/test/image/Makefile +++ b/test/image/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_SPL_UT_LOAD_FS) += spl_load_fs.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_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 07a986258d9..ab4c14d6491 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -9,6 +9,7 @@ #include <mapmem.h> #include <memalign.h> #include <rand.h> +#include <spi_flash.h> #include <spl.h> #include <test/spl.h> #include <test/ut.h> diff --git a/test/image/spl_load_spi.c b/test/image/spl_load_spi.c new file mode 100644 index 00000000000..8f9b6e0139b --- /dev/null +++ b/test/image/spl_load_spi.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson seanga2@gmail.com + */ + +#include <common.h> +#include <dm.h> +#include <spi_flash.h> +#include <spl.h> +#include <test/spl.h> +#include <test/ut.h> + +static int spl_test_spi_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + struct spi_flash *flash; + + flash = spi_flash_probe(spl_spi_boot_bus(), spl_spi_boot_cs(), + CONFIG_SF_DEFAULT_SPEED, + CONFIG_SF_DEFAULT_MODE); + ut_assertnonnull(flash); + ut_assertok(spi_flash_write(flash, spl_spi_get_uboot_offs(flash), + img_size, img)); + + return 0; +} + +static int spl_test_spi(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + return do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(1, BOOT_DEVICE_SPI, + spl_spi_load_image), + spl_test_spi_write_image); +} +SPL_IMG_TEST(spl_test_spi, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_spi, IMX8, DM_FLAGS); +SPL_IMG_TEST(spl_test_spi, FIT_INTERNAL, DM_FLAGS); +#if !IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) +SPL_IMG_TEST(spl_test_spi, FIT_EXTERNAL, DM_FLAGS); +#endif diff --git a/test/py/tests/test_spl.py b/test/py/tests/test_spl.py index bd273dad893..42e4c4342b2 100644 --- a/test/py/tests/test_spl.py +++ b/test/py/tests/test_spl.py @@ -5,6 +5,16 @@ import os.path import pytest
+@pytest.mark.buildconfigspec('spl_unit_test') +def test_ut_spl_init(u_boot_console): + """Initialize data for ut spl tests.""" + + fn = u_boot_console.config.source_dir + '/spi.bin' + if not os.path.exists(fn): + data = b'\x00' * (2 * 1024 * 1024) + with open(fn, 'wb') as fh: + fh.write(data) + def test_spl(u_boot_console, ut_spl_subtest): """Execute a "ut" subtest.

On Sat, Oct 14, 2023 at 04:47:36PM -0400, Sean Anderson wrote:
This series adds some tests for various SPL load methods, with the intent of helping debug v6 of [1]. With that in mind, notable omissions include NAND and ROMAPI, which both lack sandbox implementations, and OS_BOOT, which I have deferred due to its complexity. Semihosting is also omitted, but I think we can test that with qemu.
In order to test all of these methods, we must first generate suitable images, possibly on filesystems. While other tests have historically generated these images using external tools (e.g. mkimage, mkfs, etc.), I have chosen to generate them on the fly. This is for a few reasons:
- By removing external dependencies on pytest to create certain files, the tests become self-contained. This makes them easier to iterate on and debug.
- By generating tests at runtime, we can dynamically vary the content. This helps detect test failures, as even if tests are loaded to the same location, the expected content will be different.
- We are not testing the image parsers themselves (e.g. spl_load_simple_fit or fs_read) but rather the load methods (e.g. spl_mmc_load_image). It is unnecessary to exercise full functionality or generate 100% correct images.
- By reducing functionality to only what is necessary, the complexity of various formats can often be greatly reduced.
This series depends on [2-3], which are small fixes identified through this patch set. The organization of patches in this series is as follows:
- General fixes for bugs which are unlikely to be triggered outside of this series
- Changes to IMX8 container images to facilitate testing
- General prep. work, particularly regarding linker issues
- The tests themselves
Passing CI at [4].
[1] https://lore.kernel.org/all/20230731224304.111081-1-sean.anderson@seco.com/ [2] https://lore.kernel.org/all/20230930204246.515254-1-seanga2@gmail.com/ [3] https://lore.kernel.org/all/20231008014748.1987840-1-seanga2@gmail.com/ [4] https://source.denx.de/u-boot/custodians/u-boot-clk/-/pipelines/18128
For the series, applied to u-boot/master, thanks!
participants (4)
-
Heinrich Schuchardt
-
Sean Anderson
-
Simon Glass
-
Tom Rini