xref: /rk3399_rockchip-uboot/tools/mkimage.c (revision 570abb0ad120f6002bcaa3cf6f32bd4ca2e1b248)
1 /*
2  * (C) Copyright 2000-2004
3  * DENX Software Engineering
4  * Wolfgang Denk, wd@denx.de
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 
23 #include "mkimage.h"
24 #include <image.h>
25 
26 extern int errno;
27 
28 #ifndef MAP_FAILED
29 #define MAP_FAILED (-1)
30 #endif
31 
32 extern	unsigned long	crc32 (unsigned long crc, const char *buf, unsigned int len);
33 static	void		copy_file (int, const char *, int);
34 static	void		usage (void);
35 
36 char	*datafile;
37 char	*imagefile;
38 char	*cmdname;
39 
40 int dflag    = 0;
41 int eflag    = 0;
42 int lflag    = 0;
43 int vflag    = 0;
44 int xflag    = 0;
45 int opt_os   = IH_OS_LINUX;
46 int opt_arch = IH_ARCH_PPC;
47 int opt_type = IH_TYPE_KERNEL;
48 int opt_comp = IH_COMP_GZIP;
49 
50 image_header_t header;
51 image_header_t *hdr = &header;
52 
53 int
54 main (int argc, char **argv)
55 {
56 	int ifd;
57 	uint32_t checksum;
58 	uint32_t addr;
59 	uint32_t ep;
60 	struct stat sbuf;
61 	unsigned char *ptr;
62 	char *name = "";
63 
64 	cmdname = *argv;
65 
66 	addr = ep = 0;
67 
68 	while (--argc > 0 && **++argv == '-') {
69 		while (*++*argv) {
70 			switch (**argv) {
71 			case 'l':
72 				lflag = 1;
73 				break;
74 			case 'A':
75 				if ((--argc <= 0) ||
76 				    (opt_arch = genimg_get_arch_id (*++argv)) < 0)
77 					usage ();
78 				goto NXTARG;
79 			case 'C':
80 				if ((--argc <= 0) ||
81 				    (opt_comp = genimg_get_comp_id (*++argv)) < 0)
82 					usage ();
83 				goto NXTARG;
84 			case 'O':
85 				if ((--argc <= 0) ||
86 				    (opt_os = genimg_get_os_id (*++argv)) < 0)
87 					usage ();
88 				goto NXTARG;
89 			case 'T':
90 				if ((--argc <= 0) ||
91 				    (opt_type = genimg_get_type_id (*++argv)) < 0)
92 					usage ();
93 				goto NXTARG;
94 
95 			case 'a':
96 				if (--argc <= 0)
97 					usage ();
98 				addr = strtoul (*++argv, (char **)&ptr, 16);
99 				if (*ptr) {
100 					fprintf (stderr,
101 						"%s: invalid load address %s\n",
102 						cmdname, *argv);
103 					exit (EXIT_FAILURE);
104 				}
105 				goto NXTARG;
106 			case 'd':
107 				if (--argc <= 0)
108 					usage ();
109 				datafile = *++argv;
110 				dflag = 1;
111 				goto NXTARG;
112 			case 'e':
113 				if (--argc <= 0)
114 					usage ();
115 				ep = strtoul (*++argv, (char **)&ptr, 16);
116 				if (*ptr) {
117 					fprintf (stderr,
118 						"%s: invalid entry point %s\n",
119 						cmdname, *argv);
120 					exit (EXIT_FAILURE);
121 				}
122 				eflag = 1;
123 				goto NXTARG;
124 			case 'n':
125 				if (--argc <= 0)
126 					usage ();
127 				name = *++argv;
128 				goto NXTARG;
129 			case 'v':
130 				vflag++;
131 				break;
132 			case 'x':
133 				xflag++;
134 				break;
135 			default:
136 				usage ();
137 			}
138 		}
139 NXTARG:		;
140 	}
141 
142 	if ((argc != 1) || ((lflag ^ dflag) == 0))
143 		usage();
144 
145 	if (!eflag) {
146 		ep = addr;
147 		/* If XIP, entry point must be after the U-Boot header */
148 		if (xflag)
149 			ep += image_get_header_size ();
150 	}
151 
152 	/*
153 	 * If XIP, ensure the entry point is equal to the load address plus
154 	 * the size of the U-Boot header.
155 	 */
156 	if (xflag) {
157 		if (ep != addr + image_get_header_size ()) {
158 			fprintf (stderr,
159 				"%s: For XIP, the entry point must be the load addr + %lu\n",
160 				cmdname,
161 				(unsigned long)image_get_header_size ());
162 			exit (EXIT_FAILURE);
163 		}
164 	}
165 
166 	imagefile = *argv;
167 
168 	if (lflag) {
169 		ifd = open(imagefile, O_RDONLY|O_BINARY);
170 	} else {
171 		ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
172 	}
173 
174 	if (ifd < 0) {
175 		fprintf (stderr, "%s: Can't open %s: %s\n",
176 			cmdname, imagefile, strerror(errno));
177 		exit (EXIT_FAILURE);
178 	}
179 
180 	if (lflag) {
181 		int len;
182 		char *data;
183 		/*
184 		 * list header information of existing image
185 		 */
186 		if (fstat(ifd, &sbuf) < 0) {
187 			fprintf (stderr, "%s: Can't stat %s: %s\n",
188 				cmdname, imagefile, strerror(errno));
189 			exit (EXIT_FAILURE);
190 		}
191 
192 		if ((unsigned)sbuf.st_size < image_get_header_size ()) {
193 			fprintf (stderr,
194 				"%s: Bad size: \"%s\" is no valid image\n",
195 				cmdname, imagefile);
196 			exit (EXIT_FAILURE);
197 		}
198 
199 		ptr = (unsigned char *)mmap(0, sbuf.st_size,
200 					    PROT_READ, MAP_SHARED, ifd, 0);
201 		if ((caddr_t)ptr == (caddr_t)-1) {
202 			fprintf (stderr, "%s: Can't read %s: %s\n",
203 				cmdname, imagefile, strerror(errno));
204 			exit (EXIT_FAILURE);
205 		}
206 
207 		/*
208 		 * image_check_hcrc() creates copy of header so that
209 		 * we can blank out the checksum field for checking -
210 		 * this can't be done on the PROT_READ mapped data.
211 		 */
212 		hdr = (image_header_t *)ptr;
213 
214 		if (!image_check_magic (hdr)) {
215 			fprintf (stderr,
216 				"%s: Bad Magic Number: \"%s\" is no valid image\n",
217 				cmdname, imagefile);
218 			exit (EXIT_FAILURE);
219 		}
220 
221 		if (!image_check_hcrc (hdr)) {
222 			fprintf (stderr,
223 				"%s: ERROR: \"%s\" has bad header checksum!\n",
224 				cmdname, imagefile);
225 			exit (EXIT_FAILURE);
226 		}
227 
228 		data = (char *)image_get_data (hdr);
229 		len  = sbuf.st_size - image_get_header_size ();
230 
231 		if (crc32(0, data, len) != image_get_dcrc (hdr)) {
232 			fprintf (stderr,
233 				"%s: ERROR: \"%s\" has corrupted data!\n",
234 				cmdname, imagefile);
235 			exit (EXIT_FAILURE);
236 		}
237 
238 		/* for multi-file images we need the data part, too */
239 		image_print_contents_noindent ((image_header_t *)ptr);
240 
241 		(void) munmap((void *)ptr, sbuf.st_size);
242 		(void) close (ifd);
243 
244 		exit (EXIT_SUCCESS);
245 	}
246 
247 	/*
248 	 * Must be -w then:
249 	 *
250 	 * write dummy header, to be fixed later
251 	 */
252 	memset (hdr, 0, image_get_header_size ());
253 
254 	if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) {
255 		fprintf (stderr, "%s: Write error on %s: %s\n",
256 			cmdname, imagefile, strerror(errno));
257 		exit (EXIT_FAILURE);
258 	}
259 
260 	if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) {
261 		char *file = datafile;
262 		uint32_t size;
263 
264 		for (;;) {
265 			char *sep = NULL;
266 
267 			if (file) {
268 				if ((sep = strchr(file, ':')) != NULL) {
269 					*sep = '\0';
270 				}
271 
272 				if (stat (file, &sbuf) < 0) {
273 					fprintf (stderr, "%s: Can't stat %s: %s\n",
274 						cmdname, file, strerror(errno));
275 					exit (EXIT_FAILURE);
276 				}
277 				size = cpu_to_uimage (sbuf.st_size);
278 			} else {
279 				size = 0;
280 			}
281 
282 			if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
283 				fprintf (stderr, "%s: Write error on %s: %s\n",
284 					cmdname, imagefile, strerror(errno));
285 				exit (EXIT_FAILURE);
286 			}
287 
288 			if (!file) {
289 				break;
290 			}
291 
292 			if (sep) {
293 				*sep = ':';
294 				file = sep + 1;
295 			} else {
296 				file = NULL;
297 			}
298 		}
299 
300 		file = datafile;
301 
302 		for (;;) {
303 			char *sep = strchr(file, ':');
304 			if (sep) {
305 				*sep = '\0';
306 				copy_file (ifd, file, 1);
307 				*sep++ = ':';
308 				file = sep;
309 			} else {
310 				copy_file (ifd, file, 0);
311 				break;
312 			}
313 		}
314 	} else {
315 		copy_file (ifd, datafile, 0);
316 	}
317 
318 	/* We're a bit of paranoid */
319 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__)
320 	(void) fdatasync (ifd);
321 #else
322 	(void) fsync (ifd);
323 #endif
324 
325 	if (fstat(ifd, &sbuf) < 0) {
326 		fprintf (stderr, "%s: Can't stat %s: %s\n",
327 			cmdname, imagefile, strerror(errno));
328 		exit (EXIT_FAILURE);
329 	}
330 
331 	ptr = (unsigned char *)mmap(0, sbuf.st_size,
332 				    PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
333 	if (ptr == (unsigned char *)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_noindent (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 = (unsigned char *)mmap(0, sbuf.st_size,
412 				    PROT_READ, MAP_SHARED, dfd, 0);
413 	if (ptr == (unsigned char *)MAP_FAILED) {
414 		fprintf (stderr, "%s: Can't read %s: %s\n",
415 			cmdname, datafile, strerror(errno));
416 		exit (EXIT_FAILURE);
417 	}
418 
419 	if (xflag) {
420 		unsigned char *p = NULL;
421 		/*
422 		 * XIP: do not append the image_header_t at the
423 		 * beginning of the file, but consume the space
424 		 * reserved for it.
425 		 */
426 
427 		if ((unsigned)sbuf.st_size < image_get_header_size ()) {
428 			fprintf (stderr,
429 				"%s: Bad size: \"%s\" is too small for XIP\n",
430 				cmdname, datafile);
431 			exit (EXIT_FAILURE);
432 		}
433 
434 		for (p = ptr; p < ptr + image_get_header_size (); p++) {
435 			if ( *p != 0xff ) {
436 				fprintf (stderr,
437 					"%s: Bad file: \"%s\" has invalid buffer for XIP\n",
438 					cmdname, datafile);
439 				exit (EXIT_FAILURE);
440 			}
441 		}
442 
443 		offset = image_get_header_size ();
444 	}
445 
446 	size = sbuf.st_size - offset;
447 	if (write(ifd, ptr + offset, size) != size) {
448 		fprintf (stderr, "%s: Write error on %s: %s\n",
449 			cmdname, imagefile, strerror(errno));
450 		exit (EXIT_FAILURE);
451 	}
452 
453 	if (pad && ((tail = size % 4) != 0)) {
454 
455 		if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
456 			fprintf (stderr, "%s: Write error on %s: %s\n",
457 				cmdname, imagefile, strerror(errno));
458 			exit (EXIT_FAILURE);
459 		}
460 	}
461 
462 	(void) munmap((void *)ptr, sbuf.st_size);
463 	(void) close (dfd);
464 }
465 
466 void
467 usage ()
468 {
469 	fprintf (stderr, "Usage: %s -l image\n"
470 			 "          -l ==> list image header information\n"
471 			 "       %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 		cmdname, cmdname);
474 	fprintf (stderr, "          -A ==> set architecture to 'arch'\n"
475 			 "          -O ==> set operating system to 'os'\n"
476 			 "          -T ==> set image type to 'type'\n"
477 			 "          -C ==> set compression type 'comp'\n"
478 			 "          -a ==> set load address to 'addr' (hex)\n"
479 			 "          -e ==> set entry point to 'ep' (hex)\n"
480 			 "          -n ==> set image name to 'name'\n"
481 			 "          -d ==> use image data from 'datafile'\n"
482 			 "          -x ==> set XIP (execute in place)\n"
483 		);
484 	exit (EXIT_FAILURE);
485 }
486