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