@@ -450,6 +450,89 @@ 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_mask = info->bl_len - 1;
+ size_t overhead = offset & bl_mask;
+ size_t bl_shift = fls(bl_mask);
+ int ret;
+
+ debug("%s: buf=%p size=%lx offset=%lx\n", __func__, buf, (long)size,
+ (long)offset);
+ debug("%s: bl_len=%lx bl_mask=%lx bl_shift=%lx\n", __func__,
+ (long)info->bl_len, (long)bl_mask, (long)bl_shift);
+
+ /*
+ * Convert offset and size to units of bl_len. In order for the final
+ * value of buf to be DMA-aligned, both buf and offset must already be
+ * DMA-aligned. A bounce buffer is required to correct improper
+ * alignment if min(bl_len, ARCH_DMA_MINALIGN) > 1, so we don't bother.
+ */
+ buf -= overhead;
+ size = (size + overhead + bl_mask) >> bl_shift;
+ offset = offset >> bl_shift;
+
+ if (CONFIG_IS_ENABLED(SHOW_ERRORS) &&
+ !IS_ALIGNED((uintptr_t)buf, ARCH_DMA_MINALIGN))
+ printf("Warning: loading to misaligned address %p\n", buf);
+
+ debug("info->read(info, %lx, %lx, %p)\n", (long)offset, (long)size,
+ buf);
+ 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,
+ size_t size, size_t sector)
+{
+ struct legacy_img_hdr *header =
+ spl_get_load_buffer(-sizeof(*header), sizeof(*header));
+ size_t offset = sector * info->bl_len;
+ int ret;
+
+ ret = spl_simple_read(info, header, sizeof(*header), offset);
+ if (ret)
+ return ret;
+
+ 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);
@@ -267,7 +267,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
*/
@@ -676,6 +676,31 @@ int spl_blk_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev,
enum uclass_id uclass_id, int devnum, int partnum);
+/**
+ * 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.
+ * @size: The size of the image, in bytes, if it is known in advance. Some boot
+ * devices (such as filesystems) know how big an image is before parsing
+ * the header. If 0, then the size will be determined from the header.
+ * @sectors: The offset from the start of @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,
+ size_t size, size_t sector);
+
/**
* spl_early_init() - Set up device tree and driver model in SPL if enabled
*