Memory footprint optimizations
[platform/kernel/u-boot.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 (-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 = (unsigned char *)mmap(0, sbuf.st_size,
222                                             PROT_READ, MAP_SHARED, ifd, 0);
223                 if ((caddr_t)ptr == (caddr_t)-1) {
224                         fprintf (stderr, "%s: Can't read %s: %s\n",
225                                 cmdname, imagefile, strerror(errno));
226                         exit (EXIT_FAILURE);
227                 }
228
229                 if (fdt_check_header (ptr)) {
230                         /* old-style image */
231                         image_verify_header ((char *)ptr, sbuf.st_size);
232                         image_print_contents ((image_header_t *)ptr);
233                 } else {
234                         /* FIT image */
235                         fit_print_contents (ptr);
236                 }
237
238                 (void) munmap((void *)ptr, sbuf.st_size);
239                 (void) close (ifd);
240
241                 exit (EXIT_SUCCESS);
242         } else if (fflag) {
243                 /* Flattened Image Tree (FIT) format  handling */
244                 debug ("FIT format handling\n");
245                 fit_handle_file ();
246                 exit (EXIT_SUCCESS);
247         }
248
249         /*
250          * Must be -w then:
251          *
252          * write dummy header, to be fixed later
253          */
254         memset (hdr, 0, image_get_header_size ());
255
256         if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) {
257                 fprintf (stderr, "%s: Write error on %s: %s\n",
258                         cmdname, imagefile, strerror(errno));
259                 exit (EXIT_FAILURE);
260         }
261
262         if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) {
263                 char *file = datafile;
264                 uint32_t size;
265
266                 for (;;) {
267                         char *sep = NULL;
268
269                         if (file) {
270                                 if ((sep = strchr(file, ':')) != NULL) {
271                                         *sep = '\0';
272                                 }
273
274                                 if (stat (file, &sbuf) < 0) {
275                                         fprintf (stderr, "%s: Can't stat %s: %s\n",
276                                                 cmdname, file, strerror(errno));
277                                         exit (EXIT_FAILURE);
278                                 }
279                                 size = cpu_to_uimage (sbuf.st_size);
280                         } else {
281                                 size = 0;
282                         }
283
284                         if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
285                                 fprintf (stderr, "%s: Write error on %s: %s\n",
286                                         cmdname, imagefile, strerror(errno));
287                                 exit (EXIT_FAILURE);
288                         }
289
290                         if (!file) {
291                                 break;
292                         }
293
294                         if (sep) {
295                                 *sep = ':';
296                                 file = sep + 1;
297                         } else {
298                                 file = NULL;
299                         }
300                 }
301
302                 file = datafile;
303
304                 for (;;) {
305                         char *sep = strchr(file, ':');
306                         if (sep) {
307                                 *sep = '\0';
308                                 copy_file (ifd, file, 1);
309                                 *sep++ = ':';
310                                 file = sep;
311                         } else {
312                                 copy_file (ifd, file, 0);
313                                 break;
314                         }
315                 }
316         } else {
317                 copy_file (ifd, datafile, 0);
318         }
319
320         /* We're a bit of paranoid */
321 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
322         (void) fdatasync (ifd);
323 #else
324         (void) fsync (ifd);
325 #endif
326
327         if (fstat(ifd, &sbuf) < 0) {
328                 fprintf (stderr, "%s: Can't stat %s: %s\n",
329                         cmdname, imagefile, strerror(errno));
330                 exit (EXIT_FAILURE);
331         }
332
333         ptr = (unsigned char *)mmap(0, sbuf.st_size,
334                                     PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
335         if (ptr == (unsigned char *)MAP_FAILED) {
336                 fprintf (stderr, "%s: Can't map %s: %s\n",
337                         cmdname, imagefile, strerror(errno));
338                 exit (EXIT_FAILURE);
339         }
340
341         hdr = (image_header_t *)ptr;
342
343         checksum = crc32 (0,
344                           (const char *)(ptr + image_get_header_size ()),
345                           sbuf.st_size - image_get_header_size ()
346                          );
347
348         /* Build new header */
349         image_set_magic (hdr, IH_MAGIC);
350         image_set_time (hdr, sbuf.st_mtime);
351         image_set_size (hdr, sbuf.st_size - image_get_header_size ());
352         image_set_load (hdr, addr);
353         image_set_ep (hdr, ep);
354         image_set_dcrc (hdr, checksum);
355         image_set_os (hdr, opt_os);
356         image_set_arch (hdr, opt_arch);
357         image_set_type (hdr, opt_type);
358         image_set_comp (hdr, opt_comp);
359
360         image_set_name (hdr, name);
361
362         checksum = crc32 (0, (const char *)hdr, image_get_header_size ());
363
364         image_set_hcrc (hdr, checksum);
365
366         image_print_contents (hdr);
367
368         (void) munmap((void *)ptr, sbuf.st_size);
369
370         /* We're a bit of paranoid */
371 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
372         (void) fdatasync (ifd);
373 #else
374         (void) fsync (ifd);
375 #endif
376
377         if (close(ifd)) {
378                 fprintf (stderr, "%s: Write error on %s: %s\n",
379                         cmdname, imagefile, strerror(errno));
380                 exit (EXIT_FAILURE);
381         }
382
383         exit (EXIT_SUCCESS);
384 }
385
386 static void
387 copy_file (int ifd, const char *datafile, int pad)
388 {
389         int dfd;
390         struct stat sbuf;
391         unsigned char *ptr;
392         int tail;
393         int zero = 0;
394         int offset = 0;
395         int size;
396
397         if (vflag) {
398                 fprintf (stderr, "Adding Image %s\n", datafile);
399         }
400
401         if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
402                 fprintf (stderr, "%s: Can't open %s: %s\n",
403                         cmdname, datafile, strerror(errno));
404                 exit (EXIT_FAILURE);
405         }
406
407         if (fstat(dfd, &sbuf) < 0) {
408                 fprintf (stderr, "%s: Can't stat %s: %s\n",
409                         cmdname, datafile, strerror(errno));
410                 exit (EXIT_FAILURE);
411         }
412
413         ptr = (unsigned char *)mmap(0, sbuf.st_size,
414                                     PROT_READ, MAP_SHARED, dfd, 0);
415         if (ptr == (unsigned char *)MAP_FAILED) {
416                 fprintf (stderr, "%s: Can't read %s: %s\n",
417                         cmdname, datafile, strerror(errno));
418                 exit (EXIT_FAILURE);
419         }
420
421         if (xflag) {
422                 unsigned char *p = NULL;
423                 /*
424                  * XIP: do not append the image_header_t at the
425                  * beginning of the file, but consume the space
426                  * reserved for it.
427                  */
428
429                 if ((unsigned)sbuf.st_size < image_get_header_size ()) {
430                         fprintf (stderr,
431                                 "%s: Bad size: \"%s\" is too small for XIP\n",
432                                 cmdname, datafile);
433                         exit (EXIT_FAILURE);
434                 }
435
436                 for (p = ptr; p < ptr + image_get_header_size (); p++) {
437                         if ( *p != 0xff ) {
438                                 fprintf (stderr,
439                                         "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
440                                         cmdname, datafile);
441                                 exit (EXIT_FAILURE);
442                         }
443                 }
444
445                 offset = image_get_header_size ();
446         }
447
448         size = sbuf.st_size - offset;
449         if (write(ifd, ptr + offset, size) != size) {
450                 fprintf (stderr, "%s: Write error on %s: %s\n",
451                         cmdname, imagefile, strerror(errno));
452                 exit (EXIT_FAILURE);
453         }
454
455         if (pad && ((tail = size % 4) != 0)) {
456
457                 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
458                         fprintf (stderr, "%s: Write error on %s: %s\n",
459                                 cmdname, imagefile, strerror(errno));
460                         exit (EXIT_FAILURE);
461                 }
462         }
463
464         (void) munmap((void *)ptr, sbuf.st_size);
465         (void) close (dfd);
466 }
467
468 void
469 usage ()
470 {
471         fprintf (stderr, "Usage: %s -l image\n"
472                          "          -l ==> list image header information\n",
473                 cmdname);
474         fprintf (stderr, "       %s [-x] -A arch -O os -T type -C comp "
475                          "-a addr -e ep -n name -d data_file[:data_file...] image\n"
476                          "          -A ==> set architecture to 'arch'\n"
477                          "          -O ==> set operating system to 'os'\n"
478                          "          -T ==> set image type to 'type'\n"
479                          "          -C ==> set compression type 'comp'\n"
480                          "          -a ==> set load address to 'addr' (hex)\n"
481                          "          -e ==> set entry point to 'ep' (hex)\n"
482                          "          -n ==> set image name to 'name'\n"
483                          "          -d ==> use image data from 'datafile'\n"
484                          "          -x ==> set XIP (execute in place)\n",
485                 cmdname);
486         fprintf (stderr, "       %s [-D dtc_options] -f fit-image.its fit-image\n",
487                 cmdname);
488
489         exit (EXIT_FAILURE);
490 }
491
492 static void
493 image_verify_header (char *ptr, int image_size)
494 {
495         int len;
496         char *data;
497         uint32_t checksum;
498         image_header_t header;
499         image_header_t *hdr = &header;
500
501         /*
502          * create copy of header so that we can blank out the
503          * checksum field for checking - this can't be done
504          * on the PROT_READ mapped data.
505          */
506         memcpy (hdr, ptr, sizeof(image_header_t));
507
508         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
509                 fprintf (stderr,
510                         "%s: Bad Magic Number: \"%s\" is no valid image\n",
511                         cmdname, imagefile);
512                 exit (EXIT_FAILURE);
513         }
514
515         data = (char *)hdr;
516         len  = sizeof(image_header_t);
517
518         checksum = ntohl(hdr->ih_hcrc);
519         hdr->ih_hcrc = htonl(0);        /* clear for re-calculation */
520
521         if (crc32 (0, data, len) != checksum) {
522                 fprintf (stderr,
523                         "%s: ERROR: \"%s\" has bad header checksum!\n",
524                         cmdname, imagefile);
525                 exit (EXIT_FAILURE);
526         }
527
528         data = ptr + sizeof(image_header_t);
529         len  = image_size - sizeof(image_header_t) ;
530
531         if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) {
532                 fprintf (stderr,
533                         "%s: ERROR: \"%s\" has corrupted data!\n",
534                         cmdname, imagefile);
535                 exit (EXIT_FAILURE);
536         }
537 }
538
539 /**
540  * fit_handle_file - main FIT file processing function
541  *
542  * fit_handle_file() runs dtc to convert .its to .itb, includes
543  * binary data, updates timestamp property and calculates hashes.
544  *
545  * datafile  - .its file
546  * imagefile - .itb file
547  *
548  * returns:
549  *     only on success, otherwise calls exit (EXIT_FAILURE);
550  */
551 static void fit_handle_file (void)
552 {
553         char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
554         char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
555         int tfd;
556         struct stat sbuf;
557         unsigned char *ptr;
558
559         /* call dtc to include binary properties into the tmp file */
560         if (strlen (imagefile) + strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 >
561                 sizeof (tmpfile)) {
562                 fprintf (stderr, "%s: Image file name (%s) too long, "
563                                 "can't create tmpfile",
564                                 imagefile, cmdname);
565                 exit (EXIT_FAILURE);
566         }
567         sprintf (tmpfile, "%s%s", imagefile, MKIMAGE_TMPFILE_SUFFIX);
568
569         /* dtc -I dts -O -p 200 datafile > tmpfile */
570         sprintf (cmd, "%s %s %s > %s",
571                         MKIMAGE_DTC, opt_dtc, datafile, tmpfile);
572         debug ("Trying to execute \"%s\"\n", cmd);
573         if (system (cmd) == -1) {
574                 fprintf (stderr, "%s: system(%s) failed: %s\n",
575                                 cmdname, cmd, strerror(errno));
576                 unlink (tmpfile);
577                 exit (EXIT_FAILURE);
578         }
579
580         /* load FIT blob into memory */
581         tfd = open (tmpfile, O_RDWR|O_BINARY);
582
583         if (tfd < 0) {
584                 fprintf (stderr, "%s: Can't open %s: %s\n",
585                                 cmdname, tmpfile, strerror(errno));
586                 unlink (tmpfile);
587                 exit (EXIT_FAILURE);
588         }
589
590         if (fstat (tfd, &sbuf) < 0) {
591                 fprintf (stderr, "%s: Can't stat %s: %s\n",
592                                 cmdname, tmpfile, strerror(errno));
593                 unlink (tmpfile);
594                 exit (EXIT_FAILURE);
595         }
596
597         ptr = (unsigned char *)mmap (0, sbuf.st_size,
598                         PROT_READ|PROT_WRITE, MAP_SHARED, tfd, 0);
599         if ((caddr_t)ptr == (caddr_t)-1) {
600                 fprintf (stderr, "%s: Can't read %s: %s\n",
601                                 cmdname, tmpfile, strerror(errno));
602                 unlink (tmpfile);
603                 exit (EXIT_FAILURE);
604         }
605
606         /* check if ptr has a valid blob */
607         if (fdt_check_header (ptr)) {
608                 fprintf (stderr, "%s: Invalid FIT blob\n", cmdname);
609                 unlink (tmpfile);
610                 exit (EXIT_FAILURE);
611         }
612
613         /* set hashes for images in the blob */
614         if (fit_set_hashes (ptr)) {
615                 fprintf (stderr, "%s Can't add hashes to FIT blob", cmdname);
616                 unlink (tmpfile);
617                 exit (EXIT_FAILURE);
618         }
619
620         /* add a timestamp at offset 0 i.e., root  */
621         if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) {
622                 fprintf (stderr, "%s: Can't add image timestamp\n", cmdname);
623                 unlink (tmpfile);
624                 exit (EXIT_FAILURE);
625         }
626         debug ("Added timestamp successfully\n");
627
628         munmap ((void *)ptr, sbuf.st_size);
629         close (tfd);
630
631         if (rename (tmpfile, imagefile) == -1) {
632                 fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
633                                 cmdname, tmpfile, imagefile, strerror (errno));
634                 unlink (tmpfile);
635                 unlink (imagefile);
636                 exit (EXIT_FAILURE);
637         }
638 }