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