From 9d25438fe7d70cf35a8a293ea5e392fefc672613 Mon Sep 17 00:00:00 2001 From: Bartlomiej Sieka Date: Tue, 11 Mar 2008 12:34:47 +0100 Subject: [PATCH] [new uImage] Add support for new uImage format to mkimage tool Support for the new uImage format (FIT) is added to mkimage tool. Commandline syntax is appropriately extended: mkimage [-D dtc_options] -f fit-image.its fit-image mkimage (together with dtc) takes fit-image.its and referenced therein binaries (like vmlinux.bin.gz) as inputs, and produces fit-image file -- the final image that can be transferred to the target (e.g., via tftp) and then booted using the bootm command in U-Boot. Signed-off-by: Bartlomiej Sieka --- include/image.h | 15 +++- tools/mkimage.c | 257 ++++++++++++++++++++++++++++++++++++++++++++------------ tools/mkimage.h | 6 ++ 3 files changed, 222 insertions(+), 56 deletions(-) diff --git a/include/image.h b/include/image.h index bbd481d..681c753 100644 --- a/include/image.h +++ b/include/image.h @@ -40,14 +40,21 @@ #include #include #include -#endif /* USE_HOSTCC */ -/* new uImage format support enabled by default */ +/* new uImage format support enabled on target + * To be moved to board configuration file */ #define CONFIG_FIT 1 #define CONFIG_OF_LIBFDT 1 +#define CONFIG_FIT_VERBOSE 1 /* enable fit_format_{error,warning}() */ + +#else -/* enable fit_format_error(), fit_format_warning() */ -#define CONFIG_FIT_VERBOSE 1 +/* new uImage format support enabled on host */ +#define CONFIG_FIT 1 +#define CONFIG_OF_LIBFDT 1 +#define CONFIG_FIT_VERBOSE 1 /* enable fit_format_{error,warning}() */ + +#endif /* USE_HOSTCC */ #if defined(CONFIG_FIT) && !defined(CONFIG_OF_LIBFDT) #error "CONFIG_OF_LIBFDT not enabled, required by CONFIG_FIT!" diff --git a/tools/mkimage.c b/tools/mkimage.c index 5cb2bc7..6e1ff2b 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -1,4 +1,6 @@ /* + * (C) Copyright 2008 Semihalf + * * (C) Copyright 2000-2004 * DENX Software Engineering * Wolfgang Denk, wd@denx.de @@ -32,6 +34,8 @@ extern int errno; extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len); static void copy_file (int, const char *, int); static void usage (void); +static void image_verify_header (char *, int); +static void fit_handle_file (void); char *datafile; char *imagefile; @@ -39,6 +43,7 @@ char *cmdname; int dflag = 0; int eflag = 0; +int fflag = 0; int lflag = 0; int vflag = 0; int xflag = 0; @@ -46,6 +51,7 @@ int opt_os = IH_OS_LINUX; int opt_arch = IH_ARCH_PPC; int opt_type = IH_TYPE_KERNEL; int opt_comp = IH_COMP_GZIP; +char *opt_dtc = MKIMAGE_DEFAULT_DTC_OPTIONS; image_header_t header; image_header_t *hdr = &header; @@ -53,7 +59,7 @@ image_header_t *hdr = &header; int main (int argc, char **argv) { - int ifd; + int ifd = -1; uint32_t checksum; uint32_t addr; uint32_t ep; @@ -81,6 +87,12 @@ main (int argc, char **argv) (opt_comp = genimg_get_comp_id (*++argv)) < 0) usage (); goto NXTARG; + case 'D': + if (--argc <= 0) + usage (); + opt_dtc = *++argv; + goto NXTARG; + case 'O': if ((--argc <= 0) || (opt_os = genimg_get_os_id (*++argv)) < 0) @@ -121,6 +133,12 @@ main (int argc, char **argv) } eflag = 1; goto NXTARG; + case 'f': + if (--argc <= 0) + usage (); + datafile = *++argv; + fflag = 1; + goto NXTARG; case 'n': if (--argc <= 0) usage (); @@ -139,7 +157,10 @@ main (int argc, char **argv) NXTARG: ; } - if ((argc != 1) || ((lflag ^ dflag) == 0)) + if ((argc != 1) || + (dflag && (fflag || lflag)) || + (fflag && (dflag || lflag)) || + (lflag && (dflag || fflag))) usage(); if (!eflag) { @@ -165,21 +186,22 @@ NXTARG: ; imagefile = *argv; - if (lflag) { - ifd = open(imagefile, O_RDONLY|O_BINARY); - } else { - ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); - } + if (!fflag){ + if (lflag) { + ifd = open (imagefile, O_RDONLY|O_BINARY); + } else { + ifd = open (imagefile, + O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); + } - if (ifd < 0) { - fprintf (stderr, "%s: Can't open %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); + if (ifd < 0) { + fprintf (stderr, "%s: Can't open %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } } if (lflag) { - int len; - char *data; /* * list header information of existing image */ @@ -204,44 +226,24 @@ NXTARG: ; exit (EXIT_FAILURE); } - /* - * image_check_hcrc() creates copy of header so that - * we can blank out the checksum field for checking - - * this can't be done on the PROT_READ mapped data. - */ - hdr = (image_header_t *)ptr; - - if (!image_check_magic (hdr)) { - fprintf (stderr, - "%s: Bad Magic Number: \"%s\" is no valid image\n", - cmdname, imagefile); - exit (EXIT_FAILURE); - } - - if (!image_check_hcrc (hdr)) { - fprintf (stderr, - "%s: ERROR: \"%s\" has bad header checksum!\n", - cmdname, imagefile); - exit (EXIT_FAILURE); + if (fdt_check_header (ptr)) { + /* old-style image */ + image_verify_header ((char *)ptr, sbuf.st_size); + image_print_contents_noindent ((image_header_t *)ptr); + } else { + /* FIT image */ + fit_print_contents_noindent (ptr); } - data = (char *)image_get_data (hdr); - len = sbuf.st_size - image_get_header_size (); - - if (crc32(0, data, len) != image_get_dcrc (hdr)) { - fprintf (stderr, - "%s: ERROR: \"%s\" has corrupted data!\n", - cmdname, imagefile); - exit (EXIT_FAILURE); - } - - /* for multi-file images we need the data part, too */ - image_print_contents_noindent ((image_header_t *)ptr); - (void) munmap((void *)ptr, sbuf.st_size); (void) close (ifd); exit (EXIT_SUCCESS); + } else if (fflag) { + /* Flattened Image Tree (FIT) format handling */ + debug ("FIT format handling\n"); + fit_handle_file (); + exit (EXIT_SUCCESS); } /* @@ -467,11 +469,11 @@ void usage () { fprintf (stderr, "Usage: %s -l image\n" - " -l ==> list image header information\n" - " %s [-x] -A arch -O os -T type -C comp " - "-a addr -e ep -n name -d data_file[:data_file...] image\n", - cmdname, cmdname); - fprintf (stderr, " -A ==> set architecture to 'arch'\n" + " -l ==> list image header information\n", + cmdname); + fprintf (stderr, " %s [-x] -A arch -O os -T type -C comp " + "-a addr -e ep -n name -d data_file[:data_file...] image\n" + " -A ==> set architecture to 'arch'\n" " -O ==> set operating system to 'os'\n" " -T ==> set image type to 'type'\n" " -C ==> set compression type 'comp'\n" @@ -479,7 +481,158 @@ usage () " -e ==> set entry point to 'ep' (hex)\n" " -n ==> set image name to 'name'\n" " -d ==> use image data from 'datafile'\n" - " -x ==> set XIP (execute in place)\n" - ); + " -x ==> set XIP (execute in place)\n", + cmdname); + fprintf (stderr, " %s [-D dtc_options] -f fit-image.its fit-image\n", + cmdname); + exit (EXIT_FAILURE); } + +static void +image_verify_header (char *ptr, int image_size) +{ + int len; + char *data; + uint32_t checksum; + image_header_t header; + image_header_t *hdr = &header; + + /* + * create copy of header so that we can blank out the + * checksum field for checking - this can't be done + * on the PROT_READ mapped data. + */ + memcpy (hdr, ptr, sizeof(image_header_t)); + + if (ntohl(hdr->ih_magic) != IH_MAGIC) { + fprintf (stderr, + "%s: Bad Magic Number: \"%s\" is no valid image\n", + cmdname, imagefile); + exit (EXIT_FAILURE); + } + + data = (char *)hdr; + len = sizeof(image_header_t); + + checksum = ntohl(hdr->ih_hcrc); + hdr->ih_hcrc = htonl(0); /* clear for re-calculation */ + + if (crc32 (0, data, len) != checksum) { + fprintf (stderr, + "%s: ERROR: \"%s\" has bad header checksum!\n", + cmdname, imagefile); + exit (EXIT_FAILURE); + } + + data = ptr + sizeof(image_header_t); + len = image_size - sizeof(image_header_t) ; + + if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) { + fprintf (stderr, + "%s: ERROR: \"%s\" has corrupted data!\n", + cmdname, imagefile); + exit (EXIT_FAILURE); + } +} + +/** + * fit_handle_file - main FIT file processing function + * + * fit_handle_file() runs dtc to convert .its to .itb, includes + * binary data, updates timestamp property and calculates hashes. + * + * datafile - .its file + * imagefile - .itb file + * + * returns: + * only on success, otherwise calls exit (EXIT_FAILURE); + */ +static void fit_handle_file (void) +{ + char tmpfile[MKIMAGE_MAX_TMPFILE_LEN]; + char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; + int tfd; + struct stat sbuf; + unsigned char *ptr; + + /* call dtc to include binary properties into the tmp file */ + if (strlen (imagefile) + strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > + sizeof (tmpfile)) { + fprintf (stderr, "%s: Image file name (%s) too long, " + "can't create tmpfile", + imagefile, cmdname); + exit (EXIT_FAILURE); + } + sprintf (tmpfile, "%s%s", imagefile, MKIMAGE_TMPFILE_SUFFIX); + + /* dtc -I dts -O -p 200 datafile > tmpfile */ + sprintf (cmd, "%s %s %s > %s", + MKIMAGE_DTC, opt_dtc, datafile, tmpfile); + debug ("Trying to execute \"%s\"\n", cmd); + if (system (cmd) == -1) { + fprintf (stderr, "%s: system(%s) failed: %s\n", + cmdname, cmd, strerror(errno)); + unlink (tmpfile); + exit (EXIT_FAILURE); + } + + /* load FIT blob into memory */ + tfd = open (tmpfile, O_RDWR|O_BINARY); + + if (tfd < 0) { + fprintf (stderr, "%s: Can't open %s: %s\n", + cmdname, tmpfile, strerror(errno)); + unlink (tmpfile); + exit (EXIT_FAILURE); + } + + if (fstat (tfd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + cmdname, tmpfile, strerror(errno)); + unlink (tmpfile); + exit (EXIT_FAILURE); + } + + ptr = (unsigned char *)mmap (0, sbuf.st_size, + PROT_READ|PROT_WRITE, MAP_SHARED, tfd, 0); + if ((caddr_t)ptr == (caddr_t)-1) { + fprintf (stderr, "%s: Can't read %s: %s\n", + cmdname, tmpfile, strerror(errno)); + unlink (tmpfile); + exit (EXIT_FAILURE); + } + + /* check if ptr has a valid blob */ + if (fdt_check_header (ptr)) { + fprintf (stderr, "%s: Invalid FIT blob\n", cmdname); + unlink (tmpfile); + exit (EXIT_FAILURE); + } + + /* set hashes for images in the blob */ + if (fit_set_hashes (ptr)) { + fprintf (stderr, "%s Can't add hashes to FIT blob", cmdname); + unlink (tmpfile); + exit (EXIT_FAILURE); + } + + /* add a timestamp at offset 0 i.e., root */ + if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) { + fprintf (stderr, "%s: Can't add image timestamp\n", cmdname); + unlink (tmpfile); + exit (EXIT_FAILURE); + } + debug ("Added timestamp successfully\n"); + + munmap ((void *)ptr, sbuf.st_size); + close (tfd); + + if (rename (tmpfile, imagefile) == -1) { + fprintf (stderr, "%s: Can't rename %s to %s: %s\n", + cmdname, tmpfile, imagefile, strerror (errno)); + unlink (tmpfile); + unlink (imagefile); + exit (EXIT_FAILURE); + } +} diff --git a/tools/mkimage.h b/tools/mkimage.h index 41cd156..a2d5248 100644 --- a/tools/mkimage.h +++ b/tools/mkimage.h @@ -43,6 +43,12 @@ #define debug(fmt,args...) #endif /* MKIMAGE_DEBUG */ +#define MKIMAGE_TMPFILE_SUFFIX ".tmp" +#define MKIMAGE_MAX_TMPFILE_LEN 256 +#define MKIMAGE_DEFAULT_DTC_OPTIONS "-I dts -O dtb -p 500" +#define MKIMAGE_MAX_DTC_CMDLINE_LEN 512 +#define MKIMAGE_DTC "dtc" /* assume dtc is in $PATH */ + #if defined(__BEOS__) || defined(__NetBSD__) || defined(__APPLE__) #include #endif -- 2.7.4