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