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