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