xref: /rk3399_rockchip-uboot/tools/mkimage.c (revision 9bac0bb37402ca72fd905f3e591080b4cfb98c42)
1 /*
2  * (C) Copyright 2008 Semihalf
3  *
4  * (C) Copyright 2000-2009
5  * DENX Software Engineering
6  * Wolfgang Denk, wd@denx.de
7  *
8  * SPDX-License-Identifier:	GPL-2.0+
9  */
10 
11 #include "mkimage.h"
12 #include <image.h>
13 #include <version.h>
14 
15 static void copy_file(int, const char *, int);
16 static void usage(void);
17 
18 /* image_type_params link list to maintain registered image type supports */
19 struct image_type_params *mkimage_tparams = NULL;
20 
21 /* parameters initialized by core will be used by the image type code */
22 struct mkimage_params params = {
23 	.os = IH_OS_LINUX,
24 	.arch = IH_ARCH_PPC,
25 	.type = IH_TYPE_KERNEL,
26 	.comp = IH_COMP_GZIP,
27 	.dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
28 	.imagename = "",
29 	.imagename2 = "",
30 };
31 
32 /*
33  * mkimage_register -
34  *
35  * It is used to register respective image generation/list support to the
36  * mkimage core
37  *
38  * the input struct image_type_params is checked and appended to the link
39  * list, if the input structure is already registered, error
40  */
41 void mkimage_register (struct image_type_params *tparams)
42 {
43 	struct image_type_params **tp;
44 
45 	if (!tparams) {
46 		fprintf (stderr, "%s: %s: Null input\n",
47 			params.cmdname, __FUNCTION__);
48 		exit (EXIT_FAILURE);
49 	}
50 
51 	/* scan the linked list, check for registry and point the last one */
52 	for (tp = &mkimage_tparams; *tp != NULL; tp = &(*tp)->next) {
53 		if (!strcmp((*tp)->name, tparams->name)) {
54 			fprintf (stderr, "%s: %s already registered\n",
55 				params.cmdname, tparams->name);
56 			return;
57 		}
58 	}
59 
60 	/* add input struct entry at the end of link list */
61 	*tp = tparams;
62 	/* mark input entry as last entry in the link list */
63 	tparams->next = NULL;
64 
65 	debug ("Registered %s\n", tparams->name);
66 }
67 
68 /*
69  * mkimage_get_type -
70  *
71  * It scans all registers image type supports
72  * checks the input type_id for each supported image type
73  *
74  * if successful,
75  * 	returns respective image_type_params pointer if success
76  * if input type_id is not supported by any of image_type_support
77  * 	returns NULL
78  */
79 struct image_type_params *mkimage_get_type(int type)
80 {
81 	struct image_type_params *curr;
82 
83 	for (curr = mkimage_tparams; curr != NULL; curr = curr->next) {
84 		if (curr->check_image_type) {
85 			if (!curr->check_image_type (type))
86 				return curr;
87 		}
88 	}
89 	return NULL;
90 }
91 
92 /*
93  * mkimage_verify_print_header -
94  *
95  * It scans mkimage_tparams link list,
96  * verifies image_header for each supported image type
97  * if verification is successful, prints respective header
98  *
99  * returns negative if input image format does not match with any of
100  * supported image types
101  */
102 int mkimage_verify_print_header (void *ptr, struct stat *sbuf)
103 {
104 	int retval = -1;
105 	struct image_type_params *curr;
106 
107 	for (curr = mkimage_tparams; curr != NULL; curr = curr->next ) {
108 		if (curr->verify_header) {
109 			retval = curr->verify_header (
110 				(unsigned char *)ptr, sbuf->st_size,
111 				&params);
112 
113 			if (retval == 0) {
114 				/*
115 				 * Print the image information
116 				 * if verify is successful
117 				 */
118 				if (curr->print_header)
119 					curr->print_header (ptr);
120 				else {
121 					fprintf (stderr,
122 					"%s: print_header undefined for %s\n",
123 					params.cmdname, curr->name);
124 				}
125 				break;
126 			}
127 		}
128 	}
129 	return retval;
130 }
131 
132 int
133 main (int argc, char **argv)
134 {
135 	int ifd = -1;
136 	struct stat sbuf;
137 	char *ptr;
138 	int retval = 0;
139 	struct image_type_params *tparams = NULL;
140 	int pad_len = 0;
141 
142 	/* Init Freescale PBL Boot image generation/list support */
143 	init_pbl_image_type();
144 	/* Init Kirkwood Boot image generation/list support */
145 	init_kwb_image_type ();
146 	/* Init Freescale imx Boot image generation/list support */
147 	init_imx_image_type ();
148 	/* Init FIT image generation/list support */
149 	init_fit_image_type ();
150 	/* Init TI OMAP Boot image generation/list support */
151 	init_omap_image_type();
152 	/* Init Default image generation/list support */
153 	init_default_image_type ();
154 	/* Init Davinci UBL support */
155 	init_ubl_image_type();
156 	/* Init Davinci AIS support */
157 	init_ais_image_type();
158 
159 	params.cmdname = *argv;
160 	params.addr = params.ep = 0;
161 
162 	while (--argc > 0 && **++argv == '-') {
163 		while (*++*argv) {
164 			switch (**argv) {
165 			case 'l':
166 				params.lflag = 1;
167 				break;
168 			case 'A':
169 				if ((--argc <= 0) ||
170 					(params.arch =
171 					genimg_get_arch_id (*++argv)) < 0)
172 					usage ();
173 				goto NXTARG;
174 			case 'c':
175 				if (--argc <= 0)
176 					usage();
177 				params.comment = *++argv;
178 				goto NXTARG;
179 			case 'C':
180 				if ((--argc <= 0) ||
181 					(params.comp =
182 					genimg_get_comp_id (*++argv)) < 0)
183 					usage ();
184 				goto NXTARG;
185 			case 'D':
186 				if (--argc <= 0)
187 					usage ();
188 				params.dtc = *++argv;
189 				goto NXTARG;
190 
191 			case 'O':
192 				if ((--argc <= 0) ||
193 					(params.os =
194 					genimg_get_os_id (*++argv)) < 0)
195 					usage ();
196 				goto NXTARG;
197 			case 'T':
198 				if ((--argc <= 0) ||
199 					(params.type =
200 					genimg_get_type_id (*++argv)) < 0)
201 					usage ();
202 				goto NXTARG;
203 
204 			case 'a':
205 				if (--argc <= 0)
206 					usage ();
207 				params.addr = strtoul (*++argv, &ptr, 16);
208 				if (*ptr) {
209 					fprintf (stderr,
210 						"%s: invalid load address %s\n",
211 						params.cmdname, *argv);
212 					exit (EXIT_FAILURE);
213 				}
214 				goto NXTARG;
215 			case 'd':
216 				if (--argc <= 0)
217 					usage ();
218 				params.datafile = *++argv;
219 				params.dflag = 1;
220 				goto NXTARG;
221 			case 'e':
222 				if (--argc <= 0)
223 					usage ();
224 				params.ep = strtoul (*++argv, &ptr, 16);
225 				if (*ptr) {
226 					fprintf (stderr,
227 						"%s: invalid entry point %s\n",
228 						params.cmdname, *argv);
229 					exit (EXIT_FAILURE);
230 				}
231 				params.eflag = 1;
232 				goto NXTARG;
233 			case 'f':
234 				if (--argc <= 0)
235 					usage ();
236 				params.datafile = *++argv;
237 				/* no break */
238 			case 'F':
239 				/*
240 				 * The flattened image tree (FIT) format
241 				 * requires a flattened device tree image type
242 				 */
243 				params.type = IH_TYPE_FLATDT;
244 				params.fflag = 1;
245 				goto NXTARG;
246 			case 'k':
247 				if (--argc <= 0)
248 					usage();
249 				params.keydir = *++argv;
250 				goto NXTARG;
251 			case 'K':
252 				if (--argc <= 0)
253 					usage();
254 				params.keydest = *++argv;
255 				goto NXTARG;
256 			case 'n':
257 				if (--argc <= 0)
258 					usage ();
259 				params.imagename = *++argv;
260 				goto NXTARG;
261 			case 'r':
262 				params.require_keys = 1;
263 				break;
264 			case 'R':
265 				if (--argc <= 0)
266 					usage();
267 				/*
268 				 * This entry is for the second configuration
269 				 * file, if only one is not enough.
270 				 */
271 				params.imagename2 = *++argv;
272 				goto NXTARG;
273 			case 's':
274 				params.skipcpy = 1;
275 				break;
276 			case 'v':
277 				params.vflag++;
278 				break;
279 			case 'V':
280 				printf("mkimage version %s\n", PLAIN_VERSION);
281 				exit(EXIT_SUCCESS);
282 			case 'x':
283 				params.xflag++;
284 				break;
285 			default:
286 				usage ();
287 			}
288 		}
289 NXTARG:		;
290 	}
291 
292 	if (argc != 1)
293 		usage ();
294 
295 	/* set tparams as per input type_id */
296 	tparams = mkimage_get_type(params.type);
297 	if (tparams == NULL) {
298 		fprintf (stderr, "%s: unsupported type %s\n",
299 			params.cmdname, genimg_get_type_name(params.type));
300 		exit (EXIT_FAILURE);
301 	}
302 
303 	/*
304 	 * check the passed arguments parameters meets the requirements
305 	 * as per image type to be generated/listed
306 	 */
307 	if (tparams->check_params)
308 		if (tparams->check_params (&params))
309 			usage ();
310 
311 	if (!params.eflag) {
312 		params.ep = params.addr;
313 		/* If XIP, entry point must be after the U-Boot header */
314 		if (params.xflag)
315 			params.ep += tparams->header_size;
316 	}
317 
318 	params.imagefile = *argv;
319 
320 	if (params.fflag){
321 		if (tparams->fflag_handle)
322 			/*
323 			 * in some cases, some additional processing needs
324 			 * to be done if fflag is defined
325 			 *
326 			 * For ex. fit_handle_file for Fit file support
327 			 */
328 			retval = tparams->fflag_handle(&params);
329 
330 		if (retval != EXIT_SUCCESS)
331 			exit (retval);
332 	}
333 
334 	if (params.lflag || params.fflag) {
335 		ifd = open (params.imagefile, O_RDONLY|O_BINARY);
336 	} else {
337 		ifd = open (params.imagefile,
338 			O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
339 	}
340 
341 	if (ifd < 0) {
342 		fprintf (stderr, "%s: Can't open %s: %s\n",
343 			params.cmdname, params.imagefile,
344 			strerror(errno));
345 		exit (EXIT_FAILURE);
346 	}
347 
348 	if (params.lflag || params.fflag) {
349 		/*
350 		 * list header information of existing image
351 		 */
352 		if (fstat(ifd, &sbuf) < 0) {
353 			fprintf (stderr, "%s: Can't stat %s: %s\n",
354 				params.cmdname, params.imagefile,
355 				strerror(errno));
356 			exit (EXIT_FAILURE);
357 		}
358 
359 		if ((unsigned)sbuf.st_size < tparams->header_size) {
360 			fprintf (stderr,
361 				"%s: Bad size: \"%s\" is not valid image\n",
362 				params.cmdname, params.imagefile);
363 			exit (EXIT_FAILURE);
364 		}
365 
366 		ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
367 		if (ptr == MAP_FAILED) {
368 			fprintf (stderr, "%s: Can't read %s: %s\n",
369 				params.cmdname, params.imagefile,
370 				strerror(errno));
371 			exit (EXIT_FAILURE);
372 		}
373 
374 		/*
375 		 * scan through mkimage registry for all supported image types
376 		 * and verify the input image file header for match
377 		 * Print the image information for matched image type
378 		 * Returns the error code if not matched
379 		 */
380 		retval = mkimage_verify_print_header (ptr, &sbuf);
381 
382 		(void) munmap((void *)ptr, sbuf.st_size);
383 		(void) close (ifd);
384 
385 		exit (retval);
386 	}
387 
388 	/*
389 	 * In case there an header with a variable
390 	 * length will be added, the corresponding
391 	 * function is called. This is responsible to
392 	 * allocate memory for the header itself.
393 	 */
394 	if (tparams->vrec_header)
395 		pad_len = tparams->vrec_header(&params, tparams);
396 	else
397 		memset(tparams->hdr, 0, tparams->header_size);
398 
399 	if (write(ifd, tparams->hdr, tparams->header_size)
400 					!= tparams->header_size) {
401 		fprintf (stderr, "%s: Write error on %s: %s\n",
402 			params.cmdname, params.imagefile, strerror(errno));
403 		exit (EXIT_FAILURE);
404 	}
405 
406 	if (!params.skipcpy) {
407 		if (params.type == IH_TYPE_MULTI ||
408 		    params.type == IH_TYPE_SCRIPT) {
409 			char *file = params.datafile;
410 			uint32_t size;
411 
412 			for (;;) {
413 				char *sep = NULL;
414 
415 				if (file) {
416 					if ((sep = strchr(file, ':')) != NULL) {
417 						*sep = '\0';
418 					}
419 
420 					if (stat (file, &sbuf) < 0) {
421 						fprintf (stderr, "%s: Can't stat %s: %s\n",
422 							 params.cmdname, file, strerror(errno));
423 						exit (EXIT_FAILURE);
424 					}
425 					size = cpu_to_uimage (sbuf.st_size);
426 				} else {
427 					size = 0;
428 				}
429 
430 				if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
431 					fprintf (stderr, "%s: Write error on %s: %s\n",
432 						 params.cmdname, params.imagefile,
433 						 strerror(errno));
434 					exit (EXIT_FAILURE);
435 				}
436 
437 				if (!file) {
438 					break;
439 				}
440 
441 				if (sep) {
442 					*sep = ':';
443 					file = sep + 1;
444 				} else {
445 					file = NULL;
446 				}
447 			}
448 
449 			file = params.datafile;
450 
451 			for (;;) {
452 				char *sep = strchr(file, ':');
453 				if (sep) {
454 					*sep = '\0';
455 					copy_file (ifd, file, 1);
456 					*sep++ = ':';
457 					file = sep;
458 				} else {
459 					copy_file (ifd, file, 0);
460 					break;
461 				}
462 			}
463 		} else if (params.type == IH_TYPE_PBLIMAGE) {
464 			/* PBL has special Image format, implements its' own */
465 			pbl_load_uboot(ifd, &params);
466 		} else {
467 			copy_file(ifd, params.datafile, pad_len);
468 		}
469 	}
470 
471 	/* We're a bit of paranoid */
472 #if defined(_POSIX_SYNCHRONIZED_IO) && \
473    !defined(__sun__) && \
474    !defined(__FreeBSD__) && \
475    !defined(__APPLE__)
476 	(void) fdatasync (ifd);
477 #else
478 	(void) fsync (ifd);
479 #endif
480 
481 	if (fstat(ifd, &sbuf) < 0) {
482 		fprintf (stderr, "%s: Can't stat %s: %s\n",
483 			params.cmdname, params.imagefile, strerror(errno));
484 		exit (EXIT_FAILURE);
485 	}
486 
487 	ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
488 	if (ptr == MAP_FAILED) {
489 		fprintf (stderr, "%s: Can't map %s: %s\n",
490 			params.cmdname, params.imagefile, strerror(errno));
491 		exit (EXIT_FAILURE);
492 	}
493 
494 	/* Setup the image header as per input image type*/
495 	if (tparams->set_header)
496 		tparams->set_header (ptr, &sbuf, ifd, &params);
497 	else {
498 		fprintf (stderr, "%s: Can't set header for %s: %s\n",
499 			params.cmdname, tparams->name, strerror(errno));
500 		exit (EXIT_FAILURE);
501 	}
502 
503 	/* Print the image information by processing image header */
504 	if (tparams->print_header)
505 		tparams->print_header (ptr);
506 	else {
507 		fprintf (stderr, "%s: Can't print header for %s: %s\n",
508 			params.cmdname, tparams->name, strerror(errno));
509 		exit (EXIT_FAILURE);
510 	}
511 
512 	(void) munmap((void *)ptr, sbuf.st_size);
513 
514 	/* We're a bit of paranoid */
515 #if defined(_POSIX_SYNCHRONIZED_IO) && \
516    !defined(__sun__) && \
517    !defined(__FreeBSD__) && \
518    !defined(__APPLE__)
519 	(void) fdatasync (ifd);
520 #else
521 	(void) fsync (ifd);
522 #endif
523 
524 	if (close(ifd)) {
525 		fprintf (stderr, "%s: Write error on %s: %s\n",
526 			params.cmdname, params.imagefile, strerror(errno));
527 		exit (EXIT_FAILURE);
528 	}
529 
530 	exit (EXIT_SUCCESS);
531 }
532 
533 static void
534 copy_file (int ifd, const char *datafile, int pad)
535 {
536 	int dfd;
537 	struct stat sbuf;
538 	unsigned char *ptr;
539 	int tail;
540 	int zero = 0;
541 	uint8_t zeros[4096];
542 	int offset = 0;
543 	int size;
544 	struct image_type_params *tparams = mkimage_get_type (params.type);
545 
546 	if (pad >= sizeof(zeros)) {
547 		fprintf(stderr, "%s: Can't pad to %d\n",
548 			params.cmdname, pad);
549 		exit(EXIT_FAILURE);
550 	}
551 
552 	memset(zeros, 0, sizeof(zeros));
553 
554 	if (params.vflag) {
555 		fprintf (stderr, "Adding Image %s\n", datafile);
556 	}
557 
558 	if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
559 		fprintf (stderr, "%s: Can't open %s: %s\n",
560 			params.cmdname, datafile, strerror(errno));
561 		exit (EXIT_FAILURE);
562 	}
563 
564 	if (fstat(dfd, &sbuf) < 0) {
565 		fprintf (stderr, "%s: Can't stat %s: %s\n",
566 			params.cmdname, datafile, strerror(errno));
567 		exit (EXIT_FAILURE);
568 	}
569 
570 	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
571 	if (ptr == MAP_FAILED) {
572 		fprintf (stderr, "%s: Can't read %s: %s\n",
573 			params.cmdname, datafile, strerror(errno));
574 		exit (EXIT_FAILURE);
575 	}
576 
577 	if (params.xflag) {
578 		unsigned char *p = NULL;
579 		/*
580 		 * XIP: do not append the image_header_t at the
581 		 * beginning of the file, but consume the space
582 		 * reserved for it.
583 		 */
584 
585 		if ((unsigned)sbuf.st_size < tparams->header_size) {
586 			fprintf (stderr,
587 				"%s: Bad size: \"%s\" is too small for XIP\n",
588 				params.cmdname, datafile);
589 			exit (EXIT_FAILURE);
590 		}
591 
592 		for (p = ptr; p < ptr + tparams->header_size; p++) {
593 			if ( *p != 0xff ) {
594 				fprintf (stderr,
595 					"%s: Bad file: \"%s\" has invalid buffer for XIP\n",
596 					params.cmdname, datafile);
597 				exit (EXIT_FAILURE);
598 			}
599 		}
600 
601 		offset = tparams->header_size;
602 	}
603 
604 	size = sbuf.st_size - offset;
605 	if (write(ifd, ptr + offset, size) != size) {
606 		fprintf (stderr, "%s: Write error on %s: %s\n",
607 			params.cmdname, params.imagefile, strerror(errno));
608 		exit (EXIT_FAILURE);
609 	}
610 
611 	tail = size % 4;
612 	if ((pad == 1) && (tail != 0)) {
613 
614 		if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
615 			fprintf (stderr, "%s: Write error on %s: %s\n",
616 				params.cmdname, params.imagefile,
617 				strerror(errno));
618 			exit (EXIT_FAILURE);
619 		}
620 	} else if (pad > 1) {
621 		if (write(ifd, (char *)&zeros, pad) != pad) {
622 			fprintf(stderr, "%s: Write error on %s: %s\n",
623 				params.cmdname, params.imagefile,
624 				strerror(errno));
625 			exit(EXIT_FAILURE);
626 		}
627 	}
628 
629 	(void) munmap((void *)ptr, sbuf.st_size);
630 	(void) close (dfd);
631 }
632 
633 void
634 usage ()
635 {
636 	fprintf (stderr, "Usage: %s -l image\n"
637 			 "          -l ==> list image header information\n",
638 		params.cmdname);
639 	fprintf (stderr, "       %s [-x] -A arch -O os -T type -C comp "
640 			 "-a addr -e ep -n name -d data_file[:data_file...] image\n"
641 			 "          -A ==> set architecture to 'arch'\n"
642 			 "          -O ==> set operating system to 'os'\n"
643 			 "          -T ==> set image type to 'type'\n"
644 			 "          -C ==> set compression type 'comp'\n"
645 			 "          -a ==> set load address to 'addr' (hex)\n"
646 			 "          -e ==> set entry point to 'ep' (hex)\n"
647 			 "          -n ==> set image name to 'name'\n"
648 			 "          -d ==> use image data from 'datafile'\n"
649 			 "          -x ==> set XIP (execute in place)\n",
650 		params.cmdname);
651 	fprintf(stderr, "       %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n",
652 		params.cmdname);
653 	fprintf(stderr, "          -D => set options for device tree compiler\n"
654 			"          -f => input filename for FIT source\n");
655 #ifdef CONFIG_FIT_SIGNATURE
656 	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n"
657 			"          -k => set directory containing private keys\n"
658 			"          -K => write public keys to this .dtb file\n"
659 			"          -c => add comment in signature node\n"
660 			"          -F => re-sign existing FIT image\n"
661 			"          -r => mark keys used as 'required' in dtb\n");
662 #else
663 	fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
664 #endif
665 	fprintf (stderr, "       %s -V ==> print version information and exit\n",
666 		params.cmdname);
667 
668 	exit (EXIT_FAILURE);
669 }
670