diff options
author | Tom Rini <trini@konsulko.com> | 2022-05-04 15:44:11 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-05-04 15:44:11 -0400 |
commit | b4da738152a0cf3cec5bd4649e21aece6d4292d6 (patch) | |
tree | 0fcc837c96bc237a0e7cc05d658e60f2d0db3350 | |
parent | 1739a6db5403d187902dcebca548de0644c8078f (diff) | |
parent | 064334e21dde2d38a2f3535ddd593dc4b2dc4674 (diff) | |
download | u-boot-WIP/04May2022.zip u-boot-WIP/04May2022.tar.gz u-boot-WIP/04May2022.tar.bz2 |
Merge branch '2022-05-04-spl-use-common-function-for-loading-and-parsing-images'WIP/04May2022
To quote the author:
This series adds support for loading all image types (Legacy, FIT (with
and without LOAD_FIT_FULL), and i.MX) to the MMC, SPI, NOR, NET, FAT,
and EXT load methods. It does this by introducing a helper function
which handles the minutiae of invoking the proper parsing function, and
reading the rest of the image.
Hopefully, this will make it easier for load methods to support all
image types that U-Boot supports, without having undocumented
unsupported image types. I applied this to several loaders which were
invoking spl_load_simple_fit and/or spl_parse_image_header, but I did
not use it with others (e.g. DFU/RAM) which had complications in the
mix.
-rw-r--r-- | common/spl/spl.c | 61 | ||||
-rw-r--r-- | common/spl/spl_ext.c | 24 | ||||
-rw-r--r-- | common/spl/spl_fat.c | 36 | ||||
-rw-r--r-- | common/spl/spl_mmc.c | 73 | ||||
-rw-r--r-- | common/spl/spl_net.c | 24 | ||||
-rw-r--r-- | common/spl/spl_nor.c | 35 | ||||
-rw-r--r-- | common/spl/spl_semihosting.c | 39 | ||||
-rw-r--r-- | common/spl/spl_spi.c | 131 | ||||
-rw-r--r-- | include/spl.h | 30 |
9 files changed, 184 insertions, 269 deletions
diff --git a/common/spl/spl.c b/common/spl/spl.c index c8c463f..0dd1564 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -416,6 +416,67 @@ int spl_parse_image_header(struct spl_image_info *spl_image, return 0; } +static int spl_simple_read(struct spl_load_info *info, void *buf, size_t size, + size_t offset) +{ + size_t bl_len = info->filename ? ARCH_DMA_MINALIGN : bl_len; + size_t bl_mask = bl_len - 1; + size_t overhead = offset & bl_mask; + size_t bl_shift = ffs(bl_mask); + int ret; + + buf -= overhead; + size = (size + overhead + bl_mask) >> bl_shift; + offset = offset >> bl_shift; + + ret = info->read(info, offset, size, buf); + return ret == size ? 0 : -EIO; +} + +int spl_load(struct spl_image_info *spl_image, + const struct spl_boot_device *bootdev, struct spl_load_info *info, + struct image_header *header, size_t size, size_t sector) +{ + int ret; + size_t offset = sector * info->bl_len; + + if (image_get_magic(header) == FDT_MAGIC) { + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL)) { + void *buf; + + /* + * In order to support verifying images in the FIT, we + * need to load the whole FIT into memory. Try and + * guess how much we need to load by using the total + * size. This will fail for FITs with external data, + * but there's not much we can do about that. + */ + if (!size) + size = roundup(fdt_totalsize(header), 4); + buf = spl_get_load_buffer(0, size); + ret = spl_simple_read(info, buf, size, offset); + if (ret) + return ret; + + return spl_parse_image_header(spl_image, bootdev, buf); + } + + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) + return spl_load_simple_fit(spl_image, info, sector, + header); + } + + if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) + return spl_load_imx_container(spl_image, info, sector); + + ret = spl_parse_image_header(spl_image, bootdev, header); + if (ret) + return ret; + + return spl_simple_read(info, (void *)spl_image->load_addr, + spl_image->size, offset + spl_image->offset); +} + __weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) { typedef void __noreturn (*image_entry_noargs_t)(void); diff --git a/common/spl/spl_ext.c b/common/spl/spl_ext.c index ebd914c..1384842 100644 --- a/common/spl/spl_ext.c +++ b/common/spl/spl_ext.c @@ -9,6 +9,18 @@ #include <errno.h> #include <image.h> +static ulong spl_fit_read(struct spl_load_info *load, ulong file_offset, + ulong size, void *buf) +{ + int ret; + loff_t actlen; + + ret = ext4fs_read(buf, file_offset, size, &actlen); + if (ret) + return ret; + return actlen; +} + int spl_load_image_ext(struct spl_image_info *spl_image, struct spl_boot_device *bootdev, struct blk_desc *block_dev, int partition, @@ -18,6 +30,10 @@ int spl_load_image_ext(struct spl_image_info *spl_image, struct image_header *header; loff_t filelen, actlen; struct disk_partition part_info = {}; + struct spl_load_info load = { + .read = spl_fit_read, + .bl_len = 1, + }; header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); @@ -47,13 +63,7 @@ int spl_load_image_ext(struct spl_image_info *spl_image, goto end; } - err = spl_parse_image_header(spl_image, bootdev, header); - if (err < 0) { - puts("spl: ext: failed to parse image header\n"); - goto end; - } - - err = ext4fs_read((char *)spl_image->load_addr, 0, filelen, &actlen); + err = spl_load(spl_image, bootdev, &load, header, filelen, 0); end: #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT diff --git a/common/spl/spl_fat.c b/common/spl/spl_fat.c index 5b27054..c092eb3 100644 --- a/common/spl/spl_fat.c +++ b/common/spl/spl_fat.c @@ -61,6 +61,11 @@ int spl_load_image_fat(struct spl_image_info *spl_image, { int err; struct image_header *header; + struct spl_load_info load = { + .read = spl_fit_read, + .bl_len = 1, + .filename = filename, + }; err = spl_register_fat_device(block_dev, partition); if (err) @@ -72,36 +77,7 @@ int spl_load_image_fat(struct spl_image_info *spl_image, if (err <= 0) goto end; - 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); - if (err <= 0) - goto end; - err = spl_parse_image_header(spl_image, bootdev, - (struct image_header *)CONFIG_SYS_LOAD_ADDR); - if (err == -EAGAIN) - return err; - if (err == 0) - err = 1; - } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && - image_get_magic(header) == FDT_MAGIC) { - struct spl_load_info load; - - debug("Found FIT\n"); - load.read = spl_fit_read; - load.bl_len = 1; - load.filename = (void *)filename; - load.priv = NULL; - - return spl_load_simple_fit(spl_image, &load, 0, header); - } else { - err = spl_parse_image_header(spl_image, bootdev, header); - if (err) - goto end; - - err = file_fat_read(filename, - (u8 *)(uintptr_t)spl_image->load_addr, 0); - } + err = spl_load(spl_image, bootdev, &load, header, err, 0); end: #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 6116a68..93a28cd 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -17,48 +17,6 @@ #include <mmc.h> #include <image.h> -static int mmc_load_legacy(struct spl_image_info *spl_image, - struct spl_boot_device *bootdev, - struct mmc *mmc, - ulong sector, struct image_header *header) -{ - u32 image_offset_sectors; - u32 image_size_sectors; - unsigned long count; - u32 image_offset; - int ret; - - ret = spl_parse_image_header(spl_image, bootdev, header); - if (ret) - return ret; - - /* convert offset to sectors - round down */ - image_offset_sectors = spl_image->offset / mmc->read_bl_len; - /* calculate remaining offset */ - image_offset = spl_image->offset % mmc->read_bl_len; - - /* convert size to sectors - round up */ - image_size_sectors = (spl_image->size + mmc->read_bl_len - 1) / - mmc->read_bl_len; - - /* Read the header too to avoid extra memcpy */ - count = blk_dread(mmc_get_blk_desc(mmc), - sector + image_offset_sectors, - image_size_sectors, - (void *)(ulong)spl_image->load_addr); - debug("read %x sectors to %lx\n", image_size_sectors, - spl_image->load_addr); - if (count != image_size_sectors) - return -EIO; - - if (image_offset) - memmove((void *)(ulong)spl_image->load_addr, - (void *)(ulong)spl_image->load_addr + image_offset, - spl_image->size); - - return 0; -} - static ulong h_spl_load_read(struct spl_load_info *load, ulong sector, ulong count, void *buf) { @@ -86,6 +44,11 @@ int mmc_load_image_raw_sector(struct spl_image_info *spl_image, struct image_header *header; struct blk_desc *bd = mmc_get_blk_desc(mmc); int ret = 0; + struct spl_load_info load = { + .dev = mmc, + .bl_len = mmc->read_bl_len, + .read = h_spl_load_read, + }; header = spl_get_load_buffer(-sizeof(*header), bd->blksz); @@ -97,31 +60,7 @@ int mmc_load_image_raw_sector(struct spl_image_info *spl_image, goto end; } - if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && - image_get_magic(header) == FDT_MAGIC) { - struct spl_load_info load; - - debug("Found FIT\n"); - load.dev = mmc; - load.priv = NULL; - load.filename = NULL; - 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)) { - struct spl_load_info load; - - load.dev = mmc; - load.priv = NULL; - load.filename = NULL; - load.bl_len = mmc->read_bl_len; - load.read = h_spl_load_read; - - ret = spl_load_imx_container(spl_image, &load, sector); - } else { - ret = mmc_load_legacy(spl_image, bootdev, mmc, sector, header); - } - + ret = spl_load(spl_image, bootdev, &load, header, 0, sector); end: if (ret) { #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT diff --git a/common/spl/spl_net.c b/common/spl/spl_net.c index a853e6a..3b4374a 100644 --- a/common/spl/spl_net.c +++ b/common/spl/spl_net.c @@ -29,6 +29,10 @@ static int spl_net_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { struct image_header *header = (struct image_header *)image_load_addr; + struct spl_load_info load = { + .bl_len = 1, + .read = spl_net_load_read, + }; int rv; env_init(); @@ -47,25 +51,7 @@ static int spl_net_load_image(struct spl_image_info *spl_image, return rv; } - if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && - image_get_magic(header) == FDT_MAGIC) { - struct spl_load_info load; - - debug("Found FIT\n"); - load.bl_len = 1; - load.read = spl_net_load_read; - rv = spl_load_simple_fit(spl_image, &load, 0, header); - } else { - debug("Legacy image\n"); - - rv = spl_parse_image_header(spl_image, bootdev, header); - if (rv) - return rv; - - memcpy((void *)spl_image->load_addr, header, spl_image->size); - } - - return rv; + return spl_load(spl_image, bootdev, &load, header, 0, 0); } #endif diff --git a/common/spl/spl_nor.c b/common/spl/spl_nor.c index 0f4fff8..90ece77 100644 --- a/common/spl/spl_nor.c +++ b/common/spl/spl_nor.c @@ -26,8 +26,11 @@ 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 image_header *header; - __maybe_unused struct spl_load_info load; + struct image_header *header = (void *)spl_nor_get_uboot_base(); + struct spl_load_info load = { + .bl_len = 1, + .read = spl_nor_load_read, + }; /* * Loading of the payload to SDRAM is done with skipping of @@ -91,32 +94,6 @@ static int spl_nor_load_image(struct spl_image_info *spl_image, * Load real U-Boot from its location in NOR flash to its * defined location in SDRAM */ -#ifdef CONFIG_SPL_LOAD_FIT - header = (const struct image_header *)spl_nor_get_uboot_base(); - if (image_get_magic(header) == FDT_MAGIC) { - debug("Found FIT format U-Boot\n"); - load.bl_len = 1; - load.read = spl_nor_load_read; - return spl_load_simple_fit(spl_image, &load, - spl_nor_get_uboot_base(), - (void *)header); - } -#endif - if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { - load.bl_len = 1; - load.read = spl_nor_load_read; - return spl_load_imx_container(spl_image, &load, - spl_nor_get_uboot_base()); - } - - /* Legacy image handling */ - if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_SUPPORT)) { - load.bl_len = 1; - load.read = spl_nor_load_read; - return spl_load_legacy_img(spl_image, bootdev, &load, - spl_nor_get_uboot_base()); - } - - return 0; + return spl_load(spl_image, bootdev, &load, header, 0, 0); } SPL_LOAD_IMAGE_METHOD("NOR", 0, BOOT_DEVICE_NOR, spl_nor_load_image); diff --git a/common/spl/spl_semihosting.c b/common/spl/spl_semihosting.c index df6aeb2..35fbc2e 100644 --- a/common/spl/spl_semihosting.c +++ b/common/spl/spl_semihosting.c @@ -9,16 +9,16 @@ #include <semihosting.h> #include <spl.h> -static int smh_read_full(long fd, void *memp, size_t len) +static ulong spl_smh_fit_read(struct spl_load_info *load, ulong sector, + ulong count, void *buf) { - long read; + int ret, fd = *(int *)load->priv; - read = smh_read(fd, memp, len); - if (read < 0) - return read; - if (read != len) - return -EIO; - return 0; + if (smh_seek(fd, sector)) + return 0; + + ret = smh_read(fd, buf, count); + return ret < 0 ? 0 : ret; } static int spl_smh_load_image(struct spl_image_info *spl_image, @@ -29,12 +29,17 @@ static int spl_smh_load_image(struct spl_image_info *spl_image, long fd, len; struct image_header *header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); + struct spl_load_info load = { + .bl_len = 1, + .read = spl_smh_fit_read, + }; fd = smh_open(filename, MODE_READ | MODE_BINARY); if (fd < 0) { log_debug("could not open %s: %ld\n", filename, fd); return fd; } + load.priv = &fd; ret = smh_flen(fd); if (ret < 0) { @@ -43,25 +48,13 @@ static int spl_smh_load_image(struct spl_image_info *spl_image, } len = ret; - ret = smh_read_full(fd, header, sizeof(struct image_header)); - if (ret) { + ret = smh_read(fd, header, sizeof(struct image_header)); + if (ret != sizeof(struct image_header)) { log_debug("could not read image header: %d\n", ret); goto out; } - ret = spl_parse_image_header(spl_image, bootdev, header); - if (ret) { - log_debug("failed to parse image header: %d\n", ret); - goto out; - } - - ret = smh_seek(fd, 0); - if (ret) { - log_debug("could not seek to start of image: %d\n", ret); - goto out; - } - - ret = smh_read_full(fd, (void *)spl_image->load_addr, len); + ret = spl_load(spl_image, bootdev, &load, header, len, 0); if (ret) log_debug("could not read %s: %d\n", filename, ret); out: diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index cf3f7ef..e724a74 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -18,41 +18,6 @@ #include <asm/global_data.h> #include <dm/ofnode.h> -#if CONFIG_IS_ENABLED(OS_BOOT) -/* - * Load the kernel, check for a valid header we can parse, and if found load - * the kernel and then device tree. - */ -static int spi_load_image_os(struct spl_image_info *spl_image, - struct spl_boot_device *bootdev, - struct spi_flash *flash, - struct image_header *header) -{ - int err; - - /* Read for a header, parse or error out. */ - spi_flash_read(flash, CONFIG_SYS_SPI_KERNEL_OFFS, sizeof(*header), - (void *)header); - - if (image_get_magic(header) != IH_MAGIC) - return -1; - - err = spl_parse_image_header(spl_image, bootdev, header); - if (err) - return err; - - spi_flash_read(flash, CONFIG_SYS_SPI_KERNEL_OFFS, - spl_image->size, (void *)spl_image->load_addr); - - /* Read device tree. */ - spi_flash_read(flash, CONFIG_SYS_SPI_ARGS_OFFS, - CONFIG_SYS_SPI_ARGS_SIZE, - (void *)CONFIG_SYS_SPL_ARGS_ADDR); - - return 0; -} -#endif - static ulong spl_spi_fit_read(struct spl_load_info *load, ulong sector, ulong count, void *buf) { @@ -71,6 +36,29 @@ unsigned int __weak spl_spi_get_uboot_offs(struct spi_flash *flash) return CONFIG_SYS_SPI_U_BOOT_OFFS; } +static int spi_do_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev, + struct spl_load_info *load, + unsigned int payload_offs) +{ + int ret; + struct spi_flash *flash = load->dev; + struct image_header *header = + spl_get_load_buffer(-sizeof(*header), sizeof(*header)); + + /* mkimage header is 64 bytes. */ + ret = spi_flash_read(flash, payload_offs, sizeof(*header), + (void *)header); + if (ret) { + debug("%s: Failed to read from SPI flash (err=%d)\n", + __func__, ret); + return ret; + } + + return spl_load(spl_image, bootdev, load, header, 0, + payload_offs); +} + /* * The main entry for SPI booting. It's necessary that SDRAM is already * configured and available since this code loads the main U-Boot image @@ -79,10 +67,12 @@ unsigned int __weak spl_spi_get_uboot_offs(struct spi_flash *flash) static int spl_spi_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { - int err = 0; unsigned int payload_offs; struct spi_flash *flash; - struct image_header *header; + struct spl_load_info load = { + .bl_len = 1, + .read = spl_spi_fit_read, + }; /* * Load U-Boot image from SPI flash into RAM @@ -99,72 +89,27 @@ static int spl_spi_load_image(struct spl_image_info *spl_image, return -ENODEV; } + load.dev = flash; payload_offs = spl_spi_get_uboot_offs(flash); - header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); - if (CONFIG_IS_ENABLED(OF_REAL)) { payload_offs = ofnode_conf_read_int("u-boot,spl-payload-offset", payload_offs); } #if CONFIG_IS_ENABLED(OS_BOOT) - if (spl_start_uboot() || spi_load_image_os(spl_image, bootdev, flash, header)) -#endif - { - /* Load u-boot, mkimage header is 64 bytes. */ - err = spi_flash_read(flash, payload_offs, sizeof(*header), - (void *)header); - if (err) { - debug("%s: Failed to read from SPI flash (err=%d)\n", - __func__, err); - return err; - } - - if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) && - image_get_magic(header) == FDT_MAGIC) { - err = spi_flash_read(flash, payload_offs, - roundup(fdt_totalsize(header), 4), - (void *)CONFIG_SYS_LOAD_ADDR); - if (err) - return err; - err = spl_parse_image_header(spl_image, bootdev, - (struct image_header *)CONFIG_SYS_LOAD_ADDR); - } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && - image_get_magic(header) == FDT_MAGIC) { - struct spl_load_info load; - - debug("Found FIT\n"); - load.dev = flash; - load.priv = NULL; - load.filename = NULL; - load.bl_len = 1; - load.read = spl_spi_fit_read; - err = spl_load_simple_fit(spl_image, &load, - payload_offs, - header); - } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { - struct spl_load_info load; - - load.dev = flash; - load.priv = NULL; - load.filename = NULL; - load.bl_len = 1; - load.read = spl_spi_fit_read; - - err = spl_load_imx_container(spl_image, &load, - payload_offs); - } else { - err = spl_parse_image_header(spl_image, bootdev, header); - if (err) - return err; - err = spi_flash_read(flash, payload_offs + spl_image->offset, - spl_image->size, - (void *)spl_image->load_addr); - } + if (spl_start_uboot()) { + int err = spi_do_load_image(spl_image, bootdev, &load, + CONFIG_SYS_SPI_KERNEL_OFFS); + if (!err) + /* Read device tree. */ + return spi_flash_read(flash, CONFIG_SYS_SPI_ARGS_OFFS, + CONFIG_SYS_SPI_ARGS_SIZE, + (void *)CONFIG_SYS_SPL_ARGS_ADDR); } +#endif - return err; + return spi_do_load_image(spl_image, bootdev, &load, payload_offs); } /* Use priorty 1 so that boards can override this */ SPL_LOAD_IMAGE_METHOD("SPI", 1, BOOT_DEVICE_SPI, spl_spi_load_image); diff --git a/include/spl.h b/include/spl.h index 83ac583..47a35ff 100644 --- a/include/spl.h +++ b/include/spl.h @@ -253,7 +253,7 @@ struct spl_image_info { * * @dev: Pointer to the device, e.g. struct mmc * * @priv: Private data for the device - * @bl_len: Block length for reading in bytes + * @bl_len: Block length for reading in bytes; must be a power of 2 * @filename: Name of the fit image file. * @read: Function to call to read from the device */ @@ -626,6 +626,34 @@ int spl_load_image_ext_os(struct spl_image_info *spl_image, struct blk_desc *block_dev, int partition); /** + * spl_load() - Parse a header and load the image + * @spl_image: Image data which will be filled in by this function + * @bootdev: The device to load from + * @info: Describes how to load additional information from @bootdev. At the + * minimum, read() and bl_len must be populated. + * @header: The image header. This should already have been loaded. It may be + * clobbered by the load process (if e.g. the load address overlaps). + * @size: The size of the image, if it is known in advance. Some boot devices + * (such as filesystems) know how big an image is before parsing the + * header. If this information is unknown, then the size will be + * determined from the header. + * @sectors: The offset from the start if @bootdev, in units of @info->bl_len. + * This should have the offset @header was loaded from. It will be + * added to any offsets passed to @info->read(). + * + * This function determines the image type (FIT, legacy, i.MX, raw, etc), calls + * the appropriate parsing function, determines the load address, and the loads + * the image from storage. It is designed to replace ad-hoc image loading which + * may not support all image types (especially when config options are + * involved). + * + * Return: 0 on success, or a negative error on failure + */ +int spl_load(struct spl_image_info *spl_image, + const struct spl_boot_device *bootdev, struct spl_load_info *info, + struct image_header *header, size_t size, size_t sector); + +/** * spl_early_init() - Set up device tree and driver model in SPL if enabled * * Call this function in board_init_f() if you want to use device tree and |