xref: /rk3399_rockchip-uboot/tools/fit_image.c (revision 827e2ae92e2103f82dab5b54228ad24e40db6263)
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 <stdarg.h>
22 #include <version.h>
23 #include <u-boot/crc.h>
24 
25 static image_header_t header;
26 
27 #define ALIGN(x, a)	(((x) + (a) - 1) & ~((a) - 1))
28 
29 /* Resize the fdt to its actual size + a bit of padding */
30 static int fdt_shrink_to_minimum(void *blob, uint extrasize)
31 {
32 	uint64_t addr, size;
33 	uint actualsize;
34 	int total, ret;
35 	int i;
36 
37 	if (!blob)
38 		return 0;
39 
40 	total = fdt_num_mem_rsv(blob);
41 	for (i = 0; i < total; i++) {
42 		fdt_get_mem_rsv(blob, i, &addr, &size);
43 		if (addr == (uintptr_t)blob) {
44 			fdt_del_mem_rsv(blob, i);
45 			break;
46 		}
47 	}
48 
49 	/*
50 	 * Calculate the actual size of the fdt
51 	 * plus the size needed for 5 fdt_add_mem_rsv, one
52 	 * for the fdt itself and 4 for a possible initrd
53 	 * ((initrd-start + initrd-end) * 2 (name & value))
54 	 */
55 	actualsize = fdt_off_dt_strings(blob) +
56 		fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry);
57 
58 	actualsize += extrasize;
59 	actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x200);
60 	actualsize = actualsize - ((uintptr_t)blob & 0xfff);
61 
62 	/* Change the fdt header to reflect the correct size */
63 	fdt_set_totalsize(blob, actualsize);
64 
65 	/* Add the new reservation */
66 	ret = fdt_add_mem_rsv(blob, (uintptr_t)blob, actualsize);
67 	if (ret < 0)
68 		return ret;
69 
70 	return actualsize;
71 }
72 
73 static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
74 			     const char *tmpfile)
75 {
76 	int tfd, destfd = 0;
77 	void *dest_blob = NULL;
78 	off_t destfd_size = 0;
79 	struct stat sbuf;
80 	void *ptr;
81 	int ret = 0;
82 
83 	tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true);
84 	if (tfd < 0)
85 		return -EIO;
86 
87 	if (params->keydest) {
88 		struct stat dest_sbuf;
89 
90 		destfd = mmap_fdt(params->cmdname, params->keydest, size_inc,
91 				  &dest_blob, &dest_sbuf, false);
92 		if (destfd < 0) {
93 			ret = -EIO;
94 			goto err_keydest;
95 		}
96 		destfd_size = dest_sbuf.st_size;
97 	}
98 
99 	/* for first image creation, add a timestamp at offset 0 i.e., root  */
100 	if (params->datafile) {
101 		time_t time = imagetool_get_source_date(params, sbuf.st_mtime);
102 		ret  = fit_set_timestamp(ptr, 0, time);
103 		ret |= fit_set_totalsize(ptr, 0, sbuf.st_size);
104 	}
105 
106 	if (!ret) {
107 		ret = fit_add_verification_data(params->keydir, dest_blob, ptr,
108 						params->comment,
109 						params->require_keys,
110 						params->engine_id);
111 	}
112 
113 	/* Remove external data size from fdt totalsize */
114 	if (params->external_offset) {
115 		fdt_shrink_to_minimum(ptr, 0);
116 		if (params->external_offset < fdt_totalsize(ptr)) {
117 			ret = -EINVAL;
118 			printf("Failed: external offset 0x%x overlaps FIT length 0x%x\n",
119 			       params->external_offset, fdt_totalsize(ptr));
120 		}
121 	}
122 
123 	if (dest_blob) {
124 		munmap(dest_blob, destfd_size);
125 		close(destfd);
126 	}
127 
128 err_keydest:
129 	munmap(ptr, sbuf.st_size);
130 	close(tfd);
131 
132 	return ret;
133 }
134 
135 /**
136  * fit_calc_size() - Calculate the approximate size of the FIT we will generate
137  */
138 static int fit_calc_size(struct image_tool_params *params)
139 {
140 	struct content_info *cont;
141 	int size, total_size;
142 
143 	size = imagetool_get_filesize(params, params->datafile);
144 	if (size < 0)
145 		return -1;
146 	total_size = size;
147 
148 	if (params->fit_ramdisk) {
149 		size = imagetool_get_filesize(params, params->fit_ramdisk);
150 		if (size < 0)
151 			return -1;
152 		total_size += size;
153 	}
154 
155 	for (cont = params->content_head; cont; cont = cont->next) {
156 		size = imagetool_get_filesize(params, cont->fname);
157 		if (size < 0)
158 			return -1;
159 
160 		/* Add space for properties */
161 		total_size += size + 300;
162 	}
163 
164 	/* Add plenty of space for headers, properties, nodes, etc. */
165 	total_size += 4096;
166 
167 	return total_size;
168 }
169 
170 static int fdt_property_file(struct image_tool_params *params,
171 			     void *fdt, const char *name, const char *fname)
172 {
173 	struct stat sbuf;
174 	void *ptr;
175 	int ret;
176 	int fd;
177 
178 	fd = open(fname, O_RDWR | O_BINARY);
179 	if (fd < 0) {
180 		fprintf(stderr, "%s: Can't open %s: %s\n",
181 			params->cmdname, fname, strerror(errno));
182 		return -1;
183 	}
184 
185 	if (fstat(fd, &sbuf) < 0) {
186 		fprintf(stderr, "%s: Can't stat %s: %s\n",
187 			params->cmdname, fname, strerror(errno));
188 		goto err;
189 	}
190 
191 	ret = fdt_property_placeholder(fdt, "data", sbuf.st_size, &ptr);
192 	if (ret)
193 		goto err;
194 	ret = read(fd, ptr, sbuf.st_size);
195 	if (ret != sbuf.st_size) {
196 		fprintf(stderr, "%s: Can't read %s: %s\n",
197 			params->cmdname, fname, strerror(errno));
198 		goto err;
199 	}
200 	close(fd);
201 
202 	return 0;
203 err:
204 	close(fd);
205 	return -1;
206 }
207 
208 static int fdt_property_strf(void *fdt, const char *name, const char *fmt, ...)
209 {
210 	char str[100];
211 	va_list ptr;
212 
213 	va_start(ptr, fmt);
214 	vsnprintf(str, sizeof(str), fmt, ptr);
215 	va_end(ptr);
216 	return fdt_property_string(fdt, name, str);
217 }
218 
219 static void get_basename(char *str, int size, const char *fname)
220 {
221 	const char *p, *start, *end;
222 	int len;
223 
224 	/*
225 	 * Use the base name as the 'name' field. So for example:
226 	 *
227 	 * "arch/arm/dts/sun7i-a20-bananapro.dtb"
228 	 * becomes "sun7i-a20-bananapro"
229 	 */
230 	p = strrchr(fname, '/');
231 	start = p ? p + 1 : fname;
232 	p = strrchr(fname, '.');
233 	end = p ? p : fname + strlen(fname);
234 	len = end - start;
235 	if (len >= size)
236 		len = size - 1;
237 	memcpy(str, start, len);
238 	str[len] = '\0';
239 }
240 
241 /**
242  * fit_write_images() - Write out a list of images to the FIT
243  *
244  * We always include the main image (params->datafile). If there are device
245  * tree files, we include an fdt@ node for each of those too.
246  */
247 static int fit_write_images(struct image_tool_params *params, char *fdt)
248 {
249 	struct content_info *cont;
250 	const char *typename;
251 	char str[100];
252 	int upto;
253 	int ret;
254 
255 	fdt_begin_node(fdt, "images");
256 
257 	/* First the main image */
258 	typename = genimg_get_type_short_name(params->fit_image_type);
259 	snprintf(str, sizeof(str), "%s@1", typename);
260 	fdt_begin_node(fdt, str);
261 	fdt_property_string(fdt, "description", params->imagename);
262 	fdt_property_string(fdt, "type", typename);
263 	fdt_property_string(fdt, "arch",
264 			    genimg_get_arch_short_name(params->arch));
265 	fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os));
266 	fdt_property_string(fdt, "compression",
267 			    genimg_get_comp_short_name(params->comp));
268 	fdt_property_u32(fdt, "load", params->addr);
269 	fdt_property_u32(fdt, "entry", params->ep);
270 
271 	/*
272 	 * Put data last since it is large. SPL may only load the first part
273 	 * of the DT, so this way it can access all the above fields.
274 	 */
275 	ret = fdt_property_file(params, fdt, "data", params->datafile);
276 	if (ret)
277 		return ret;
278 	fdt_end_node(fdt);
279 
280 	/* Now the device tree files if available */
281 	upto = 0;
282 	for (cont = params->content_head; cont; cont = cont->next) {
283 		if (cont->type != IH_TYPE_FLATDT)
284 			continue;
285 		snprintf(str, sizeof(str), "%s@%d", FIT_FDT_PROP, ++upto);
286 		fdt_begin_node(fdt, str);
287 
288 		get_basename(str, sizeof(str), cont->fname);
289 		fdt_property_string(fdt, "description", str);
290 		ret = fdt_property_file(params, fdt, "data", cont->fname);
291 		if (ret)
292 			return ret;
293 		fdt_property_string(fdt, "type", typename);
294 		fdt_property_string(fdt, "arch",
295 				    genimg_get_arch_short_name(params->arch));
296 		fdt_property_string(fdt, "compression",
297 				    genimg_get_comp_short_name(IH_COMP_NONE));
298 		fdt_end_node(fdt);
299 	}
300 
301 	/* And a ramdisk file if available */
302 	if (params->fit_ramdisk) {
303 		fdt_begin_node(fdt, FIT_RAMDISK_PROP "@1");
304 
305 		fdt_property_string(fdt, "type", FIT_RAMDISK_PROP);
306 		fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os));
307 
308 		ret = fdt_property_file(params, fdt, "data", params->fit_ramdisk);
309 		if (ret)
310 			return ret;
311 
312 		fdt_end_node(fdt);
313 	}
314 
315 	fdt_end_node(fdt);
316 
317 	return 0;
318 }
319 
320 /**
321  * fit_write_configs() - Write out a list of configurations to the FIT
322  *
323  * If there are device tree files, we include a configuration for each, which
324  * selects the main image (params->datafile) and its corresponding device
325  * tree file.
326  *
327  * Otherwise we just create a configuration with the main image in it.
328  */
329 static void fit_write_configs(struct image_tool_params *params, char *fdt)
330 {
331 	struct content_info *cont;
332 	const char *typename;
333 	char str[100];
334 	int upto;
335 
336 	fdt_begin_node(fdt, "configurations");
337 	fdt_property_string(fdt, "default", "conf@1");
338 
339 	upto = 0;
340 	for (cont = params->content_head; cont; cont = cont->next) {
341 		if (cont->type != IH_TYPE_FLATDT)
342 			continue;
343 		typename = genimg_get_type_short_name(cont->type);
344 		snprintf(str, sizeof(str), "conf@%d", ++upto);
345 		fdt_begin_node(fdt, str);
346 
347 		get_basename(str, sizeof(str), cont->fname);
348 		fdt_property_string(fdt, "description", str);
349 
350 		typename = genimg_get_type_short_name(params->fit_image_type);
351 		snprintf(str, sizeof(str), "%s@1", typename);
352 		fdt_property_string(fdt, typename, str);
353 
354 		if (params->fit_ramdisk)
355 			fdt_property_string(fdt, FIT_RAMDISK_PROP,
356 					    FIT_RAMDISK_PROP "@1");
357 
358 		snprintf(str, sizeof(str), FIT_FDT_PROP "@%d", upto);
359 		fdt_property_string(fdt, FIT_FDT_PROP, str);
360 		fdt_end_node(fdt);
361 	}
362 
363 	if (!upto) {
364 		fdt_begin_node(fdt, "conf@1");
365 		typename = genimg_get_type_short_name(params->fit_image_type);
366 		snprintf(str, sizeof(str), "%s@1", typename);
367 		fdt_property_string(fdt, typename, str);
368 
369 		if (params->fit_ramdisk)
370 			fdt_property_string(fdt, FIT_RAMDISK_PROP,
371 					    FIT_RAMDISK_PROP "@1");
372 
373 		fdt_end_node(fdt);
374 	}
375 
376 	fdt_end_node(fdt);
377 }
378 
379 static int fit_build_fdt(struct image_tool_params *params, char *fdt, int size)
380 {
381 	int ret;
382 
383 	ret = fdt_create(fdt, size);
384 	if (ret)
385 		return ret;
386 	fdt_finish_reservemap(fdt);
387 	fdt_begin_node(fdt, "");
388 	fdt_property_strf(fdt, "description",
389 			  "%s image with one or more FDT blobs",
390 			  genimg_get_type_name(params->fit_image_type));
391 	fdt_property_strf(fdt, "creator", "U-Boot mkimage %s", PLAIN_VERSION);
392 	fdt_property_u32(fdt, "#address-cells", 1);
393 	ret = fit_write_images(params, fdt);
394 	if (ret)
395 		return ret;
396 	fit_write_configs(params, fdt);
397 	fdt_end_node(fdt);
398 	ret = fdt_finish(fdt);
399 	if (ret)
400 		return ret;
401 
402 	return fdt_totalsize(fdt);
403 }
404 
405 static int fit_build(struct image_tool_params *params, const char *fname)
406 {
407 	char *buf;
408 	int size;
409 	int ret;
410 	int fd;
411 
412 	size = fit_calc_size(params);
413 	if (size < 0)
414 		return -1;
415 	buf = malloc(size);
416 	if (!buf) {
417 		fprintf(stderr, "%s: Out of memory (%d bytes)\n",
418 			params->cmdname, size);
419 		return -1;
420 	}
421 	ret = fit_build_fdt(params, buf, size);
422 	if (ret < 0) {
423 		fprintf(stderr, "%s: Failed to build FIT image\n",
424 			params->cmdname);
425 		goto err_buf;
426 	}
427 	size = ret;
428 	fd = open(fname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666);
429 	if (fd < 0) {
430 		fprintf(stderr, "%s: Can't open %s: %s\n",
431 			params->cmdname, fname, strerror(errno));
432 		goto err_buf;
433 	}
434 	ret = write(fd, buf, size);
435 	if (ret != size) {
436 		fprintf(stderr, "%s: Can't write %s: %s\n",
437 			params->cmdname, fname, strerror(errno));
438 		goto err;
439 	}
440 	close(fd);
441 	free(buf);
442 
443 	return 0;
444 err:
445 	close(fd);
446 err_buf:
447 	free(buf);
448 	return -1;
449 }
450 
451 /**
452  * fit_extract_data() - Move all data outside the FIT
453  *
454  * This takes a normal FIT file and removes all the 'data' properties from it.
455  * The data is placed in an area after the FIT so that it can be accessed
456  * using an offset into that area. The 'data' properties turn into
457  * 'data-offset' properties.
458  *
459  * This function cannot cope with FITs with 'data-offset' properties. All
460  * data must be in 'data' properties on entry.
461  */
462 static int fit_extract_data(struct image_tool_params *params, const char *fname)
463 {
464 	void *buf;
465 	int buf_ptr;
466 	int fit_size, new_size;
467 	int fd;
468 	struct stat sbuf;
469 	void *fdt;
470 	int ret;
471 	int images;
472 	int node;
473 
474 	fd = mmap_fdt(params->cmdname, fname, 0x400, &fdt, &sbuf, false);
475 	if (fd < 0)
476 		return -EIO;
477 	fit_size = fdt_totalsize(fdt);
478 
479 	/* Allocate space to hold the image data we will extract */
480 	buf = malloc(fit_size);
481 	if (!buf) {
482 		ret = -ENOMEM;
483 		goto err_munmap;
484 	}
485 	buf_ptr = 0;
486 
487 	images = fdt_path_offset(fdt, FIT_IMAGES_PATH);
488 	if (images < 0) {
489 		debug("%s: Cannot find /images node: %d\n", __func__, images);
490 		ret = -EINVAL;
491 		goto err_munmap;
492 	}
493 
494 	for (node = fdt_first_subnode(fdt, images);
495 	     node >= 0;
496 	     node = fdt_next_subnode(fdt, node)) {
497 		const char *data;
498 		int len;
499 
500 		data = fdt_getprop(fdt, node, "data", &len);
501 		if (!data)
502 			continue;
503 		memcpy(buf + buf_ptr, data, len);
504 		debug("Extracting data size %x\n", len);
505 
506 		ret = fdt_delprop(fdt, node, "data");
507 		if (ret) {
508 			ret = -EPERM;
509 			goto err_munmap;
510 		}
511 		if (params->external_offset > 0) {
512 			/* An external offset positions the data absolutely. */
513 			fdt_setprop_u32(fdt, node, "data-position",
514 					params->external_offset + buf_ptr);
515 		} else {
516 			fdt_setprop_u32(fdt, node, "data-offset", buf_ptr);
517 		}
518 		fdt_setprop_u32(fdt, node, "data-size", len);
519 
520 		buf_ptr += FIT_ALIGN(len);
521 	}
522 
523 	/* Pack the FDT and place the data after it */
524 	fdt_pack(fdt);
525 
526 	debug("Size reduced from %x to %x\n", fit_size, fdt_totalsize(fdt));
527 	debug("External data size %x\n", buf_ptr);
528 	new_size = fdt_totalsize(fdt);
529 	new_size = FIT_ALIGN(new_size);
530 	munmap(fdt, sbuf.st_size);
531 
532 	if (ftruncate(fd, new_size)) {
533 		debug("%s: Failed to truncate file: %s\n", __func__,
534 		      strerror(errno));
535 		ret = -EIO;
536 		goto err;
537 	}
538 
539 	/* Check if an offset for the external data was set. */
540 	if (params->external_offset > 0) {
541 		if (params->external_offset < new_size) {
542 			printf("Failed: external offset 0x%x overlaps FIT length 0x%x\n",
543 			       params->external_offset, new_size);
544 			ret = -EINVAL;
545 			goto err;
546 		}
547 		new_size = params->external_offset;
548 	}
549 	if (lseek(fd, new_size, SEEK_SET) < 0) {
550 		debug("%s: Failed to seek to end of file: %s\n", __func__,
551 		      strerror(errno));
552 		ret = -EIO;
553 		goto err;
554 	}
555 	if (write(fd, buf, buf_ptr) != buf_ptr) {
556 		debug("%s: Failed to write external data to file %s\n",
557 		      __func__, strerror(errno));
558 		ret = -EIO;
559 		goto err;
560 	}
561 	free(buf);
562 	close(fd);
563 	return 0;
564 
565 err_munmap:
566 	munmap(fdt, sbuf.st_size);
567 err:
568 	if (buf)
569 		free(buf);
570 	close(fd);
571 	return ret;
572 }
573 
574 static int fit_import_data(struct image_tool_params *params, const char *fname)
575 {
576 	void *fdt, *old_fdt;
577 	int fit_size, new_size, size, data_base;
578 	int fd;
579 	struct stat sbuf;
580 	int ret;
581 	int images;
582 	int node;
583 
584 	fd = mmap_fdt(params->cmdname, fname, 0, &old_fdt, &sbuf, false);
585 	if (fd < 0)
586 		return -EIO;
587 	fit_size = fdt_totalsize(old_fdt);
588 	data_base = FIT_ALIGN(fit_size);
589 
590 	/* Allocate space to hold the new FIT */
591 	size = sbuf.st_size + 16384;
592 	fdt = malloc(size);
593 	if (!fdt) {
594 		fprintf(stderr, "%s: Failed to allocate memory (%d bytes)\n",
595 			__func__, size);
596 		ret = -ENOMEM;
597 		goto err_has_fd;
598 	}
599 	ret = fdt_open_into(old_fdt, fdt, size);
600 	if (ret) {
601 		debug("%s: Failed to expand FIT: %s\n", __func__,
602 		      fdt_strerror(errno));
603 		ret = -EINVAL;
604 		goto err_has_fd;
605 	}
606 
607 	images = fdt_path_offset(fdt, FIT_IMAGES_PATH);
608 	if (images < 0) {
609 		debug("%s: Cannot find /images node: %d\n", __func__, images);
610 		ret = -EINVAL;
611 		goto err_has_fd;
612 	}
613 
614 	for (node = fdt_first_subnode(fdt, images);
615 	     node >= 0;
616 	     node = fdt_next_subnode(fdt, node)) {
617 		int buf_ptr;
618 		int len;
619 
620 		buf_ptr = fdtdec_get_int(fdt, node, "data-offset", -1);
621 		len = fdtdec_get_int(fdt, node, "data-size", -1);
622 		if (buf_ptr == -1 || len == -1)
623 			continue;
624 		debug("Importing data size %x\n", len);
625 
626 		ret = fdt_setprop(fdt, node, "data", fdt + data_base + buf_ptr,
627 				  len);
628 		if (ret) {
629 			debug("%s: Failed to write property: %s\n", __func__,
630 			      fdt_strerror(ret));
631 			ret = -EINVAL;
632 			goto err_has_fd;
633 		}
634 	}
635 
636 	/* Close the old fd so we can re-use it. */
637 	close(fd);
638 
639 	/* Pack the FDT and place the data after it */
640 	fdt_pack(fdt);
641 
642 	new_size = fdt_totalsize(fdt);
643 	debug("Size expanded from %x to %x\n", fit_size, new_size);
644 
645 	fd = open(fname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666);
646 	if (fd < 0) {
647 		fprintf(stderr, "%s: Can't open %s: %s\n",
648 			params->cmdname, fname, strerror(errno));
649 		ret = -EIO;
650 		goto err_no_fd;
651 	}
652 	if (write(fd, fdt, new_size) != new_size) {
653 		debug("%s: Failed to write external data to file %s\n",
654 		      __func__, strerror(errno));
655 		ret = -EIO;
656 		goto err_has_fd;
657 	}
658 
659 	ret = 0;
660 
661 err_has_fd:
662 	close(fd);
663 err_no_fd:
664 	munmap(old_fdt, sbuf.st_size);
665 	free(fdt);
666 	return ret;
667 }
668 
669 /**
670  * fit_handle_file - main FIT file processing function
671  *
672  * fit_handle_file() runs dtc to convert .its to .itb, includes
673  * binary data, updates timestamp property and calculates hashes.
674  *
675  * datafile  - .its file
676  * imagefile - .itb file
677  *
678  * returns:
679  *     only on success, otherwise calls exit (EXIT_FAILURE);
680  */
681 static int fit_handle_file(struct image_tool_params *params)
682 {
683 	char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
684 	char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
685 	size_t size_inc;
686 	int ret;
687 
688 	/* Flattened Image Tree (FIT) format  handling */
689 	debug ("FIT format handling\n");
690 
691 	/* call dtc to include binary properties into the tmp file */
692 	if (strlen (params->imagefile) +
693 		strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) {
694 		fprintf (stderr, "%s: Image file name (%s) too long, "
695 				"can't create tmpfile",
696 				params->imagefile, params->cmdname);
697 		return (EXIT_FAILURE);
698 	}
699 	sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
700 
701 	/* We either compile the source file, or use the existing FIT image */
702 	if (params->auto_its) {
703 		if (fit_build(params, tmpfile)) {
704 			fprintf(stderr, "%s: failed to build FIT\n",
705 				params->cmdname);
706 			return EXIT_FAILURE;
707 		}
708 		*cmd = '\0';
709 	} else if (params->datafile) {
710 		/* dtc -I dts -O dtb -p 500 datafile > tmpfile */
711 		snprintf(cmd, sizeof(cmd), "%s %s \"%s\" > \"%s\"",
712 			 MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
713 		debug("Trying to execute \"%s\"\n", cmd);
714 	} else {
715 		snprintf(cmd, sizeof(cmd), "cp \"%s\" \"%s\"",
716 			 params->imagefile, tmpfile);
717 	}
718 	if (*cmd && system(cmd) == -1) {
719 		fprintf (stderr, "%s: system(%s) failed: %s\n",
720 				params->cmdname, cmd, strerror(errno));
721 		goto err_system;
722 	}
723 
724 	/* Move the data so it is internal to the FIT, if needed */
725 	ret = fit_import_data(params, tmpfile);
726 	if (ret)
727 		goto err_system;
728 
729 	/* Args "-E -p": move the data so it is external to the FIT, if requested */
730 	if (params->external_data && params->external_offset) {
731 		ret = fit_extract_data(params, tmpfile);
732 		if (ret)
733 			goto err_system;
734 	}
735 
736 	/*
737 	 * Set hashes for images in the blob. Unfortunately we may need more
738 	 * space in either FDT, so keep trying until we succeed.
739 	 *
740 	 * Note: this is pretty inefficient for signing, since we must
741 	 * calculate the signature every time. It would be better to calculate
742 	 * all the data and then store it in a separate step. However, this
743 	 * would be considerably more complex to implement. Generally a few
744 	 * steps of this loop is enough to sign with several keys.
745 	 */
746 	for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) {
747 		ret = fit_add_file_data(params, size_inc, tmpfile);
748 		if (!ret || ret != -ENOSPC)
749 			break;
750 	}
751 
752 	if (ret) {
753 		fprintf(stderr, "%s Can't add hashes to FIT blob: %d\n",
754 			params->cmdname, ret);
755 		goto err_system;
756 	}
757 
758 	/* Args "-E": move the data so it is external to the FIT, if requested */
759 	if (params->external_data && !params->external_offset) {
760 		ret = fit_extract_data(params, tmpfile);
761 		if (ret)
762 			goto err_system;
763 	}
764 
765 	if (rename (tmpfile, params->imagefile) == -1) {
766 		fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
767 				params->cmdname, tmpfile, params->imagefile,
768 				strerror (errno));
769 		unlink (tmpfile);
770 		unlink (params->imagefile);
771 		return EXIT_FAILURE;
772 	}
773 	return EXIT_SUCCESS;
774 
775 err_system:
776 	unlink(tmpfile);
777 	return -1;
778 }
779 
780 /**
781  * fit_image_extract - extract a FIT component image
782  * @fit: pointer to the FIT format image header
783  * @image_noffset: offset of the component image node
784  * @file_name: name of the file to store the FIT sub-image
785  *
786  * returns:
787  *     zero in case of success or a negative value if fail.
788  */
789 static int fit_image_extract(
790 	const void *fit,
791 	int image_noffset,
792 	const char *file_name)
793 {
794 	const void *file_data;
795 	size_t file_size = 0;
796 
797 	/* get the "data" property of component at offset "image_noffset" */
798 	fit_image_get_data(fit, image_noffset, &file_data, &file_size);
799 
800 	/* save the "file_data" into the file specified by "file_name" */
801 	return imagetool_save_subimage(file_name, (ulong) file_data, file_size);
802 }
803 
804 /**
805  * fit_extract_contents - retrieve a sub-image component from the FIT image
806  * @ptr: pointer to the FIT format image header
807  * @params: command line parameters
808  *
809  * returns:
810  *     zero in case of success or a negative value if fail.
811  */
812 static int fit_extract_contents(void *ptr, struct image_tool_params *params)
813 {
814 	int images_noffset;
815 	int noffset;
816 	int ndepth;
817 	const void *fit = ptr;
818 	int count = 0;
819 	const char *p;
820 
821 	/* Indent string is defined in header image.h */
822 	p = IMAGE_INDENT_STRING;
823 
824 	if (!fit_check_format(fit)) {
825 		printf("Bad FIT image format\n");
826 		return -1;
827 	}
828 
829 	/* Find images parent node offset */
830 	images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
831 	if (images_noffset < 0) {
832 		printf("Can't find images parent node '%s' (%s)\n",
833 		       FIT_IMAGES_PATH, fdt_strerror(images_noffset));
834 		return -1;
835 	}
836 
837 	/* Avoid any overrun */
838 	count = fit_get_subimage_count(fit, images_noffset);
839 	if ((params->pflag < 0) || (count <= params->pflag)) {
840 		printf("No such component at '%d'\n", params->pflag);
841 		return -1;
842 	}
843 
844 	/* Process its subnodes, extract the desired component from image */
845 	for (ndepth = 0, count = 0,
846 		noffset = fdt_next_node(fit, images_noffset, &ndepth);
847 		(noffset >= 0) && (ndepth > 0);
848 		noffset = fdt_next_node(fit, noffset, &ndepth)) {
849 		if (ndepth == 1) {
850 			/*
851 			 * Direct child node of the images parent node,
852 			 * i.e. component image node.
853 			 */
854 			if (params->pflag == count) {
855 				printf("Extracted:\n%s Image %u (%s)\n", p,
856 				       count, fit_get_name(fit, noffset, NULL));
857 
858 				fit_image_print(fit, noffset, p);
859 
860 				return fit_image_extract(fit, noffset,
861 						params->outfile);
862 			}
863 
864 			count++;
865 		}
866 	}
867 
868 	return 0;
869 }
870 
871 static int fit_check_params(struct image_tool_params *params)
872 {
873 	if (params->auto_its)
874 		return 0;
875 	return	((params->dflag && (params->fflag || params->lflag)) ||
876 		(params->fflag && (params->dflag || params->lflag)) ||
877 		(params->lflag && (params->dflag || params->fflag)));
878 }
879 
880 U_BOOT_IMAGE_TYPE(
881 	fitimage,
882 	"FIT Image support",
883 	sizeof(image_header_t),
884 	(void *)&header,
885 	fit_check_params,
886 	fit_verify_header,
887 	fit_print_contents,
888 	NULL,
889 	fit_extract_contents,
890 	fit_check_image_types,
891 	fit_handle_file,
892 	NULL /* FIT images use DTB header */
893 );
894