blob: 525e0c9e86c6f014d993d0f945bbaa29aa025a29 [file] [log] [blame]
Sean Anderson3a4a2b72023-11-08 11:48:47 -05001/* 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
Simon Glass43e4f792025-01-26 11:43:19 -070023 log_debug("\nloading hdr from %lx to %p\n", (ulong)offset, header);
Sean Anderson3a4a2b72023-11-08 11:48:47 -050024 read = info->read(info, offset, ALIGN(sizeof(*header),
25 spl_get_bl_len(info)), header);
Franco Venturi13135872024-07-31 09:09:00 -040026 if (read < (int)sizeof(*header))
Sean Anderson3a4a2b72023-11-08 11:48:47 -050027 return -EIO;
28
29 if (image_get_magic(header) == FDT_MAGIC) {
Simon Glass43e4f792025-01-26 11:43:19 -070030 log_debug("Found FIT\n");
31 if (CONFIG_IS_ENABLED(LOAD_FIT_FULL)) {
Sean Anderson3a4a2b72023-11-08 11:48:47 -050032 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
Simon Glass43e4f792025-01-26 11:43:19 -070053 if (CONFIG_IS_ENABLED(LOAD_FIT)) {
54 log_debug("Simple loading\n");
Sean Anderson3a4a2b72023-11-08 11:48:47 -050055 return spl_load_simple_fit(spl_image, info, offset,
56 header);
Simon Glass43e4f792025-01-26 11:43:19 -070057 }
58 log_debug("No FIT support\n");
Sean Anderson3a4a2b72023-11-08 11:48:47 -050059 }
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));
Daniel Palmeraf8ebba2024-08-31 12:17:06 +090091
92 if (read < 0)
93 return read;
94
Sean Anderson3a4a2b72023-11-08 11:48:47 -050095 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 \
Sean Anderson73143252023-11-08 11:48:54 -0500107 IS_ENABLED(CONFIG_SPL_BLK_FS) + \
Sean Andersonf727cc12023-11-08 11:48:48 -0500108 IS_ENABLED(CONFIG_SPL_FS_EXT4) + \
Sean Anderson09a46022023-11-08 11:48:49 -0500109 IS_ENABLED(CONFIG_SPL_FS_FAT) + \
Sean Anderson29e338f2023-11-08 11:48:50 -0500110 IS_ENABLED(CONFIG_SPL_SYS_MMCSD_RAW_MODE) + \
Sean Anderson1c398062023-11-08 11:48:51 -0500111 (IS_ENABLED(CONFIG_SPL_NAND_SUPPORT) && !IS_ENABLED(CONFIG_SPL_UBI)) + \
Sean Anderson810e16e2023-11-08 11:48:52 -0500112 IS_ENABLED(CONFIG_SPL_NET) + \
Sean Anderson2a5d23f2023-11-08 11:48:53 -0500113 IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) + \
Sean Anderson531d8372023-11-08 11:48:55 -0500114 IS_ENABLED(CONFIG_SPL_SEMIHOSTING) + \
Sean Anderson38e4f622023-11-08 11:48:56 -0500115 IS_ENABLED(CONFIG_SPL_SPI_LOAD) + \
Sean Anderson3a4a2b72023-11-08 11:48:47 -0500116 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 */
140int 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
144static 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_ */