Commit | Line | Data |
---|---|---|
cf491568 JB |
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 | #ifdef __APPLE__ | |
23 | #define __FreeBSD__ 10 | |
24 | #endif | |
25 | ||
26 | #include <errno.h> | |
27 | #include <fcntl.h> | |
28 | #include <stdio.h> | |
29 | #include <stdlib.h> | |
30 | #include <string.h> | |
31 | #ifndef __WIN32__ | |
32 | #include <netinet/in.h> /* for host / network byte order conversions */ | |
33 | #endif | |
34 | #include <sys/mman.h> | |
35 | #include <sys/stat.h> | |
36 | #include <time.h> | |
37 | #include <unistd.h> | |
38 | ||
39 | #if defined(__BEOS__) || defined(__NetBSD__) || defined(__APPLE__) | |
40 | #include <inttypes.h> | |
41 | #include <sys/types.h> | |
42 | #endif | |
43 | #ifdef __WIN32__ | |
44 | typedef unsigned int __u32; | |
45 | ||
46 | #define SWAP_LONG(x) \ | |
47 | ((__u32)( \ | |
48 | (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ | |
49 | (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ | |
50 | (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ | |
51 | (((__u32)(x) & (__u32)0xff000000UL) >> 24) )) | |
52 | typedef unsigned char uint8_t; | |
53 | typedef unsigned short uint16_t; | |
54 | typedef unsigned int uint32_t; | |
55 | ||
56 | #define ntohl(a) SWAP_LONG(a) | |
57 | #define htonl(a) SWAP_LONG(a) | |
58 | #endif /* __WIN32__ */ | |
59 | ||
60 | #ifndef O_BINARY /* should be define'd on __WIN32__ */ | |
61 | #define O_BINARY 0 | |
62 | #endif | |
63 | ||
64 | #include "image.h" | |
65 | ||
66 | extern int errno; | |
67 | ||
68 | #ifndef MAP_FAILED | |
69 | #define MAP_FAILED (-1) | |
70 | #endif | |
71 | ||
72 | char *cmdname; | |
73 | ||
74 | extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len); | |
75 | ||
76 | typedef struct table_entry { | |
77 | int val; /* as defined in image.h */ | |
78 | char *sname; /* short (input) name */ | |
79 | char *lname; /* long (output) name */ | |
80 | } table_entry_t; | |
81 | ||
82 | table_entry_t arch_name[] = { | |
83 | { IH_CPU_INVALID, NULL, "Invalid CPU", }, | |
84 | { IH_CPU_ALPHA, "alpha", "Alpha", }, | |
85 | { IH_CPU_ARM, "arm", "ARM", }, | |
86 | { IH_CPU_I386, "x86", "Intel x86", }, | |
87 | { IH_CPU_IA64, "ia64", "IA64", }, | |
88 | { IH_CPU_M68K, "m68k", "MC68000", }, | |
89 | { IH_CPU_MICROBLAZE, "microblaze", "MicroBlaze", }, | |
90 | { IH_CPU_MIPS, "mips", "MIPS", }, | |
91 | { IH_CPU_MIPS64, "mips64", "MIPS 64 Bit", }, | |
92 | { IH_CPU_NIOS, "nios", "NIOS", }, | |
93 | { IH_CPU_NIOS2, "nios2", "NIOS II", }, | |
94 | { IH_CPU_PPC, "ppc", "PowerPC", }, | |
95 | { IH_CPU_S390, "s390", "IBM S390", }, | |
96 | { IH_CPU_SH, "sh", "SuperH", }, | |
97 | { IH_CPU_SPARC, "sparc", "SPARC", }, | |
98 | { IH_CPU_SPARC64, "sparc64", "SPARC 64 Bit", }, | |
99 | { IH_CPU_BLACKFIN, "blackfin", "Blackfin", }, | |
100 | { IH_CPU_AVR32, "avr32", "AVR32", }, | |
101 | { -1, "", "", }, | |
102 | }; | |
103 | ||
104 | table_entry_t os_name[] = { | |
105 | { IH_OS_INVALID, NULL, "Invalid OS", }, | |
106 | { IH_OS_4_4BSD, "4_4bsd", "4_4BSD", }, | |
107 | { IH_OS_ARTOS, "artos", "ARTOS", }, | |
108 | { IH_OS_DELL, "dell", "Dell", }, | |
109 | { IH_OS_ESIX, "esix", "Esix", }, | |
110 | { IH_OS_FREEBSD, "freebsd", "FreeBSD", }, | |
111 | { IH_OS_IRIX, "irix", "Irix", }, | |
112 | { IH_OS_LINUX, "linux", "Linux", }, | |
113 | { IH_OS_LYNXOS, "lynxos", "LynxOS", }, | |
114 | { IH_OS_NCR, "ncr", "NCR", }, | |
115 | { IH_OS_NETBSD, "netbsd", "NetBSD", }, | |
116 | { IH_OS_OPENBSD, "openbsd", "OpenBSD", }, | |
117 | { IH_OS_PSOS, "psos", "pSOS", }, | |
118 | { IH_OS_QNX, "qnx", "QNX", }, | |
119 | { IH_OS_RTEMS, "rtems", "RTEMS", }, | |
120 | { IH_OS_SCO, "sco", "SCO", }, | |
121 | { IH_OS_SOLARIS, "solaris", "Solaris", }, | |
122 | { IH_OS_SVR4, "svr4", "SVR4", }, | |
123 | { IH_OS_U_BOOT, "u-boot", "U-Boot", }, | |
124 | { IH_OS_VXWORKS, "vxworks", "VxWorks", }, | |
125 | { -1, "", "", }, | |
126 | }; | |
127 | ||
128 | table_entry_t type_name[] = { | |
129 | { IH_TYPE_INVALID, NULL, "Invalid Image", }, | |
130 | { IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image", }, | |
131 | { IH_TYPE_FIRMWARE, "firmware", "Firmware", }, | |
132 | { IH_TYPE_KERNEL, "kernel", "Kernel Image", }, | |
133 | { IH_TYPE_MULTI, "multi", "Multi-File Image", }, | |
134 | { IH_TYPE_RAMDISK, "ramdisk", "RAMDisk Image", }, | |
135 | { IH_TYPE_SCRIPT, "script", "Script", }, | |
136 | { IH_TYPE_STANDALONE, "standalone", "Standalone Program", }, | |
137 | { IH_TYPE_FLATDT, "flat_dt", "Flat Device Tree", }, | |
138 | { -1, "", "", }, | |
139 | }; | |
140 | ||
141 | table_entry_t comp_name[] = { | |
142 | { IH_COMP_NONE, "none", "uncompressed", }, | |
143 | { IH_COMP_BZIP2, "bzip2", "bzip2 compressed", }, | |
144 | { IH_COMP_GZIP, "gzip", "gzip compressed", }, | |
145 | { IH_COMP_LZMA, "lzma", "lzma compressed", }, | |
146 | { -1, "", "", }, | |
147 | }; | |
148 | ||
149 | static void copy_file (int, const char *, int); | |
150 | static void usage (void); | |
151 | static void print_header (image_header_t *); | |
152 | static void print_type (image_header_t *); | |
153 | static char *put_table_entry (table_entry_t *, char *, int); | |
154 | static char *put_arch (int); | |
155 | static char *put_type (int); | |
156 | static char *put_os (int); | |
157 | static char *put_comp (int); | |
158 | static int get_table_entry (table_entry_t *, char *, char *); | |
159 | static int get_arch(char *); | |
160 | static int get_comp(char *); | |
161 | static int get_os (char *); | |
162 | static int get_type(char *); | |
163 | ||
164 | ||
165 | char *datafile; | |
166 | char *imagefile; | |
167 | ||
168 | int dflag = 0; | |
169 | int eflag = 0; | |
170 | int lflag = 0; | |
171 | int vflag = 0; | |
172 | int xflag = 0; | |
173 | int opt_os = IH_OS_LINUX; | |
174 | int opt_arch = IH_CPU_PPC; | |
175 | int opt_type = IH_TYPE_KERNEL; | |
176 | int opt_comp = IH_COMP_GZIP; | |
177 | ||
178 | image_header_t header; | |
179 | image_header_t *hdr = &header; | |
180 | ||
181 | int | |
182 | main (int argc, char **argv) | |
183 | { | |
184 | int ifd; | |
185 | uint32_t checksum; | |
186 | uint32_t addr; | |
187 | uint32_t ep; | |
188 | struct stat sbuf; | |
189 | unsigned char *ptr; | |
190 | char *name = ""; | |
191 | ||
192 | cmdname = *argv; | |
193 | ||
194 | addr = ep = 0; | |
195 | ||
196 | while (--argc > 0 && **++argv == '-') { | |
197 | while (*++*argv) { | |
198 | switch (**argv) { | |
199 | case 'l': | |
200 | lflag = 1; | |
201 | break; | |
202 | case 'A': | |
203 | if ((--argc <= 0) || | |
204 | (opt_arch = get_arch(*++argv)) < 0) | |
205 | usage (); | |
206 | goto NXTARG; | |
207 | case 'C': | |
208 | if ((--argc <= 0) || | |
209 | (opt_comp = get_comp(*++argv)) < 0) | |
210 | usage (); | |
211 | goto NXTARG; | |
212 | case 'O': | |
213 | if ((--argc <= 0) || | |
214 | (opt_os = get_os(*++argv)) < 0) | |
215 | usage (); | |
216 | goto NXTARG; | |
217 | case 'T': | |
218 | if ((--argc <= 0) || | |
219 | (opt_type = get_type(*++argv)) < 0) | |
220 | usage (); | |
221 | goto NXTARG; | |
222 | ||
223 | case 'a': | |
224 | if (--argc <= 0) | |
225 | usage (); | |
226 | addr = strtoul (*++argv, (char **)&ptr, 16); | |
227 | if (*ptr) { | |
228 | fprintf (stderr, | |
229 | "%s: invalid load address %s\n", | |
230 | cmdname, *argv); | |
231 | exit (EXIT_FAILURE); | |
232 | } | |
233 | goto NXTARG; | |
234 | case 'd': | |
235 | if (--argc <= 0) | |
236 | usage (); | |
237 | datafile = *++argv; | |
238 | dflag = 1; | |
239 | goto NXTARG; | |
240 | case 'e': | |
241 | if (--argc <= 0) | |
242 | usage (); | |
243 | ep = strtoul (*++argv, (char **)&ptr, 16); | |
244 | if (*ptr) { | |
245 | fprintf (stderr, | |
246 | "%s: invalid entry point %s\n", | |
247 | cmdname, *argv); | |
248 | exit (EXIT_FAILURE); | |
249 | } | |
250 | eflag = 1; | |
251 | goto NXTARG; | |
252 | case 'n': | |
253 | if (--argc <= 0) | |
254 | usage (); | |
255 | name = *++argv; | |
256 | goto NXTARG; | |
257 | case 'v': | |
258 | vflag++; | |
259 | break; | |
260 | case 'x': | |
261 | xflag++; | |
262 | break; | |
263 | default: | |
264 | usage (); | |
265 | } | |
266 | } | |
267 | NXTARG: ; | |
268 | } | |
269 | ||
270 | if ((argc != 1) || ((lflag ^ dflag) == 0)) | |
271 | usage(); | |
272 | ||
273 | if (!eflag) { | |
274 | ep = addr; | |
275 | /* If XIP, entry point must be after the U-Boot header */ | |
276 | if (xflag) | |
277 | ep += sizeof(image_header_t); | |
278 | } | |
279 | ||
280 | /* | |
281 | * If XIP, ensure the entry point is equal to the load address plus | |
282 | * the size of the U-Boot header. | |
283 | */ | |
284 | if (xflag) { | |
285 | if (ep != addr + sizeof(image_header_t)) { | |
286 | fprintf (stderr, | |
287 | "%s: For XIP, the entry point must be the load addr + %lu\n", | |
288 | cmdname, | |
289 | (unsigned long)sizeof(image_header_t)); | |
290 | exit (EXIT_FAILURE); | |
291 | } | |
292 | } | |
293 | ||
294 | imagefile = *argv; | |
295 | ||
296 | if (lflag) { | |
297 | ifd = open(imagefile, O_RDONLY|O_BINARY); | |
298 | } else { | |
299 | ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); | |
300 | } | |
301 | ||
302 | if (ifd < 0) { | |
303 | fprintf (stderr, "%s: Can't open %s: %s\n", | |
304 | cmdname, imagefile, strerror(errno)); | |
305 | exit (EXIT_FAILURE); | |
306 | } | |
307 | ||
308 | if (lflag) { | |
309 | int len; | |
310 | char *data; | |
311 | /* | |
312 | * list header information of existing image | |
313 | */ | |
314 | if (fstat(ifd, &sbuf) < 0) { | |
315 | fprintf (stderr, "%s: Can't stat %s: %s\n", | |
316 | cmdname, imagefile, strerror(errno)); | |
317 | exit (EXIT_FAILURE); | |
318 | } | |
319 | ||
320 | if ((unsigned)sbuf.st_size < sizeof(image_header_t)) { | |
321 | fprintf (stderr, | |
322 | "%s: Bad size: \"%s\" is no valid image\n", | |
323 | cmdname, imagefile); | |
324 | exit (EXIT_FAILURE); | |
325 | } | |
326 | ||
327 | ptr = (unsigned char *)mmap(0, sbuf.st_size, | |
328 | PROT_READ, MAP_SHARED, ifd, 0); | |
329 | if ((caddr_t)ptr == (caddr_t)-1) { | |
330 | fprintf (stderr, "%s: Can't read %s: %s\n", | |
331 | cmdname, imagefile, strerror(errno)); | |
332 | exit (EXIT_FAILURE); | |
333 | } | |
334 | ||
335 | /* | |
336 | * create copy of header so that we can blank out the | |
337 | * checksum field for checking - this can't be done | |
338 | * on the PROT_READ mapped data. | |
339 | */ | |
340 | memcpy (hdr, ptr, sizeof(image_header_t)); | |
341 | ||
342 | if (ntohl(hdr->ih_magic) != IH_MAGIC) { | |
343 | fprintf (stderr, | |
344 | "%s: Bad Magic Number: \"%s\" is no valid image\n", | |
345 | cmdname, imagefile); | |
346 | exit (EXIT_FAILURE); | |
347 | } | |
348 | ||
349 | data = (char *)hdr; | |
350 | len = sizeof(image_header_t); | |
351 | ||
352 | checksum = ntohl(hdr->ih_hcrc); | |
353 | hdr->ih_hcrc = htonl(0); /* clear for re-calculation */ | |
354 | ||
355 | if (crc32 (0, data, len) != checksum) { | |
356 | fprintf (stderr, | |
357 | "%s: ERROR: \"%s\" has bad header checksum!\n", | |
358 | cmdname, imagefile); | |
359 | exit (EXIT_FAILURE); | |
360 | } | |
361 | ||
362 | data = (char *)(ptr + sizeof(image_header_t)); | |
363 | len = sbuf.st_size - sizeof(image_header_t) ; | |
364 | ||
365 | if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) { | |
366 | fprintf (stderr, | |
367 | "%s: ERROR: \"%s\" has corrupted data!\n", | |
368 | cmdname, imagefile); | |
369 | exit (EXIT_FAILURE); | |
370 | } | |
371 | ||
372 | /* for multi-file images we need the data part, too */ | |
373 | print_header ((image_header_t *)ptr); | |
374 | ||
375 | (void) munmap((void *)ptr, sbuf.st_size); | |
376 | (void) close (ifd); | |
377 | ||
378 | exit (EXIT_SUCCESS); | |
379 | } | |
380 | ||
381 | /* | |
382 | * Must be -w then: | |
383 | * | |
384 | * write dummy header, to be fixed later | |
385 | */ | |
386 | memset (hdr, 0, sizeof(image_header_t)); | |
387 | ||
388 | if (write(ifd, hdr, sizeof(image_header_t)) != sizeof(image_header_t)) { | |
389 | fprintf (stderr, "%s: Write error on %s: %s\n", | |
390 | cmdname, imagefile, strerror(errno)); | |
391 | exit (EXIT_FAILURE); | |
392 | } | |
393 | ||
394 | if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) { | |
395 | char *file = datafile; | |
396 | uint32_t size; | |
397 | ||
398 | for (;;) { | |
399 | char *sep = NULL; | |
400 | ||
401 | if (file) { | |
402 | if ((sep = strchr(file, ':')) != NULL) { | |
403 | *sep = '\0'; | |
404 | } | |
405 | ||
406 | if (stat (file, &sbuf) < 0) { | |
407 | fprintf (stderr, "%s: Can't stat %s: %s\n", | |
408 | cmdname, file, strerror(errno)); | |
409 | exit (EXIT_FAILURE); | |
410 | } | |
411 | size = htonl(sbuf.st_size); | |
412 | } else { | |
413 | size = 0; | |
414 | } | |
415 | ||
416 | if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { | |
417 | fprintf (stderr, "%s: Write error on %s: %s\n", | |
418 | cmdname, imagefile, strerror(errno)); | |
419 | exit (EXIT_FAILURE); | |
420 | } | |
421 | ||
422 | if (!file) { | |
423 | break; | |
424 | } | |
425 | ||
426 | if (sep) { | |
427 | *sep = ':'; | |
428 | file = sep + 1; | |
429 | } else { | |
430 | file = NULL; | |
431 | } | |
432 | } | |
433 | ||
434 | file = datafile; | |
435 | ||
436 | for (;;) { | |
437 | char *sep = strchr(file, ':'); | |
438 | if (sep) { | |
439 | *sep = '\0'; | |
440 | copy_file (ifd, file, 1); | |
441 | *sep++ = ':'; | |
442 | file = sep; | |
443 | } else { | |
444 | copy_file (ifd, file, 0); | |
445 | break; | |
446 | } | |
447 | } | |
448 | } else { | |
449 | copy_file (ifd, datafile, 0); | |
450 | } | |
451 | ||
452 | /* We're a bit of paranoid */ | |
453 | #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) | |
454 | (void) fdatasync (ifd); | |
455 | #else | |
456 | (void) fsync (ifd); | |
457 | #endif | |
458 | ||
459 | if (fstat(ifd, &sbuf) < 0) { | |
460 | fprintf (stderr, "%s: Can't stat %s: %s\n", | |
461 | cmdname, imagefile, strerror(errno)); | |
462 | exit (EXIT_FAILURE); | |
463 | } | |
464 | ||
465 | ptr = (unsigned char *)mmap(0, sbuf.st_size, | |
466 | PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); | |
467 | if (ptr == (unsigned char *)MAP_FAILED) { | |
468 | fprintf (stderr, "%s: Can't map %s: %s\n", | |
469 | cmdname, imagefile, strerror(errno)); | |
470 | exit (EXIT_FAILURE); | |
471 | } | |
472 | ||
473 | hdr = (image_header_t *)ptr; | |
474 | ||
475 | checksum = crc32 (0, | |
476 | (const char *)(ptr + sizeof(image_header_t)), | |
477 | sbuf.st_size - sizeof(image_header_t) | |
478 | ); | |
479 | ||
480 | /* Build new header */ | |
481 | hdr->ih_magic = htonl(IH_MAGIC); | |
482 | hdr->ih_time = htonl(sbuf.st_mtime); | |
483 | hdr->ih_size = htonl(sbuf.st_size - sizeof(image_header_t)); | |
484 | hdr->ih_load = htonl(addr); | |
485 | hdr->ih_ep = htonl(ep); | |
486 | hdr->ih_dcrc = htonl(checksum); | |
487 | hdr->ih_os = opt_os; | |
488 | hdr->ih_arch = opt_arch; | |
489 | hdr->ih_type = opt_type; | |
490 | hdr->ih_comp = opt_comp; | |
491 | ||
492 | strncpy((char *)hdr->ih_name, name, IH_NMLEN); | |
493 | ||
494 | checksum = crc32(0,(const char *)hdr,sizeof(image_header_t)); | |
495 | ||
496 | hdr->ih_hcrc = htonl(checksum); | |
497 | ||
498 | print_header (hdr); | |
499 | ||
500 | (void) munmap((void *)ptr, sbuf.st_size); | |
501 | ||
502 | /* We're a bit of paranoid */ | |
503 | #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) | |
504 | (void) fdatasync (ifd); | |
505 | #else | |
506 | (void) fsync (ifd); | |
507 | #endif | |
508 | ||
509 | if (close(ifd)) { | |
510 | fprintf (stderr, "%s: Write error on %s: %s\n", | |
511 | cmdname, imagefile, strerror(errno)); | |
512 | exit (EXIT_FAILURE); | |
513 | } | |
514 | ||
515 | exit (EXIT_SUCCESS); | |
516 | } | |
517 | ||
518 | static void | |
519 | copy_file (int ifd, const char *datafile, int pad) | |
520 | { | |
521 | int dfd; | |
522 | struct stat sbuf; | |
523 | unsigned char *ptr; | |
524 | int tail; | |
525 | int zero = 0; | |
526 | int offset = 0; | |
527 | int size; | |
528 | ||
529 | if (vflag) { | |
530 | fprintf (stderr, "Adding Image %s\n", datafile); | |
531 | } | |
532 | ||
533 | if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { | |
534 | fprintf (stderr, "%s: Can't open %s: %s\n", | |
535 | cmdname, datafile, strerror(errno)); | |
536 | exit (EXIT_FAILURE); | |
537 | } | |
538 | ||
539 | if (fstat(dfd, &sbuf) < 0) { | |
540 | fprintf (stderr, "%s: Can't stat %s: %s\n", | |
541 | cmdname, datafile, strerror(errno)); | |
542 | exit (EXIT_FAILURE); | |
543 | } | |
544 | ||
545 | ptr = (unsigned char *)mmap(0, sbuf.st_size, | |
546 | PROT_READ, MAP_SHARED, dfd, 0); | |
547 | if (ptr == (unsigned char *)MAP_FAILED) { | |
548 | fprintf (stderr, "%s: Can't read %s: %s\n", | |
549 | cmdname, datafile, strerror(errno)); | |
550 | exit (EXIT_FAILURE); | |
551 | } | |
552 | ||
553 | if (xflag) { | |
554 | unsigned char *p = NULL; | |
555 | /* | |
556 | * XIP: do not append the image_header_t at the | |
557 | * beginning of the file, but consume the space | |
558 | * reserved for it. | |
559 | */ | |
560 | ||
561 | if ((unsigned)sbuf.st_size < sizeof(image_header_t)) { | |
562 | fprintf (stderr, | |
563 | "%s: Bad size: \"%s\" is too small for XIP\n", | |
564 | cmdname, datafile); | |
565 | exit (EXIT_FAILURE); | |
566 | } | |
567 | ||
568 | for (p=ptr; p < ptr+sizeof(image_header_t); p++) { | |
569 | if ( *p != 0xff ) { | |
570 | fprintf (stderr, | |
571 | "%s: Bad file: \"%s\" has invalid buffer for XIP\n", | |
572 | cmdname, datafile); | |
573 | exit (EXIT_FAILURE); | |
574 | } | |
575 | } | |
576 | ||
577 | offset = sizeof(image_header_t); | |
578 | } | |
579 | ||
580 | size = sbuf.st_size - offset; | |
581 | if (write(ifd, ptr + offset, size) != size) { | |
582 | fprintf (stderr, "%s: Write error on %s: %s\n", | |
583 | cmdname, imagefile, strerror(errno)); | |
584 | exit (EXIT_FAILURE); | |
585 | } | |
586 | ||
587 | if (pad && ((tail = size % 4) != 0)) { | |
588 | ||
589 | if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { | |
590 | fprintf (stderr, "%s: Write error on %s: %s\n", | |
591 | cmdname, imagefile, strerror(errno)); | |
592 | exit (EXIT_FAILURE); | |
593 | } | |
594 | } | |
595 | ||
596 | (void) munmap((void *)ptr, sbuf.st_size); | |
597 | (void) close (dfd); | |
598 | } | |
599 | ||
600 | void | |
601 | usage () | |
602 | { | |
603 | fprintf (stderr, "Usage: %s -l image\n" | |
604 | " -l ==> list image header information\n" | |
605 | " %s [-x] -A arch -O os -T type -C comp " | |
606 | "-a addr -e ep -n name -d data_file[:data_file...] image\n", | |
607 | cmdname, cmdname); | |
608 | fprintf (stderr, " -A ==> set architecture to 'arch'\n" | |
609 | " -O ==> set operating system to 'os'\n" | |
610 | " -T ==> set image type to 'type'\n" | |
611 | " -C ==> set compression type 'comp'\n" | |
612 | " -a ==> set load address to 'addr' (hex)\n" | |
613 | " -e ==> set entry point to 'ep' (hex)\n" | |
614 | " -n ==> set image name to 'name'\n" | |
615 | " -d ==> use image data from 'datafile'\n" | |
616 | " -x ==> set XIP (execute in place)\n" | |
617 | ); | |
618 | exit (EXIT_FAILURE); | |
619 | } | |
620 | ||
621 | static void | |
622 | print_header (image_header_t *hdr) | |
623 | { | |
624 | time_t timestamp; | |
625 | uint32_t size; | |
626 | ||
627 | timestamp = (time_t)ntohl(hdr->ih_time); | |
628 | size = ntohl(hdr->ih_size); | |
629 | ||
630 | printf ("Image Name: %.*s\n", IH_NMLEN, hdr->ih_name); | |
631 | printf ("Created: %s", ctime(×tamp)); | |
632 | printf ("Image Type: "); print_type(hdr); | |
633 | printf ("Data Size: %d Bytes = %.2f kB = %.2f MB\n", | |
634 | size, (double)size / 1.024e3, (double)size / 1.048576e6 ); | |
635 | printf ("Load Address: 0x%08X\n", ntohl(hdr->ih_load)); | |
636 | printf ("Entry Point: 0x%08X\n", ntohl(hdr->ih_ep)); | |
637 | ||
638 | if (hdr->ih_type == IH_TYPE_MULTI || hdr->ih_type == IH_TYPE_SCRIPT) { | |
639 | int i, ptrs; | |
640 | uint32_t pos; | |
641 | uint32_t *len_ptr = (uint32_t *) ( | |
642 | (unsigned long)hdr + sizeof(image_header_t) | |
643 | ); | |
644 | ||
645 | /* determine number of images first (to calculate image offsets) */ | |
646 | for (i=0; len_ptr[i]; ++i) /* null pointer terminates list */ | |
647 | ; | |
648 | ptrs = i; /* null pointer terminates list */ | |
649 | ||
650 | pos = sizeof(image_header_t) + ptrs * sizeof(long); | |
651 | printf ("Contents:\n"); | |
652 | for (i=0; len_ptr[i]; ++i) { | |
653 | size = ntohl(len_ptr[i]); | |
654 | ||
655 | printf (" Image %d: %8d Bytes = %4d kB = %d MB\n", | |
656 | i, size, size>>10, size>>20); | |
657 | if (hdr->ih_type == IH_TYPE_SCRIPT && i > 0) { | |
658 | /* | |
659 | * the user may need to know offsets | |
660 | * if planning to do something with | |
661 | * multiple files | |
662 | */ | |
663 | printf (" Offset = %08X\n", pos); | |
664 | } | |
665 | /* copy_file() will pad the first files to even word align */ | |
666 | size += 3; | |
667 | size &= ~3; | |
668 | pos += size; | |
669 | } | |
670 | } | |
671 | } | |
672 | ||
673 | ||
674 | static void | |
675 | print_type (image_header_t *hdr) | |
676 | { | |
677 | printf ("%s %s %s (%s)\n", | |
678 | put_arch (hdr->ih_arch), | |
679 | put_os (hdr->ih_os ), | |
680 | put_type (hdr->ih_type), | |
681 | put_comp (hdr->ih_comp) | |
682 | ); | |
683 | } | |
684 | ||
685 | static char *put_arch (int arch) | |
686 | { | |
687 | return (put_table_entry(arch_name, "Unknown Architecture", arch)); | |
688 | } | |
689 | ||
690 | static char *put_os (int os) | |
691 | { | |
692 | return (put_table_entry(os_name, "Unknown OS", os)); | |
693 | } | |
694 | ||
695 | static char *put_type (int type) | |
696 | { | |
697 | return (put_table_entry(type_name, "Unknown Image", type)); | |
698 | } | |
699 | ||
700 | static char *put_comp (int comp) | |
701 | { | |
702 | return (put_table_entry(comp_name, "Unknown Compression", comp)); | |
703 | } | |
704 | ||
705 | static char *put_table_entry (table_entry_t *table, char *msg, int type) | |
706 | { | |
707 | for (; table->val>=0; ++table) { | |
708 | if (table->val == type) | |
709 | return (table->lname); | |
710 | } | |
711 | return (msg); | |
712 | } | |
713 | ||
714 | static int get_arch(char *name) | |
715 | { | |
716 | return (get_table_entry(arch_name, "CPU", name)); | |
717 | } | |
718 | ||
719 | ||
720 | static int get_comp(char *name) | |
721 | { | |
722 | return (get_table_entry(comp_name, "Compression", name)); | |
723 | } | |
724 | ||
725 | ||
726 | static int get_os (char *name) | |
727 | { | |
728 | return (get_table_entry(os_name, "OS", name)); | |
729 | } | |
730 | ||
731 | ||
732 | static int get_type(char *name) | |
733 | { | |
734 | return (get_table_entry(type_name, "Image", name)); | |
735 | } | |
736 | ||
737 | static int get_table_entry (table_entry_t *table, char *msg, char *name) | |
738 | { | |
739 | table_entry_t *t; | |
740 | int first = 1; | |
741 | ||
742 | for (t=table; t->val>=0; ++t) { | |
743 | if (t->sname && strcasecmp(t->sname, name)==0) | |
744 | return (t->val); | |
745 | } | |
746 | fprintf (stderr, "\nInvalid %s Type - valid names are", msg); | |
747 | for (t=table; t->val>=0; ++t) { | |
748 | if (t->sname == NULL) | |
749 | continue; | |
750 | fprintf (stderr, "%c %s", (first) ? ':' : ',', t->sname); | |
751 | first = 0; | |
752 | } | |
753 | fprintf (stderr, "\n"); | |
754 | return (-1); | |
755 | } |