uboot/tools/mkimage.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 * All rights reserved.
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License as
  11 * published by the Free Software Foundation; either version 2 of
  12 * the License, or (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22 * MA 02111-1307 USA
  23 */
  24
  25#include "mkimage.h"
  26#include <image.h>
  27
  28extern int errno;
  29
  30#ifndef MAP_FAILED
  31#define MAP_FAILED (void *)(-1)
  32#endif
  33
  34extern  unsigned long   crc32 (unsigned long crc, const char *buf, unsigned int len);
  35static  void            copy_file (int, const char *, int);
  36static  void            usage (void);
  37static  void            image_verify_header (char *, int);
  38static  void            fit_handle_file (void);
  39
  40char    *datafile;
  41char    *imagefile;
  42char    *cmdname;
  43
  44int dflag    = 0;
  45int eflag    = 0;
  46int fflag    = 0;
  47int lflag    = 0;
  48int vflag    = 0;
  49int xflag    = 0;
  50int opt_os   = IH_OS_LINUX;
  51int opt_arch = IH_ARCH_PPC;
  52int opt_type = IH_TYPE_KERNEL;
  53int opt_comp = IH_COMP_GZIP;
  54char *opt_dtc = MKIMAGE_DEFAULT_DTC_OPTIONS;
  55
  56image_header_t header;
  57image_header_t *hdr = &header;
  58
  59int
  60main (int argc, char **argv)
  61{
  62        int ifd = -1;
  63        uint32_t checksum;
  64        uint32_t addr;
  65        uint32_t ep;
  66        struct stat sbuf;
  67        unsigned char *ptr;
  68        char *name = "";
  69
  70        cmdname = *argv;
  71
  72        addr = ep = 0;
  73
  74        while (--argc > 0 && **++argv == '-') {
  75                while (*++*argv) {
  76                        switch (**argv) {
  77                        case 'l':
  78                                lflag = 1;
  79                                break;
  80                        case 'A':
  81                                if ((--argc <= 0) ||
  82                                    (opt_arch = genimg_get_arch_id (*++argv)) < 0)
  83                                        usage ();
  84                                goto NXTARG;
  85                        case 'C':
  86                                if ((--argc <= 0) ||
  87                                    (opt_comp = genimg_get_comp_id (*++argv)) < 0)
  88                                        usage ();
  89                                goto NXTARG;
  90                        case 'D':
  91                                if (--argc <= 0)
  92                                        usage ();
  93                                opt_dtc = *++argv;
  94                                goto NXTARG;
  95
  96                        case 'O':
  97                                if ((--argc <= 0) ||
  98                                    (opt_os = genimg_get_os_id (*++argv)) < 0)
  99                                        usage ();
 100                                goto NXTARG;
 101                        case 'T':
 102                                if ((--argc <= 0) ||
 103                                    (opt_type = genimg_get_type_id (*++argv)) < 0)
 104                                        usage ();
 105                                goto NXTARG;
 106
 107                        case 'a':
 108                                if (--argc <= 0)
 109                                        usage ();
 110                                addr = strtoul (*++argv, (char **)&ptr, 16);
 111                                if (*ptr) {
 112                                        fprintf (stderr,
 113                                                "%s: invalid load address %s\n",
 114                                                cmdname, *argv);
 115                                        exit (EXIT_FAILURE);
 116                                }
 117                                goto NXTARG;
 118                        case 'd':
 119                                if (--argc <= 0)
 120                                        usage ();
 121                                datafile = *++argv;
 122                                dflag = 1;
 123                                goto NXTARG;
 124                        case 'e':
 125                                if (--argc <= 0)
 126                                        usage ();
 127                                ep = strtoul (*++argv, (char **)&ptr, 16);
 128                                if (*ptr) {
 129                                        fprintf (stderr,
 130                                                "%s: invalid entry point %s\n",
 131                                                cmdname, *argv);
 132                                        exit (EXIT_FAILURE);
 133                                }
 134                                eflag = 1;
 135                                goto NXTARG;
 136                        case 'f':
 137                                if (--argc <= 0)
 138                                        usage ();
 139                                datafile = *++argv;
 140                                fflag = 1;
 141                                goto NXTARG;
 142                        case 'n':
 143                                if (--argc <= 0)
 144                                        usage ();
 145                                name = *++argv;
 146                                goto NXTARG;
 147                        case 'v':
 148                                vflag++;
 149                                break;
 150                        case 'x':
 151                                xflag++;
 152                                break;
 153                        default:
 154                                usage ();
 155                        }
 156                }
 157NXTARG:         ;
 158        }
 159
 160        if ((argc != 1) ||
 161                (dflag && (fflag || lflag)) ||
 162                (fflag && (dflag || lflag)) ||
 163                (lflag && (dflag || fflag)))
 164                usage();
 165
 166        if (!eflag) {
 167                ep = addr;
 168                /* If XIP, entry point must be after the U-Boot header */
 169                if (xflag)
 170                        ep += image_get_header_size ();
 171        }
 172
 173        /*
 174         * If XIP, ensure the entry point is equal to the load address plus
 175         * the size of the U-Boot header.
 176         */
 177        if (xflag) {
 178                if (ep != addr + image_get_header_size ()) {
 179                        fprintf (stderr,
 180                                "%s: For XIP, the entry point must be the load addr + %lu\n",
 181                                cmdname,
 182                                (unsigned long)image_get_header_size ());
 183                        exit (EXIT_FAILURE);
 184                }
 185        }
 186
 187        imagefile = *argv;
 188
 189        if (!fflag){
 190                if (lflag) {
 191                        ifd = open (imagefile, O_RDONLY|O_BINARY);
 192                } else {
 193                        ifd = open (imagefile,
 194                                O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
 195                }
 196
 197                if (ifd < 0) {
 198                        fprintf (stderr, "%s: Can't open %s: %s\n",
 199                                cmdname, imagefile, strerror(errno));
 200                        exit (EXIT_FAILURE);
 201                }
 202        }
 203
 204        if (lflag) {
 205                /*
 206                 * list header information of existing image
 207                 */
 208                if (fstat(ifd, &sbuf) < 0) {
 209                        fprintf (stderr, "%s: Can't stat %s: %s\n",
 210                                cmdname, imagefile, strerror(errno));
 211                        exit (EXIT_FAILURE);
 212                }
 213
 214                if ((unsigned)sbuf.st_size < image_get_header_size ()) {
 215                        fprintf (stderr,
 216                                "%s: Bad size: \"%s\" is no valid image\n",
 217                                cmdname, imagefile);
 218                        exit (EXIT_FAILURE);
 219                }
 220
 221                ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
 222                if (ptr == MAP_FAILED) {
 223                        fprintf (stderr, "%s: Can't read %s: %s\n",
 224                                cmdname, imagefile, strerror(errno));
 225                        exit (EXIT_FAILURE);
 226                }
 227
 228                if (fdt_check_header (ptr)) {
 229                        /* old-style image */
 230                        image_verify_header ((char *)ptr, sbuf.st_size);
 231                        image_print_contents ((image_header_t *)ptr);
 232                } else {
 233                        /* FIT image */
 234                        fit_print_contents (ptr);
 235                }
 236
 237                (void) munmap((void *)ptr, sbuf.st_size);
 238                (void) close (ifd);
 239
 240                exit (EXIT_SUCCESS);
 241        } else if (fflag) {
 242                /* Flattened Image Tree (FIT) format  handling */
 243                debug ("FIT format handling\n");
 244                fit_handle_file ();
 245                exit (EXIT_SUCCESS);
 246        }
 247
 248        /*
 249         * Must be -w then:
 250         *
 251         * write dummy header, to be fixed later
 252         */
 253        memset (hdr, 0, image_get_header_size ());
 254
 255        if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) {
 256                fprintf (stderr, "%s: Write error on %s: %s\n",
 257                        cmdname, imagefile, strerror(errno));
 258                exit (EXIT_FAILURE);
 259        }
 260
 261        if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) {
 262                char *file = datafile;
 263                uint32_t size;
 264
 265                for (;;) {
 266                        char *sep = NULL;
 267
 268                        if (file) {
 269                                if ((sep = strchr(file, ':')) != NULL) {
 270                                        *sep = '\0';
 271                                }
 272
 273                                if (stat (file, &sbuf) < 0) {
 274                                        fprintf (stderr, "%s: Can't stat %s: %s\n",
 275                                                cmdname, file, strerror(errno));
 276                                        exit (EXIT_FAILURE);
 277                                }
 278                                size = cpu_to_uimage (sbuf.st_size);
 279                        } else {
 280                                size = 0;
 281                        }
 282
 283                        if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
 284                                fprintf (stderr, "%s: Write error on %s: %s\n",
 285                                        cmdname, imagefile, strerror(errno));
 286                                exit (EXIT_FAILURE);
 287                        }
 288
 289                        if (!file) {
 290                                break;
 291                        }
 292
 293                        if (sep) {
 294                                *sep = ':';
 295                                file = sep + 1;
 296                        } else {
 297                                file = NULL;
 298                        }
 299                }
 300
 301                file = datafile;
 302
 303                for (;;) {
 304                        char *sep = strchr(file, ':');
 305                        if (sep) {
 306                                *sep = '\0';
 307                                copy_file (ifd, file, 1);
 308                                *sep++ = ':';
 309                                file = sep;
 310                        } else {
 311                                copy_file (ifd, file, 0);
 312                                break;
 313                        }
 314                }
 315        } else {
 316                copy_file (ifd, datafile, 0);
 317        }
 318
 319        /* We're a bit of paranoid */
 320#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
 321        (void) fdatasync (ifd);
 322#else
 323        (void) fsync (ifd);
 324#endif
 325
 326        if (fstat(ifd, &sbuf) < 0) {
 327                fprintf (stderr, "%s: Can't stat %s: %s\n",
 328                        cmdname, imagefile, strerror(errno));
 329                exit (EXIT_FAILURE);
 330        }
 331
 332        ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
 333        if (ptr == MAP_FAILED) {
 334                fprintf (stderr, "%s: Can't map %s: %s\n",
 335                        cmdname, imagefile, strerror(errno));
 336                exit (EXIT_FAILURE);
 337        }
 338
 339        hdr = (image_header_t *)ptr;
 340
 341        checksum = crc32 (0,
 342                          (const char *)(ptr + image_get_header_size ()),
 343                          sbuf.st_size - image_get_header_size ()
 344                         );
 345
 346        /* Build new header */
 347        image_set_magic (hdr, IH_MAGIC);
 348        image_set_time (hdr, sbuf.st_mtime);
 349        image_set_size (hdr, sbuf.st_size - image_get_header_size ());
 350        image_set_load (hdr, addr);
 351        image_set_ep (hdr, ep);
 352        image_set_dcrc (hdr, checksum);
 353        image_set_os (hdr, opt_os);
 354        image_set_arch (hdr, opt_arch);
 355        image_set_type (hdr, opt_type);
 356        image_set_comp (hdr, opt_comp);
 357
 358        image_set_name (hdr, name);
 359
 360        checksum = crc32 (0, (const char *)hdr, image_get_header_size ());
 361
 362        image_set_hcrc (hdr, checksum);
 363
 364        image_print_contents (hdr);
 365
 366        (void) munmap((void *)ptr, sbuf.st_size);
 367
 368        /* We're a bit of paranoid */
 369#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
 370        (void) fdatasync (ifd);
 371#else
 372        (void) fsync (ifd);
 373#endif
 374
 375        if (close(ifd)) {
 376                fprintf (stderr, "%s: Write error on %s: %s\n",
 377                        cmdname, imagefile, strerror(errno));
 378                exit (EXIT_FAILURE);
 379        }
 380
 381        exit (EXIT_SUCCESS);
 382}
 383
 384static void
 385copy_file (int ifd, const char *datafile, int pad)
 386{
 387        int dfd;
 388        struct stat sbuf;
 389        unsigned char *ptr;
 390        int tail;
 391        int zero = 0;
 392        int offset = 0;
 393        int size;
 394
 395        if (vflag) {
 396                fprintf (stderr, "Adding Image %s\n", datafile);
 397        }
 398
 399        if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
 400                fprintf (stderr, "%s: Can't open %s: %s\n",
 401                        cmdname, datafile, strerror(errno));
 402                exit (EXIT_FAILURE);
 403        }
 404
 405        if (fstat(dfd, &sbuf) < 0) {
 406                fprintf (stderr, "%s: Can't stat %s: %s\n",
 407                        cmdname, datafile, strerror(errno));
 408                exit (EXIT_FAILURE);
 409        }
 410
 411        ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
 412        if (ptr == MAP_FAILED) {
 413                fprintf (stderr, "%s: Can't read %s: %s\n",
 414                        cmdname, datafile, strerror(errno));
 415                exit (EXIT_FAILURE);
 416        }
 417
 418        if (xflag) {
 419                unsigned char *p = NULL;
 420                /*
 421                 * XIP: do not append the image_header_t at the
 422                 * beginning of the file, but consume the space
 423                 * reserved for it.
 424                 */
 425
 426                if ((unsigned)sbuf.st_size < image_get_header_size ()) {
 427                        fprintf (stderr,
 428                                "%s: Bad size: \"%s\" is too small for XIP\n",
 429                                cmdname, datafile);
 430                        exit (EXIT_FAILURE);
 431                }
 432
 433                for (p = ptr; p < ptr + image_get_header_size (); p++) {
 434                        if ( *p != 0xff ) {
 435                                fprintf (stderr,
 436                                        "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
 437                                        cmdname, datafile);
 438                                exit (EXIT_FAILURE);
 439                        }
 440                }
 441
 442                offset = image_get_header_size ();
 443        }
 444
 445        size = sbuf.st_size - offset;
 446        if (write(ifd, ptr + offset, size) != size) {
 447                fprintf (stderr, "%s: Write error on %s: %s\n",
 448                        cmdname, imagefile, strerror(errno));
 449                exit (EXIT_FAILURE);
 450        }
 451
 452        if (pad && ((tail = size % 4) != 0)) {
 453
 454                if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
 455                        fprintf (stderr, "%s: Write error on %s: %s\n",
 456                                cmdname, imagefile, strerror(errno));
 457                        exit (EXIT_FAILURE);
 458                }
 459        }
 460
 461        (void) munmap((void *)ptr, sbuf.st_size);
 462        (void) close (dfd);
 463}
 464
 465void
 466usage ()
 467{
 468        fprintf (stderr, "Usage: %s -l image\n"
 469                         "          -l ==> list image header information\n",
 470                cmdname);
 471        fprintf (stderr, "       %s [-x] -A arch -O os -T type -C comp "
 472                         "-a addr -e ep -n name -d data_file[:data_file...] image\n"
 473                         "          -A ==> set architecture to 'arch'\n"
 474                         "          -O ==> set operating system to 'os'\n"
 475                         "          -T ==> set image type to 'type'\n"
 476                         "          -C ==> set compression type 'comp'\n"
 477                         "          -a ==> set load address to 'addr' (hex)\n"
 478                         "          -e ==> set entry point to 'ep' (hex)\n"
 479                         "          -n ==> set image name to 'name'\n"
 480                         "          -d ==> use image data from 'datafile'\n"
 481                         "          -x ==> set XIP (execute in place)\n",
 482                cmdname);
 483        fprintf (stderr, "       %s [-D dtc_options] -f fit-image.its fit-image\n",
 484                cmdname);
 485
 486        exit (EXIT_FAILURE);
 487}
 488
 489static void
 490image_verify_header (char *ptr, int image_size)
 491{
 492        int len;
 493        char *data;
 494        uint32_t checksum;
 495        image_header_t header;
 496        image_header_t *hdr = &header;
 497
 498        /*
 499         * create copy of header so that we can blank out the
 500         * checksum field for checking - this can't be done
 501         * on the PROT_READ mapped data.
 502         */
 503        memcpy (hdr, ptr, sizeof(image_header_t));
 504
 505        if (ntohl(hdr->ih_magic) != IH_MAGIC) {
 506                fprintf (stderr,
 507                        "%s: Bad Magic Number: \"%s\" is no valid image\n",
 508                        cmdname, imagefile);
 509                exit (EXIT_FAILURE);
 510        }
 511
 512        data = (char *)hdr;
 513        len  = sizeof(image_header_t);
 514
 515        checksum = ntohl(hdr->ih_hcrc);
 516        hdr->ih_hcrc = htonl(0);        /* clear for re-calculation */
 517
 518        if (crc32 (0, data, len) != checksum) {
 519                fprintf (stderr,
 520                        "%s: ERROR: \"%s\" has bad header checksum!\n",
 521                        cmdname, imagefile);
 522                exit (EXIT_FAILURE);
 523        }
 524
 525        data = ptr + sizeof(image_header_t);
 526        len  = image_size - sizeof(image_header_t) ;
 527
 528        if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) {
 529                fprintf (stderr,
 530                        "%s: ERROR: \"%s\" has corrupted data!\n",
 531                        cmdname, imagefile);
 532                exit (EXIT_FAILURE);
 533        }
 534}
 535
 536/**
 537 * fit_handle_file - main FIT file processing function
 538 *
 539 * fit_handle_file() runs dtc to convert .its to .itb, includes
 540 * binary data, updates timestamp property and calculates hashes.
 541 *
 542 * datafile  - .its file
 543 * imagefile - .itb file
 544 *
 545 * returns:
 546 *     only on success, otherwise calls exit (EXIT_FAILURE);
 547 */
 548static void fit_handle_file (void)
 549{
 550        char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
 551        char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
 552        int tfd;
 553        struct stat sbuf;
 554        unsigned char *ptr;
 555
 556        /* call dtc to include binary properties into the tmp file */
 557        if (strlen (imagefile) + strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 >
 558                sizeof (tmpfile)) {
 559                fprintf (stderr, "%s: Image file name (%s) too long, "
 560                                "can't create tmpfile",
 561                                imagefile, cmdname);
 562                exit (EXIT_FAILURE);
 563        }
 564        sprintf (tmpfile, "%s%s", imagefile, MKIMAGE_TMPFILE_SUFFIX);
 565
 566        /* dtc -I dts -O -p 200 datafile > tmpfile */
 567        sprintf (cmd, "%s %s %s > %s",
 568                        MKIMAGE_DTC, opt_dtc, datafile, tmpfile);
 569        debug ("Trying to execute \"%s\"\n", cmd);
 570        if (system (cmd) == -1) {
 571                fprintf (stderr, "%s: system(%s) failed: %s\n",
 572                                cmdname, cmd, strerror(errno));
 573                unlink (tmpfile);
 574                exit (EXIT_FAILURE);
 575        }
 576
 577        /* load FIT blob into memory */
 578        tfd = open (tmpfile, O_RDWR|O_BINARY);
 579
 580        if (tfd < 0) {
 581                fprintf (stderr, "%s: Can't open %s: %s\n",
 582                                cmdname, tmpfile, strerror(errno));
 583                unlink (tmpfile);
 584                exit (EXIT_FAILURE);
 585        }
 586
 587        if (fstat (tfd, &sbuf) < 0) {
 588                fprintf (stderr, "%s: Can't stat %s: %s\n",
 589                                cmdname, tmpfile, strerror(errno));
 590                unlink (tmpfile);
 591                exit (EXIT_FAILURE);
 592        }
 593
 594        ptr = mmap (0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, tfd, 0);
 595        if (ptr == MAP_FAILED) {
 596                fprintf (stderr, "%s: Can't read %s: %s\n",
 597                                cmdname, tmpfile, strerror(errno));
 598                unlink (tmpfile);
 599                exit (EXIT_FAILURE);
 600        }
 601
 602        /* check if ptr has a valid blob */
 603        if (fdt_check_header (ptr)) {
 604                fprintf (stderr, "%s: Invalid FIT blob\n", cmdname);
 605                unlink (tmpfile);
 606                exit (EXIT_FAILURE);
 607        }
 608
 609        /* set hashes for images in the blob */
 610        if (fit_set_hashes (ptr)) {
 611                fprintf (stderr, "%s Can't add hashes to FIT blob", cmdname);
 612                unlink (tmpfile);
 613                exit (EXIT_FAILURE);
 614        }
 615
 616        /* add a timestamp at offset 0 i.e., root  */
 617        if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) {
 618                fprintf (stderr, "%s: Can't add image timestamp\n", cmdname);
 619                unlink (tmpfile);
 620                exit (EXIT_FAILURE);
 621        }
 622        debug ("Added timestamp successfully\n");
 623
 624        munmap ((void *)ptr, sbuf.st_size);
 625        close (tfd);
 626
 627        if (rename (tmpfile, imagefile) == -1) {
 628                fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
 629                                cmdname, tmpfile, imagefile, strerror (errno));
 630                unlink (tmpfile);
 631                unlink (imagefile);
 632                exit (EXIT_FAILURE);
 633        }
 634}
 635