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