blob: 5cb2bc74ee64cdcbd6d7ce0e7a3b1ca289057dc5 [file] [log] [blame]
wdenk5b1d7132002-11-03 00:07:02 +00001/*
wdenk0c852a22004-02-26 23:01:04 +00002 * (C) Copyright 2000-2004
wdenk5b1d7132002-11-03 00:07:02 +00003 * DENX Software Engineering
4 * Wolfgang Denk, wd@denx.de
5 * All rights reserved.
wdenk0c852a22004-02-26 23:01:04 +00006 *
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
wdenk5b1d7132002-11-03 00:07:02 +000021 */
22
Marian Balakowiczb97a2a02008-01-08 18:14:09 +010023#include "mkimage.h"
wdenk5b1d7132002-11-03 00:07:02 +000024#include <image.h>
25
26extern int errno;
27
28#ifndef MAP_FAILED
29#define MAP_FAILED (-1)
30#endif
31
Marian Balakowicz570abb02008-02-29 15:59:59 +010032extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len);
33static void copy_file (int, const char *, int);
34static void usage (void);
wdenk5b1d7132002-11-03 00:07:02 +000035
36char *datafile;
37char *imagefile;
Marian Balakowicz570abb02008-02-29 15:59:59 +010038char *cmdname;
wdenk5b1d7132002-11-03 00:07:02 +000039
40int dflag = 0;
41int eflag = 0;
42int lflag = 0;
43int vflag = 0;
44int xflag = 0;
45int opt_os = IH_OS_LINUX;
Marian Balakowiczb97a2a02008-01-08 18:14:09 +010046int opt_arch = IH_ARCH_PPC;
wdenk5b1d7132002-11-03 00:07:02 +000047int opt_type = IH_TYPE_KERNEL;
48int opt_comp = IH_COMP_GZIP;
49
50image_header_t header;
51image_header_t *hdr = &header;
52
53int
54main (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) ||
Marian Balakowicz570abb02008-02-29 15:59:59 +010076 (opt_arch = genimg_get_arch_id (*++argv)) < 0)
wdenk5b1d7132002-11-03 00:07:02 +000077 usage ();
78 goto NXTARG;
79 case 'C':
80 if ((--argc <= 0) ||
Marian Balakowicz570abb02008-02-29 15:59:59 +010081 (opt_comp = genimg_get_comp_id (*++argv)) < 0)
wdenk5b1d7132002-11-03 00:07:02 +000082 usage ();
83 goto NXTARG;
84 case 'O':
85 if ((--argc <= 0) ||
Marian Balakowicz570abb02008-02-29 15:59:59 +010086 (opt_os = genimg_get_os_id (*++argv)) < 0)
wdenk5b1d7132002-11-03 00:07:02 +000087 usage ();
88 goto NXTARG;
89 case 'T':
90 if ((--argc <= 0) ||
Marian Balakowicz570abb02008-02-29 15:59:59 +010091 (opt_type = genimg_get_type_id (*++argv)) < 0)
wdenk5b1d7132002-11-03 00:07:02 +000092 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 }
139NXTARG: ;
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)
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100149 ep += image_get_header_size ();
wdenk5b1d7132002-11-03 00:07:02 +0000150 }
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) {
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100157 if (ep != addr + image_get_header_size ()) {
Wolfgang Denk3577d3a2006-04-28 21:24:32 +0200158 fprintf (stderr,
159 "%s: For XIP, the entry point must be the load addr + %lu\n",
wdenka6c7ad22002-12-03 21:28:10 +0000160 cmdname,
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100161 (unsigned long)image_get_header_size ());
wdenk5b1d7132002-11-03 00:07:02 +0000162 exit (EXIT_FAILURE);
163 }
164 }
165
166 imagefile = *argv;
167
168 if (lflag) {
wdenkef1464c2003-10-08 22:14:02 +0000169 ifd = open(imagefile, O_RDONLY|O_BINARY);
wdenk5b1d7132002-11-03 00:07:02 +0000170 } else {
wdenk5b1d7132002-11-03 00:07:02 +0000171 ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
wdenk5b1d7132002-11-03 00:07:02 +0000172 }
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
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100192 if ((unsigned)sbuf.st_size < image_get_header_size ()) {
wdenk5b1d7132002-11-03 00:07:02 +0000193 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 /*
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100208 * 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.
wdenk5b1d7132002-11-03 00:07:02 +0000211 */
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100212 hdr = (image_header_t *)ptr;
wdenk5b1d7132002-11-03 00:07:02 +0000213
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100214 if (!image_check_magic (hdr)) {
wdenk5b1d7132002-11-03 00:07:02 +0000215 fprintf (stderr,
216 "%s: Bad Magic Number: \"%s\" is no valid image\n",
217 cmdname, imagefile);
218 exit (EXIT_FAILURE);
219 }
220
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100221 if (!image_check_hcrc (hdr)) {
wdenk5b1d7132002-11-03 00:07:02 +0000222 fprintf (stderr,
Wolfgang Denk3577d3a2006-04-28 21:24:32 +0200223 "%s: ERROR: \"%s\" has bad header checksum!\n",
224 cmdname, imagefile);
225 exit (EXIT_FAILURE);
wdenk5b1d7132002-11-03 00:07:02 +0000226 }
227
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100228 data = (char *)image_get_data (hdr);
229 len = sbuf.st_size - image_get_header_size ();
wdenk5b1d7132002-11-03 00:07:02 +0000230
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100231 if (crc32(0, data, len) != image_get_dcrc (hdr)) {
wdenk5b1d7132002-11-03 00:07:02 +0000232 fprintf (stderr,
Wolfgang Denk3577d3a2006-04-28 21:24:32 +0200233 "%s: ERROR: \"%s\" has corrupted data!\n",
234 cmdname, imagefile);
235 exit (EXIT_FAILURE);
wdenk5b1d7132002-11-03 00:07:02 +0000236 }
237
238 /* for multi-file images we need the data part, too */
Marian Balakowicz570abb02008-02-29 15:59:59 +0100239 image_print_contents_noindent ((image_header_t *)ptr);
wdenk5b1d7132002-11-03 00:07:02 +0000240
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 */
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100252 memset (hdr, 0, image_get_header_size ());
wdenk5b1d7132002-11-03 00:07:02 +0000253
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100254 if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) {
wdenk5b1d7132002-11-03 00:07:02 +0000255 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;
Wolfgang Denk3bb66802006-01-11 13:03:54 +0100262 uint32_t size;
wdenk5b1d7132002-11-03 00:07:02 +0000263
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 }
Marian Balakowicz9a4daad2008-02-29 14:58:34 +0100277 size = cpu_to_uimage (sbuf.st_size);
wdenk5b1d7132002-11-03 00:07:02 +0000278 } 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 */
Aubrey.Li5dfaa502007-05-14 11:47:35 +0800319#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
wdenk5b1d7132002-11-03 00:07:02 +0000320 (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,
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100342 (const char *)(ptr + image_get_header_size ()),
343 sbuf.st_size - image_get_header_size ()
wdenk5b1d7132002-11-03 00:07:02 +0000344 );
345
346 /* Build new header */
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100347 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);
wdenk5b1d7132002-11-03 00:07:02 +0000357
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100358 image_set_name (hdr, name);
wdenk5b1d7132002-11-03 00:07:02 +0000359
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100360 checksum = crc32 (0, (const char *)hdr, image_get_header_size ());
wdenk5b1d7132002-11-03 00:07:02 +0000361
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100362 image_set_hcrc (hdr, checksum);
wdenk5b1d7132002-11-03 00:07:02 +0000363
Marian Balakowicz570abb02008-02-29 15:59:59 +0100364 image_print_contents_noindent (hdr);
wdenk5b1d7132002-11-03 00:07:02 +0000365
366 (void) munmap((void *)ptr, sbuf.st_size);
367
368 /* We're a bit of paranoid */
Aubrey.Li5dfaa502007-05-14 11:47:35 +0800369#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
wdenk5b1d7132002-11-03 00:07:02 +0000370 (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
384static void
385copy_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
wdenkef1464c2003-10-08 22:14:02 +0000399 if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
wdenk5b1d7132002-11-03 00:07:02 +0000400 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
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100427 if ((unsigned)sbuf.st_size < image_get_header_size ()) {
wdenk5b1d7132002-11-03 00:07:02 +0000428 fprintf (stderr,
429 "%s: Bad size: \"%s\" is too small for XIP\n",
430 cmdname, datafile);
431 exit (EXIT_FAILURE);
432 }
433
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100434 for (p = ptr; p < ptr + image_get_header_size (); p++) {
wdenk5b1d7132002-11-03 00:07:02 +0000435 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
Marian Balakowiczb97a2a02008-01-08 18:14:09 +0100443 offset = image_get_header_size ();
wdenk5b1d7132002-11-03 00:07:02 +0000444 }
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
466void
467usage ()
468{
469 fprintf (stderr, "Usage: %s -l image\n"
470 " -l ==> list image header information\n"
wdenk9d5028c2004-11-21 00:06:33 +0000471 " %s [-x] -A arch -O os -T type -C comp "
wdenk5b1d7132002-11-03 00:07:02 +0000472 "-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}