xref: /openbmc/u-boot/tools/fit_image.c (revision 9c21d06c)
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 static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
28 			     const char *tmpfile)
29 {
30 	int tfd, destfd = 0;
31 	void *dest_blob = NULL;
32 	off_t destfd_size = 0;
33 	struct stat sbuf;
34 	void *ptr;
35 	int ret = 0;
36 
37 	tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true);
38 	if (tfd < 0)
39 		return -EIO;
40 
41 	if (params->keydest) {
42 		struct stat dest_sbuf;
43 
44 		destfd = mmap_fdt(params->cmdname, params->keydest, size_inc,
45 				  &dest_blob, &dest_sbuf, false);
46 		if (destfd < 0) {
47 			ret = -EIO;
48 			goto err_keydest;
49 		}
50 		destfd_size = dest_sbuf.st_size;
51 	}
52 
53 	/* for first image creation, add a timestamp at offset 0 i.e., root  */
54 	if (params->datafile) {
55 		time_t time = imagetool_get_source_date(params, sbuf.st_mtime);
56 		ret = fit_set_timestamp(ptr, 0, time);
57 	}
58 
59 	if (!ret) {
60 		ret = fit_add_verification_data(params->keydir, dest_blob, ptr,
61 						params->comment,
62 						params->require_keys);
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;
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 	close(fd);
504 	return 0;
505 
506 err_munmap:
507 	munmap(fdt, sbuf.st_size);
508 err:
509 	if (buf)
510 		free(buf);
511 	close(fd);
512 	return ret;
513 }
514 
515 static int fit_import_data(struct image_tool_params *params, const char *fname)
516 {
517 	void *fdt, *old_fdt;
518 	int fit_size, new_size, size, data_base;
519 	int fd;
520 	struct stat sbuf;
521 	int ret;
522 	int images;
523 	int node;
524 
525 	fd = mmap_fdt(params->cmdname, fname, 0, &old_fdt, &sbuf, false);
526 	if (fd < 0)
527 		return -EIO;
528 	fit_size = fdt_totalsize(old_fdt);
529 	data_base = (fit_size + 3) & ~3;
530 
531 	/* Allocate space to hold the new FIT */
532 	size = sbuf.st_size + 16384;
533 	fdt = malloc(size);
534 	if (!fdt) {
535 		fprintf(stderr, "%s: Failed to allocate memory (%d bytes)\n",
536 			__func__, size);
537 		ret = -ENOMEM;
538 		goto err;
539 	}
540 	ret = fdt_open_into(old_fdt, fdt, size);
541 	if (ret) {
542 		debug("%s: Failed to expand FIT: %s\n", __func__,
543 		      fdt_strerror(errno));
544 		ret = -EINVAL;
545 		goto err;
546 	}
547 
548 	images = fdt_path_offset(fdt, FIT_IMAGES_PATH);
549 	if (images < 0) {
550 		debug("%s: Cannot find /images node: %d\n", __func__, images);
551 		ret = -EINVAL;
552 		goto err;
553 	}
554 
555 	for (node = fdt_first_subnode(fdt, images);
556 	     node >= 0;
557 	     node = fdt_next_subnode(fdt, node)) {
558 		int buf_ptr;
559 		int len;
560 
561 		buf_ptr = fdtdec_get_int(fdt, node, "data-offset", -1);
562 		len = fdtdec_get_int(fdt, node, "data-size", -1);
563 		if (buf_ptr == -1 || len == -1)
564 			continue;
565 		debug("Importing data size %x\n", len);
566 
567 		ret = fdt_setprop(fdt, node, "data", fdt + data_base + buf_ptr,
568 				  len);
569 		if (ret) {
570 			debug("%s: Failed to write property: %s\n", __func__,
571 			      fdt_strerror(ret));
572 			ret = -EINVAL;
573 			goto err;
574 		}
575 	}
576 
577 	munmap(old_fdt, sbuf.st_size);
578 	close(fd);
579 
580 	/* Pack the FDT and place the data after it */
581 	fdt_pack(fdt);
582 
583 	new_size = fdt_totalsize(fdt);
584 	debug("Size expanded from %x to %x\n", fit_size, new_size);
585 
586 	fd = open(fname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666);
587 	if (fd < 0) {
588 		fprintf(stderr, "%s: Can't open %s: %s\n",
589 			params->cmdname, fname, strerror(errno));
590 		free(fdt);
591 		return -EIO;
592 	}
593 	if (write(fd, fdt, new_size) != new_size) {
594 		debug("%s: Failed to write external data to file %s\n",
595 		      __func__, strerror(errno));
596 		ret = -EIO;
597 		goto err;
598 	}
599 
600 	ret = 0;
601 
602 err:
603 	free(fdt);
604 	close(fd);
605 	return ret;
606 }
607 
608 /**
609  * fit_handle_file - main FIT file processing function
610  *
611  * fit_handle_file() runs dtc to convert .its to .itb, includes
612  * binary data, updates timestamp property and calculates hashes.
613  *
614  * datafile  - .its file
615  * imagefile - .itb file
616  *
617  * returns:
618  *     only on success, otherwise calls exit (EXIT_FAILURE);
619  */
620 static int fit_handle_file(struct image_tool_params *params)
621 {
622 	char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
623 	char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
624 	size_t size_inc;
625 	int ret;
626 
627 	/* Flattened Image Tree (FIT) format  handling */
628 	debug ("FIT format handling\n");
629 
630 	/* call dtc to include binary properties into the tmp file */
631 	if (strlen (params->imagefile) +
632 		strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) {
633 		fprintf (stderr, "%s: Image file name (%s) too long, "
634 				"can't create tmpfile",
635 				params->imagefile, params->cmdname);
636 		return (EXIT_FAILURE);
637 	}
638 	sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
639 
640 	/* We either compile the source file, or use the existing FIT image */
641 	if (params->auto_its) {
642 		if (fit_build(params, tmpfile)) {
643 			fprintf(stderr, "%s: failed to build FIT\n",
644 				params->cmdname);
645 			return EXIT_FAILURE;
646 		}
647 		*cmd = '\0';
648 	} else if (params->datafile) {
649 		/* dtc -I dts -O dtb -p 500 datafile > tmpfile */
650 		snprintf(cmd, sizeof(cmd), "%s %s %s > %s",
651 			 MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
652 		debug("Trying to execute \"%s\"\n", cmd);
653 	} else {
654 		snprintf(cmd, sizeof(cmd), "cp %s %s",
655 			 params->imagefile, tmpfile);
656 	}
657 	if (*cmd && system(cmd) == -1) {
658 		fprintf (stderr, "%s: system(%s) failed: %s\n",
659 				params->cmdname, cmd, strerror(errno));
660 		goto err_system;
661 	}
662 
663 	/* Move the data so it is internal to the FIT, if needed */
664 	ret = fit_import_data(params, tmpfile);
665 	if (ret)
666 		goto err_system;
667 
668 	/*
669 	 * Set hashes for images in the blob. Unfortunately we may need more
670 	 * space in either FDT, so keep trying until we succeed.
671 	 *
672 	 * Note: this is pretty inefficient for signing, since we must
673 	 * calculate the signature every time. It would be better to calculate
674 	 * all the data and then store it in a separate step. However, this
675 	 * would be considerably more complex to implement. Generally a few
676 	 * steps of this loop is enough to sign with several keys.
677 	 */
678 	for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) {
679 		ret = fit_add_file_data(params, size_inc, tmpfile);
680 		if (!ret || ret != -ENOSPC)
681 			break;
682 	}
683 
684 	if (ret) {
685 		fprintf(stderr, "%s Can't add hashes to FIT blob: %d\n",
686 			params->cmdname, ret);
687 		goto err_system;
688 	}
689 
690 	/* Move the data so it is external to the FIT, if requested */
691 	if (params->external_data) {
692 		ret = fit_extract_data(params, tmpfile);
693 		if (ret)
694 			goto err_system;
695 	}
696 
697 	if (rename (tmpfile, params->imagefile) == -1) {
698 		fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
699 				params->cmdname, tmpfile, params->imagefile,
700 				strerror (errno));
701 		unlink (tmpfile);
702 		unlink (params->imagefile);
703 		return EXIT_FAILURE;
704 	}
705 	return EXIT_SUCCESS;
706 
707 err_system:
708 	unlink(tmpfile);
709 	return -1;
710 }
711 
712 /**
713  * fit_image_extract - extract a FIT component image
714  * @fit: pointer to the FIT format image header
715  * @image_noffset: offset of the component image node
716  * @file_name: name of the file to store the FIT sub-image
717  *
718  * returns:
719  *     zero in case of success or a negative value if fail.
720  */
721 static int fit_image_extract(
722 	const void *fit,
723 	int image_noffset,
724 	const char *file_name)
725 {
726 	const void *file_data;
727 	size_t file_size = 0;
728 
729 	/* get the "data" property of component at offset "image_noffset" */
730 	fit_image_get_data(fit, image_noffset, &file_data, &file_size);
731 
732 	/* save the "file_data" into the file specified by "file_name" */
733 	return imagetool_save_subimage(file_name, (ulong) file_data, file_size);
734 }
735 
736 /**
737  * fit_extract_contents - retrieve a sub-image component from the FIT image
738  * @ptr: pointer to the FIT format image header
739  * @params: command line parameters
740  *
741  * returns:
742  *     zero in case of success or a negative value if fail.
743  */
744 static int fit_extract_contents(void *ptr, struct image_tool_params *params)
745 {
746 	int images_noffset;
747 	int noffset;
748 	int ndepth;
749 	const void *fit = ptr;
750 	int count = 0;
751 	const char *p;
752 
753 	/* Indent string is defined in header image.h */
754 	p = IMAGE_INDENT_STRING;
755 
756 	if (!fit_check_format(fit)) {
757 		printf("Bad FIT image format\n");
758 		return -1;
759 	}
760 
761 	/* Find images parent node offset */
762 	images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
763 	if (images_noffset < 0) {
764 		printf("Can't find images parent node '%s' (%s)\n",
765 		       FIT_IMAGES_PATH, fdt_strerror(images_noffset));
766 		return -1;
767 	}
768 
769 	/* Avoid any overrun */
770 	count = fit_get_subimage_count(fit, images_noffset);
771 	if ((params->pflag < 0) || (count <= params->pflag)) {
772 		printf("No such component at '%d'\n", params->pflag);
773 		return -1;
774 	}
775 
776 	/* Process its subnodes, extract the desired component from image */
777 	for (ndepth = 0, count = 0,
778 		noffset = fdt_next_node(fit, images_noffset, &ndepth);
779 		(noffset >= 0) && (ndepth > 0);
780 		noffset = fdt_next_node(fit, noffset, &ndepth)) {
781 		if (ndepth == 1) {
782 			/*
783 			 * Direct child node of the images parent node,
784 			 * i.e. component image node.
785 			 */
786 			if (params->pflag == count) {
787 				printf("Extracted:\n%s Image %u (%s)\n", p,
788 				       count, fit_get_name(fit, noffset, NULL));
789 
790 				fit_image_print(fit, noffset, p);
791 
792 				return fit_image_extract(fit, noffset,
793 						params->outfile);
794 			}
795 
796 			count++;
797 		}
798 	}
799 
800 	return 0;
801 }
802 
803 static int fit_check_params(struct image_tool_params *params)
804 {
805 	if (params->auto_its)
806 		return 0;
807 	return	((params->dflag && (params->fflag || params->lflag)) ||
808 		(params->fflag && (params->dflag || params->lflag)) ||
809 		(params->lflag && (params->dflag || params->fflag)));
810 }
811 
812 U_BOOT_IMAGE_TYPE(
813 	fitimage,
814 	"FIT Image support",
815 	sizeof(image_header_t),
816 	(void *)&header,
817 	fit_check_params,
818 	fit_verify_header,
819 	fit_print_contents,
820 	NULL,
821 	fit_extract_contents,
822 	fit_check_image_types,
823 	fit_handle_file,
824 	NULL /* FIT images use DTB header */
825 );
826