[new uImage] Add support for new uImage format to mkimage tool
authorBartlomiej Sieka <tur@semihalf.com>
Tue, 11 Mar 2008 11:34:47 +0000 (12:34 +0100)
committerMarian Balakowicz <m8@semihalf.com>
Tue, 11 Mar 2008 11:34:47 +0000 (12:34 +0100)
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 <tur@semihalf.com>
include/image.h
tools/mkimage.c
tools/mkimage.h

index bbd481d..681c753 100644 (file)
 #include <lmb.h>
 #include <linux/string.h>
 #include <asm/u-boot.h>
-#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!"
index 5cb2bc7..6e1ff2b 100644 (file)
@@ -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);
+       }
+}
index 41cd156..a2d5248 100644 (file)
 #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 <inttypes.h>
 #endif