1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Copyright (C) Sean Anderson <seanga2@gmail.com>
4 */
5#ifndef	_SPL_LOAD_H_
6#define	_SPL_LOAD_H_
7
8#include <image.h>
9#include <imx_container.h>
10#include <mapmem.h>
11#include <spl.h>
12
13static inline int _spl_load(struct spl_image_info *spl_image,
14			    const struct spl_boot_device *bootdev,
15			    struct spl_load_info *info, size_t size,
16			    size_t offset)
17{
18	struct legacy_img_hdr *header =
19		spl_get_load_buffer(-sizeof(*header), sizeof(*header));
20	ulong base_offset, image_offset, overhead;
21	int read, ret;
22
23	read = info->read(info, offset, ALIGN(sizeof(*header),
24					      spl_get_bl_len(info)), header);
25	if (read < sizeof(*header))
26		return -EIO;
27
28	if (image_get_magic(header) == FDT_MAGIC) {
29		if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL)) {
30			void *buf;
31
32			/*
33			 * In order to support verifying images in the FIT, we
34			 * need to load the whole FIT into memory. Try and
35			 * guess how much we need to load by using the total
36			 * size. This will fail for FITs with external data,
37			 * but there's not much we can do about that.
38			 */
39			if (!size)
40				size = round_up(fdt_totalsize(header), 4);
41			buf = map_sysmem(CONFIG_SYS_LOAD_ADDR, size);
42			read = info->read(info, offset,
43					  ALIGN(size, spl_get_bl_len(info)),
44					  buf);
45			if (read < size)
46				return -EIO;
47
48			return spl_parse_image_header(spl_image, bootdev, buf);
49		}
50
51		if (IS_ENABLED(CONFIG_SPL_LOAD_FIT))
52			return spl_load_simple_fit(spl_image, info, offset,
53						   header);
54	}
55
56	if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) &&
57	    valid_container_hdr((void *)header))
58		return spl_load_imx_container(spl_image, info, offset);
59
60	if (IS_ENABLED(CONFIG_SPL_LZMA) &&
61	    image_get_magic(header) == IH_MAGIC &&
62	    image_get_comp(header) == IH_COMP_LZMA) {
63		spl_image->flags |= SPL_COPY_PAYLOAD_ONLY;
64		ret = spl_parse_image_header(spl_image, bootdev, header);
65		if (ret)
66			return ret;
67
68		return spl_load_legacy_lzma(spl_image, info, offset);
69	}
70
71	ret = spl_parse_image_header(spl_image, bootdev, header);
72	if (ret)
73		return ret;
74
75	base_offset = spl_image->offset;
76	/* Only NOR sets this flag. */
77	if (IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) &&
78	    spl_image->flags & SPL_COPY_PAYLOAD_ONLY)
79		base_offset += sizeof(*header);
80	image_offset = ALIGN_DOWN(base_offset, spl_get_bl_len(info));
81	overhead = base_offset - image_offset;
82	size = ALIGN(spl_image->size + overhead, spl_get_bl_len(info));
83
84	read = info->read(info, offset + image_offset, size,
85			  map_sysmem(spl_image->load_addr - overhead, size));
86	return read < spl_image->size ? -EIO : 0;
87}
88
89/*
90 * Although spl_load results in size reduction for callers, this is generally
91 * not enough to counteract the bloat if there is only one caller. The core
92 * problem is that the compiler can't optimize across translation units. The
93 * general solution to this is CONFIG_LTO, but that is not available on all
94 * architectures. Perform a pseudo-LTO just for this function by declaring it
95 * inline if there is one caller, and extern otherwise.
96 */
97#define SPL_LOAD_USERS \
98	IS_ENABLED(CONFIG_SPL_BLK_FS) + \
99	IS_ENABLED(CONFIG_SPL_FS_EXT4) + \
100	IS_ENABLED(CONFIG_SPL_FS_FAT) + \
101	IS_ENABLED(CONFIG_SPL_SYS_MMCSD_RAW_MODE) + \
102	(IS_ENABLED(CONFIG_SPL_NAND_SUPPORT) && !IS_ENABLED(CONFIG_SPL_UBI)) + \
103	IS_ENABLED(CONFIG_SPL_NET) + \
104	IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) + \
105	IS_ENABLED(CONFIG_SPL_SEMIHOSTING) + \
106	IS_ENABLED(CONFIG_SPL_SPI_LOAD) + \
107	0
108
109#if SPL_LOAD_USERS > 1
110/**
111 * spl_load() - Parse a header and load the image
112 * @spl_image: Image data which will be filled in by this function
113 * @bootdev: The device to load from
114 * @info: Describes how to load additional information from @bootdev. At the
115 *        minimum, read() and bl_len must be populated.
116 * @size: The size of the image, in bytes, if it is known in advance. Some boot
117 *        devices (such as filesystems) know how big an image is before parsing
118 *        the header. If 0, then the size will be determined from the header.
119 * @offset: The offset from the start of @bootdev, in bytes. This should have
120 *          the offset @header was loaded from. It will be added to any offsets
121 *          passed to @info->read().
122 *
123 * This function determines the image type (FIT, legacy, i.MX, raw, etc), calls
124 * the appropriate parsing function, determines the load address, and the loads
125 * the image from storage. It is designed to replace ad-hoc image loading which
126 * may not support all image types (especially when config options are
127 * involved).
128 *
129 * Return: 0 on success, or a negative error on failure
130 */
131int spl_load(struct spl_image_info *spl_image,
132	     const struct spl_boot_device *bootdev, struct spl_load_info *info,
133	     size_t size, size_t offset);
134#else
135static inline int spl_load(struct spl_image_info *spl_image,
136			   const struct spl_boot_device *bootdev,
137			   struct spl_load_info *info, size_t size,
138			   size_t offset)
139{
140	return _spl_load(spl_image, bootdev, info, size, offset);
141}
142#endif
143
144#endif /* _SPL_LOAD_H_ */
145