diff options
| author | Tom Rini <trini@konsulko.com> | 2023-10-18 08:28:00 -0400 |
|---|---|---|
| committer | Tom Rini <trini@konsulko.com> | 2023-10-18 08:28:00 -0400 |
| commit | 9a0cf3993f71043ba08c315572c54622de42d447 (patch) | |
| tree | 8e63d4db50b7aef9db5b2106e5e6ec3780410ebc | |
| parent | e65b5d35c9116485366bb08138043d51220551da (diff) | |
| parent | 60d76e332d8031eab6937778b3ed7b6558c2b3f1 (diff) | |
Merge branch '2023-10-17-spl-test-some-load-methods'
To quote the author:
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
70 files changed, 1994 insertions, 161 deletions
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/MAINTAINERS b/MAINTAINERS index 16b17fdd96d..cde778bc4d3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -300,7 +300,9 @@ 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 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/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 6904cf38802..a3b44c93e3d 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/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 785b0d6ec3c..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> @@ -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..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> @@ -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..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" @@ -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/spl_imx_romapi.c b/arch/arm/mach-imx/spl_imx_romapi.c index c4a4185eed1..93d48e56aca 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)); @@ -202,7 +203,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; } diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 7590f1b80a6..16b76627983 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -129,6 +129,10 @@ void spl_board_init(void) if (!CONFIG_IS_ENABLED(UNIT_TEST)) return; + /* 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/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; 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/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h index 2f8b5fcfcfe..f349ea19971 100644 --- a/arch/sandbox/include/asm/spl.h +++ b/arch/sandbox/include/asm/spl.h @@ -12,6 +12,9 @@ enum { BOOT_DEVICE_MMC2_2, BOOT_DEVICE_BOARD, BOOT_DEVICE_VBE, + BOOT_DEVICE_CPGMAC, + BOOT_DEVICE_NOR, + BOOT_DEVICE_SPI, }; /** diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 46323597942..6bc4066fad7 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 @@ -643,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/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/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 c6e2526ade1..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> @@ -20,6 +21,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; @@ -74,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) @@ -99,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 1409b926372..c026e1a1945 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> @@ -393,25 +394,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; @@ -876,7 +884,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); @@ -884,15 +892,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); } @@ -901,8 +909,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); @@ -913,9 +922,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/arch/arm/mach-imx/parse-container.c b/common/spl/spl_imx_container.c index e2a9e2b2732..127802f5cb7 100644 --- a/arch/arm/mach-imx/parse-container.c +++ b/common/spl/spl_imx_container.c @@ -3,12 +3,14 @@ * Copyright 2018-2021 NXP */ +#define LOG_CATEGORY LOGC_ARCH #include <common.h> #include <stdlib.h> #include <errno.h> +#include <imx_container.h> #include <log.h> +#include <mapmem.h> #include <spl.h> -#include <asm/mach-imx/image.h> #ifdef CONFIG_AHAB_BOOT #include <asm/mach-imx/ahab.h> #endif @@ -45,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].entry) != sectors) { + map_sysmem(images[image_index].dst, + images[image_index].size)) != sectors) { printf("%s wrong\n", __func__); return NULL; } @@ -84,14 +87,14 @@ static int read_auth_container(struct spl_image_info *spl_image, goto end; } - if (container->tag != 0x87 && container->version != 0x0) { - printf("Wrong container header"); + if (!valid_container_hdr(container)) { + log_err("Wrong container header\n"); ret = -ENOENT; goto end; } if (!container->num_images) { - printf("Wrong container, no image found"); + log_err("Wrong container, no image found\n"); ret = -ENOENT; goto end; } diff --git a/common/spl/spl_legacy.c b/common/spl/spl_legacy.c index 095443c63d8..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> @@ -19,7 +20,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) || @@ -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 0ab85d2168c..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> @@ -16,6 +17,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, @@ -45,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) @@ -108,7 +111,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; @@ -396,18 +400,24 @@ static int spl_mmc_get_mmc_devnum(struct mmc *mmc) #if !CONFIG_IS_ENABLED(BLK) block_dev = &mmc->block_dev; #else - block_dev = dev_get_uclass_plat(mmc->dev); + block_dev = mmc_get_blk_desc(mmc); #endif 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/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_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 79d4f1d7aa8..236b0718283 100644 --- a/common/spl/spl_nor.c +++ b/common/spl/spl_nor.c @@ -5,7 +5,9 @@ #include <common.h> #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, @@ -13,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; } @@ -26,7 +28,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 +43,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 +93,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 */ + header = map_sysmem(spl_nor_get_uboot_base(), sizeof(*header)); #ifdef CONFIG_SPL_LOAD_FIT - header = (const struct legacy_img_hdr *)spl_nor_get_uboot_base(); if (image_get_magic(header) == FDT_MAGIC) { debug("Found FIT format U-Boot\n"); load.bl_len = 1; @@ -102,7 +104,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, @@ -111,14 +114,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; diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index d69069a75bf..3ac4b1b5091 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -10,12 +10,15 @@ #include <common.h> #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) @@ -133,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; @@ -153,7 +159,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; @@ -170,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); 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/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index d39e54f98d2..db05e630832 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -4,13 +4,18 @@ 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 CONFIG_SPL_SERIAL=y CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_SYS_LOAD_ADDR=0x0 +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 CONFIG_DEBUG_UART=y @@ -32,9 +37,26 @@ 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 +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_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 @@ -91,10 +113,13 @@ 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" 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 @@ -112,6 +137,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 @@ -153,6 +179,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 @@ -214,6 +241,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 @@ -236,6 +264,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 4a67af2f088..56072b15ad2 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -32,9 +32,16 @@ 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 +CONFIG_SPL_NOR_SUPPORT=y CONFIG_SPL_RTC=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y @@ -243,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/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/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/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 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/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/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/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 9a9c520e22c..f50de7c089e 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -2373,10 +2373,6 @@ int ext4fs_mount(unsigned part_length) struct ext2_data *data; int status; struct ext_filesystem *fs = get_fs(); - - if (part_length < SUPERBLOCK_SIZE) - return 0; - data = zalloc(SUPERBLOCK_SIZE); if (!data) return 0; @@ -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", 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/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)) diff --git a/arch/arm/include/asm/mach-imx/image.h b/include/imx_container.h index ee67ca96f4c..54cd684e35d 100644 --- a/arch/arm/include/asm/mach-imx/image.h +++ b/include/imx_container.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/include/spl.h b/include/spl.h index 1d416b4c929..0d49e4a454c 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. * @@ -673,7 +683,23 @@ 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 */ + +/** + * 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 +779,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); diff --git a/include/test/spl.h b/include/test/spl.h new file mode 100644 index 00000000000..c1f64658502 --- /dev/null +++ b/include/test/spl.h @@ -0,0 +1,155 @@ +/* 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 + * @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, +}; + +/** + * 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); + +/** + * 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 + * + * Return: %true if supported and %false otherwise + */ +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: + 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 + +/* Flags necessary for accessing DM devices */ +#define DM_FLAGS (UT_TESTF_DM | UT_TESTF_SCAN_FDT) + +#endif /* TEST_SPL_H */ 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/ 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/bootp.c b/net/bootp.c index 8b1a4ae2ef8..7b0f45e18a9 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 @@ -1076,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)) @@ -1102,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); 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. */ 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; 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..8f9e6ae036b --- /dev/null +++ b/test/image/Kconfig @@ -0,0 +1,50 @@ +# 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_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 + depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR + default y + 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_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 + 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..b30210106a4 100644 --- a/test/image/Makefile +++ b/test/image/Makefile @@ -2,4 +2,9 @@ # # Copyright 2021 Google LLC -obj-$(CONFIG_SPL_BUILD) += spl_load.o +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 +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 4e27ff460ab..ab4c14d6491 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -1,91 +1,661 @@ // 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 <imx_container.h> #include <mapmem.h> -#include <os.h> +#include <memalign.h> +#include <rand.h> +#include <spi_flash.h> #include <spl.h> +#include <test/spl.h> #include <test/ut.h> +#include <u-boot/crc.h> -/* Declare a new SPL test */ -#define SPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, spl_test) +int board_fit_config_name_match(const char *name) +{ + return 0; +} -/* Context used for this test */ -struct text_ctx { - int fd; -}; +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 +#define SPL_COMP_LZMA 0x40000000 -static ulong read_fit_image(struct spl_load_info *load, ulong sector, - ulong count, void *buf) +void generate_data(char *data, size_t size, const char *test_name) { - struct text_ctx *text_ctx = load->priv; - off_t offset, ret; - ssize_t res; + 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, 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))); + +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; - 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); + 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; } - 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); + 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; } - return count; + 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; } -int board_fit_config_name_match(const char *name) +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_LZMA: + info->flags = SPL_COMP_LZMA; + 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; } -struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) +int check_image_info(struct unit_test_state *uts, struct spl_image_info *info1, + struct spl_image_info *info2) { - return map_sysmem(0x100000, 0); + 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 if (!(info1->flags & SPL_COMP_LZMA)) + 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_load(struct unit_test_state *uts) +static int spl_test_image(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) { - 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; + 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); } - load.filename = fname; - header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); + 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); + +/* + * 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 +}; - fd = os_open(fname, OS_O_RDONLY); - ut_assert(fd >= 0); - ut_asserteq(512, os_read(fd, header, 512)); - text_ctx.fd = fd; +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 = type == LEGACY_LZMA ? sizeof(lzma_compressed) : + plain_size, + }, info_read = { }; + struct spl_boot_device bootdev = { + .boot_device = loader->boot_device, + }; + char *data, *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); + + 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)); - load.priv = &text_ctx; + if (write_image(uts, img, img_size)) + return CMD_RET_FAILURE; - ut_assertok(spl_load_simple_fit(&image, &load, 0, header)); + 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; } -SPL_TEST(spl_test_load, 0); diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c new file mode 100644 index 00000000000..297ab08a820 --- /dev/null +++ b/test/image/spl_load_fs.c @@ -0,0 +1,428 @@ +// 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 <spl.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); + +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, + bool blk_mode) +{ + 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_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; + + 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)); + + 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); + + 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, true)) + return CMD_RET_FAILURE; + + 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); 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); 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); diff --git a/test/image/spl_load_os.c b/test/image/spl_load_os.c new file mode 100644 index 00000000000..49edf152d78 --- /dev/null +++ b/test/image/spl_load_os.c @@ -0,0 +1,76 @@ +// 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/spl.h> +#include <test/ut.h> + +/* 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) + ut_assertf(0, "%s not found, error %d\n", fname, 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_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. 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 |
