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