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