|
@@ -1,4 +1,6 @@
|
|
/*
|
|
/*
|
|
|
|
+ * (C) Copyright 2008 Semihalf
|
|
|
|
+ *
|
|
* (C) Copyright 2000-2004
|
|
* (C) Copyright 2000-2004
|
|
* DENX Software Engineering
|
|
* DENX Software Engineering
|
|
* Wolfgang Denk, wd@denx.de
|
|
* 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);
|
|
extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len);
|
|
static void copy_file (int, const char *, int);
|
|
static void copy_file (int, const char *, int);
|
|
static void usage (void);
|
|
static void usage (void);
|
|
|
|
+static void image_verify_header (char *, int);
|
|
|
|
+static void fit_handle_file (void);
|
|
|
|
|
|
char *datafile;
|
|
char *datafile;
|
|
char *imagefile;
|
|
char *imagefile;
|
|
@@ -39,6 +43,7 @@ char *cmdname;
|
|
|
|
|
|
int dflag = 0;
|
|
int dflag = 0;
|
|
int eflag = 0;
|
|
int eflag = 0;
|
|
|
|
+int fflag = 0;
|
|
int lflag = 0;
|
|
int lflag = 0;
|
|
int vflag = 0;
|
|
int vflag = 0;
|
|
int xflag = 0;
|
|
int xflag = 0;
|
|
@@ -46,6 +51,7 @@ int opt_os = IH_OS_LINUX;
|
|
int opt_arch = IH_ARCH_PPC;
|
|
int opt_arch = IH_ARCH_PPC;
|
|
int opt_type = IH_TYPE_KERNEL;
|
|
int opt_type = IH_TYPE_KERNEL;
|
|
int opt_comp = IH_COMP_GZIP;
|
|
int opt_comp = IH_COMP_GZIP;
|
|
|
|
+char *opt_dtc = MKIMAGE_DEFAULT_DTC_OPTIONS;
|
|
|
|
|
|
image_header_t header;
|
|
image_header_t header;
|
|
image_header_t *hdr = &header;
|
|
image_header_t *hdr = &header;
|
|
@@ -53,7 +59,7 @@ image_header_t *hdr = &header;
|
|
int
|
|
int
|
|
main (int argc, char **argv)
|
|
main (int argc, char **argv)
|
|
{
|
|
{
|
|
- int ifd;
|
|
|
|
|
|
+ int ifd = -1;
|
|
uint32_t checksum;
|
|
uint32_t checksum;
|
|
uint32_t addr;
|
|
uint32_t addr;
|
|
uint32_t ep;
|
|
uint32_t ep;
|
|
@@ -81,6 +87,12 @@ main (int argc, char **argv)
|
|
(opt_comp = genimg_get_comp_id (*++argv)) < 0)
|
|
(opt_comp = genimg_get_comp_id (*++argv)) < 0)
|
|
usage ();
|
|
usage ();
|
|
goto NXTARG;
|
|
goto NXTARG;
|
|
|
|
+ case 'D':
|
|
|
|
+ if (--argc <= 0)
|
|
|
|
+ usage ();
|
|
|
|
+ opt_dtc = *++argv;
|
|
|
|
+ goto NXTARG;
|
|
|
|
+
|
|
case 'O':
|
|
case 'O':
|
|
if ((--argc <= 0) ||
|
|
if ((--argc <= 0) ||
|
|
(opt_os = genimg_get_os_id (*++argv)) < 0)
|
|
(opt_os = genimg_get_os_id (*++argv)) < 0)
|
|
@@ -121,6 +133,12 @@ main (int argc, char **argv)
|
|
}
|
|
}
|
|
eflag = 1;
|
|
eflag = 1;
|
|
goto NXTARG;
|
|
goto NXTARG;
|
|
|
|
+ case 'f':
|
|
|
|
+ if (--argc <= 0)
|
|
|
|
+ usage ();
|
|
|
|
+ datafile = *++argv;
|
|
|
|
+ fflag = 1;
|
|
|
|
+ goto NXTARG;
|
|
case 'n':
|
|
case 'n':
|
|
if (--argc <= 0)
|
|
if (--argc <= 0)
|
|
usage ();
|
|
usage ();
|
|
@@ -139,7 +157,10 @@ main (int argc, char **argv)
|
|
NXTARG: ;
|
|
NXTARG: ;
|
|
}
|
|
}
|
|
|
|
|
|
- if ((argc != 1) || ((lflag ^ dflag) == 0))
|
|
|
|
|
|
+ if ((argc != 1) ||
|
|
|
|
+ (dflag && (fflag || lflag)) ||
|
|
|
|
+ (fflag && (dflag || lflag)) ||
|
|
|
|
+ (lflag && (dflag || fflag)))
|
|
usage();
|
|
usage();
|
|
|
|
|
|
if (!eflag) {
|
|
if (!eflag) {
|
|
@@ -165,21 +186,22 @@ NXTARG: ;
|
|
|
|
|
|
imagefile = *argv;
|
|
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) {
|
|
if (lflag) {
|
|
- int len;
|
|
|
|
- char *data;
|
|
|
|
/*
|
|
/*
|
|
* list header information of existing image
|
|
* list header information of existing image
|
|
*/
|
|
*/
|
|
@@ -204,43 +226,23 @@ NXTARG: ;
|
|
exit (EXIT_FAILURE);
|
|
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) munmap((void *)ptr, sbuf.st_size);
|
|
(void) close (ifd);
|
|
(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);
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -467,11 +469,11 @@ void
|
|
usage ()
|
|
usage ()
|
|
{
|
|
{
|
|
fprintf (stderr, "Usage: %s -l image\n"
|
|
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"
|
|
" -O ==> set operating system to 'os'\n"
|
|
" -T ==> set image type to 'type'\n"
|
|
" -T ==> set image type to 'type'\n"
|
|
" -C ==> set compression type 'comp'\n"
|
|
" -C ==> set compression type 'comp'\n"
|
|
@@ -479,7 +481,158 @@ usage ()
|
|
" -e ==> set entry point to 'ep' (hex)\n"
|
|
" -e ==> set entry point to 'ep' (hex)\n"
|
|
" -n ==> set image name to 'name'\n"
|
|
" -n ==> set image name to 'name'\n"
|
|
" -d ==> use image data from 'datafile'\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);
|
|
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);
|
|
|
|
+ }
|
|
|
|
+}
|