15b1d7137Swdenk /* 20c852a28Swdenk * (C) Copyright 2000-2004 35b1d7137Swdenk * DENX Software Engineering 45b1d7137Swdenk * Wolfgang Denk, wd@denx.de 55b1d7137Swdenk * All rights reserved. 60c852a28Swdenk * 70c852a28Swdenk * This program is free software; you can redistribute it and/or 80c852a28Swdenk * modify it under the terms of the GNU General Public License as 90c852a28Swdenk * published by the Free Software Foundation; either version 2 of 100c852a28Swdenk * the License, or (at your option) any later version. 110c852a28Swdenk * 120c852a28Swdenk * This program is distributed in the hope that it will be useful, 130c852a28Swdenk * but WITHOUT ANY WARRANTY; without even the implied warranty of 140c852a28Swdenk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 150c852a28Swdenk * GNU General Public License for more details. 160c852a28Swdenk * 170c852a28Swdenk * You should have received a copy of the GNU General Public License 180c852a28Swdenk * along with this program; if not, write to the Free Software 190c852a28Swdenk * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 200c852a28Swdenk * MA 02111-1307 USA 215b1d7137Swdenk */ 225b1d7137Swdenk 235b1d7137Swdenk #include <errno.h> 245b1d7137Swdenk #include <fcntl.h> 255b1d7137Swdenk #include <stdio.h> 265b1d7137Swdenk #include <stdlib.h> 275b1d7137Swdenk #include <string.h> 285b1d7137Swdenk #ifndef __WIN32__ 295b1d7137Swdenk #include <netinet/in.h> /* for host / network byte order conversions */ 305b1d7137Swdenk #endif 315b1d7137Swdenk #include <sys/mman.h> 325b1d7137Swdenk #include <sys/stat.h> 335b1d7137Swdenk #include <time.h> 345b1d7137Swdenk #include <unistd.h> 355b1d7137Swdenk 365b1d7137Swdenk #if defined(__BEOS__) || defined(__NetBSD__) || defined(__APPLE__) 375b1d7137Swdenk #include <inttypes.h> 385b1d7137Swdenk #endif 395b1d7137Swdenk 405b1d7137Swdenk #ifdef __WIN32__ 415b1d7137Swdenk typedef unsigned int __u32; 425b1d7137Swdenk 435b1d7137Swdenk #define SWAP_LONG(x) \ 445b1d7137Swdenk ((__u32)( \ 455b1d7137Swdenk (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ 465b1d7137Swdenk (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ 475b1d7137Swdenk (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ 485b1d7137Swdenk (((__u32)(x) & (__u32)0xff000000UL) >> 24) )) 495b1d7137Swdenk typedef unsigned char uint8_t; 505b1d7137Swdenk typedef unsigned short uint16_t; 515b1d7137Swdenk typedef unsigned int uint32_t; 525b1d7137Swdenk 535b1d7137Swdenk #define ntohl(a) SWAP_LONG(a) 545b1d7137Swdenk #define htonl(a) SWAP_LONG(a) 555b1d7137Swdenk #endif /* __WIN32__ */ 565b1d7137Swdenk 57acf98e7fSwdenk #ifndef O_BINARY /* should be define'd on __WIN32__ */ 58acf98e7fSwdenk #define O_BINARY 0 59acf98e7fSwdenk #endif 60acf98e7fSwdenk 615b1d7137Swdenk #include <image.h> 625b1d7137Swdenk 635b1d7137Swdenk extern int errno; 645b1d7137Swdenk 655b1d7137Swdenk #ifndef MAP_FAILED 665b1d7137Swdenk #define MAP_FAILED (-1) 675b1d7137Swdenk #endif 685b1d7137Swdenk 695b1d7137Swdenk char *cmdname; 705b1d7137Swdenk 715b1d7137Swdenk extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len); 725b1d7137Swdenk 735b1d7137Swdenk typedef struct table_entry { 745b1d7137Swdenk int val; /* as defined in image.h */ 755b1d7137Swdenk char *sname; /* short (input) name */ 765b1d7137Swdenk char *lname; /* long (output) name */ 775b1d7137Swdenk } table_entry_t; 785b1d7137Swdenk 795b1d7137Swdenk table_entry_t arch_name[] = { 805b1d7137Swdenk { IH_CPU_INVALID, NULL, "Invalid CPU", }, 815b1d7137Swdenk { IH_CPU_ALPHA, "alpha", "Alpha", }, 825b1d7137Swdenk { IH_CPU_ARM, "arm", "ARM", }, 835b1d7137Swdenk { IH_CPU_I386, "x86", "Intel x86", }, 845b1d7137Swdenk { IH_CPU_IA64, "ia64", "IA64", }, 85466b7410Swdenk { IH_CPU_M68K, "m68k", "MC68000", }, 86466b7410Swdenk { IH_CPU_MICROBLAZE, "microblaze", "MicroBlaze", }, 875b1d7137Swdenk { IH_CPU_MIPS, "mips", "MIPS", }, 885b1d7137Swdenk { IH_CPU_MIPS64, "mips64", "MIPS 64 Bit", }, 89c1a11c19Swdenk { IH_CPU_NIOS, "nios", "NIOS", }, 90c1a11c19Swdenk { IH_CPU_NIOS2, "nios2", "NIOS II", }, 915b1d7137Swdenk { IH_CPU_PPC, "ppc", "PowerPC", }, 925b1d7137Swdenk { IH_CPU_S390, "s390", "IBM S390", }, 935b1d7137Swdenk { IH_CPU_SH, "sh", "SuperH", }, 945b1d7137Swdenk { IH_CPU_SPARC, "sparc", "SPARC", }, 955b1d7137Swdenk { IH_CPU_SPARC64, "sparc64", "SPARC 64 Bit", }, 960afe519aSWolfgang Denk { IH_CPU_BLACKFIN, "blackfin", "Blackfin", }, 975b1d7137Swdenk { -1, "", "", }, 985b1d7137Swdenk }; 995b1d7137Swdenk 1005b1d7137Swdenk table_entry_t os_name[] = { 1015b1d7137Swdenk { IH_OS_INVALID, NULL, "Invalid OS", }, 1025b1d7137Swdenk { IH_OS_4_4BSD, "4_4bsd", "4_4BSD", }, 103466b7410Swdenk { IH_OS_ARTOS, "artos", "ARTOS", }, 1045b1d7137Swdenk { IH_OS_DELL, "dell", "Dell", }, 105466b7410Swdenk { IH_OS_ESIX, "esix", "Esix", }, 106466b7410Swdenk { IH_OS_FREEBSD, "freebsd", "FreeBSD", }, 107466b7410Swdenk { IH_OS_IRIX, "irix", "Irix", }, 108466b7410Swdenk { IH_OS_LINUX, "linux", "Linux", }, 1095b1d7137Swdenk { IH_OS_LYNXOS, "lynxos", "LynxOS", }, 110466b7410Swdenk { IH_OS_NCR, "ncr", "NCR", }, 111466b7410Swdenk { IH_OS_NETBSD, "netbsd", "NetBSD", }, 112466b7410Swdenk { IH_OS_OPENBSD, "openbsd", "OpenBSD", }, 1135b1d7137Swdenk { IH_OS_PSOS, "psos", "pSOS", }, 1145b1d7137Swdenk { IH_OS_QNX, "qnx", "QNX", }, 115d791b1dcSwdenk { IH_OS_RTEMS, "rtems", "RTEMS", }, 116466b7410Swdenk { IH_OS_SCO, "sco", "SCO", }, 117466b7410Swdenk { IH_OS_SOLARIS, "solaris", "Solaris", }, 118466b7410Swdenk { IH_OS_SVR4, "svr4", "SVR4", }, 119466b7410Swdenk { IH_OS_U_BOOT, "u-boot", "U-Boot", }, 120466b7410Swdenk { IH_OS_VXWORKS, "vxworks", "VxWorks", }, 1215b1d7137Swdenk { -1, "", "", }, 1225b1d7137Swdenk }; 1235b1d7137Swdenk 1245b1d7137Swdenk table_entry_t type_name[] = { 1255b1d7137Swdenk { IH_TYPE_INVALID, NULL, "Invalid Image", }, 126887b372fSwdenk { IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image", }, 127466b7410Swdenk { IH_TYPE_FIRMWARE, "firmware", "Firmware", }, 128466b7410Swdenk { IH_TYPE_KERNEL, "kernel", "Kernel Image", }, 129466b7410Swdenk { IH_TYPE_MULTI, "multi", "Multi-File Image", }, 130466b7410Swdenk { IH_TYPE_RAMDISK, "ramdisk", "RAMDisk Image", }, 131466b7410Swdenk { IH_TYPE_SCRIPT, "script", "Script", }, 132466b7410Swdenk { IH_TYPE_STANDALONE, "standalone", "Standalone Program", }, 1335b1d7137Swdenk { -1, "", "", }, 1345b1d7137Swdenk }; 1355b1d7137Swdenk 1365b1d7137Swdenk table_entry_t comp_name[] = { 1375b1d7137Swdenk { IH_COMP_NONE, "none", "uncompressed", }, 1385b1d7137Swdenk { IH_COMP_BZIP2, "bzip2", "bzip2 compressed", }, 139466b7410Swdenk { IH_COMP_GZIP, "gzip", "gzip compressed", }, 1405b1d7137Swdenk { -1, "", "", }, 1415b1d7137Swdenk }; 1425b1d7137Swdenk 1435b1d7137Swdenk static void copy_file (int, const char *, int); 1445b1d7137Swdenk static void usage (void); 1455b1d7137Swdenk static void print_header (image_header_t *); 1465b1d7137Swdenk static void print_type (image_header_t *); 1475b1d7137Swdenk static char *put_table_entry (table_entry_t *, char *, int); 1485b1d7137Swdenk static char *put_arch (int); 1495b1d7137Swdenk static char *put_type (int); 1505b1d7137Swdenk static char *put_os (int); 1515b1d7137Swdenk static char *put_comp (int); 1525b1d7137Swdenk static int get_table_entry (table_entry_t *, char *, char *); 1535b1d7137Swdenk static int get_arch(char *); 1545b1d7137Swdenk static int get_comp(char *); 1555b1d7137Swdenk static int get_os (char *); 1565b1d7137Swdenk static int get_type(char *); 1575b1d7137Swdenk 1585b1d7137Swdenk 1595b1d7137Swdenk char *datafile; 1605b1d7137Swdenk char *imagefile; 1615b1d7137Swdenk 1625b1d7137Swdenk int dflag = 0; 1635b1d7137Swdenk int eflag = 0; 1645b1d7137Swdenk int lflag = 0; 1655b1d7137Swdenk int vflag = 0; 1665b1d7137Swdenk int xflag = 0; 1675b1d7137Swdenk int opt_os = IH_OS_LINUX; 1685b1d7137Swdenk int opt_arch = IH_CPU_PPC; 1695b1d7137Swdenk int opt_type = IH_TYPE_KERNEL; 1705b1d7137Swdenk int opt_comp = IH_COMP_GZIP; 1715b1d7137Swdenk 1725b1d7137Swdenk image_header_t header; 1735b1d7137Swdenk image_header_t *hdr = &header; 1745b1d7137Swdenk 1755b1d7137Swdenk int 1765b1d7137Swdenk main (int argc, char **argv) 1775b1d7137Swdenk { 1785b1d7137Swdenk int ifd; 1795b1d7137Swdenk uint32_t checksum; 1805b1d7137Swdenk uint32_t addr; 1815b1d7137Swdenk uint32_t ep; 1825b1d7137Swdenk struct stat sbuf; 1835b1d7137Swdenk unsigned char *ptr; 1845b1d7137Swdenk char *name = ""; 1855b1d7137Swdenk 1865b1d7137Swdenk cmdname = *argv; 1875b1d7137Swdenk 1885b1d7137Swdenk addr = ep = 0; 1895b1d7137Swdenk 1905b1d7137Swdenk while (--argc > 0 && **++argv == '-') { 1915b1d7137Swdenk while (*++*argv) { 1925b1d7137Swdenk switch (**argv) { 1935b1d7137Swdenk case 'l': 1945b1d7137Swdenk lflag = 1; 1955b1d7137Swdenk break; 1965b1d7137Swdenk case 'A': 1975b1d7137Swdenk if ((--argc <= 0) || 1985b1d7137Swdenk (opt_arch = get_arch(*++argv)) < 0) 1995b1d7137Swdenk usage (); 2005b1d7137Swdenk goto NXTARG; 2015b1d7137Swdenk case 'C': 2025b1d7137Swdenk if ((--argc <= 0) || 2035b1d7137Swdenk (opt_comp = get_comp(*++argv)) < 0) 2045b1d7137Swdenk usage (); 2055b1d7137Swdenk goto NXTARG; 2065b1d7137Swdenk case 'O': 2075b1d7137Swdenk if ((--argc <= 0) || 2085b1d7137Swdenk (opt_os = get_os(*++argv)) < 0) 2095b1d7137Swdenk usage (); 2105b1d7137Swdenk goto NXTARG; 2115b1d7137Swdenk case 'T': 2125b1d7137Swdenk if ((--argc <= 0) || 2135b1d7137Swdenk (opt_type = get_type(*++argv)) < 0) 2145b1d7137Swdenk usage (); 2155b1d7137Swdenk goto NXTARG; 2165b1d7137Swdenk 2175b1d7137Swdenk case 'a': 2185b1d7137Swdenk if (--argc <= 0) 2195b1d7137Swdenk usage (); 2205b1d7137Swdenk addr = strtoul (*++argv, (char **)&ptr, 16); 2215b1d7137Swdenk if (*ptr) { 2225b1d7137Swdenk fprintf (stderr, 2235b1d7137Swdenk "%s: invalid load address %s\n", 2245b1d7137Swdenk cmdname, *argv); 2255b1d7137Swdenk exit (EXIT_FAILURE); 2265b1d7137Swdenk } 2275b1d7137Swdenk goto NXTARG; 2285b1d7137Swdenk case 'd': 2295b1d7137Swdenk if (--argc <= 0) 2305b1d7137Swdenk usage (); 2315b1d7137Swdenk datafile = *++argv; 2325b1d7137Swdenk dflag = 1; 2335b1d7137Swdenk goto NXTARG; 2345b1d7137Swdenk case 'e': 2355b1d7137Swdenk if (--argc <= 0) 2365b1d7137Swdenk usage (); 2375b1d7137Swdenk ep = strtoul (*++argv, (char **)&ptr, 16); 2385b1d7137Swdenk if (*ptr) { 2395b1d7137Swdenk fprintf (stderr, 2405b1d7137Swdenk "%s: invalid entry point %s\n", 2415b1d7137Swdenk cmdname, *argv); 2425b1d7137Swdenk exit (EXIT_FAILURE); 2435b1d7137Swdenk } 2445b1d7137Swdenk eflag = 1; 2455b1d7137Swdenk goto NXTARG; 2465b1d7137Swdenk case 'n': 2475b1d7137Swdenk if (--argc <= 0) 2485b1d7137Swdenk usage (); 2495b1d7137Swdenk name = *++argv; 2505b1d7137Swdenk goto NXTARG; 2515b1d7137Swdenk case 'v': 2525b1d7137Swdenk vflag++; 2535b1d7137Swdenk break; 2545b1d7137Swdenk case 'x': 2555b1d7137Swdenk xflag++; 2565b1d7137Swdenk break; 2575b1d7137Swdenk default: 2585b1d7137Swdenk usage (); 2595b1d7137Swdenk } 2605b1d7137Swdenk } 2615b1d7137Swdenk NXTARG: ; 2625b1d7137Swdenk } 2635b1d7137Swdenk 2645b1d7137Swdenk if ((argc != 1) || ((lflag ^ dflag) == 0)) 2655b1d7137Swdenk usage(); 2665b1d7137Swdenk 2675b1d7137Swdenk if (!eflag) { 2685b1d7137Swdenk ep = addr; 2695b1d7137Swdenk /* If XIP, entry point must be after the U-Boot header */ 2705b1d7137Swdenk if (xflag) 2715b1d7137Swdenk ep += sizeof(image_header_t); 2725b1d7137Swdenk } 2735b1d7137Swdenk 2745b1d7137Swdenk /* 2755b1d7137Swdenk * If XIP, ensure the entry point is equal to the load address plus 2765b1d7137Swdenk * the size of the U-Boot header. 2775b1d7137Swdenk */ 2785b1d7137Swdenk if (xflag) { 2795b1d7137Swdenk if (ep != addr + sizeof(image_header_t)) { 280*3577d3a3SWolfgang Denk fprintf (stderr, 281*3577d3a3SWolfgang Denk "%s: For XIP, the entry point must be the load addr + %lu\n", 282a6c7ad2fSwdenk cmdname, 283a6c7ad2fSwdenk (unsigned long)sizeof(image_header_t)); 2845b1d7137Swdenk exit (EXIT_FAILURE); 2855b1d7137Swdenk } 2865b1d7137Swdenk } 2875b1d7137Swdenk 2885b1d7137Swdenk imagefile = *argv; 2895b1d7137Swdenk 2905b1d7137Swdenk if (lflag) { 291ef1464ccSwdenk ifd = open(imagefile, O_RDONLY|O_BINARY); 2925b1d7137Swdenk } else { 2935b1d7137Swdenk ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); 2945b1d7137Swdenk } 2955b1d7137Swdenk 2965b1d7137Swdenk if (ifd < 0) { 2975b1d7137Swdenk fprintf (stderr, "%s: Can't open %s: %s\n", 2985b1d7137Swdenk cmdname, imagefile, strerror(errno)); 2995b1d7137Swdenk exit (EXIT_FAILURE); 3005b1d7137Swdenk } 3015b1d7137Swdenk 3025b1d7137Swdenk if (lflag) { 3035b1d7137Swdenk int len; 3045b1d7137Swdenk char *data; 3055b1d7137Swdenk /* 3065b1d7137Swdenk * list header information of existing image 3075b1d7137Swdenk */ 3085b1d7137Swdenk if (fstat(ifd, &sbuf) < 0) { 3095b1d7137Swdenk fprintf (stderr, "%s: Can't stat %s: %s\n", 3105b1d7137Swdenk cmdname, imagefile, strerror(errno)); 3115b1d7137Swdenk exit (EXIT_FAILURE); 3125b1d7137Swdenk } 3135b1d7137Swdenk 3145bb226e8Swdenk if ((unsigned)sbuf.st_size < sizeof(image_header_t)) { 3155b1d7137Swdenk fprintf (stderr, 3165b1d7137Swdenk "%s: Bad size: \"%s\" is no valid image\n", 3175b1d7137Swdenk cmdname, imagefile); 3185b1d7137Swdenk exit (EXIT_FAILURE); 3195b1d7137Swdenk } 3205b1d7137Swdenk 3215b1d7137Swdenk ptr = (unsigned char *)mmap(0, sbuf.st_size, 3225b1d7137Swdenk PROT_READ, MAP_SHARED, ifd, 0); 3235b1d7137Swdenk if ((caddr_t)ptr == (caddr_t)-1) { 3245b1d7137Swdenk fprintf (stderr, "%s: Can't read %s: %s\n", 3255b1d7137Swdenk cmdname, imagefile, strerror(errno)); 3265b1d7137Swdenk exit (EXIT_FAILURE); 3275b1d7137Swdenk } 3285b1d7137Swdenk 3295b1d7137Swdenk /* 3305b1d7137Swdenk * create copy of header so that we can blank out the 3315b1d7137Swdenk * checksum field for checking - this can't be done 3325b1d7137Swdenk * on the PROT_READ mapped data. 3335b1d7137Swdenk */ 3345b1d7137Swdenk memcpy (hdr, ptr, sizeof(image_header_t)); 3355b1d7137Swdenk 3365b1d7137Swdenk if (ntohl(hdr->ih_magic) != IH_MAGIC) { 3375b1d7137Swdenk fprintf (stderr, 3385b1d7137Swdenk "%s: Bad Magic Number: \"%s\" is no valid image\n", 3395b1d7137Swdenk cmdname, imagefile); 3405b1d7137Swdenk exit (EXIT_FAILURE); 3415b1d7137Swdenk } 3425b1d7137Swdenk 3435b1d7137Swdenk data = (char *)hdr; 3445b1d7137Swdenk len = sizeof(image_header_t); 3455b1d7137Swdenk 3465b1d7137Swdenk checksum = ntohl(hdr->ih_hcrc); 3475b1d7137Swdenk hdr->ih_hcrc = htonl(0); /* clear for re-calculation */ 3485b1d7137Swdenk 3495b1d7137Swdenk if (crc32 (0, data, len) != checksum) { 3505b1d7137Swdenk fprintf (stderr, 351*3577d3a3SWolfgang Denk "%s: ERROR: \"%s\" has bad header checksum!\n", 352*3577d3a3SWolfgang Denk cmdname, imagefile); 353*3577d3a3SWolfgang Denk exit (EXIT_FAILURE); 3545b1d7137Swdenk } 3555b1d7137Swdenk 3565b1d7137Swdenk data = (char *)(ptr + sizeof(image_header_t)); 3575b1d7137Swdenk len = sbuf.st_size - sizeof(image_header_t) ; 3585b1d7137Swdenk 3595b1d7137Swdenk if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) { 3605b1d7137Swdenk fprintf (stderr, 361*3577d3a3SWolfgang Denk "%s: ERROR: \"%s\" has corrupted data!\n", 362*3577d3a3SWolfgang Denk cmdname, imagefile); 363*3577d3a3SWolfgang Denk exit (EXIT_FAILURE); 3645b1d7137Swdenk } 3655b1d7137Swdenk 3665b1d7137Swdenk /* for multi-file images we need the data part, too */ 3675b1d7137Swdenk print_header ((image_header_t *)ptr); 3685b1d7137Swdenk 3695b1d7137Swdenk (void) munmap((void *)ptr, sbuf.st_size); 3705b1d7137Swdenk (void) close (ifd); 3715b1d7137Swdenk 3725b1d7137Swdenk exit (EXIT_SUCCESS); 3735b1d7137Swdenk } 3745b1d7137Swdenk 3755b1d7137Swdenk /* 3765b1d7137Swdenk * Must be -w then: 3775b1d7137Swdenk * 3785b1d7137Swdenk * write dummy header, to be fixed later 3795b1d7137Swdenk */ 3805b1d7137Swdenk memset (hdr, 0, sizeof(image_header_t)); 3815b1d7137Swdenk 3825b1d7137Swdenk if (write(ifd, hdr, sizeof(image_header_t)) != sizeof(image_header_t)) { 3835b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 3845b1d7137Swdenk cmdname, imagefile, strerror(errno)); 3855b1d7137Swdenk exit (EXIT_FAILURE); 3865b1d7137Swdenk } 3875b1d7137Swdenk 3885b1d7137Swdenk if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) { 3895b1d7137Swdenk char *file = datafile; 3903bb66806SWolfgang Denk uint32_t size; 3915b1d7137Swdenk 3925b1d7137Swdenk for (;;) { 3935b1d7137Swdenk char *sep = NULL; 3945b1d7137Swdenk 3955b1d7137Swdenk if (file) { 3965b1d7137Swdenk if ((sep = strchr(file, ':')) != NULL) { 3975b1d7137Swdenk *sep = '\0'; 3985b1d7137Swdenk } 3995b1d7137Swdenk 4005b1d7137Swdenk if (stat (file, &sbuf) < 0) { 4015b1d7137Swdenk fprintf (stderr, "%s: Can't stat %s: %s\n", 4025b1d7137Swdenk cmdname, file, strerror(errno)); 4035b1d7137Swdenk exit (EXIT_FAILURE); 4045b1d7137Swdenk } 4055b1d7137Swdenk size = htonl(sbuf.st_size); 4065b1d7137Swdenk } else { 4075b1d7137Swdenk size = 0; 4085b1d7137Swdenk } 4095b1d7137Swdenk 4105b1d7137Swdenk if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { 4115b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 4125b1d7137Swdenk cmdname, imagefile, strerror(errno)); 4135b1d7137Swdenk exit (EXIT_FAILURE); 4145b1d7137Swdenk } 4155b1d7137Swdenk 4165b1d7137Swdenk if (!file) { 4175b1d7137Swdenk break; 4185b1d7137Swdenk } 4195b1d7137Swdenk 4205b1d7137Swdenk if (sep) { 4215b1d7137Swdenk *sep = ':'; 4225b1d7137Swdenk file = sep + 1; 4235b1d7137Swdenk } else { 4245b1d7137Swdenk file = NULL; 4255b1d7137Swdenk } 4265b1d7137Swdenk } 4275b1d7137Swdenk 4285b1d7137Swdenk file = datafile; 4295b1d7137Swdenk 4305b1d7137Swdenk for (;;) { 4315b1d7137Swdenk char *sep = strchr(file, ':'); 4325b1d7137Swdenk if (sep) { 4335b1d7137Swdenk *sep = '\0'; 4345b1d7137Swdenk copy_file (ifd, file, 1); 4355b1d7137Swdenk *sep++ = ':'; 4365b1d7137Swdenk file = sep; 4375b1d7137Swdenk } else { 4385b1d7137Swdenk copy_file (ifd, file, 0); 4395b1d7137Swdenk break; 4405b1d7137Swdenk } 4415b1d7137Swdenk } 4425b1d7137Swdenk } else { 4435b1d7137Swdenk copy_file (ifd, datafile, 0); 4445b1d7137Swdenk } 4455b1d7137Swdenk 4465b1d7137Swdenk /* We're a bit of paranoid */ 447147031aeSwdenk #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) 4485b1d7137Swdenk (void) fdatasync (ifd); 4495b1d7137Swdenk #else 4505b1d7137Swdenk (void) fsync (ifd); 4515b1d7137Swdenk #endif 4525b1d7137Swdenk 4535b1d7137Swdenk if (fstat(ifd, &sbuf) < 0) { 4545b1d7137Swdenk fprintf (stderr, "%s: Can't stat %s: %s\n", 4555b1d7137Swdenk cmdname, imagefile, strerror(errno)); 4565b1d7137Swdenk exit (EXIT_FAILURE); 4575b1d7137Swdenk } 4585b1d7137Swdenk 4595b1d7137Swdenk ptr = (unsigned char *)mmap(0, sbuf.st_size, 4605b1d7137Swdenk PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); 4615b1d7137Swdenk if (ptr == (unsigned char *)MAP_FAILED) { 4625b1d7137Swdenk fprintf (stderr, "%s: Can't map %s: %s\n", 4635b1d7137Swdenk cmdname, imagefile, strerror(errno)); 4645b1d7137Swdenk exit (EXIT_FAILURE); 4655b1d7137Swdenk } 4665b1d7137Swdenk 4675b1d7137Swdenk hdr = (image_header_t *)ptr; 4685b1d7137Swdenk 4695b1d7137Swdenk checksum = crc32 (0, 4705b1d7137Swdenk (const char *)(ptr + sizeof(image_header_t)), 4715b1d7137Swdenk sbuf.st_size - sizeof(image_header_t) 4725b1d7137Swdenk ); 4735b1d7137Swdenk 4745b1d7137Swdenk /* Build new header */ 4755b1d7137Swdenk hdr->ih_magic = htonl(IH_MAGIC); 4765b1d7137Swdenk hdr->ih_time = htonl(sbuf.st_mtime); 4775b1d7137Swdenk hdr->ih_size = htonl(sbuf.st_size - sizeof(image_header_t)); 4785b1d7137Swdenk hdr->ih_load = htonl(addr); 4795b1d7137Swdenk hdr->ih_ep = htonl(ep); 4805b1d7137Swdenk hdr->ih_dcrc = htonl(checksum); 4815b1d7137Swdenk hdr->ih_os = opt_os; 4825b1d7137Swdenk hdr->ih_arch = opt_arch; 4835b1d7137Swdenk hdr->ih_type = opt_type; 4845b1d7137Swdenk hdr->ih_comp = opt_comp; 4855b1d7137Swdenk 4865b1d7137Swdenk strncpy((char *)hdr->ih_name, name, IH_NMLEN); 4875b1d7137Swdenk 4885b1d7137Swdenk checksum = crc32(0,(const char *)hdr,sizeof(image_header_t)); 4895b1d7137Swdenk 4905b1d7137Swdenk hdr->ih_hcrc = htonl(checksum); 4915b1d7137Swdenk 4925b1d7137Swdenk print_header (hdr); 4935b1d7137Swdenk 4945b1d7137Swdenk (void) munmap((void *)ptr, sbuf.st_size); 4955b1d7137Swdenk 4965b1d7137Swdenk /* We're a bit of paranoid */ 497147031aeSwdenk #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) 4985b1d7137Swdenk (void) fdatasync (ifd); 4995b1d7137Swdenk #else 5005b1d7137Swdenk (void) fsync (ifd); 5015b1d7137Swdenk #endif 5025b1d7137Swdenk 5035b1d7137Swdenk if (close(ifd)) { 5045b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 5055b1d7137Swdenk cmdname, imagefile, strerror(errno)); 5065b1d7137Swdenk exit (EXIT_FAILURE); 5075b1d7137Swdenk } 5085b1d7137Swdenk 5095b1d7137Swdenk exit (EXIT_SUCCESS); 5105b1d7137Swdenk } 5115b1d7137Swdenk 5125b1d7137Swdenk static void 5135b1d7137Swdenk copy_file (int ifd, const char *datafile, int pad) 5145b1d7137Swdenk { 5155b1d7137Swdenk int dfd; 5165b1d7137Swdenk struct stat sbuf; 5175b1d7137Swdenk unsigned char *ptr; 5185b1d7137Swdenk int tail; 5195b1d7137Swdenk int zero = 0; 5205b1d7137Swdenk int offset = 0; 5215b1d7137Swdenk int size; 5225b1d7137Swdenk 5235b1d7137Swdenk if (vflag) { 5245b1d7137Swdenk fprintf (stderr, "Adding Image %s\n", datafile); 5255b1d7137Swdenk } 5265b1d7137Swdenk 527ef1464ccSwdenk if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { 5285b1d7137Swdenk fprintf (stderr, "%s: Can't open %s: %s\n", 5295b1d7137Swdenk cmdname, datafile, strerror(errno)); 5305b1d7137Swdenk exit (EXIT_FAILURE); 5315b1d7137Swdenk } 5325b1d7137Swdenk 5335b1d7137Swdenk if (fstat(dfd, &sbuf) < 0) { 5345b1d7137Swdenk fprintf (stderr, "%s: Can't stat %s: %s\n", 5355b1d7137Swdenk cmdname, datafile, strerror(errno)); 5365b1d7137Swdenk exit (EXIT_FAILURE); 5375b1d7137Swdenk } 5385b1d7137Swdenk 5395b1d7137Swdenk ptr = (unsigned char *)mmap(0, sbuf.st_size, 5405b1d7137Swdenk PROT_READ, MAP_SHARED, dfd, 0); 5415b1d7137Swdenk if (ptr == (unsigned char *)MAP_FAILED) { 5425b1d7137Swdenk fprintf (stderr, "%s: Can't read %s: %s\n", 5435b1d7137Swdenk cmdname, datafile, strerror(errno)); 5445b1d7137Swdenk exit (EXIT_FAILURE); 5455b1d7137Swdenk } 5465b1d7137Swdenk 5475b1d7137Swdenk if (xflag) { 5485b1d7137Swdenk unsigned char *p = NULL; 5495b1d7137Swdenk /* 5505b1d7137Swdenk * XIP: do not append the image_header_t at the 5515b1d7137Swdenk * beginning of the file, but consume the space 5525b1d7137Swdenk * reserved for it. 5535b1d7137Swdenk */ 5545b1d7137Swdenk 5555bb226e8Swdenk if ((unsigned)sbuf.st_size < sizeof(image_header_t)) { 5565b1d7137Swdenk fprintf (stderr, 5575b1d7137Swdenk "%s: Bad size: \"%s\" is too small for XIP\n", 5585b1d7137Swdenk cmdname, datafile); 5595b1d7137Swdenk exit (EXIT_FAILURE); 5605b1d7137Swdenk } 5615b1d7137Swdenk 5625b1d7137Swdenk for (p=ptr; p < ptr+sizeof(image_header_t); p++) { 5635b1d7137Swdenk if ( *p != 0xff ) { 5645b1d7137Swdenk fprintf (stderr, 5655b1d7137Swdenk "%s: Bad file: \"%s\" has invalid buffer for XIP\n", 5665b1d7137Swdenk cmdname, datafile); 5675b1d7137Swdenk exit (EXIT_FAILURE); 5685b1d7137Swdenk } 5695b1d7137Swdenk } 5705b1d7137Swdenk 5715b1d7137Swdenk offset = sizeof(image_header_t); 5725b1d7137Swdenk } 5735b1d7137Swdenk 5745b1d7137Swdenk size = sbuf.st_size - offset; 5755b1d7137Swdenk if (write(ifd, ptr + offset, size) != size) { 5765b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 5775b1d7137Swdenk cmdname, imagefile, strerror(errno)); 5785b1d7137Swdenk exit (EXIT_FAILURE); 5795b1d7137Swdenk } 5805b1d7137Swdenk 5815b1d7137Swdenk if (pad && ((tail = size % 4) != 0)) { 5825b1d7137Swdenk 5835b1d7137Swdenk if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { 5845b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 5855b1d7137Swdenk cmdname, imagefile, strerror(errno)); 5865b1d7137Swdenk exit (EXIT_FAILURE); 5875b1d7137Swdenk } 5885b1d7137Swdenk } 5895b1d7137Swdenk 5905b1d7137Swdenk (void) munmap((void *)ptr, sbuf.st_size); 5915b1d7137Swdenk (void) close (dfd); 5925b1d7137Swdenk } 5935b1d7137Swdenk 5945b1d7137Swdenk void 5955b1d7137Swdenk usage () 5965b1d7137Swdenk { 5975b1d7137Swdenk fprintf (stderr, "Usage: %s -l image\n" 5985b1d7137Swdenk " -l ==> list image header information\n" 5999d5028c2Swdenk " %s [-x] -A arch -O os -T type -C comp " 6005b1d7137Swdenk "-a addr -e ep -n name -d data_file[:data_file...] image\n", 6015b1d7137Swdenk cmdname, cmdname); 6025b1d7137Swdenk fprintf (stderr, " -A ==> set architecture to 'arch'\n" 6035b1d7137Swdenk " -O ==> set operating system to 'os'\n" 6045b1d7137Swdenk " -T ==> set image type to 'type'\n" 6055b1d7137Swdenk " -C ==> set compression type 'comp'\n" 6065b1d7137Swdenk " -a ==> set load address to 'addr' (hex)\n" 6075b1d7137Swdenk " -e ==> set entry point to 'ep' (hex)\n" 6085b1d7137Swdenk " -n ==> set image name to 'name'\n" 6095b1d7137Swdenk " -d ==> use image data from 'datafile'\n" 6105b1d7137Swdenk " -x ==> set XIP (execute in place)\n" 6115b1d7137Swdenk ); 6125b1d7137Swdenk exit (EXIT_FAILURE); 6135b1d7137Swdenk } 6145b1d7137Swdenk 6155b1d7137Swdenk static void 6165b1d7137Swdenk print_header (image_header_t *hdr) 6175b1d7137Swdenk { 6185b1d7137Swdenk time_t timestamp; 6195b1d7137Swdenk uint32_t size; 6205b1d7137Swdenk 6215b1d7137Swdenk timestamp = (time_t)ntohl(hdr->ih_time); 6225b1d7137Swdenk size = ntohl(hdr->ih_size); 6235b1d7137Swdenk 6245b1d7137Swdenk printf ("Image Name: %.*s\n", IH_NMLEN, hdr->ih_name); 6255b1d7137Swdenk printf ("Created: %s", ctime(×tamp)); 6265b1d7137Swdenk printf ("Image Type: "); print_type(hdr); 6275b1d7137Swdenk printf ("Data Size: %d Bytes = %.2f kB = %.2f MB\n", 6285b1d7137Swdenk size, (double)size / 1.024e3, (double)size / 1.048576e6 ); 629bdccc4feSwdenk printf ("Load Address: 0x%08X\n", ntohl(hdr->ih_load)); 630bdccc4feSwdenk printf ("Entry Point: 0x%08X\n", ntohl(hdr->ih_ep)); 6315b1d7137Swdenk 6325b1d7137Swdenk if (hdr->ih_type == IH_TYPE_MULTI || hdr->ih_type == IH_TYPE_SCRIPT) { 6335b1d7137Swdenk int i, ptrs; 6345b1d7137Swdenk uint32_t pos; 6355b1d7137Swdenk unsigned long *len_ptr = (unsigned long *) ( 6365b1d7137Swdenk (unsigned long)hdr + sizeof(image_header_t) 6375b1d7137Swdenk ); 6385b1d7137Swdenk 6395b1d7137Swdenk /* determine number of images first (to calculate image offsets) */ 6405b1d7137Swdenk for (i=0; len_ptr[i]; ++i) /* null pointer terminates list */ 6415b1d7137Swdenk ; 6425b1d7137Swdenk ptrs = i; /* null pointer terminates list */ 6435b1d7137Swdenk 6445b1d7137Swdenk pos = sizeof(image_header_t) + ptrs * sizeof(long); 6455b1d7137Swdenk printf ("Contents:\n"); 6465b1d7137Swdenk for (i=0; len_ptr[i]; ++i) { 6475b1d7137Swdenk size = ntohl(len_ptr[i]); 6485b1d7137Swdenk 6495b1d7137Swdenk printf (" Image %d: %8d Bytes = %4d kB = %d MB\n", 6505b1d7137Swdenk i, size, size>>10, size>>20); 6515b1d7137Swdenk if (hdr->ih_type == IH_TYPE_SCRIPT && i > 0) { 6525b1d7137Swdenk /* 6535b1d7137Swdenk * the user may need to know offsets 6545b1d7137Swdenk * if planning to do something with 6555b1d7137Swdenk * multiple files 6565b1d7137Swdenk */ 657bdccc4feSwdenk printf (" Offset = %08X\n", pos); 6585b1d7137Swdenk } 6595b1d7137Swdenk /* copy_file() will pad the first files to even word align */ 6605b1d7137Swdenk size += 3; 6615b1d7137Swdenk size &= ~3; 6625b1d7137Swdenk pos += size; 6635b1d7137Swdenk } 6645b1d7137Swdenk } 6655b1d7137Swdenk } 6665b1d7137Swdenk 6675b1d7137Swdenk 6685b1d7137Swdenk static void 6695b1d7137Swdenk print_type (image_header_t *hdr) 6705b1d7137Swdenk { 6715b1d7137Swdenk printf ("%s %s %s (%s)\n", 6725b1d7137Swdenk put_arch (hdr->ih_arch), 6735b1d7137Swdenk put_os (hdr->ih_os ), 6745b1d7137Swdenk put_type (hdr->ih_type), 6755b1d7137Swdenk put_comp (hdr->ih_comp) 6765b1d7137Swdenk ); 6775b1d7137Swdenk } 6785b1d7137Swdenk 6795b1d7137Swdenk static char *put_arch (int arch) 6805b1d7137Swdenk { 6815b1d7137Swdenk return (put_table_entry(arch_name, "Unknown Architecture", arch)); 6825b1d7137Swdenk } 6835b1d7137Swdenk 6845b1d7137Swdenk static char *put_os (int os) 6855b1d7137Swdenk { 6865b1d7137Swdenk return (put_table_entry(os_name, "Unknown OS", os)); 6875b1d7137Swdenk } 6885b1d7137Swdenk 6895b1d7137Swdenk static char *put_type (int type) 6905b1d7137Swdenk { 6915b1d7137Swdenk return (put_table_entry(type_name, "Unknown Image", type)); 6925b1d7137Swdenk } 6935b1d7137Swdenk 6945b1d7137Swdenk static char *put_comp (int comp) 6955b1d7137Swdenk { 6965b1d7137Swdenk return (put_table_entry(comp_name, "Unknown Compression", comp)); 6975b1d7137Swdenk } 6985b1d7137Swdenk 6995b1d7137Swdenk static char *put_table_entry (table_entry_t *table, char *msg, int type) 7005b1d7137Swdenk { 7015b1d7137Swdenk for (; table->val>=0; ++table) { 7025b1d7137Swdenk if (table->val == type) 7035b1d7137Swdenk return (table->lname); 7045b1d7137Swdenk } 7055b1d7137Swdenk return (msg); 7065b1d7137Swdenk } 7075b1d7137Swdenk 7085b1d7137Swdenk static int get_arch(char *name) 7095b1d7137Swdenk { 7105b1d7137Swdenk return (get_table_entry(arch_name, "CPU", name)); 7115b1d7137Swdenk } 7125b1d7137Swdenk 7135b1d7137Swdenk 7145b1d7137Swdenk static int get_comp(char *name) 7155b1d7137Swdenk { 7165b1d7137Swdenk return (get_table_entry(comp_name, "Compression", name)); 7175b1d7137Swdenk } 7185b1d7137Swdenk 7195b1d7137Swdenk 7205b1d7137Swdenk static int get_os (char *name) 7215b1d7137Swdenk { 7225b1d7137Swdenk return (get_table_entry(os_name, "OS", name)); 7235b1d7137Swdenk } 7245b1d7137Swdenk 7255b1d7137Swdenk 7265b1d7137Swdenk static int get_type(char *name) 7275b1d7137Swdenk { 7285b1d7137Swdenk return (get_table_entry(type_name, "Image", name)); 7295b1d7137Swdenk } 7305b1d7137Swdenk 7315b1d7137Swdenk static int get_table_entry (table_entry_t *table, char *msg, char *name) 7325b1d7137Swdenk { 7335b1d7137Swdenk table_entry_t *t; 7345b1d7137Swdenk int first = 1; 7355b1d7137Swdenk 7365b1d7137Swdenk for (t=table; t->val>=0; ++t) { 7375b1d7137Swdenk if (t->sname && strcasecmp(t->sname, name)==0) 7385b1d7137Swdenk return (t->val); 7395b1d7137Swdenk } 7405b1d7137Swdenk fprintf (stderr, "\nInvalid %s Type - valid names are", msg); 7415b1d7137Swdenk for (t=table; t->val>=0; ++t) { 7425b1d7137Swdenk if (t->sname == NULL) 7435b1d7137Swdenk continue; 7445b1d7137Swdenk fprintf (stderr, "%c %s", (first) ? ':' : ',', t->sname); 7455b1d7137Swdenk first = 0; 7465b1d7137Swdenk } 7475b1d7137Swdenk fprintf (stderr, "\n"); 7485b1d7137Swdenk return (-1); 7495b1d7137Swdenk } 750