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