xref: /openbmc/u-boot/tools/fit_image.c (revision 19268834)
1  /*
2   * (C) Copyright 2008 Semihalf
3   *
4   * (C) Copyright 2000-2004
5   * DENX Software Engineering
6   * Wolfgang Denk, wd@denx.de
7   *
8   * Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
9   *		FIT image specific code abstracted from mkimage.c
10   *		some functions added to address abstraction
11   *
12   * All rights reserved.
13   *
14   * SPDX-License-Identifier:	GPL-2.0+
15   */
16  
17  #include "imagetool.h"
18  #include "fit_common.h"
19  #include "mkimage.h"
20  #include <image.h>
21  #include <u-boot/crc.h>
22  
23  static image_header_t header;
24  
25  static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
26  			     const char *tmpfile)
27  {
28  	int tfd, destfd = 0;
29  	void *dest_blob = NULL;
30  	off_t destfd_size = 0;
31  	struct stat sbuf;
32  	void *ptr;
33  	int ret = 0;
34  
35  	tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true);
36  	if (tfd < 0)
37  		return -EIO;
38  
39  	if (params->keydest) {
40  		struct stat dest_sbuf;
41  
42  		destfd = mmap_fdt(params->cmdname, params->keydest, size_inc,
43  				  &dest_blob, &dest_sbuf, false);
44  		if (destfd < 0) {
45  			ret = -EIO;
46  			goto err_keydest;
47  		}
48  		destfd_size = dest_sbuf.st_size;
49  	}
50  
51  	/* for first image creation, add a timestamp at offset 0 i.e., root  */
52  	if (params->datafile)
53  		ret = fit_set_timestamp(ptr, 0, sbuf.st_mtime);
54  
55  	if (!ret) {
56  		ret = fit_add_verification_data(params->keydir, dest_blob, ptr,
57  						params->comment,
58  						params->require_keys);
59  	}
60  
61  	if (dest_blob) {
62  		munmap(dest_blob, destfd_size);
63  		close(destfd);
64  	}
65  
66  err_keydest:
67  	munmap(ptr, sbuf.st_size);
68  	close(tfd);
69  
70  	return ret;
71  }
72  
73  /**
74   * fit_handle_file - main FIT file processing function
75   *
76   * fit_handle_file() runs dtc to convert .its to .itb, includes
77   * binary data, updates timestamp property and calculates hashes.
78   *
79   * datafile  - .its file
80   * imagefile - .itb file
81   *
82   * returns:
83   *     only on success, otherwise calls exit (EXIT_FAILURE);
84   */
85  static int fit_handle_file(struct image_tool_params *params)
86  {
87  	char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
88  	char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
89  	size_t size_inc;
90  	int ret;
91  
92  	/* Flattened Image Tree (FIT) format  handling */
93  	debug ("FIT format handling\n");
94  
95  	/* call dtc to include binary properties into the tmp file */
96  	if (strlen (params->imagefile) +
97  		strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) {
98  		fprintf (stderr, "%s: Image file name (%s) too long, "
99  				"can't create tmpfile",
100  				params->imagefile, params->cmdname);
101  		return (EXIT_FAILURE);
102  	}
103  	sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
104  
105  	/* We either compile the source file, or use the existing FIT image */
106  	if (params->datafile) {
107  		/* dtc -I dts -O dtb -p 500 datafile > tmpfile */
108  		snprintf(cmd, sizeof(cmd), "%s %s %s > %s",
109  			 MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
110  		debug("Trying to execute \"%s\"\n", cmd);
111  	} else {
112  		snprintf(cmd, sizeof(cmd), "cp %s %s",
113  			 params->imagefile, tmpfile);
114  	}
115  	if (system (cmd) == -1) {
116  		fprintf (stderr, "%s: system(%s) failed: %s\n",
117  				params->cmdname, cmd, strerror(errno));
118  		goto err_system;
119  	}
120  
121  	/*
122  	 * Set hashes for images in the blob. Unfortunately we may need more
123  	 * space in either FDT, so keep trying until we succeed.
124  	 *
125  	 * Note: this is pretty inefficient for signing, since we must
126  	 * calculate the signature every time. It would be better to calculate
127  	 * all the data and then store it in a separate step. However, this
128  	 * would be considerably more complex to implement. Generally a few
129  	 * steps of this loop is enough to sign with several keys.
130  	 */
131  	for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) {
132  		ret = fit_add_file_data(params, size_inc, tmpfile);
133  		if (!ret || ret != -ENOSPC)
134  			break;
135  	}
136  
137  	if (ret) {
138  		fprintf(stderr, "%s Can't add hashes to FIT blob\n",
139  			params->cmdname);
140  		goto err_system;
141  	}
142  
143  	if (rename (tmpfile, params->imagefile) == -1) {
144  		fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
145  				params->cmdname, tmpfile, params->imagefile,
146  				strerror (errno));
147  		unlink (tmpfile);
148  		unlink (params->imagefile);
149  		return EXIT_FAILURE;
150  	}
151  	return EXIT_SUCCESS;
152  
153  err_system:
154  	unlink(tmpfile);
155  	return -1;
156  }
157  
158  /**
159   * fit_image_extract - extract a FIT component image
160   * @fit: pointer to the FIT format image header
161   * @image_noffset: offset of the component image node
162   * @file_name: name of the file to store the FIT sub-image
163   *
164   * returns:
165   *     zero in case of success or a negative value if fail.
166   */
167  static int fit_image_extract(
168  	const void *fit,
169  	int image_noffset,
170  	const char *file_name)
171  {
172  	const void *file_data;
173  	size_t file_size = 0;
174  
175  	/* get the "data" property of component at offset "image_noffset" */
176  	fit_image_get_data(fit, image_noffset, &file_data, &file_size);
177  
178  	/* save the "file_data" into the file specified by "file_name" */
179  	return imagetool_save_subimage(file_name, (ulong) file_data, file_size);
180  }
181  
182  /**
183   * fit_extract_contents - retrieve a sub-image component from the FIT image
184   * @ptr: pointer to the FIT format image header
185   * @params: command line parameters
186   *
187   * returns:
188   *     zero in case of success or a negative value if fail.
189   */
190  static int fit_extract_contents(void *ptr, struct image_tool_params *params)
191  {
192  	int images_noffset;
193  	int noffset;
194  	int ndepth;
195  	const void *fit = ptr;
196  	int count = 0;
197  	const char *p;
198  
199  	/* Indent string is defined in header image.h */
200  	p = IMAGE_INDENT_STRING;
201  
202  	if (!fit_check_format(fit)) {
203  		printf("Bad FIT image format\n");
204  		return -1;
205  	}
206  
207  	/* Find images parent node offset */
208  	images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
209  	if (images_noffset < 0) {
210  		printf("Can't find images parent node '%s' (%s)\n",
211  		       FIT_IMAGES_PATH, fdt_strerror(images_noffset));
212  		return -1;
213  	}
214  
215  	/* Avoid any overrun */
216  	count = fit_get_subimage_count(fit, images_noffset);
217  	if ((params->pflag < 0) || (count <= params->pflag)) {
218  		printf("No such component at '%d'\n", params->pflag);
219  		return -1;
220  	}
221  
222  	/* Process its subnodes, extract the desired component from image */
223  	for (ndepth = 0, count = 0,
224  		noffset = fdt_next_node(fit, images_noffset, &ndepth);
225  		(noffset >= 0) && (ndepth > 0);
226  		noffset = fdt_next_node(fit, noffset, &ndepth)) {
227  		if (ndepth == 1) {
228  			/*
229  			 * Direct child node of the images parent node,
230  			 * i.e. component image node.
231  			 */
232  			if (params->pflag == count) {
233  				printf("Extracted:\n%s Image %u (%s)\n", p,
234  				       count, fit_get_name(fit, noffset, NULL));
235  
236  				fit_image_print(fit, noffset, p);
237  
238  				return fit_image_extract(fit, noffset,
239  						params->outfile);
240  			}
241  
242  			count++;
243  		}
244  	}
245  
246  	return 0;
247  }
248  
249  static int fit_check_params(struct image_tool_params *params)
250  {
251  	return	((params->dflag && (params->fflag || params->lflag)) ||
252  		(params->fflag && (params->dflag || params->lflag)) ||
253  		(params->lflag && (params->dflag || params->fflag)));
254  }
255  
256  U_BOOT_IMAGE_TYPE(
257  	fitimage,
258  	"FIT Image support",
259  	sizeof(image_header_t),
260  	(void *)&header,
261  	fit_check_params,
262  	fit_verify_header,
263  	fit_print_contents,
264  	NULL,
265  	fit_extract_contents,
266  	fit_check_image_types,
267  	fit_handle_file,
268  	NULL /* FIT images use DTB header */
269  );
270