]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/mkimage.c
mkimage: make mmap() checks consistent
[karo-tx-uboot.git] / tools / mkimage.c
1 /*
2  * (C) Copyright 2008 Semihalf
3  *
4  * (C) Copyright 2000-2004
5  * DENX Software Engineering
6  * Wolfgang Denk, wd@denx.de
7  * All rights reserved.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 #include "mkimage.h"
26 #include <image.h>
27
28 extern int errno;
29
30 #ifndef MAP_FAILED
31 #define MAP_FAILED (void *)(-1)
32 #endif
33
34 extern  unsigned long   crc32 (unsigned long crc, const char *buf, unsigned int len);
35 static  void            copy_file (int, const char *, int);
36 static  void            usage (void);
37 static  void            image_verify_header (char *, int);
38 static  void            fit_handle_file (void);
39
40 char    *datafile;
41 char    *imagefile;
42 char    *cmdname;
43
44 int dflag    = 0;
45 int eflag    = 0;
46 int fflag    = 0;
47 int lflag    = 0;
48 int vflag    = 0;
49 int xflag    = 0;
50 int opt_os   = IH_OS_LINUX;
51 int opt_arch = IH_ARCH_PPC;
52 int opt_type = IH_TYPE_KERNEL;
53 int opt_comp = IH_COMP_GZIP;
54 char *opt_dtc = MKIMAGE_DEFAULT_DTC_OPTIONS;
55
56 image_header_t header;
57 image_header_t *hdr = &header;
58
59 int
60 main (int argc, char **argv)
61 {
62         int ifd = -1;
63         uint32_t checksum;
64         uint32_t addr;
65         uint32_t ep;
66         struct stat sbuf;
67         unsigned char *ptr;
68         char *name = "";
69
70         cmdname = *argv;
71
72         addr = ep = 0;
73
74         while (--argc > 0 && **++argv == '-') {
75                 while (*++*argv) {
76                         switch (**argv) {
77                         case 'l':
78                                 lflag = 1;
79                                 break;
80                         case 'A':
81                                 if ((--argc <= 0) ||
82                                     (opt_arch = genimg_get_arch_id (*++argv)) < 0)
83                                         usage ();
84                                 goto NXTARG;
85                         case 'C':
86                                 if ((--argc <= 0) ||
87                                     (opt_comp = genimg_get_comp_id (*++argv)) < 0)
88                                         usage ();
89                                 goto NXTARG;
90                         case 'D':
91                                 if (--argc <= 0)
92                                         usage ();
93                                 opt_dtc = *++argv;
94                                 goto NXTARG;
95
96                         case 'O':
97                                 if ((--argc <= 0) ||
98                                     (opt_os = genimg_get_os_id (*++argv)) < 0)
99                                         usage ();
100                                 goto NXTARG;
101                         case 'T':
102                                 if ((--argc <= 0) ||
103                                     (opt_type = genimg_get_type_id (*++argv)) < 0)
104                                         usage ();
105                                 goto NXTARG;
106
107                         case 'a':
108                                 if (--argc <= 0)
109                                         usage ();
110                                 addr = strtoul (*++argv, (char **)&ptr, 16);
111                                 if (*ptr) {
112                                         fprintf (stderr,
113                                                 "%s: invalid load address %s\n",
114                                                 cmdname, *argv);
115                                         exit (EXIT_FAILURE);
116                                 }
117                                 goto NXTARG;
118                         case 'd':
119                                 if (--argc <= 0)
120                                         usage ();
121                                 datafile = *++argv;
122                                 dflag = 1;
123                                 goto NXTARG;
124                         case 'e':
125                                 if (--argc <= 0)
126                                         usage ();
127                                 ep = strtoul (*++argv, (char **)&ptr, 16);
128                                 if (*ptr) {
129                                         fprintf (stderr,
130                                                 "%s: invalid entry point %s\n",
131                                                 cmdname, *argv);
132                                         exit (EXIT_FAILURE);
133                                 }
134                                 eflag = 1;
135                                 goto NXTARG;
136                         case 'f':
137                                 if (--argc <= 0)
138                                         usage ();
139                                 datafile = *++argv;
140                                 fflag = 1;
141                                 goto NXTARG;
142                         case 'n':
143                                 if (--argc <= 0)
144                                         usage ();
145                                 name = *++argv;
146                                 goto NXTARG;
147                         case 'v':
148                                 vflag++;
149                                 break;
150                         case 'x':
151                                 xflag++;
152                                 break;
153                         default:
154                                 usage ();
155                         }
156                 }
157 NXTARG:         ;
158         }
159
160         if ((argc != 1) ||
161                 (dflag && (fflag || lflag)) ||
162                 (fflag && (dflag || lflag)) ||
163                 (lflag && (dflag || fflag)))
164                 usage();
165
166         if (!eflag) {
167                 ep = addr;
168                 /* If XIP, entry point must be after the U-Boot header */
169                 if (xflag)
170                         ep += image_get_header_size ();
171         }
172
173         /*
174          * If XIP, ensure the entry point is equal to the load address plus
175          * the size of the U-Boot header.
176          */
177         if (xflag) {
178                 if (ep != addr + image_get_header_size ()) {
179                         fprintf (stderr,
180                                 "%s: For XIP, the entry point must be the load addr + %lu\n",
181                                 cmdname,
182                                 (unsigned long)image_get_header_size ());
183                         exit (EXIT_FAILURE);
184                 }
185         }
186
187         imagefile = *argv;
188
189         if (!fflag){
190                 if (lflag) {
191                         ifd = open (imagefile, O_RDONLY|O_BINARY);
192                 } else {
193                         ifd = open (imagefile,
194                                 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
195                 }
196
197                 if (ifd < 0) {
198                         fprintf (stderr, "%s: Can't open %s: %s\n",
199                                 cmdname, imagefile, strerror(errno));
200                         exit (EXIT_FAILURE);
201                 }
202         }
203
204         if (lflag) {
205                 /*
206                  * list header information of existing image
207                  */
208                 if (fstat(ifd, &sbuf) < 0) {
209                         fprintf (stderr, "%s: Can't stat %s: %s\n",
210                                 cmdname, imagefile, strerror(errno));
211                         exit (EXIT_FAILURE);
212                 }
213
214                 if ((unsigned)sbuf.st_size < image_get_header_size ()) {
215                         fprintf (stderr,
216                                 "%s: Bad size: \"%s\" is no valid image\n",
217                                 cmdname, imagefile);
218                         exit (EXIT_FAILURE);
219                 }
220
221                 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
222                 if (ptr == MAP_FAILED) {
223                         fprintf (stderr, "%s: Can't read %s: %s\n",
224                                 cmdname, imagefile, strerror(errno));
225                         exit (EXIT_FAILURE);
226                 }
227
228                 if (fdt_check_header (ptr)) {
229                         /* old-style image */
230                         image_verify_header ((char *)ptr, sbuf.st_size);
231                         image_print_contents ((image_header_t *)ptr);
232                 } else {
233                         /* FIT image */
234                         fit_print_contents (ptr);
235                 }
236
237                 (void) munmap((void *)ptr, sbuf.st_size);
238                 (void) close (ifd);
239
240                 exit (EXIT_SUCCESS);
241         } else if (fflag) {
242                 /* Flattened Image Tree (FIT) format  handling */
243                 debug ("FIT format handling\n");
244                 fit_handle_file ();
245                 exit (EXIT_SUCCESS);
246         }
247
248         /*
249          * Must be -w then:
250          *
251          * write dummy header, to be fixed later
252          */
253         memset (hdr, 0, image_get_header_size ());
254
255         if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) {
256                 fprintf (stderr, "%s: Write error on %s: %s\n",
257                         cmdname, imagefile, strerror(errno));
258                 exit (EXIT_FAILURE);
259         }
260
261         if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) {
262                 char *file = datafile;
263                 uint32_t size;
264
265                 for (;;) {
266                         char *sep = NULL;
267
268                         if (file) {
269                                 if ((sep = strchr(file, ':')) != NULL) {
270                                         *sep = '\0';
271                                 }
272
273                                 if (stat (file, &sbuf) < 0) {
274                                         fprintf (stderr, "%s: Can't stat %s: %s\n",
275                                                 cmdname, file, strerror(errno));
276                                         exit (EXIT_FAILURE);
277                                 }
278                                 size = cpu_to_uimage (sbuf.st_size);
279                         } else {
280                                 size = 0;
281                         }
282
283                         if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
284                                 fprintf (stderr, "%s: Write error on %s: %s\n",
285                                         cmdname, imagefile, strerror(errno));
286                                 exit (EXIT_FAILURE);
287                         }
288
289                         if (!file) {
290                                 break;
291                         }
292
293                         if (sep) {
294                                 *sep = ':';
295                                 file = sep + 1;
296                         } else {
297                                 file = NULL;
298                         }
299                 }
300
301                 file = datafile;
302
303                 for (;;) {
304                         char *sep = strchr(file, ':');
305                         if (sep) {
306                                 *sep = '\0';
307                                 copy_file (ifd, file, 1);
308                                 *sep++ = ':';
309                                 file = sep;
310                         } else {
311                                 copy_file (ifd, file, 0);
312                                 break;
313                         }
314                 }
315         } else {
316                 copy_file (ifd, datafile, 0);
317         }
318
319         /* We're a bit of paranoid */
320 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
321         (void) fdatasync (ifd);
322 #else
323         (void) fsync (ifd);
324 #endif
325
326         if (fstat(ifd, &sbuf) < 0) {
327                 fprintf (stderr, "%s: Can't stat %s: %s\n",
328                         cmdname, imagefile, strerror(errno));
329                 exit (EXIT_FAILURE);
330         }
331
332         ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
333         if (ptr == MAP_FAILED) {
334                 fprintf (stderr, "%s: Can't map %s: %s\n",
335                         cmdname, imagefile, strerror(errno));
336                 exit (EXIT_FAILURE);
337         }
338
339         hdr = (image_header_t *)ptr;
340
341         checksum = crc32 (0,
342                           (const char *)(ptr + image_get_header_size ()),
343                           sbuf.st_size - image_get_header_size ()
344                          );
345
346         /* Build new header */
347         image_set_magic (hdr, IH_MAGIC);
348         image_set_time (hdr, sbuf.st_mtime);
349         image_set_size (hdr, sbuf.st_size - image_get_header_size ());
350         image_set_load (hdr, addr);
351         image_set_ep (hdr, ep);
352         image_set_dcrc (hdr, checksum);
353         image_set_os (hdr, opt_os);
354         image_set_arch (hdr, opt_arch);
355         image_set_type (hdr, opt_type);
356         image_set_comp (hdr, opt_comp);
357
358         image_set_name (hdr, name);
359
360         checksum = crc32 (0, (const char *)hdr, image_get_header_size ());
361
362         image_set_hcrc (hdr, checksum);
363
364         image_print_contents (hdr);
365
366         (void) munmap((void *)ptr, sbuf.st_size);
367
368         /* We're a bit of paranoid */
369 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
370         (void) fdatasync (ifd);
371 #else
372         (void) fsync (ifd);
373 #endif
374
375         if (close(ifd)) {
376                 fprintf (stderr, "%s: Write error on %s: %s\n",
377                         cmdname, imagefile, strerror(errno));
378                 exit (EXIT_FAILURE);
379         }
380
381         exit (EXIT_SUCCESS);
382 }
383
384 static void
385 copy_file (int ifd, const char *datafile, int pad)
386 {
387         int dfd;
388         struct stat sbuf;
389         unsigned char *ptr;
390         int tail;
391         int zero = 0;
392         int offset = 0;
393         int size;
394
395         if (vflag) {
396                 fprintf (stderr, "Adding Image %s\n", datafile);
397         }
398
399         if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
400                 fprintf (stderr, "%s: Can't open %s: %s\n",
401                         cmdname, datafile, strerror(errno));
402                 exit (EXIT_FAILURE);
403         }
404
405         if (fstat(dfd, &sbuf) < 0) {
406                 fprintf (stderr, "%s: Can't stat %s: %s\n",
407                         cmdname, datafile, strerror(errno));
408                 exit (EXIT_FAILURE);
409         }
410
411         ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
412         if (ptr == MAP_FAILED) {
413                 fprintf (stderr, "%s: Can't read %s: %s\n",
414                         cmdname, datafile, strerror(errno));
415                 exit (EXIT_FAILURE);
416         }
417
418         if (xflag) {
419                 unsigned char *p = NULL;
420                 /*
421                  * XIP: do not append the image_header_t at the
422                  * beginning of the file, but consume the space
423                  * reserved for it.
424                  */
425
426                 if ((unsigned)sbuf.st_size < image_get_header_size ()) {
427                         fprintf (stderr,
428                                 "%s: Bad size: \"%s\" is too small for XIP\n",
429                                 cmdname, datafile);
430                         exit (EXIT_FAILURE);
431                 }
432
433                 for (p = ptr; p < ptr + image_get_header_size (); p++) {
434                         if ( *p != 0xff ) {
435                                 fprintf (stderr,
436                                         "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
437                                         cmdname, datafile);
438                                 exit (EXIT_FAILURE);
439                         }
440                 }
441
442                 offset = image_get_header_size ();
443         }
444
445         size = sbuf.st_size - offset;
446         if (write(ifd, ptr + offset, size) != size) {
447                 fprintf (stderr, "%s: Write error on %s: %s\n",
448                         cmdname, imagefile, strerror(errno));
449                 exit (EXIT_FAILURE);
450         }
451
452         if (pad && ((tail = size % 4) != 0)) {
453
454                 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
455                         fprintf (stderr, "%s: Write error on %s: %s\n",
456                                 cmdname, imagefile, strerror(errno));
457                         exit (EXIT_FAILURE);
458                 }
459         }
460
461         (void) munmap((void *)ptr, sbuf.st_size);
462         (void) close (dfd);
463 }
464
465 void
466 usage ()
467 {
468         fprintf (stderr, "Usage: %s -l image\n"
469                          "          -l ==> list image header information\n",
470                 cmdname);
471         fprintf (stderr, "       %s [-x] -A arch -O os -T type -C comp "
472                          "-a addr -e ep -n name -d data_file[:data_file...] image\n"
473                          "          -A ==> set architecture to 'arch'\n"
474                          "          -O ==> set operating system to 'os'\n"
475                          "          -T ==> set image type to 'type'\n"
476                          "          -C ==> set compression type 'comp'\n"
477                          "          -a ==> set load address to 'addr' (hex)\n"
478                          "          -e ==> set entry point to 'ep' (hex)\n"
479                          "          -n ==> set image name to 'name'\n"
480                          "          -d ==> use image data from 'datafile'\n"
481                          "          -x ==> set XIP (execute in place)\n",
482                 cmdname);
483         fprintf (stderr, "       %s [-D dtc_options] -f fit-image.its fit-image\n",
484                 cmdname);
485
486         exit (EXIT_FAILURE);
487 }
488
489 static void
490 image_verify_header (char *ptr, int image_size)
491 {
492         int len;
493         char *data;
494         uint32_t checksum;
495         image_header_t header;
496         image_header_t *hdr = &header;
497
498         /*
499          * create copy of header so that we can blank out the
500          * checksum field for checking - this can't be done
501          * on the PROT_READ mapped data.
502          */
503         memcpy (hdr, ptr, sizeof(image_header_t));
504
505         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
506                 fprintf (stderr,
507                         "%s: Bad Magic Number: \"%s\" is no valid image\n",
508                         cmdname, imagefile);
509                 exit (EXIT_FAILURE);
510         }
511
512         data = (char *)hdr;
513         len  = sizeof(image_header_t);
514
515         checksum = ntohl(hdr->ih_hcrc);
516         hdr->ih_hcrc = htonl(0);        /* clear for re-calculation */
517
518         if (crc32 (0, data, len) != checksum) {
519                 fprintf (stderr,
520                         "%s: ERROR: \"%s\" has bad header checksum!\n",
521                         cmdname, imagefile);
522                 exit (EXIT_FAILURE);
523         }
524
525         data = ptr + sizeof(image_header_t);
526         len  = image_size - sizeof(image_header_t) ;
527
528         if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) {
529                 fprintf (stderr,
530                         "%s: ERROR: \"%s\" has corrupted data!\n",
531                         cmdname, imagefile);
532                 exit (EXIT_FAILURE);
533         }
534 }
535
536 /**
537  * fit_handle_file - main FIT file processing function
538  *
539  * fit_handle_file() runs dtc to convert .its to .itb, includes
540  * binary data, updates timestamp property and calculates hashes.
541  *
542  * datafile  - .its file
543  * imagefile - .itb file
544  *
545  * returns:
546  *     only on success, otherwise calls exit (EXIT_FAILURE);
547  */
548 static void fit_handle_file (void)
549 {
550         char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
551         char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
552         int tfd;
553         struct stat sbuf;
554         unsigned char *ptr;
555
556         /* call dtc to include binary properties into the tmp file */
557         if (strlen (imagefile) + strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 >
558                 sizeof (tmpfile)) {
559                 fprintf (stderr, "%s: Image file name (%s) too long, "
560                                 "can't create tmpfile",
561                                 imagefile, cmdname);
562                 exit (EXIT_FAILURE);
563         }
564         sprintf (tmpfile, "%s%s", imagefile, MKIMAGE_TMPFILE_SUFFIX);
565
566         /* dtc -I dts -O -p 200 datafile > tmpfile */
567         sprintf (cmd, "%s %s %s > %s",
568                         MKIMAGE_DTC, opt_dtc, datafile, tmpfile);
569         debug ("Trying to execute \"%s\"\n", cmd);
570         if (system (cmd) == -1) {
571                 fprintf (stderr, "%s: system(%s) failed: %s\n",
572                                 cmdname, cmd, strerror(errno));
573                 unlink (tmpfile);
574                 exit (EXIT_FAILURE);
575         }
576
577         /* load FIT blob into memory */
578         tfd = open (tmpfile, O_RDWR|O_BINARY);
579
580         if (tfd < 0) {
581                 fprintf (stderr, "%s: Can't open %s: %s\n",
582                                 cmdname, tmpfile, strerror(errno));
583                 unlink (tmpfile);
584                 exit (EXIT_FAILURE);
585         }
586
587         if (fstat (tfd, &sbuf) < 0) {
588                 fprintf (stderr, "%s: Can't stat %s: %s\n",
589                                 cmdname, tmpfile, strerror(errno));
590                 unlink (tmpfile);
591                 exit (EXIT_FAILURE);
592         }
593
594         ptr = mmap (0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, tfd, 0);
595         if (ptr == MAP_FAILED) {
596                 fprintf (stderr, "%s: Can't read %s: %s\n",
597                                 cmdname, tmpfile, strerror(errno));
598                 unlink (tmpfile);
599                 exit (EXIT_FAILURE);
600         }
601
602         /* check if ptr has a valid blob */
603         if (fdt_check_header (ptr)) {
604                 fprintf (stderr, "%s: Invalid FIT blob\n", cmdname);
605                 unlink (tmpfile);
606                 exit (EXIT_FAILURE);
607         }
608
609         /* set hashes for images in the blob */
610         if (fit_set_hashes (ptr)) {
611                 fprintf (stderr, "%s Can't add hashes to FIT blob", cmdname);
612                 unlink (tmpfile);
613                 exit (EXIT_FAILURE);
614         }
615
616         /* add a timestamp at offset 0 i.e., root  */
617         if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) {
618                 fprintf (stderr, "%s: Can't add image timestamp\n", cmdname);
619                 unlink (tmpfile);
620                 exit (EXIT_FAILURE);
621         }
622         debug ("Added timestamp successfully\n");
623
624         munmap ((void *)ptr, sbuf.st_size);
625         close (tfd);
626
627         if (rename (tmpfile, imagefile) == -1) {
628                 fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
629                                 cmdname, tmpfile, imagefile, strerror (errno));
630                 unlink (tmpfile);
631                 unlink (imagefile);
632                 exit (EXIT_FAILURE);
633         }
634 }