xref: /openbmc/u-boot/tools/mkimage.c (revision bf9a5215)
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 }
635