15b1d7137Swdenk /* 2*9d25438fSBartlomiej Sieka * (C) Copyright 2008 Semihalf 3*9d25438fSBartlomiej Sieka * 40c852a28Swdenk * (C) Copyright 2000-2004 55b1d7137Swdenk * DENX Software Engineering 65b1d7137Swdenk * Wolfgang Denk, wd@denx.de 75b1d7137Swdenk * All rights reserved. 80c852a28Swdenk * 90c852a28Swdenk * This program is free software; you can redistribute it and/or 100c852a28Swdenk * modify it under the terms of the GNU General Public License as 110c852a28Swdenk * published by the Free Software Foundation; either version 2 of 120c852a28Swdenk * the License, or (at your option) any later version. 130c852a28Swdenk * 140c852a28Swdenk * This program is distributed in the hope that it will be useful, 150c852a28Swdenk * but WITHOUT ANY WARRANTY; without even the implied warranty of 160c852a28Swdenk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 170c852a28Swdenk * GNU General Public License for more details. 180c852a28Swdenk * 190c852a28Swdenk * You should have received a copy of the GNU General Public License 200c852a28Swdenk * along with this program; if not, write to the Free Software 210c852a28Swdenk * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 220c852a28Swdenk * MA 02111-1307 USA 235b1d7137Swdenk */ 245b1d7137Swdenk 25b97a2a0aSMarian Balakowicz #include "mkimage.h" 265b1d7137Swdenk #include <image.h> 275b1d7137Swdenk 285b1d7137Swdenk extern int errno; 295b1d7137Swdenk 305b1d7137Swdenk #ifndef MAP_FAILED 315b1d7137Swdenk #define MAP_FAILED (-1) 325b1d7137Swdenk #endif 335b1d7137Swdenk 345b1d7137Swdenk extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len); 355b1d7137Swdenk static void copy_file (int, const char *, int); 365b1d7137Swdenk static void usage (void); 37*9d25438fSBartlomiej Sieka static void image_verify_header (char *, int); 38*9d25438fSBartlomiej Sieka static void fit_handle_file (void); 395b1d7137Swdenk 405b1d7137Swdenk char *datafile; 415b1d7137Swdenk char *imagefile; 42570abb0aSMarian Balakowicz char *cmdname; 435b1d7137Swdenk 445b1d7137Swdenk int dflag = 0; 455b1d7137Swdenk int eflag = 0; 46*9d25438fSBartlomiej Sieka int fflag = 0; 475b1d7137Swdenk int lflag = 0; 485b1d7137Swdenk int vflag = 0; 495b1d7137Swdenk int xflag = 0; 505b1d7137Swdenk int opt_os = IH_OS_LINUX; 51b97a2a0aSMarian Balakowicz int opt_arch = IH_ARCH_PPC; 525b1d7137Swdenk int opt_type = IH_TYPE_KERNEL; 535b1d7137Swdenk int opt_comp = IH_COMP_GZIP; 54*9d25438fSBartlomiej Sieka char *opt_dtc = MKIMAGE_DEFAULT_DTC_OPTIONS; 555b1d7137Swdenk 565b1d7137Swdenk image_header_t header; 575b1d7137Swdenk image_header_t *hdr = &header; 585b1d7137Swdenk 595b1d7137Swdenk int 605b1d7137Swdenk main (int argc, char **argv) 615b1d7137Swdenk { 62*9d25438fSBartlomiej Sieka int ifd = -1; 635b1d7137Swdenk uint32_t checksum; 645b1d7137Swdenk uint32_t addr; 655b1d7137Swdenk uint32_t ep; 665b1d7137Swdenk struct stat sbuf; 675b1d7137Swdenk unsigned char *ptr; 685b1d7137Swdenk char *name = ""; 695b1d7137Swdenk 705b1d7137Swdenk cmdname = *argv; 715b1d7137Swdenk 725b1d7137Swdenk addr = ep = 0; 735b1d7137Swdenk 745b1d7137Swdenk while (--argc > 0 && **++argv == '-') { 755b1d7137Swdenk while (*++*argv) { 765b1d7137Swdenk switch (**argv) { 775b1d7137Swdenk case 'l': 785b1d7137Swdenk lflag = 1; 795b1d7137Swdenk break; 805b1d7137Swdenk case 'A': 815b1d7137Swdenk if ((--argc <= 0) || 82570abb0aSMarian Balakowicz (opt_arch = genimg_get_arch_id (*++argv)) < 0) 835b1d7137Swdenk usage (); 845b1d7137Swdenk goto NXTARG; 855b1d7137Swdenk case 'C': 865b1d7137Swdenk if ((--argc <= 0) || 87570abb0aSMarian Balakowicz (opt_comp = genimg_get_comp_id (*++argv)) < 0) 885b1d7137Swdenk usage (); 895b1d7137Swdenk goto NXTARG; 90*9d25438fSBartlomiej Sieka case 'D': 91*9d25438fSBartlomiej Sieka if (--argc <= 0) 92*9d25438fSBartlomiej Sieka usage (); 93*9d25438fSBartlomiej Sieka opt_dtc = *++argv; 94*9d25438fSBartlomiej Sieka goto NXTARG; 95*9d25438fSBartlomiej Sieka 965b1d7137Swdenk case 'O': 975b1d7137Swdenk if ((--argc <= 0) || 98570abb0aSMarian Balakowicz (opt_os = genimg_get_os_id (*++argv)) < 0) 995b1d7137Swdenk usage (); 1005b1d7137Swdenk goto NXTARG; 1015b1d7137Swdenk case 'T': 1025b1d7137Swdenk if ((--argc <= 0) || 103570abb0aSMarian Balakowicz (opt_type = genimg_get_type_id (*++argv)) < 0) 1045b1d7137Swdenk usage (); 1055b1d7137Swdenk goto NXTARG; 1065b1d7137Swdenk 1075b1d7137Swdenk case 'a': 1085b1d7137Swdenk if (--argc <= 0) 1095b1d7137Swdenk usage (); 1105b1d7137Swdenk addr = strtoul (*++argv, (char **)&ptr, 16); 1115b1d7137Swdenk if (*ptr) { 1125b1d7137Swdenk fprintf (stderr, 1135b1d7137Swdenk "%s: invalid load address %s\n", 1145b1d7137Swdenk cmdname, *argv); 1155b1d7137Swdenk exit (EXIT_FAILURE); 1165b1d7137Swdenk } 1175b1d7137Swdenk goto NXTARG; 1185b1d7137Swdenk case 'd': 1195b1d7137Swdenk if (--argc <= 0) 1205b1d7137Swdenk usage (); 1215b1d7137Swdenk datafile = *++argv; 1225b1d7137Swdenk dflag = 1; 1235b1d7137Swdenk goto NXTARG; 1245b1d7137Swdenk case 'e': 1255b1d7137Swdenk if (--argc <= 0) 1265b1d7137Swdenk usage (); 1275b1d7137Swdenk ep = strtoul (*++argv, (char **)&ptr, 16); 1285b1d7137Swdenk if (*ptr) { 1295b1d7137Swdenk fprintf (stderr, 1305b1d7137Swdenk "%s: invalid entry point %s\n", 1315b1d7137Swdenk cmdname, *argv); 1325b1d7137Swdenk exit (EXIT_FAILURE); 1335b1d7137Swdenk } 1345b1d7137Swdenk eflag = 1; 1355b1d7137Swdenk goto NXTARG; 136*9d25438fSBartlomiej Sieka case 'f': 137*9d25438fSBartlomiej Sieka if (--argc <= 0) 138*9d25438fSBartlomiej Sieka usage (); 139*9d25438fSBartlomiej Sieka datafile = *++argv; 140*9d25438fSBartlomiej Sieka fflag = 1; 141*9d25438fSBartlomiej Sieka goto NXTARG; 1425b1d7137Swdenk case 'n': 1435b1d7137Swdenk if (--argc <= 0) 1445b1d7137Swdenk usage (); 1455b1d7137Swdenk name = *++argv; 1465b1d7137Swdenk goto NXTARG; 1475b1d7137Swdenk case 'v': 1485b1d7137Swdenk vflag++; 1495b1d7137Swdenk break; 1505b1d7137Swdenk case 'x': 1515b1d7137Swdenk xflag++; 1525b1d7137Swdenk break; 1535b1d7137Swdenk default: 1545b1d7137Swdenk usage (); 1555b1d7137Swdenk } 1565b1d7137Swdenk } 1575b1d7137Swdenk NXTARG: ; 1585b1d7137Swdenk } 1595b1d7137Swdenk 160*9d25438fSBartlomiej Sieka if ((argc != 1) || 161*9d25438fSBartlomiej Sieka (dflag && (fflag || lflag)) || 162*9d25438fSBartlomiej Sieka (fflag && (dflag || lflag)) || 163*9d25438fSBartlomiej Sieka (lflag && (dflag || fflag))) 1645b1d7137Swdenk usage(); 1655b1d7137Swdenk 1665b1d7137Swdenk if (!eflag) { 1675b1d7137Swdenk ep = addr; 1685b1d7137Swdenk /* If XIP, entry point must be after the U-Boot header */ 1695b1d7137Swdenk if (xflag) 170b97a2a0aSMarian Balakowicz ep += image_get_header_size (); 1715b1d7137Swdenk } 1725b1d7137Swdenk 1735b1d7137Swdenk /* 1745b1d7137Swdenk * If XIP, ensure the entry point is equal to the load address plus 1755b1d7137Swdenk * the size of the U-Boot header. 1765b1d7137Swdenk */ 1775b1d7137Swdenk if (xflag) { 178b97a2a0aSMarian Balakowicz if (ep != addr + image_get_header_size ()) { 1793577d3a3SWolfgang Denk fprintf (stderr, 1803577d3a3SWolfgang Denk "%s: For XIP, the entry point must be the load addr + %lu\n", 181a6c7ad2fSwdenk cmdname, 182b97a2a0aSMarian Balakowicz (unsigned long)image_get_header_size ()); 1835b1d7137Swdenk exit (EXIT_FAILURE); 1845b1d7137Swdenk } 1855b1d7137Swdenk } 1865b1d7137Swdenk 1875b1d7137Swdenk imagefile = *argv; 1885b1d7137Swdenk 189*9d25438fSBartlomiej Sieka if (!fflag){ 1905b1d7137Swdenk if (lflag) { 191ef1464ccSwdenk ifd = open (imagefile, O_RDONLY|O_BINARY); 1925b1d7137Swdenk } else { 193*9d25438fSBartlomiej Sieka ifd = open (imagefile, 194*9d25438fSBartlomiej Sieka O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); 1955b1d7137Swdenk } 1965b1d7137Swdenk 1975b1d7137Swdenk if (ifd < 0) { 1985b1d7137Swdenk fprintf (stderr, "%s: Can't open %s: %s\n", 1995b1d7137Swdenk cmdname, imagefile, strerror(errno)); 2005b1d7137Swdenk exit (EXIT_FAILURE); 2015b1d7137Swdenk } 202*9d25438fSBartlomiej Sieka } 2035b1d7137Swdenk 2045b1d7137Swdenk if (lflag) { 2055b1d7137Swdenk /* 2065b1d7137Swdenk * list header information of existing image 2075b1d7137Swdenk */ 2085b1d7137Swdenk if (fstat(ifd, &sbuf) < 0) { 2095b1d7137Swdenk fprintf (stderr, "%s: Can't stat %s: %s\n", 2105b1d7137Swdenk cmdname, imagefile, strerror(errno)); 2115b1d7137Swdenk exit (EXIT_FAILURE); 2125b1d7137Swdenk } 2135b1d7137Swdenk 214b97a2a0aSMarian Balakowicz if ((unsigned)sbuf.st_size < image_get_header_size ()) { 2155b1d7137Swdenk fprintf (stderr, 2165b1d7137Swdenk "%s: Bad size: \"%s\" is no valid image\n", 2175b1d7137Swdenk cmdname, imagefile); 2185b1d7137Swdenk exit (EXIT_FAILURE); 2195b1d7137Swdenk } 2205b1d7137Swdenk 2215b1d7137Swdenk ptr = (unsigned char *)mmap(0, sbuf.st_size, 2225b1d7137Swdenk PROT_READ, MAP_SHARED, ifd, 0); 2235b1d7137Swdenk if ((caddr_t)ptr == (caddr_t)-1) { 2245b1d7137Swdenk fprintf (stderr, "%s: Can't read %s: %s\n", 2255b1d7137Swdenk cmdname, imagefile, strerror(errno)); 2265b1d7137Swdenk exit (EXIT_FAILURE); 2275b1d7137Swdenk } 2285b1d7137Swdenk 229*9d25438fSBartlomiej Sieka if (fdt_check_header (ptr)) { 230*9d25438fSBartlomiej Sieka /* old-style image */ 231*9d25438fSBartlomiej Sieka image_verify_header ((char *)ptr, sbuf.st_size); 232570abb0aSMarian Balakowicz image_print_contents_noindent ((image_header_t *)ptr); 233*9d25438fSBartlomiej Sieka } else { 234*9d25438fSBartlomiej Sieka /* FIT image */ 235*9d25438fSBartlomiej Sieka fit_print_contents_noindent (ptr); 236*9d25438fSBartlomiej Sieka } 2375b1d7137Swdenk 2385b1d7137Swdenk (void) munmap((void *)ptr, sbuf.st_size); 2395b1d7137Swdenk (void) close (ifd); 2405b1d7137Swdenk 2415b1d7137Swdenk exit (EXIT_SUCCESS); 242*9d25438fSBartlomiej Sieka } else if (fflag) { 243*9d25438fSBartlomiej Sieka /* Flattened Image Tree (FIT) format handling */ 244*9d25438fSBartlomiej Sieka debug ("FIT format handling\n"); 245*9d25438fSBartlomiej Sieka fit_handle_file (); 246*9d25438fSBartlomiej Sieka exit (EXIT_SUCCESS); 2475b1d7137Swdenk } 2485b1d7137Swdenk 2495b1d7137Swdenk /* 2505b1d7137Swdenk * Must be -w then: 2515b1d7137Swdenk * 2525b1d7137Swdenk * write dummy header, to be fixed later 2535b1d7137Swdenk */ 254b97a2a0aSMarian Balakowicz memset (hdr, 0, image_get_header_size ()); 2555b1d7137Swdenk 256b97a2a0aSMarian Balakowicz if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) { 2575b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 2585b1d7137Swdenk cmdname, imagefile, strerror(errno)); 2595b1d7137Swdenk exit (EXIT_FAILURE); 2605b1d7137Swdenk } 2615b1d7137Swdenk 2625b1d7137Swdenk if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) { 2635b1d7137Swdenk char *file = datafile; 2643bb66806SWolfgang Denk uint32_t size; 2655b1d7137Swdenk 2665b1d7137Swdenk for (;;) { 2675b1d7137Swdenk char *sep = NULL; 2685b1d7137Swdenk 2695b1d7137Swdenk if (file) { 2705b1d7137Swdenk if ((sep = strchr(file, ':')) != NULL) { 2715b1d7137Swdenk *sep = '\0'; 2725b1d7137Swdenk } 2735b1d7137Swdenk 2745b1d7137Swdenk if (stat (file, &sbuf) < 0) { 2755b1d7137Swdenk fprintf (stderr, "%s: Can't stat %s: %s\n", 2765b1d7137Swdenk cmdname, file, strerror(errno)); 2775b1d7137Swdenk exit (EXIT_FAILURE); 2785b1d7137Swdenk } 2799a4daad0SMarian Balakowicz size = cpu_to_uimage (sbuf.st_size); 2805b1d7137Swdenk } else { 2815b1d7137Swdenk size = 0; 2825b1d7137Swdenk } 2835b1d7137Swdenk 2845b1d7137Swdenk if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { 2855b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 2865b1d7137Swdenk cmdname, imagefile, strerror(errno)); 2875b1d7137Swdenk exit (EXIT_FAILURE); 2885b1d7137Swdenk } 2895b1d7137Swdenk 2905b1d7137Swdenk if (!file) { 2915b1d7137Swdenk break; 2925b1d7137Swdenk } 2935b1d7137Swdenk 2945b1d7137Swdenk if (sep) { 2955b1d7137Swdenk *sep = ':'; 2965b1d7137Swdenk file = sep + 1; 2975b1d7137Swdenk } else { 2985b1d7137Swdenk file = NULL; 2995b1d7137Swdenk } 3005b1d7137Swdenk } 3015b1d7137Swdenk 3025b1d7137Swdenk file = datafile; 3035b1d7137Swdenk 3045b1d7137Swdenk for (;;) { 3055b1d7137Swdenk char *sep = strchr(file, ':'); 3065b1d7137Swdenk if (sep) { 3075b1d7137Swdenk *sep = '\0'; 3085b1d7137Swdenk copy_file (ifd, file, 1); 3095b1d7137Swdenk *sep++ = ':'; 3105b1d7137Swdenk file = sep; 3115b1d7137Swdenk } else { 3125b1d7137Swdenk copy_file (ifd, file, 0); 3135b1d7137Swdenk break; 3145b1d7137Swdenk } 3155b1d7137Swdenk } 3165b1d7137Swdenk } else { 3175b1d7137Swdenk copy_file (ifd, datafile, 0); 3185b1d7137Swdenk } 3195b1d7137Swdenk 3205b1d7137Swdenk /* We're a bit of paranoid */ 3215dfaa50eSAubrey.Li #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__) 3225b1d7137Swdenk (void) fdatasync (ifd); 3235b1d7137Swdenk #else 3245b1d7137Swdenk (void) fsync (ifd); 3255b1d7137Swdenk #endif 3265b1d7137Swdenk 3275b1d7137Swdenk if (fstat(ifd, &sbuf) < 0) { 3285b1d7137Swdenk fprintf (stderr, "%s: Can't stat %s: %s\n", 3295b1d7137Swdenk cmdname, imagefile, strerror(errno)); 3305b1d7137Swdenk exit (EXIT_FAILURE); 3315b1d7137Swdenk } 3325b1d7137Swdenk 3335b1d7137Swdenk ptr = (unsigned char *)mmap(0, sbuf.st_size, 3345b1d7137Swdenk PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); 3355b1d7137Swdenk if (ptr == (unsigned char *)MAP_FAILED) { 3365b1d7137Swdenk fprintf (stderr, "%s: Can't map %s: %s\n", 3375b1d7137Swdenk cmdname, imagefile, strerror(errno)); 3385b1d7137Swdenk exit (EXIT_FAILURE); 3395b1d7137Swdenk } 3405b1d7137Swdenk 3415b1d7137Swdenk hdr = (image_header_t *)ptr; 3425b1d7137Swdenk 3435b1d7137Swdenk checksum = crc32 (0, 344b97a2a0aSMarian Balakowicz (const char *)(ptr + image_get_header_size ()), 345b97a2a0aSMarian Balakowicz sbuf.st_size - image_get_header_size () 3465b1d7137Swdenk ); 3475b1d7137Swdenk 3485b1d7137Swdenk /* Build new header */ 349b97a2a0aSMarian Balakowicz image_set_magic (hdr, IH_MAGIC); 350b97a2a0aSMarian Balakowicz image_set_time (hdr, sbuf.st_mtime); 351b97a2a0aSMarian Balakowicz image_set_size (hdr, sbuf.st_size - image_get_header_size ()); 352b97a2a0aSMarian Balakowicz image_set_load (hdr, addr); 353b97a2a0aSMarian Balakowicz image_set_ep (hdr, ep); 354b97a2a0aSMarian Balakowicz image_set_dcrc (hdr, checksum); 355b97a2a0aSMarian Balakowicz image_set_os (hdr, opt_os); 356b97a2a0aSMarian Balakowicz image_set_arch (hdr, opt_arch); 357b97a2a0aSMarian Balakowicz image_set_type (hdr, opt_type); 358b97a2a0aSMarian Balakowicz image_set_comp (hdr, opt_comp); 3595b1d7137Swdenk 360b97a2a0aSMarian Balakowicz image_set_name (hdr, name); 3615b1d7137Swdenk 362b97a2a0aSMarian Balakowicz checksum = crc32 (0, (const char *)hdr, image_get_header_size ()); 3635b1d7137Swdenk 364b97a2a0aSMarian Balakowicz image_set_hcrc (hdr, checksum); 3655b1d7137Swdenk 366570abb0aSMarian Balakowicz image_print_contents_noindent (hdr); 3675b1d7137Swdenk 3685b1d7137Swdenk (void) munmap((void *)ptr, sbuf.st_size); 3695b1d7137Swdenk 3705b1d7137Swdenk /* We're a bit of paranoid */ 3715dfaa50eSAubrey.Li #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__) 3725b1d7137Swdenk (void) fdatasync (ifd); 3735b1d7137Swdenk #else 3745b1d7137Swdenk (void) fsync (ifd); 3755b1d7137Swdenk #endif 3765b1d7137Swdenk 3775b1d7137Swdenk if (close(ifd)) { 3785b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 3795b1d7137Swdenk cmdname, imagefile, strerror(errno)); 3805b1d7137Swdenk exit (EXIT_FAILURE); 3815b1d7137Swdenk } 3825b1d7137Swdenk 3835b1d7137Swdenk exit (EXIT_SUCCESS); 3845b1d7137Swdenk } 3855b1d7137Swdenk 3865b1d7137Swdenk static void 3875b1d7137Swdenk copy_file (int ifd, const char *datafile, int pad) 3885b1d7137Swdenk { 3895b1d7137Swdenk int dfd; 3905b1d7137Swdenk struct stat sbuf; 3915b1d7137Swdenk unsigned char *ptr; 3925b1d7137Swdenk int tail; 3935b1d7137Swdenk int zero = 0; 3945b1d7137Swdenk int offset = 0; 3955b1d7137Swdenk int size; 3965b1d7137Swdenk 3975b1d7137Swdenk if (vflag) { 3985b1d7137Swdenk fprintf (stderr, "Adding Image %s\n", datafile); 3995b1d7137Swdenk } 4005b1d7137Swdenk 401ef1464ccSwdenk if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { 4025b1d7137Swdenk fprintf (stderr, "%s: Can't open %s: %s\n", 4035b1d7137Swdenk cmdname, datafile, strerror(errno)); 4045b1d7137Swdenk exit (EXIT_FAILURE); 4055b1d7137Swdenk } 4065b1d7137Swdenk 4075b1d7137Swdenk if (fstat(dfd, &sbuf) < 0) { 4085b1d7137Swdenk fprintf (stderr, "%s: Can't stat %s: %s\n", 4095b1d7137Swdenk cmdname, datafile, strerror(errno)); 4105b1d7137Swdenk exit (EXIT_FAILURE); 4115b1d7137Swdenk } 4125b1d7137Swdenk 4135b1d7137Swdenk ptr = (unsigned char *)mmap(0, sbuf.st_size, 4145b1d7137Swdenk PROT_READ, MAP_SHARED, dfd, 0); 4155b1d7137Swdenk if (ptr == (unsigned char *)MAP_FAILED) { 4165b1d7137Swdenk fprintf (stderr, "%s: Can't read %s: %s\n", 4175b1d7137Swdenk cmdname, datafile, strerror(errno)); 4185b1d7137Swdenk exit (EXIT_FAILURE); 4195b1d7137Swdenk } 4205b1d7137Swdenk 4215b1d7137Swdenk if (xflag) { 4225b1d7137Swdenk unsigned char *p = NULL; 4235b1d7137Swdenk /* 4245b1d7137Swdenk * XIP: do not append the image_header_t at the 4255b1d7137Swdenk * beginning of the file, but consume the space 4265b1d7137Swdenk * reserved for it. 4275b1d7137Swdenk */ 4285b1d7137Swdenk 429b97a2a0aSMarian Balakowicz if ((unsigned)sbuf.st_size < image_get_header_size ()) { 4305b1d7137Swdenk fprintf (stderr, 4315b1d7137Swdenk "%s: Bad size: \"%s\" is too small for XIP\n", 4325b1d7137Swdenk cmdname, datafile); 4335b1d7137Swdenk exit (EXIT_FAILURE); 4345b1d7137Swdenk } 4355b1d7137Swdenk 436b97a2a0aSMarian Balakowicz for (p = ptr; p < ptr + image_get_header_size (); p++) { 4375b1d7137Swdenk if ( *p != 0xff ) { 4385b1d7137Swdenk fprintf (stderr, 4395b1d7137Swdenk "%s: Bad file: \"%s\" has invalid buffer for XIP\n", 4405b1d7137Swdenk cmdname, datafile); 4415b1d7137Swdenk exit (EXIT_FAILURE); 4425b1d7137Swdenk } 4435b1d7137Swdenk } 4445b1d7137Swdenk 445b97a2a0aSMarian Balakowicz offset = image_get_header_size (); 4465b1d7137Swdenk } 4475b1d7137Swdenk 4485b1d7137Swdenk size = sbuf.st_size - offset; 4495b1d7137Swdenk if (write(ifd, ptr + offset, size) != size) { 4505b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 4515b1d7137Swdenk cmdname, imagefile, strerror(errno)); 4525b1d7137Swdenk exit (EXIT_FAILURE); 4535b1d7137Swdenk } 4545b1d7137Swdenk 4555b1d7137Swdenk if (pad && ((tail = size % 4) != 0)) { 4565b1d7137Swdenk 4575b1d7137Swdenk if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { 4585b1d7137Swdenk fprintf (stderr, "%s: Write error on %s: %s\n", 4595b1d7137Swdenk cmdname, imagefile, strerror(errno)); 4605b1d7137Swdenk exit (EXIT_FAILURE); 4615b1d7137Swdenk } 4625b1d7137Swdenk } 4635b1d7137Swdenk 4645b1d7137Swdenk (void) munmap((void *)ptr, sbuf.st_size); 4655b1d7137Swdenk (void) close (dfd); 4665b1d7137Swdenk } 4675b1d7137Swdenk 4685b1d7137Swdenk void 4695b1d7137Swdenk usage () 4705b1d7137Swdenk { 4715b1d7137Swdenk fprintf (stderr, "Usage: %s -l image\n" 472*9d25438fSBartlomiej Sieka " -l ==> list image header information\n", 473*9d25438fSBartlomiej Sieka cmdname); 474*9d25438fSBartlomiej Sieka fprintf (stderr, " %s [-x] -A arch -O os -T type -C comp " 475*9d25438fSBartlomiej Sieka "-a addr -e ep -n name -d data_file[:data_file...] image\n" 476*9d25438fSBartlomiej Sieka " -A ==> set architecture to 'arch'\n" 4775b1d7137Swdenk " -O ==> set operating system to 'os'\n" 4785b1d7137Swdenk " -T ==> set image type to 'type'\n" 4795b1d7137Swdenk " -C ==> set compression type 'comp'\n" 4805b1d7137Swdenk " -a ==> set load address to 'addr' (hex)\n" 4815b1d7137Swdenk " -e ==> set entry point to 'ep' (hex)\n" 4825b1d7137Swdenk " -n ==> set image name to 'name'\n" 4835b1d7137Swdenk " -d ==> use image data from 'datafile'\n" 484*9d25438fSBartlomiej Sieka " -x ==> set XIP (execute in place)\n", 485*9d25438fSBartlomiej Sieka cmdname); 486*9d25438fSBartlomiej Sieka fprintf (stderr, " %s [-D dtc_options] -f fit-image.its fit-image\n", 487*9d25438fSBartlomiej Sieka cmdname); 488*9d25438fSBartlomiej Sieka 4895b1d7137Swdenk exit (EXIT_FAILURE); 4905b1d7137Swdenk } 491*9d25438fSBartlomiej Sieka 492*9d25438fSBartlomiej Sieka static void 493*9d25438fSBartlomiej Sieka image_verify_header (char *ptr, int image_size) 494*9d25438fSBartlomiej Sieka { 495*9d25438fSBartlomiej Sieka int len; 496*9d25438fSBartlomiej Sieka char *data; 497*9d25438fSBartlomiej Sieka uint32_t checksum; 498*9d25438fSBartlomiej Sieka image_header_t header; 499*9d25438fSBartlomiej Sieka image_header_t *hdr = &header; 500*9d25438fSBartlomiej Sieka 501*9d25438fSBartlomiej Sieka /* 502*9d25438fSBartlomiej Sieka * create copy of header so that we can blank out the 503*9d25438fSBartlomiej Sieka * checksum field for checking - this can't be done 504*9d25438fSBartlomiej Sieka * on the PROT_READ mapped data. 505*9d25438fSBartlomiej Sieka */ 506*9d25438fSBartlomiej Sieka memcpy (hdr, ptr, sizeof(image_header_t)); 507*9d25438fSBartlomiej Sieka 508*9d25438fSBartlomiej Sieka if (ntohl(hdr->ih_magic) != IH_MAGIC) { 509*9d25438fSBartlomiej Sieka fprintf (stderr, 510*9d25438fSBartlomiej Sieka "%s: Bad Magic Number: \"%s\" is no valid image\n", 511*9d25438fSBartlomiej Sieka cmdname, imagefile); 512*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 513*9d25438fSBartlomiej Sieka } 514*9d25438fSBartlomiej Sieka 515*9d25438fSBartlomiej Sieka data = (char *)hdr; 516*9d25438fSBartlomiej Sieka len = sizeof(image_header_t); 517*9d25438fSBartlomiej Sieka 518*9d25438fSBartlomiej Sieka checksum = ntohl(hdr->ih_hcrc); 519*9d25438fSBartlomiej Sieka hdr->ih_hcrc = htonl(0); /* clear for re-calculation */ 520*9d25438fSBartlomiej Sieka 521*9d25438fSBartlomiej Sieka if (crc32 (0, data, len) != checksum) { 522*9d25438fSBartlomiej Sieka fprintf (stderr, 523*9d25438fSBartlomiej Sieka "%s: ERROR: \"%s\" has bad header checksum!\n", 524*9d25438fSBartlomiej Sieka cmdname, imagefile); 525*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 526*9d25438fSBartlomiej Sieka } 527*9d25438fSBartlomiej Sieka 528*9d25438fSBartlomiej Sieka data = ptr + sizeof(image_header_t); 529*9d25438fSBartlomiej Sieka len = image_size - sizeof(image_header_t) ; 530*9d25438fSBartlomiej Sieka 531*9d25438fSBartlomiej Sieka if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) { 532*9d25438fSBartlomiej Sieka fprintf (stderr, 533*9d25438fSBartlomiej Sieka "%s: ERROR: \"%s\" has corrupted data!\n", 534*9d25438fSBartlomiej Sieka cmdname, imagefile); 535*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 536*9d25438fSBartlomiej Sieka } 537*9d25438fSBartlomiej Sieka } 538*9d25438fSBartlomiej Sieka 539*9d25438fSBartlomiej Sieka /** 540*9d25438fSBartlomiej Sieka * fit_handle_file - main FIT file processing function 541*9d25438fSBartlomiej Sieka * 542*9d25438fSBartlomiej Sieka * fit_handle_file() runs dtc to convert .its to .itb, includes 543*9d25438fSBartlomiej Sieka * binary data, updates timestamp property and calculates hashes. 544*9d25438fSBartlomiej Sieka * 545*9d25438fSBartlomiej Sieka * datafile - .its file 546*9d25438fSBartlomiej Sieka * imagefile - .itb file 547*9d25438fSBartlomiej Sieka * 548*9d25438fSBartlomiej Sieka * returns: 549*9d25438fSBartlomiej Sieka * only on success, otherwise calls exit (EXIT_FAILURE); 550*9d25438fSBartlomiej Sieka */ 551*9d25438fSBartlomiej Sieka static void fit_handle_file (void) 552*9d25438fSBartlomiej Sieka { 553*9d25438fSBartlomiej Sieka char tmpfile[MKIMAGE_MAX_TMPFILE_LEN]; 554*9d25438fSBartlomiej Sieka char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; 555*9d25438fSBartlomiej Sieka int tfd; 556*9d25438fSBartlomiej Sieka struct stat sbuf; 557*9d25438fSBartlomiej Sieka unsigned char *ptr; 558*9d25438fSBartlomiej Sieka 559*9d25438fSBartlomiej Sieka /* call dtc to include binary properties into the tmp file */ 560*9d25438fSBartlomiej Sieka if (strlen (imagefile) + strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > 561*9d25438fSBartlomiej Sieka sizeof (tmpfile)) { 562*9d25438fSBartlomiej Sieka fprintf (stderr, "%s: Image file name (%s) too long, " 563*9d25438fSBartlomiej Sieka "can't create tmpfile", 564*9d25438fSBartlomiej Sieka imagefile, cmdname); 565*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 566*9d25438fSBartlomiej Sieka } 567*9d25438fSBartlomiej Sieka sprintf (tmpfile, "%s%s", imagefile, MKIMAGE_TMPFILE_SUFFIX); 568*9d25438fSBartlomiej Sieka 569*9d25438fSBartlomiej Sieka /* dtc -I dts -O -p 200 datafile > tmpfile */ 570*9d25438fSBartlomiej Sieka sprintf (cmd, "%s %s %s > %s", 571*9d25438fSBartlomiej Sieka MKIMAGE_DTC, opt_dtc, datafile, tmpfile); 572*9d25438fSBartlomiej Sieka debug ("Trying to execute \"%s\"\n", cmd); 573*9d25438fSBartlomiej Sieka if (system (cmd) == -1) { 574*9d25438fSBartlomiej Sieka fprintf (stderr, "%s: system(%s) failed: %s\n", 575*9d25438fSBartlomiej Sieka cmdname, cmd, strerror(errno)); 576*9d25438fSBartlomiej Sieka unlink (tmpfile); 577*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 578*9d25438fSBartlomiej Sieka } 579*9d25438fSBartlomiej Sieka 580*9d25438fSBartlomiej Sieka /* load FIT blob into memory */ 581*9d25438fSBartlomiej Sieka tfd = open (tmpfile, O_RDWR|O_BINARY); 582*9d25438fSBartlomiej Sieka 583*9d25438fSBartlomiej Sieka if (tfd < 0) { 584*9d25438fSBartlomiej Sieka fprintf (stderr, "%s: Can't open %s: %s\n", 585*9d25438fSBartlomiej Sieka cmdname, tmpfile, strerror(errno)); 586*9d25438fSBartlomiej Sieka unlink (tmpfile); 587*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 588*9d25438fSBartlomiej Sieka } 589*9d25438fSBartlomiej Sieka 590*9d25438fSBartlomiej Sieka if (fstat (tfd, &sbuf) < 0) { 591*9d25438fSBartlomiej Sieka fprintf (stderr, "%s: Can't stat %s: %s\n", 592*9d25438fSBartlomiej Sieka cmdname, tmpfile, strerror(errno)); 593*9d25438fSBartlomiej Sieka unlink (tmpfile); 594*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 595*9d25438fSBartlomiej Sieka } 596*9d25438fSBartlomiej Sieka 597*9d25438fSBartlomiej Sieka ptr = (unsigned char *)mmap (0, sbuf.st_size, 598*9d25438fSBartlomiej Sieka PROT_READ|PROT_WRITE, MAP_SHARED, tfd, 0); 599*9d25438fSBartlomiej Sieka if ((caddr_t)ptr == (caddr_t)-1) { 600*9d25438fSBartlomiej Sieka fprintf (stderr, "%s: Can't read %s: %s\n", 601*9d25438fSBartlomiej Sieka cmdname, tmpfile, strerror(errno)); 602*9d25438fSBartlomiej Sieka unlink (tmpfile); 603*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 604*9d25438fSBartlomiej Sieka } 605*9d25438fSBartlomiej Sieka 606*9d25438fSBartlomiej Sieka /* check if ptr has a valid blob */ 607*9d25438fSBartlomiej Sieka if (fdt_check_header (ptr)) { 608*9d25438fSBartlomiej Sieka fprintf (stderr, "%s: Invalid FIT blob\n", cmdname); 609*9d25438fSBartlomiej Sieka unlink (tmpfile); 610*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 611*9d25438fSBartlomiej Sieka } 612*9d25438fSBartlomiej Sieka 613*9d25438fSBartlomiej Sieka /* set hashes for images in the blob */ 614*9d25438fSBartlomiej Sieka if (fit_set_hashes (ptr)) { 615*9d25438fSBartlomiej Sieka fprintf (stderr, "%s Can't add hashes to FIT blob", cmdname); 616*9d25438fSBartlomiej Sieka unlink (tmpfile); 617*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 618*9d25438fSBartlomiej Sieka } 619*9d25438fSBartlomiej Sieka 620*9d25438fSBartlomiej Sieka /* add a timestamp at offset 0 i.e., root */ 621*9d25438fSBartlomiej Sieka if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) { 622*9d25438fSBartlomiej Sieka fprintf (stderr, "%s: Can't add image timestamp\n", cmdname); 623*9d25438fSBartlomiej Sieka unlink (tmpfile); 624*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 625*9d25438fSBartlomiej Sieka } 626*9d25438fSBartlomiej Sieka debug ("Added timestamp successfully\n"); 627*9d25438fSBartlomiej Sieka 628*9d25438fSBartlomiej Sieka munmap ((void *)ptr, sbuf.st_size); 629*9d25438fSBartlomiej Sieka close (tfd); 630*9d25438fSBartlomiej Sieka 631*9d25438fSBartlomiej Sieka if (rename (tmpfile, imagefile) == -1) { 632*9d25438fSBartlomiej Sieka fprintf (stderr, "%s: Can't rename %s to %s: %s\n", 633*9d25438fSBartlomiej Sieka cmdname, tmpfile, imagefile, strerror (errno)); 634*9d25438fSBartlomiej Sieka unlink (tmpfile); 635*9d25438fSBartlomiej Sieka unlink (imagefile); 636*9d25438fSBartlomiej Sieka exit (EXIT_FAILURE); 637*9d25438fSBartlomiej Sieka } 638*9d25438fSBartlomiej Sieka } 639