uboot/tools/mkimage.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2008 Semihalf
   4 *
   5 * (C) Copyright 2000-2009
   6 * DENX Software Engineering
   7 * Wolfgang Denk, wd@denx.de
   8 */
   9
  10#include "imagetool.h"
  11#include "mkimage.h"
  12#include "imximage.h"
  13#include <image.h>
  14#include <version.h>
  15
  16static void copy_file(int, const char *, int);
  17
  18/* parameters initialized by core will be used by the image type code */
  19static struct image_tool_params params = {
  20        .os = IH_OS_LINUX,
  21        .arch = IH_ARCH_PPC,
  22        .type = IH_TYPE_KERNEL,
  23        .comp = IH_COMP_GZIP,
  24        .dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
  25        .imagename = "",
  26        .imagename2 = "",
  27};
  28
  29static enum ih_category cur_category;
  30
  31static int h_compare_category_name(const void *vtype1, const void *vtype2)
  32{
  33        const int *type1 = vtype1;
  34        const int *type2 = vtype2;
  35        const char *name1 = genimg_get_cat_short_name(cur_category, *type1);
  36        const char *name2 = genimg_get_cat_short_name(cur_category, *type2);
  37
  38        return strcmp(name1, name2);
  39}
  40
  41static int show_valid_options(enum ih_category category)
  42{
  43        int *order;
  44        int count;
  45        int item;
  46        int i;
  47
  48        count = genimg_get_cat_count(category);
  49        order = calloc(count, sizeof(*order));
  50        if (!order)
  51                return -ENOMEM;
  52
  53        /* Sort the names in order of short name for easier reading */
  54        for (i = 0, item = 0; i < count; i++, item++) {
  55                while (!genimg_cat_has_id(category, item) && i < count) {
  56                        item++;
  57                        count--;
  58                }
  59                order[i] = item;
  60        }
  61        cur_category = category;
  62        qsort(order, count, sizeof(int), h_compare_category_name);
  63
  64        fprintf(stderr, "\nInvalid %s, supported are:\n",
  65                genimg_get_cat_desc(category));
  66        for (i = 0; i < count; i++) {
  67                item = order[i];
  68                fprintf(stderr, "\t%-15s  %s\n",
  69                        genimg_get_cat_short_name(category, item),
  70                        genimg_get_cat_name(category, item));
  71        }
  72        fprintf(stderr, "\n");
  73        free(order);
  74
  75        return 0;
  76}
  77
  78static void usage(const char *msg)
  79{
  80        fprintf(stderr, "Error: %s\n", msg);
  81        fprintf(stderr, "Usage: %s -l image\n"
  82                         "          -l ==> list image header information\n",
  83                params.cmdname);
  84        fprintf(stderr,
  85                "       %s [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image\n"
  86                "          -A ==> set architecture to 'arch'\n"
  87                "          -O ==> set operating system to 'os'\n"
  88                "          -T ==> set image type to 'type'\n"
  89                "          -C ==> set compression type 'comp'\n"
  90                "          -a ==> set load address to 'addr' (hex)\n"
  91                "          -e ==> set entry point to 'ep' (hex)\n"
  92                "          -n ==> set image name to 'name'\n"
  93                "          -d ==> use image data from 'datafile'\n"
  94                "          -x ==> set XIP (execute in place)\n",
  95                params.cmdname);
  96        fprintf(stderr,
  97                "       %s [-D dtc_options] [-f fit-image.its|-f auto|-F] [-b <dtb> [-b <dtb>]] [-i <ramdisk.cpio.gz>] fit-image\n"
  98                "           <dtb> file is used with -f auto, it may occur multiple times.\n",
  99                params.cmdname);
 100        fprintf(stderr,
 101                "          -D => set all options for device tree compiler\n"
 102                "          -f => input filename for FIT source\n"
 103                "          -i => input filename for ramdisk file\n");
 104#ifdef CONFIG_FIT_SIGNATURE
 105        fprintf(stderr,
 106                "Signing / verified boot options: [-E] [-B size] [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]\n"
 107                "          -E => place data outside of the FIT structure\n"
 108                "          -B => align size in hex for FIT structure and header\n"
 109                "          -k => set directory containing private keys\n"
 110                "          -K => write public keys to this .dtb file\n"
 111                "          -c => add comment in signature node\n"
 112                "          -F => re-sign existing FIT image\n"
 113                "          -p => place external data at a static position\n"
 114                "          -r => mark keys used as 'required' in dtb\n"
 115                "          -N => openssl engine to use for signing\n");
 116#else
 117        fprintf(stderr,
 118                "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
 119#endif
 120        fprintf(stderr, "       %s -V ==> print version information and exit\n",
 121                params.cmdname);
 122        fprintf(stderr, "Use '-T list' to see a list of available image types\n");
 123
 124        exit(EXIT_FAILURE);
 125}
 126
 127static int add_content(int type, const char *fname)
 128{
 129        struct content_info *cont;
 130
 131        cont = calloc(1, sizeof(*cont));
 132        if (!cont)
 133                return -1;
 134        cont->type = type;
 135        cont->fname = fname;
 136        if (params.content_tail)
 137                params.content_tail->next = cont;
 138        else
 139                params.content_head = cont;
 140        params.content_tail = cont;
 141
 142        return 0;
 143}
 144
 145static void process_args(int argc, char **argv)
 146{
 147        char *ptr;
 148        int type = IH_TYPE_INVALID;
 149        char *datafile = NULL;
 150        int opt;
 151
 152        while ((opt = getopt(argc, argv,
 153                   "a:A:b:B:c:C:d:D:e:Ef:Fk:i:K:ln:N:p:O:rR:qstT:vVx")) != -1) {
 154                switch (opt) {
 155                case 'a':
 156                        params.addr = strtoull(optarg, &ptr, 16);
 157                        if (*ptr) {
 158                                fprintf(stderr, "%s: invalid load address %s\n",
 159                                        params.cmdname, optarg);
 160                                exit(EXIT_FAILURE);
 161                        }
 162                        break;
 163                case 'A':
 164                        params.arch = genimg_get_arch_id(optarg);
 165                        if (params.arch < 0) {
 166                                show_valid_options(IH_ARCH);
 167                                usage("Invalid architecture");
 168                        }
 169                        break;
 170                case 'b':
 171                        if (add_content(IH_TYPE_FLATDT, optarg)) {
 172                                fprintf(stderr,
 173                                        "%s: Out of memory adding content '%s'",
 174                                        params.cmdname, optarg);
 175                                exit(EXIT_FAILURE);
 176                        }
 177                        break;
 178                case 'B':
 179                        params.bl_len = strtoull(optarg, &ptr, 16);
 180                        if (*ptr) {
 181                                fprintf(stderr, "%s: invalid block length %s\n",
 182                                        params.cmdname, optarg);
 183                                exit(EXIT_FAILURE);
 184                        }
 185
 186                        break;
 187                case 'c':
 188                        params.comment = optarg;
 189                        break;
 190                case 'C':
 191                        params.comp = genimg_get_comp_id(optarg);
 192                        if (params.comp < 0) {
 193                                show_valid_options(IH_COMP);
 194                                usage("Invalid compression type");
 195                        }
 196                        break;
 197                case 'd':
 198                        params.datafile = optarg;
 199                        params.dflag = 1;
 200                        break;
 201                case 'D':
 202                        params.dtc = optarg;
 203                        break;
 204                case 'e':
 205                        params.ep = strtoull(optarg, &ptr, 16);
 206                        if (*ptr) {
 207                                fprintf(stderr, "%s: invalid entry point %s\n",
 208                                        params.cmdname, optarg);
 209                                exit(EXIT_FAILURE);
 210                        }
 211                        params.eflag = 1;
 212                        break;
 213                case 'E':
 214                        params.external_data = true;
 215                        break;
 216                case 'f':
 217                        datafile = optarg;
 218                        params.auto_its = !strcmp(datafile, "auto");
 219                        /* fallthrough */
 220                case 'F':
 221                        /*
 222                         * The flattened image tree (FIT) format
 223                         * requires a flattened device tree image type
 224                         */
 225                        params.type = IH_TYPE_FLATDT;
 226                        params.fflag = 1;
 227                        break;
 228                case 'i':
 229                        params.fit_ramdisk = optarg;
 230                        break;
 231                case 'k':
 232                        params.keydir = optarg;
 233                        break;
 234                case 'K':
 235                        params.keydest = optarg;
 236                        break;
 237                case 'l':
 238                        params.lflag = 1;
 239                        break;
 240                case 'n':
 241                        params.imagename = optarg;
 242                        break;
 243                case 'N':
 244                        params.engine_id = optarg;
 245                        break;
 246                case 'O':
 247                        params.os = genimg_get_os_id(optarg);
 248                        if (params.os < 0) {
 249                                show_valid_options(IH_OS);
 250                                usage("Invalid operating system");
 251                        }
 252                        break;
 253                case 'p':
 254                        params.external_offset = strtoull(optarg, &ptr, 16);
 255                        if (*ptr) {
 256                                fprintf(stderr, "%s: invalid offset size %s\n",
 257                                        params.cmdname, optarg);
 258                                exit(EXIT_FAILURE);
 259                        }
 260                        break;
 261                case 'q':
 262                        params.quiet = 1;
 263                        break;
 264                case 'r':
 265                        params.require_keys = 1;
 266                        break;
 267                case 'R':
 268                        /*
 269                         * This entry is for the second configuration
 270                         * file, if only one is not enough.
 271                         */
 272                        params.imagename2 = optarg;
 273                        break;
 274                case 's':
 275                        params.skipcpy = 1;
 276                        break;
 277                case 't':
 278                        params.reset_timestamp = 1;
 279                        break;
 280                case 'T':
 281                        if (strcmp(optarg, "list") == 0) {
 282                                show_valid_options(IH_TYPE);
 283                                exit(EXIT_SUCCESS);
 284                        }
 285                        type = genimg_get_type_id(optarg);
 286                        if (type < 0) {
 287                                show_valid_options(IH_TYPE);
 288                                usage("Invalid image type");
 289                        }
 290                        break;
 291                case 'v':
 292                        params.vflag++;
 293                        break;
 294                case 'V':
 295                        printf("mkimage version %s\n", PLAIN_VERSION);
 296                        exit(EXIT_SUCCESS);
 297                case 'x':
 298                        params.xflag++;
 299                        break;
 300                default:
 301                        usage("Invalid option");
 302                }
 303        }
 304
 305        /* The last parameter is expected to be the imagefile */
 306        if (optind < argc)
 307                params.imagefile = argv[optind];
 308
 309        /*
 310         * For auto-generated FIT images we need to know the image type to put
 311         * in the FIT, which is separate from the file's image type (which
 312         * will always be IH_TYPE_FLATDT in this case).
 313         */
 314        if (params.type == IH_TYPE_FLATDT) {
 315                params.fit_image_type = type ? type : IH_TYPE_KERNEL;
 316                /* For auto_its, datafile is always 'auto' */
 317                if (!params.auto_its)
 318                        params.datafile = datafile;
 319                else if (!params.datafile)
 320                        usage("Missing data file for auto-FIT (use -d)");
 321        } else if (type != IH_TYPE_INVALID) {
 322                if (type == IH_TYPE_SCRIPT && !params.datafile)
 323                        usage("Missing data file for script (use -d)");
 324                params.type = type;
 325        }
 326
 327        if (!params.imagefile)
 328                usage("Missing output filename");
 329}
 330
 331int main(int argc, char **argv)
 332{
 333        int ifd = -1;
 334        struct stat sbuf;
 335        char *ptr;
 336        int retval = 0;
 337        struct image_type_params *tparams = NULL;
 338        int pad_len = 0;
 339        int dfd;
 340        size_t map_len;
 341
 342        params.cmdname = *argv;
 343        params.addr = 0;
 344        params.ep = 0;
 345
 346        process_args(argc, argv);
 347
 348        /* set tparams as per input type_id */
 349        tparams = imagetool_get_type(params.type);
 350        if (tparams == NULL) {
 351                fprintf (stderr, "%s: unsupported type %s\n",
 352                        params.cmdname, genimg_get_type_name(params.type));
 353                exit (EXIT_FAILURE);
 354        }
 355
 356        /*
 357         * check the passed arguments parameters meets the requirements
 358         * as per image type to be generated/listed
 359         */
 360        if (tparams->check_params)
 361                if (tparams->check_params (&params))
 362                        usage("Bad parameters for image type");
 363
 364        if (!params.eflag) {
 365                params.ep = params.addr;
 366                /* If XIP, entry point must be after the U-Boot header */
 367                if (params.xflag)
 368                        params.ep += tparams->header_size;
 369        }
 370
 371        if (params.fflag){
 372                if (tparams->fflag_handle)
 373                        /*
 374                         * in some cases, some additional processing needs
 375                         * to be done if fflag is defined
 376                         *
 377                         * For ex. fit_handle_file for Fit file support
 378                         */
 379                        retval = tparams->fflag_handle(&params);
 380
 381                if (retval != EXIT_SUCCESS)
 382                        exit (retval);
 383        }
 384
 385        if (params.lflag || params.fflag) {
 386                ifd = open (params.imagefile, O_RDONLY|O_BINARY);
 387        } else {
 388                ifd = open (params.imagefile,
 389                        O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
 390        }
 391
 392        if (ifd < 0) {
 393                fprintf (stderr, "%s: Can't open %s: %s\n",
 394                        params.cmdname, params.imagefile,
 395                        strerror(errno));
 396                exit (EXIT_FAILURE);
 397        }
 398
 399        if (params.lflag || params.fflag) {
 400                /*
 401                 * list header information of existing image
 402                 */
 403                if (fstat(ifd, &sbuf) < 0) {
 404                        fprintf (stderr, "%s: Can't stat %s: %s\n",
 405                                params.cmdname, params.imagefile,
 406                                strerror(errno));
 407                        exit (EXIT_FAILURE);
 408                }
 409
 410                if ((unsigned)sbuf.st_size < tparams->header_size) {
 411                        fprintf (stderr,
 412                                "%s: Bad size: \"%s\" is not valid image\n",
 413                                params.cmdname, params.imagefile);
 414                        exit (EXIT_FAILURE);
 415                }
 416
 417                ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
 418                if (ptr == MAP_FAILED) {
 419                        fprintf (stderr, "%s: Can't read %s: %s\n",
 420                                params.cmdname, params.imagefile,
 421                                strerror(errno));
 422                        exit (EXIT_FAILURE);
 423                }
 424
 425                if (params.fflag) {
 426                        /*
 427                         * Verifies the header format based on the expected header for image
 428                         * type in tparams
 429                         */
 430                        retval = imagetool_verify_print_header_by_type(ptr, &sbuf,
 431                                        tparams, &params);
 432                } else {
 433                        /**
 434                         * When listing the image, we are not given the image type. Simply check all
 435                         * image types to find one that matches our header
 436                         */
 437                        retval = imagetool_verify_print_header(ptr, &sbuf,
 438                                        tparams, &params);
 439                }
 440
 441                (void) munmap((void *)ptr, sbuf.st_size);
 442                (void) close (ifd);
 443
 444                exit (retval);
 445        }
 446
 447        if ((params.type != IH_TYPE_MULTI) && (params.type != IH_TYPE_SCRIPT)) {
 448                dfd = open(params.datafile, O_RDONLY | O_BINARY);
 449                if (dfd < 0) {
 450                        fprintf(stderr, "%s: Can't open %s: %s\n",
 451                                params.cmdname, params.datafile,
 452                                strerror(errno));
 453                        exit(EXIT_FAILURE);
 454                }
 455
 456                if (fstat(dfd, &sbuf) < 0) {
 457                        fprintf(stderr, "%s: Can't stat %s: %s\n",
 458                                params.cmdname, params.datafile,
 459                                strerror(errno));
 460                        exit(EXIT_FAILURE);
 461                }
 462
 463                params.file_size = sbuf.st_size + tparams->header_size;
 464                close(dfd);
 465        }
 466
 467        /*
 468         * In case there an header with a variable
 469         * length will be added, the corresponding
 470         * function is called. This is responsible to
 471         * allocate memory for the header itself.
 472         */
 473        if (tparams->vrec_header)
 474                pad_len = tparams->vrec_header(&params, tparams);
 475        else
 476                memset(tparams->hdr, 0, tparams->header_size);
 477
 478        if (write(ifd, tparams->hdr, tparams->header_size)
 479                                        != tparams->header_size) {
 480                fprintf (stderr, "%s: Write error on %s: %s\n",
 481                        params.cmdname, params.imagefile, strerror(errno));
 482                exit (EXIT_FAILURE);
 483        }
 484
 485        if (!params.skipcpy) {
 486                if (params.type == IH_TYPE_MULTI ||
 487                    params.type == IH_TYPE_SCRIPT) {
 488                        char *file = params.datafile;
 489                        uint32_t size;
 490
 491                        for (;;) {
 492                                char *sep = NULL;
 493
 494                                if (file) {
 495                                        if ((sep = strchr(file, ':')) != NULL) {
 496                                                *sep = '\0';
 497                                        }
 498
 499                                        if (stat (file, &sbuf) < 0) {
 500                                                fprintf (stderr, "%s: Can't stat %s: %s\n",
 501                                                         params.cmdname, file, strerror(errno));
 502                                                exit (EXIT_FAILURE);
 503                                        }
 504                                        size = cpu_to_uimage (sbuf.st_size);
 505                                } else {
 506                                        size = 0;
 507                                }
 508
 509                                if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
 510                                        fprintf (stderr, "%s: Write error on %s: %s\n",
 511                                                 params.cmdname, params.imagefile,
 512                                                 strerror(errno));
 513                                        exit (EXIT_FAILURE);
 514                                }
 515
 516                                if (!file) {
 517                                        break;
 518                                }
 519
 520                                if (sep) {
 521                                        *sep = ':';
 522                                        file = sep + 1;
 523                                } else {
 524                                        file = NULL;
 525                                }
 526                        }
 527
 528                        file = params.datafile;
 529
 530                        for (;;) {
 531                                char *sep = strchr(file, ':');
 532                                if (sep) {
 533                                        *sep = '\0';
 534                                        copy_file (ifd, file, 1);
 535                                        *sep++ = ':';
 536                                        file = sep;
 537                                } else {
 538                                        copy_file (ifd, file, 0);
 539                                        break;
 540                                }
 541                        }
 542                } else if (params.type == IH_TYPE_PBLIMAGE) {
 543                        /* PBL has special Image format, implements its' own */
 544                        pbl_load_uboot(ifd, &params);
 545                } else if (params.type == IH_TYPE_ZYNQMPBIF) {
 546                        /* Image file is meta, walk through actual targets */
 547                        int ret;
 548
 549                        ret = zynqmpbif_copy_image(ifd, &params);
 550                        if (ret)
 551                                return ret;
 552                } else if (params.type == IH_TYPE_IMX8IMAGE) {
 553                        /* i.MX8/8X has special Image format */
 554                        int ret;
 555
 556                        ret = imx8image_copy_image(ifd, &params);
 557                        if (ret)
 558                                return ret;
 559                } else if (params.type == IH_TYPE_IMX8MIMAGE) {
 560                        /* i.MX8M has special Image format */
 561                        int ret;
 562
 563                        ret = imx8mimage_copy_image(ifd, &params);
 564                        if (ret)
 565                                return ret;
 566                } else if ((params.type == IH_TYPE_RKSD) ||
 567                                (params.type == IH_TYPE_RKSPI)) {
 568                        /* Rockchip has special Image format */
 569                        int ret;
 570
 571                        ret = rockchip_copy_image(ifd, &params);
 572                        if (ret)
 573                                return ret;
 574                } else {
 575                        copy_file(ifd, params.datafile, pad_len);
 576                }
 577                if (params.type == IH_TYPE_FIRMWARE_IVT) {
 578                        /* Add alignment and IVT */
 579                        uint32_t aligned_filesize = ALIGN(params.file_size,
 580                                                          0x1000);
 581                        flash_header_v2_t ivt_header = { { 0xd1, 0x2000, 0x40 },
 582                                        params.addr, 0, 0, 0, params.addr
 583                                                        + aligned_filesize
 584                                                        - tparams->header_size,
 585                                        params.addr + aligned_filesize
 586                                                        - tparams->header_size
 587                                                        + 0x20, 0 };
 588                        int i = params.file_size;
 589                        for (; i < aligned_filesize; i++) {
 590                                if (write(ifd, (char *) &i, 1) != 1) {
 591                                        fprintf(stderr,
 592                                                        "%s: Write error on %s: %s\n",
 593                                                        params.cmdname,
 594                                                        params.imagefile,
 595                                                        strerror(errno));
 596                                        exit(EXIT_FAILURE);
 597                                }
 598                        }
 599                        if (write(ifd, &ivt_header, sizeof(flash_header_v2_t))
 600                                        != sizeof(flash_header_v2_t)) {
 601                                fprintf(stderr, "%s: Write error on %s: %s\n",
 602                                                params.cmdname,
 603                                                params.imagefile,
 604                                                strerror(errno));
 605                                exit(EXIT_FAILURE);
 606                        }
 607                }
 608        }
 609
 610        /* We're a bit of paranoid */
 611#if defined(_POSIX_SYNCHRONIZED_IO) && \
 612   !defined(__sun__) && \
 613   !defined(__FreeBSD__) && \
 614   !defined(__OpenBSD__) && \
 615   !defined(__APPLE__)
 616        (void) fdatasync (ifd);
 617#else
 618        (void) fsync (ifd);
 619#endif
 620
 621        if (fstat(ifd, &sbuf) < 0) {
 622                fprintf (stderr, "%s: Can't stat %s: %s\n",
 623                        params.cmdname, params.imagefile, strerror(errno));
 624                exit (EXIT_FAILURE);
 625        }
 626        params.file_size = sbuf.st_size;
 627
 628        map_len = sbuf.st_size;
 629        ptr = mmap(0, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, ifd, 0);
 630        if (ptr == MAP_FAILED) {
 631                fprintf (stderr, "%s: Can't map %s: %s\n",
 632                        params.cmdname, params.imagefile, strerror(errno));
 633                exit (EXIT_FAILURE);
 634        }
 635
 636        /* Setup the image header as per input image type*/
 637        if (tparams->set_header)
 638                tparams->set_header (ptr, &sbuf, ifd, &params);
 639        else {
 640                fprintf (stderr, "%s: Can't set header for %s: %s\n",
 641                        params.cmdname, tparams->name, strerror(errno));
 642                exit (EXIT_FAILURE);
 643        }
 644
 645        /* Print the image information by processing image header */
 646        if (tparams->print_header)
 647                tparams->print_header (ptr);
 648        else {
 649                fprintf (stderr, "%s: Can't print header for %s\n",
 650                        params.cmdname, tparams->name);
 651        }
 652
 653        (void)munmap((void *)ptr, map_len);
 654
 655        /* We're a bit of paranoid */
 656#if defined(_POSIX_SYNCHRONIZED_IO) && \
 657   !defined(__sun__) && \
 658   !defined(__FreeBSD__) && \
 659   !defined(__OpenBSD__) && \
 660   !defined(__APPLE__)
 661        (void) fdatasync (ifd);
 662#else
 663        (void) fsync (ifd);
 664#endif
 665
 666        if (close(ifd)) {
 667                fprintf (stderr, "%s: Write error on %s: %s\n",
 668                        params.cmdname, params.imagefile, strerror(errno));
 669                exit (EXIT_FAILURE);
 670        }
 671
 672        exit (EXIT_SUCCESS);
 673}
 674
 675static void
 676copy_file (int ifd, const char *datafile, int pad)
 677{
 678        int dfd;
 679        struct stat sbuf;
 680        unsigned char *ptr;
 681        int tail;
 682        int zero = 0;
 683        uint8_t zeros[4096];
 684        int offset = 0;
 685        int size, ret;
 686        struct image_type_params *tparams = imagetool_get_type(params.type);
 687
 688        memset(zeros, 0, sizeof(zeros));
 689
 690        if (params.vflag) {
 691                fprintf (stderr, "Adding Image %s\n", datafile);
 692        }
 693
 694        if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
 695                fprintf (stderr, "%s: Can't open %s: %s\n",
 696                        params.cmdname, datafile, strerror(errno));
 697                exit (EXIT_FAILURE);
 698        }
 699
 700        if (fstat(dfd, &sbuf) < 0) {
 701                fprintf (stderr, "%s: Can't stat %s: %s\n",
 702                        params.cmdname, datafile, strerror(errno));
 703                exit (EXIT_FAILURE);
 704        }
 705
 706        ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
 707        if (ptr == MAP_FAILED) {
 708                fprintf (stderr, "%s: Can't read %s: %s\n",
 709                        params.cmdname, datafile, strerror(errno));
 710                exit (EXIT_FAILURE);
 711        }
 712
 713        if (params.xflag) {
 714                unsigned char *p = NULL;
 715                /*
 716                 * XIP: do not append the image_header_t at the
 717                 * beginning of the file, but consume the space
 718                 * reserved for it.
 719                 */
 720
 721                if ((unsigned)sbuf.st_size < tparams->header_size) {
 722                        fprintf (stderr,
 723                                "%s: Bad size: \"%s\" is too small for XIP\n",
 724                                params.cmdname, datafile);
 725                        exit (EXIT_FAILURE);
 726                }
 727
 728                for (p = ptr; p < ptr + tparams->header_size; p++) {
 729                        if ( *p != 0xff ) {
 730                                fprintf (stderr,
 731                                        "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
 732                                        params.cmdname, datafile);
 733                                exit (EXIT_FAILURE);
 734                        }
 735                }
 736
 737                offset = tparams->header_size;
 738        }
 739
 740        size = sbuf.st_size - offset;
 741
 742        ret = write(ifd, ptr + offset, size);
 743        if (ret != size) {
 744                if (ret < 0)
 745                        fprintf (stderr, "%s: Write error on %s: %s\n",
 746                                 params.cmdname, params.imagefile, strerror(errno));
 747                else if (ret < size)
 748                        fprintf (stderr, "%s: Write only %d/%d bytes, "\
 749                                 "probably no space left on the device\n",
 750                                 params.cmdname, ret, size);
 751                exit (EXIT_FAILURE);
 752        }
 753
 754        tail = size % 4;
 755        if ((pad == 1) && (tail != 0)) {
 756
 757                if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
 758                        fprintf (stderr, "%s: Write error on %s: %s\n",
 759                                params.cmdname, params.imagefile,
 760                                strerror(errno));
 761                        exit (EXIT_FAILURE);
 762                }
 763        } else if (pad > 1) {
 764                while (pad > 0) {
 765                        int todo = sizeof(zeros);
 766
 767                        if (todo > pad)
 768                                todo = pad;
 769                        if (write(ifd, (char *)&zeros, todo) != todo) {
 770                                fprintf(stderr, "%s: Write error on %s: %s\n",
 771                                        params.cmdname, params.imagefile,
 772                                        strerror(errno));
 773                                exit(EXIT_FAILURE);
 774                        }
 775                        pad -= todo;
 776                }
 777        }
 778
 779        (void) munmap((void *)ptr, sbuf.st_size);
 780        (void) close (dfd);
 781}
 782