]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/mkimage.c
[new uImage] Share common uImage code between mkimage and U-boot
[karo-tx-uboot.git] / tools / mkimage.c
1 /*
2  * (C) Copyright 2000-2004
3  * DENX Software Engineering
4  * Wolfgang Denk, wd@denx.de
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22
23 #include "mkimage.h"
24 #include <image.h>
25
26 extern int errno;
27
28 #ifndef MAP_FAILED
29 #define MAP_FAILED (-1)
30 #endif
31
32 extern  unsigned long   crc32 (unsigned long crc, const char *buf, unsigned int len);
33 static  void            copy_file (int, const char *, int);
34 static  void            usage (void);
35
36 char    *datafile;
37 char    *imagefile;
38 char    *cmdname;
39
40 int dflag    = 0;
41 int eflag    = 0;
42 int lflag    = 0;
43 int vflag    = 0;
44 int xflag    = 0;
45 int opt_os   = IH_OS_LINUX;
46 int opt_arch = IH_ARCH_PPC;
47 int opt_type = IH_TYPE_KERNEL;
48 int opt_comp = IH_COMP_GZIP;
49
50 image_header_t header;
51 image_header_t *hdr = &header;
52
53 int
54 main (int argc, char **argv)
55 {
56         int ifd;
57         uint32_t checksum;
58         uint32_t addr;
59         uint32_t ep;
60         struct stat sbuf;
61         unsigned char *ptr;
62         char *name = "";
63
64         cmdname = *argv;
65
66         addr = ep = 0;
67
68         while (--argc > 0 && **++argv == '-') {
69                 while (*++*argv) {
70                         switch (**argv) {
71                         case 'l':
72                                 lflag = 1;
73                                 break;
74                         case 'A':
75                                 if ((--argc <= 0) ||
76                                     (opt_arch = genimg_get_arch_id (*++argv)) < 0)
77                                         usage ();
78                                 goto NXTARG;
79                         case 'C':
80                                 if ((--argc <= 0) ||
81                                     (opt_comp = genimg_get_comp_id (*++argv)) < 0)
82                                         usage ();
83                                 goto NXTARG;
84                         case 'O':
85                                 if ((--argc <= 0) ||
86                                     (opt_os = genimg_get_os_id (*++argv)) < 0)
87                                         usage ();
88                                 goto NXTARG;
89                         case 'T':
90                                 if ((--argc <= 0) ||
91                                     (opt_type = genimg_get_type_id (*++argv)) < 0)
92                                         usage ();
93                                 goto NXTARG;
94
95                         case 'a':
96                                 if (--argc <= 0)
97                                         usage ();
98                                 addr = strtoul (*++argv, (char **)&ptr, 16);
99                                 if (*ptr) {
100                                         fprintf (stderr,
101                                                 "%s: invalid load address %s\n",
102                                                 cmdname, *argv);
103                                         exit (EXIT_FAILURE);
104                                 }
105                                 goto NXTARG;
106                         case 'd':
107                                 if (--argc <= 0)
108                                         usage ();
109                                 datafile = *++argv;
110                                 dflag = 1;
111                                 goto NXTARG;
112                         case 'e':
113                                 if (--argc <= 0)
114                                         usage ();
115                                 ep = strtoul (*++argv, (char **)&ptr, 16);
116                                 if (*ptr) {
117                                         fprintf (stderr,
118                                                 "%s: invalid entry point %s\n",
119                                                 cmdname, *argv);
120                                         exit (EXIT_FAILURE);
121                                 }
122                                 eflag = 1;
123                                 goto NXTARG;
124                         case 'n':
125                                 if (--argc <= 0)
126                                         usage ();
127                                 name = *++argv;
128                                 goto NXTARG;
129                         case 'v':
130                                 vflag++;
131                                 break;
132                         case 'x':
133                                 xflag++;
134                                 break;
135                         default:
136                                 usage ();
137                         }
138                 }
139 NXTARG:         ;
140         }
141
142         if ((argc != 1) || ((lflag ^ dflag) == 0))
143                 usage();
144
145         if (!eflag) {
146                 ep = addr;
147                 /* If XIP, entry point must be after the U-Boot header */
148                 if (xflag)
149                         ep += image_get_header_size ();
150         }
151
152         /*
153          * If XIP, ensure the entry point is equal to the load address plus
154          * the size of the U-Boot header.
155          */
156         if (xflag) {
157                 if (ep != addr + image_get_header_size ()) {
158                         fprintf (stderr,
159                                 "%s: For XIP, the entry point must be the load addr + %lu\n",
160                                 cmdname,
161                                 (unsigned long)image_get_header_size ());
162                         exit (EXIT_FAILURE);
163                 }
164         }
165
166         imagefile = *argv;
167
168         if (lflag) {
169                 ifd = open(imagefile, O_RDONLY|O_BINARY);
170         } else {
171                 ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
172         }
173
174         if (ifd < 0) {
175                 fprintf (stderr, "%s: Can't open %s: %s\n",
176                         cmdname, imagefile, strerror(errno));
177                 exit (EXIT_FAILURE);
178         }
179
180         if (lflag) {
181                 int len;
182                 char *data;
183                 /*
184                  * list header information of existing image
185                  */
186                 if (fstat(ifd, &sbuf) < 0) {
187                         fprintf (stderr, "%s: Can't stat %s: %s\n",
188                                 cmdname, imagefile, strerror(errno));
189                         exit (EXIT_FAILURE);
190                 }
191
192                 if ((unsigned)sbuf.st_size < image_get_header_size ()) {
193                         fprintf (stderr,
194                                 "%s: Bad size: \"%s\" is no valid image\n",
195                                 cmdname, imagefile);
196                         exit (EXIT_FAILURE);
197                 }
198
199                 ptr = (unsigned char *)mmap(0, sbuf.st_size,
200                                             PROT_READ, MAP_SHARED, ifd, 0);
201                 if ((caddr_t)ptr == (caddr_t)-1) {
202                         fprintf (stderr, "%s: Can't read %s: %s\n",
203                                 cmdname, imagefile, strerror(errno));
204                         exit (EXIT_FAILURE);
205                 }
206
207                 /*
208                  * image_check_hcrc() creates copy of header so that
209                  * we can blank out the checksum field for checking -
210                  * this can't be done on the PROT_READ mapped data.
211                  */
212                 hdr = (image_header_t *)ptr;
213
214                 if (!image_check_magic (hdr)) {
215                         fprintf (stderr,
216                                 "%s: Bad Magic Number: \"%s\" is no valid image\n",
217                                 cmdname, imagefile);
218                         exit (EXIT_FAILURE);
219                 }
220
221                 if (!image_check_hcrc (hdr)) {
222                         fprintf (stderr,
223                                 "%s: ERROR: \"%s\" has bad header checksum!\n",
224                                 cmdname, imagefile);
225                         exit (EXIT_FAILURE);
226                 }
227
228                 data = (char *)image_get_data (hdr);
229                 len  = sbuf.st_size - image_get_header_size ();
230
231                 if (crc32(0, data, len) != image_get_dcrc (hdr)) {
232                         fprintf (stderr,
233                                 "%s: ERROR: \"%s\" has corrupted data!\n",
234                                 cmdname, imagefile);
235                         exit (EXIT_FAILURE);
236                 }
237
238                 /* for multi-file images we need the data part, too */
239                 image_print_contents_noindent ((image_header_t *)ptr);
240
241                 (void) munmap((void *)ptr, sbuf.st_size);
242                 (void) close (ifd);
243
244                 exit (EXIT_SUCCESS);
245         }
246
247         /*
248          * Must be -w then:
249          *
250          * write dummy header, to be fixed later
251          */
252         memset (hdr, 0, image_get_header_size ());
253
254         if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) {
255                 fprintf (stderr, "%s: Write error on %s: %s\n",
256                         cmdname, imagefile, strerror(errno));
257                 exit (EXIT_FAILURE);
258         }
259
260         if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) {
261                 char *file = datafile;
262                 uint32_t size;
263
264                 for (;;) {
265                         char *sep = NULL;
266
267                         if (file) {
268                                 if ((sep = strchr(file, ':')) != NULL) {
269                                         *sep = '\0';
270                                 }
271
272                                 if (stat (file, &sbuf) < 0) {
273                                         fprintf (stderr, "%s: Can't stat %s: %s\n",
274                                                 cmdname, file, strerror(errno));
275                                         exit (EXIT_FAILURE);
276                                 }
277                                 size = cpu_to_uimage (sbuf.st_size);
278                         } else {
279                                 size = 0;
280                         }
281
282                         if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
283                                 fprintf (stderr, "%s: Write error on %s: %s\n",
284                                         cmdname, imagefile, strerror(errno));
285                                 exit (EXIT_FAILURE);
286                         }
287
288                         if (!file) {
289                                 break;
290                         }
291
292                         if (sep) {
293                                 *sep = ':';
294                                 file = sep + 1;
295                         } else {
296                                 file = NULL;
297                         }
298                 }
299
300                 file = datafile;
301
302                 for (;;) {
303                         char *sep = strchr(file, ':');
304                         if (sep) {
305                                 *sep = '\0';
306                                 copy_file (ifd, file, 1);
307                                 *sep++ = ':';
308                                 file = sep;
309                         } else {
310                                 copy_file (ifd, file, 0);
311                                 break;
312                         }
313                 }
314         } else {
315                 copy_file (ifd, datafile, 0);
316         }
317
318         /* We're a bit of paranoid */
319 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
320         (void) fdatasync (ifd);
321 #else
322         (void) fsync (ifd);
323 #endif
324
325         if (fstat(ifd, &sbuf) < 0) {
326                 fprintf (stderr, "%s: Can't stat %s: %s\n",
327                         cmdname, imagefile, strerror(errno));
328                 exit (EXIT_FAILURE);
329         }
330
331         ptr = (unsigned char *)mmap(0, sbuf.st_size,
332                                     PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
333         if (ptr == (unsigned char *)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_noindent (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 = (unsigned char *)mmap(0, sbuf.st_size,
412                                     PROT_READ, MAP_SHARED, dfd, 0);
413         if (ptr == (unsigned char *)MAP_FAILED) {
414                 fprintf (stderr, "%s: Can't read %s: %s\n",
415                         cmdname, datafile, strerror(errno));
416                 exit (EXIT_FAILURE);
417         }
418
419         if (xflag) {
420                 unsigned char *p = NULL;
421                 /*
422                  * XIP: do not append the image_header_t at the
423                  * beginning of the file, but consume the space
424                  * reserved for it.
425                  */
426
427                 if ((unsigned)sbuf.st_size < image_get_header_size ()) {
428                         fprintf (stderr,
429                                 "%s: Bad size: \"%s\" is too small for XIP\n",
430                                 cmdname, datafile);
431                         exit (EXIT_FAILURE);
432                 }
433
434                 for (p = ptr; p < ptr + image_get_header_size (); p++) {
435                         if ( *p != 0xff ) {
436                                 fprintf (stderr,
437                                         "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
438                                         cmdname, datafile);
439                                 exit (EXIT_FAILURE);
440                         }
441                 }
442
443                 offset = image_get_header_size ();
444         }
445
446         size = sbuf.st_size - offset;
447         if (write(ifd, ptr + offset, size) != size) {
448                 fprintf (stderr, "%s: Write error on %s: %s\n",
449                         cmdname, imagefile, strerror(errno));
450                 exit (EXIT_FAILURE);
451         }
452
453         if (pad && ((tail = size % 4) != 0)) {
454
455                 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
456                         fprintf (stderr, "%s: Write error on %s: %s\n",
457                                 cmdname, imagefile, strerror(errno));
458                         exit (EXIT_FAILURE);
459                 }
460         }
461
462         (void) munmap((void *)ptr, sbuf.st_size);
463         (void) close (dfd);
464 }
465
466 void
467 usage ()
468 {
469         fprintf (stderr, "Usage: %s -l image\n"
470                          "          -l ==> list image header information\n"
471                          "       %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                 cmdname, cmdname);
474         fprintf (stderr, "          -A ==> set architecture to 'arch'\n"
475                          "          -O ==> set operating system to 'os'\n"
476                          "          -T ==> set image type to 'type'\n"
477                          "          -C ==> set compression type 'comp'\n"
478                          "          -a ==> set load address to 'addr' (hex)\n"
479                          "          -e ==> set entry point to 'ep' (hex)\n"
480                          "          -n ==> set image name to 'name'\n"
481                          "          -d ==> use image data from 'datafile'\n"
482                          "          -x ==> set XIP (execute in place)\n"
483                 );
484         exit (EXIT_FAILURE);
485 }