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