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