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