[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 <tur@semihalf.com>
This commit is contained in:
Bartlomiej Sieka 2008-03-11 12:34:47 +01:00 committed by Marian Balakowicz
parent eb6175edd6
commit 9d25438fe7
3 changed files with 222 additions and 56 deletions

View File

@ -40,14 +40,21 @@
#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}() */
/* enable fit_format_error(), fit_format_warning() */
#define CONFIG_FIT_VERBOSE 1
#else
/* 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!"

View 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,43 +226,23 @@ 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 (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);
}
if (!image_check_hcrc (hdr)) {
fprintf (stderr,
"%s: ERROR: \"%s\" has bad header checksum!\n",
cmdname, imagefile);
exit (EXIT_FAILURE);
}
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);
}
}

View File

@ -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 <inttypes.h>
#endif