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