xref: /openbmc/u-boot/common/spl/spl_fit.c (revision 9b643e312d528f291966c1f30b0d90bf3b1d43dc)
1  /*
2   * Copyright (C) 2016 Google, Inc
3   * Written by Simon Glass <sjg@chromium.org>
4   *
5   * SPDX-License-Identifier:     GPL-2.0+
6   */
7  
8  #include <common.h>
9  #include <errno.h>
10  #include <image.h>
11  #include <libfdt.h>
12  #include <spl.h>
13  
14  #ifndef CONFIG_SYS_BOOTM_LEN
15  #define CONFIG_SYS_BOOTM_LEN	(64 << 20)
16  #endif
17  
18  /**
19   * spl_fit_get_image_node(): By using the matching configuration subnode,
20   * retrieve the name of an image, specified by a property name and an index
21   * into that.
22   * @fit:	Pointer to the FDT blob.
23   * @images:	Offset of the /images subnode.
24   * @type:	Name of the property within the configuration subnode.
25   * @index:	Index into the list of strings in this property.
26   *
27   * Return:	the node offset of the respective image node or a negative
28   * 		error number.
29   */
30  static int spl_fit_get_image_node(const void *fit, int images,
31  				  const char *type, int index)
32  {
33  	const char *name, *str;
34  	int node, conf_node;
35  	int len, i;
36  
37  	conf_node = fit_find_config_node(fit);
38  	if (conf_node < 0) {
39  #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
40  		printf("No matching DT out of these options:\n");
41  		for (node = fdt_first_subnode(fit, conf_node);
42  		     node >= 0;
43  		     node = fdt_next_subnode(fit, node)) {
44  			name = fdt_getprop(fit, node, "description", &len);
45  			printf("   %s\n", name);
46  		}
47  #endif
48  		return conf_node;
49  	}
50  
51  	name = fdt_getprop(fit, conf_node, type, &len);
52  	if (!name) {
53  		debug("cannot find property '%s': %d\n", type, len);
54  		return -EINVAL;
55  	}
56  
57  	str = name;
58  	for (i = 0; i < index; i++) {
59  		str = strchr(str, '\0') + 1;
60  		if (!str || (str - name >= len)) {
61  			debug("no string for index %d\n", index);
62  			return -E2BIG;
63  		}
64  	}
65  
66  	debug("%s: '%s'\n", type, str);
67  	node = fdt_subnode_offset(fit, images, str);
68  	if (node < 0) {
69  		debug("cannot find image node '%s': %d\n", str, node);
70  		return -EINVAL;
71  	}
72  
73  	return node;
74  }
75  
76  static int get_aligned_image_offset(struct spl_load_info *info, int offset)
77  {
78  	/*
79  	 * If it is a FS read, get the first address before offset which is
80  	 * aligned to ARCH_DMA_MINALIGN. If it is raw read return the
81  	 * block number to which offset belongs.
82  	 */
83  	if (info->filename)
84  		return offset & ~(ARCH_DMA_MINALIGN - 1);
85  
86  	return offset / info->bl_len;
87  }
88  
89  static int get_aligned_image_overhead(struct spl_load_info *info, int offset)
90  {
91  	/*
92  	 * If it is a FS read, get the difference between the offset and
93  	 * the first address before offset which is aligned to
94  	 * ARCH_DMA_MINALIGN. If it is raw read return the offset within the
95  	 * block.
96  	 */
97  	if (info->filename)
98  		return offset & (ARCH_DMA_MINALIGN - 1);
99  
100  	return offset % info->bl_len;
101  }
102  
103  static int get_aligned_image_size(struct spl_load_info *info, int data_size,
104  				  int offset)
105  {
106  	data_size = data_size + get_aligned_image_overhead(info, offset);
107  
108  	if (info->filename)
109  		return data_size;
110  
111  	return (data_size + info->bl_len - 1) / info->bl_len;
112  }
113  
114  /**
115   * spl_load_fit_image(): load the image described in a certain FIT node
116   * @info:	points to information about the device to load data from
117   * @sector:	the start sector of the FIT image on the device
118   * @fit:	points to the flattened device tree blob describing the FIT
119   * 		image
120   * @base_offset: the beginning of the data area containing the actual
121   *		image data, relative to the beginning of the FIT
122   * @node:	offset of the DT node describing the image to load (relative
123   * 		to @fit)
124   * @image_info:	will be filled with information about the loaded image
125   * 		If the FIT node does not contain a "load" (address) property,
126   * 		the image gets loaded to the address pointed to by the
127   * 		load_addr member in this struct.
128   *
129   * Return:	0 on success or a negative error number.
130   */
131  static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
132  			      void *fit, ulong base_offset, int node,
133  			      struct spl_image_info *image_info)
134  {
135  	int offset;
136  	size_t length;
137  	int len;
138  	ulong size;
139  	ulong load_addr, load_ptr;
140  	void *src;
141  	ulong overhead;
142  	int nr_sectors;
143  	int align_len = ARCH_DMA_MINALIGN - 1;
144  	uint8_t image_comp = -1, type = -1;
145  	const void *data;
146  
147  	if (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP)) {
148  		if (fit_image_get_comp(fit, node, &image_comp))
149  			puts("Cannot get image compression format.\n");
150  		else
151  			debug("%s ", genimg_get_comp_name(image_comp));
152  
153  		if (fit_image_get_type(fit, node, &type))
154  			puts("Cannot get image type.\n");
155  		else
156  			debug("%s ", genimg_get_type_name(type));
157  	}
158  
159  	if (fit_image_get_load(fit, node, &load_addr))
160  		load_addr = image_info->load_addr;
161  
162  	if (!fit_image_get_data_offset(fit, node, &offset)) {
163  		/* External data */
164  		offset += base_offset;
165  		if (fit_image_get_data_size(fit, node, &len))
166  			return -ENOENT;
167  
168  		load_ptr = (load_addr + align_len) & ~align_len;
169  		length = len;
170  
171  		overhead = get_aligned_image_overhead(info, offset);
172  		nr_sectors = get_aligned_image_size(info, length, offset);
173  
174  		if (info->read(info,
175  			       sector + get_aligned_image_offset(info, offset),
176  			       nr_sectors, (void *)load_ptr) != nr_sectors)
177  			return -EIO;
178  
179  		debug("External data: dst=%lx, offset=%x, size=%lx\n",
180  		      load_ptr, offset, (unsigned long)length);
181  		src = (void *)load_ptr + overhead;
182  	} else {
183  		/* Embedded data */
184  		if (fit_image_get_data(fit, node, &data, &length)) {
185  			puts("Cannot get image data/size\n");
186  			return -ENOENT;
187  		}
188  		debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
189  		      (unsigned long)length);
190  		src = (void *)data;
191  	}
192  
193  #ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
194  	board_fit_image_post_process(&src, &length);
195  #endif
196  
197  	if (IS_ENABLED(CONFIG_SPL_OS_BOOT)	&&
198  	    IS_ENABLED(CONFIG_SPL_GZIP)		&&
199  	    image_comp == IH_COMP_GZIP		&&
200  	    type == IH_TYPE_KERNEL) {
201  		size = length;
202  		if (gunzip((void *)load_addr, CONFIG_SYS_BOOTM_LEN,
203  			   src, &size)) {
204  			puts("Uncompressing error\n");
205  			return -EIO;
206  		}
207  		length = size;
208  	} else {
209  		memcpy((void *)load_addr, src, length);
210  	}
211  
212  	if (image_info) {
213  		image_info->load_addr = load_addr;
214  		image_info->size = length;
215  		image_info->entry_point = fdt_getprop_u32(fit, node, "entry");
216  	}
217  
218  	return 0;
219  }
220  
221  int spl_load_simple_fit(struct spl_image_info *spl_image,
222  			struct spl_load_info *info, ulong sector, void *fit)
223  {
224  	int sectors;
225  	ulong size;
226  	unsigned long count;
227  	struct spl_image_info image_info;
228  	bool boot_os = false;
229  	int node = -1;
230  	int images, ret;
231  	int base_offset, align_len = ARCH_DMA_MINALIGN - 1;
232  	int index = 0;
233  
234  	/*
235  	 * For FIT with external data, figure out where the external images
236  	 * start. This is the base for the data-offset properties in each
237  	 * image.
238  	 */
239  	size = fdt_totalsize(fit);
240  	size = (size + 3) & ~3;
241  	base_offset = (size + 3) & ~3;
242  
243  	/*
244  	 * So far we only have one block of data from the FIT. Read the entire
245  	 * thing, including that first block, placing it so it finishes before
246  	 * where we will load the image.
247  	 *
248  	 * Note that we will load the image such that its first byte will be
249  	 * at the load address. Since that byte may be part-way through a
250  	 * block, we may load the image up to one block before the load
251  	 * address. So take account of that here by subtracting an addition
252  	 * block length from the FIT start position.
253  	 *
254  	 * In fact the FIT has its own load address, but we assume it cannot
255  	 * be before CONFIG_SYS_TEXT_BASE.
256  	 *
257  	 * For FIT with data embedded, data is loaded as part of FIT image.
258  	 * For FIT with external data, data is not loaded in this step.
259  	 */
260  	fit = (void *)((CONFIG_SYS_TEXT_BASE - size - info->bl_len -
261  			align_len) & ~align_len);
262  	sectors = get_aligned_image_size(info, size, 0);
263  	count = info->read(info, sector, sectors, fit);
264  	debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n",
265  	      sector, sectors, fit, count);
266  	if (count == 0)
267  		return -EIO;
268  
269  	/* find the node holding the images information */
270  	images = fdt_path_offset(fit, FIT_IMAGES_PATH);
271  	if (images < 0) {
272  		debug("%s: Cannot find /images node: %d\n", __func__, images);
273  		return -1;
274  	}
275  
276  #ifdef CONFIG_SPL_OS_BOOT
277  	/* Find OS image first */
278  	node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0);
279  	if (node < 0)
280  		debug("No kernel image.\n");
281  	else
282  		boot_os = true;
283  #endif
284  	/* find the U-Boot image */
285  	if (node < 0)
286  		node = spl_fit_get_image_node(fit, images, "firmware", 0);
287  	if (node < 0) {
288  		debug("could not find firmware image, trying loadables...\n");
289  		node = spl_fit_get_image_node(fit, images, "loadables", 0);
290  		/*
291  		 * If we pick the U-Boot image from "loadables", start at
292  		 * the second image when later loading additional images.
293  		 */
294  		index = 1;
295  	}
296  	if (node < 0) {
297  		debug("%s: Cannot find u-boot image node: %d\n",
298  		      __func__, node);
299  		return -1;
300  	}
301  
302  	/* Load the image and set up the spl_image structure */
303  	ret = spl_load_fit_image(info, sector, fit, base_offset, node,
304  				 spl_image);
305  	if (ret)
306  		return ret;
307  
308  #ifdef CONFIG_SPL_OS_BOOT
309  	if (!fit_image_get_os(fit, node, &spl_image->os))
310  		debug("Image OS is %s\n", genimg_get_os_name(spl_image->os));
311  #else
312  	spl_image->os = IH_OS_U_BOOT;
313  #endif
314  
315  	if (!boot_os) {
316  		/* Figure out which device tree the board wants to use */
317  		node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0);
318  		if (node < 0) {
319  			debug("%s: cannot find FDT node\n", __func__);
320  			return node;
321  		}
322  
323  		/*
324  		 * Read the device tree and place it after the image.
325  		 * Align the destination address to ARCH_DMA_MINALIGN.
326  		 */
327  		image_info.load_addr = spl_image->load_addr + spl_image->size;
328  		ret = spl_load_fit_image(info, sector, fit, base_offset, node,
329  					 &image_info);
330  		if (ret < 0)
331  			return ret;
332  	}
333  
334  	/* Now check if there are more images for us to load */
335  	for (; ; index++) {
336  		node = spl_fit_get_image_node(fit, images, "loadables", index);
337  		if (node < 0)
338  			break;
339  
340  		ret = spl_load_fit_image(info, sector, fit, base_offset, node,
341  					 &image_info);
342  		if (ret < 0)
343  			continue;
344  
345  		/*
346  		 * If the "firmware" image did not provide an entry point,
347  		 * use the first valid entry point from the loadables.
348  		 */
349  		if (spl_image->entry_point == FDT_ERROR &&
350  		    image_info.entry_point != FDT_ERROR)
351  			spl_image->entry_point = image_info.entry_point;
352  	}
353  
354  	/*
355  	 * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's
356  	 * Makefile will set it to 0 and it will end up as the entry point
357  	 * here. What it actually means is: use the load address.
358  	 */
359  	if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0)
360  		spl_image->entry_point = spl_image->load_addr;
361  
362  	return 0;
363  }
364