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