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