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