diff options
| -rw-r--r-- | common/image.c | 1265 | ||||
| -rw-r--r-- | include/image.h | 153 | ||||
| -rw-r--r-- | tools/mkimage.h | 8 | 
3 files changed, 1420 insertions, 6 deletions
| diff --git a/common/image.c b/common/image.c index 3911b2f75..9278ea92b 100644 --- a/common/image.c +++ b/common/image.c @@ -45,10 +45,13 @@  #include <rtc.h>  #endif +#include <image.h> +  #if defined(CONFIG_FIT)  #include <fdt.h>  #include <libfdt.h>  #include <fdt_support.h> +#include <sha1.h>  #endif  #ifdef CONFIG_CMD_BDI @@ -62,9 +65,9 @@ static image_header_t* image_get_ramdisk (cmd_tbl_t *cmdtp, int flag,  		ulong rd_addr, uint8_t arch, int verify);  #else  #include "mkimage.h" -#endif /* !USE_HOSTCC*/ - +#include <time.h>  #include <image.h> +#endif /* !USE_HOSTCC*/  typedef struct table_entry {  	int	id;		/* as defined in image.h	*/ @@ -306,6 +309,18 @@ static void image_print_type (image_header_t *hdr)  	printf ("%s %s %s (%s)\n", arch, os, type, comp);  } +/** + * __image_print_contents - prints out the contents of the legacy format image + * @hdr: pointer to the legacy format image header + * @p: pointer to prefix string + * + * __image_print_contents() formats a multi line legacy image contents description. + * The routine prints out all header fields followed by the size/offset data + * for MULTI/SCRIPT images. + * + * returns: + *     no returned results + */  static void __image_print_contents (image_header_t *hdr, const char *p)  {  	printf ("%sImage Name:   %.*s\n", p, IH_NMLEN, image_get_name (hdr)); @@ -701,7 +716,7 @@ ulong genimg_get_image (ulong img_addr)  			break;  #if defined(CONFIG_FIT)  		case IMAGE_FORMAT_FIT: -			d_size = fdt_totalsize((void *)ram_addr) - h_size; +			d_size = fit_get_size ((const void *)ram_addr) - h_size;  			debug ("   FIT/FDT format image found at 0x%08lx, size 0x%08lx\n",  					ram_addr, d_size);  			break; @@ -1040,11 +1055,13 @@ int boot_get_kbd (struct lmb *lmb, bd_t **kbd, ulong bootmap_base)  	return 0;  }  #endif /* CONFIG_PPC || CONFIG_M68K */ +#endif /* !USE_HOSTCC */  #if defined(CONFIG_FIT)  /*****************************************************************************/  /* New uImage format routines */  /*****************************************************************************/ +#ifndef USE_HOSTCC  static int fit_parse_spec (const char *spec, char sepc, ulong addr_curr,  		ulong *addr, const char **name)  { @@ -1117,6 +1134,1246 @@ inline int fit_parse_subimage (const char *spec, ulong addr_curr,  {  	return fit_parse_spec (spec, ':', addr_curr, addr, image_name);  } +#endif /* !USE_HOSTCC */ + +static void fit_get_debug (const void *fit, int noffset, +		char *prop_name, int err) +{ +	debug ("Can't get '%s' property from FIT 0x%08lx, " +		"node: offset %d, name %s (%s)\n", +		prop_name, (ulong)fit, noffset, +		fit_get_name (fit, noffset, NULL), +		fdt_strerror (err)); +} + +/** + * __fit_print_contents - prints out the contents of the FIT format image + * @fit: pointer to the FIT format image header + * @p: pointer to prefix string + * + * __fit_print_contents() formats a multi line FIT image contents description. + * The routine prints out FIT image properties (root node level) follwed by + * the details of each component image. + * + * returns: + *     no returned results + */ +static void __fit_print_contents (const void *fit, const char *p) +{ +	char *desc; +	char *uname; +	int images_noffset; +	int confs_noffset; +	int noffset; +	int ndepth; +	int count = 0; +	int ret; +#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC) +	time_t timestamp; +#endif + +	/* Root node properties */ +	ret = fit_get_desc (fit, 0, &desc); +	printf ("%sFIT description: ", p); +	if (ret) +		printf ("unavailable\n"); +	else +		printf ("%s\n", desc); + +#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC) +	ret = fit_get_timestamp (fit, 0, ×tamp); +	printf ("%sCreated:         ", p); +	if (ret) +		printf ("unavailable\n"); +	else +		genimg_print_time (timestamp); +#endif + +	/* Find images parent node offset */ +	images_noffset = fdt_path_offset (fit, FIT_IMAGES_PATH); +	if (images_noffset < 0) { +		printf ("Can't find images parent node '%s' (%s)\n", +			FIT_IMAGES_PATH, fdt_strerror (images_noffset)); +		return; +	} + +	/* Process its subnodes, print out component images details */ +	for (ndepth = 0, count = 0, noffset = fdt_next_node (fit, images_noffset, &ndepth); +	     (noffset >= 0) && (ndepth > 0); +	     noffset = fdt_next_node (fit, noffset, &ndepth)) { +		if (ndepth == 1) { +			/* +			 * Direct child node of the images parent node, +			 * i.e. component image node. +			 */ +			printf ("%s Image %u (%s)\n", p, count++, +					fit_get_name(fit, noffset, NULL)); + +			fit_image_print (fit, noffset, p); +		} +	} + +	/* Find configurations parent node offset */ +	confs_noffset = fdt_path_offset (fit, FIT_CONFS_PATH); +	if (confs_noffset < 0) { +		debug ("Can't get configurations parent node '%s' (%s)\n", +			FIT_CONFS_PATH, fdt_strerror (confs_noffset)); +		return; +	} + +	/* get default configuration unit name from default property */ +	uname = (char *)fdt_getprop (fit, noffset, FIT_DEFAULT_PROP, NULL); +	if (uname) +		printf ("%s Default Configuration: '%s'\n", p, uname); + +	/* Process its subnodes, print out configurations details */ +	for (ndepth = 0, count = 0, noffset = fdt_next_node (fit, confs_noffset, &ndepth); +	     (noffset >= 0) && (ndepth > 0); +	     noffset = fdt_next_node (fit, noffset, &ndepth)) { +		if (ndepth == 1) { +			/* +			 * Direct child node of the configurations parent node, +			 * i.e. configuration node. +			 */ +			printf ("%s Configuration %u (%s)\n", p, count++, +					fit_get_name(fit, noffset, NULL)); + +			fit_conf_print (fit, noffset, p); +		} +	} +} + +inline void fit_print_contents (const void *fit) +{ +	__fit_print_contents (fit, "   "); +} + +inline void fit_print_contents_noindent (const void *fit) +{ +	__fit_print_contents (fit, ""); +} + +/** + * fit_image_print - prints out the FIT component image details + * @fit: pointer to the FIT format image header + * @image_noffset: offset of the component image node + * @p: pointer to prefix string + * + * fit_image_print() lists all mandatory properies for the processed component + * image. If present, hash nodes are printed out as well. + * + * returns: + *     no returned results + */ +void fit_image_print (const void *fit, int image_noffset, const char *p) +{ +	char *desc; +	uint8_t type, arch, os, comp; +	size_t size; +	ulong load, entry; +	const void *data; +	int noffset; +	int ndepth; +	int ret; + +	/* Mandatory properties */ +	ret = fit_get_desc (fit, image_noffset, &desc); +	printf ("%s  Description:  ", p); +	if (ret) +		printf ("unavailable\n"); +	else +		printf ("%s\n", desc); + +	fit_image_get_type (fit, image_noffset, &type); +	printf ("%s  Type:         %s\n", p, genimg_get_type_name (type)); + +	fit_image_get_comp (fit, image_noffset, &comp); +	printf ("%s  Compression:  %s\n", p, genimg_get_comp_name (comp)); + +	ret = fit_image_get_data (fit, image_noffset, &data, &size); + +#ifndef USE_HOSTCC +	printf ("%s  Data Start:   ", p); +	if (ret) +		printf ("unavailable\n"); +	else +		printf ("0x%08lx\n", (ulong)data); +#endif + +	printf ("%s  Data Size:    ", p); +	if (ret) +		printf ("unavailable\n"); +	else +		genimg_print_size (size); + +	/* Remaining, type dependent properties */ +	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) || +	    (type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE) || +	    (type == IH_TYPE_FLATDT)) { +		fit_image_get_arch (fit, image_noffset, &arch); +		printf ("%s  Architecture: %s\n", p, genimg_get_arch_name (arch)); +	} + +	if (type == IH_TYPE_KERNEL) { +		fit_image_get_os (fit, image_noffset, &os); +		printf ("%s  OS:           %s\n", p, genimg_get_os_name (os)); +	} + +	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE)) { +		ret = fit_image_get_load (fit, image_noffset, &load); +		printf ("%s  Load Address: ", p); +		if (ret) +			printf ("unavailable\n"); +		else +			printf ("0x%08lx\n", load); + +		fit_image_get_entry (fit, image_noffset, &entry); +		printf ("%s  Entry Point:  ", p); +		if (ret) +			printf ("unavailable\n"); +		else +			printf ("0x%08lx\n", entry); +	} + +	/* Process all hash subnodes of the component image node */ +	for (ndepth = 0, noffset = fdt_next_node (fit, image_noffset, &ndepth); +	     (noffset >= 0) && (ndepth > 0); +	     noffset = fdt_next_node (fit, noffset, &ndepth)) { +		if (ndepth == 1) { +			/* Direct child node of the component image node */ +			fit_image_print_hash (fit, noffset, p); +		} +	} +} + +/** + * fit_image_print_hash - prints out the hash node details + * @fit: pointer to the FIT format image header + * @noffset: offset of the hash node + * @p: pointer to prefix string + * + * fit_image_print_hash() lists properies for the processed hash node + * + * returns: + *     no returned results + */ +void fit_image_print_hash (const void *fit, int noffset, const char *p) +{ +	char *algo; +	uint8_t *value; +	int value_len; +	int i, ret; + +	/* +	 * Check subnode name, must be equal to "hash". +	 * Multiple hash nodes require unique unit node +	 * names, e.g. hash@1, hash@2, etc. +	 */ +	if (strncmp (fit_get_name(fit, noffset, NULL), +			FIT_HASH_NODENAME, +			strlen(FIT_HASH_NODENAME)) != 0) +		return; + +	debug ("%s  Hash node:    '%s'\n", p, +			fit_get_name (fit, noffset, NULL)); + +	printf ("%s  Hash algo:    ", p); +	if (fit_image_hash_get_algo (fit, noffset, &algo)) { +		printf ("invalid/unsupported\n"); +		return; +	} +	printf ("%s\n", algo); + +	ret = fit_image_hash_get_value (fit, noffset, &value, +					&value_len); +	printf ("%s  Hash value:   ", p); +	if (ret) { +		printf ("unavailable\n"); +	} else { +		for (i = 0; i < value_len; i++) +			printf ("%02x", value[i]); +		printf ("\n"); +	} + +	debug  ("%s  Hash len:     %d\n", p, value_len); +} + +/** + * fit_get_desc - get node description property + * @fit: pointer to the FIT format image header + * @noffset: node offset + * @desc: double pointer to the char, will hold pointer to the descrption + * + * fit_get_desc() reads description property from a given node, if + * description is found pointer to it is returened in third call argument. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_get_desc (const void *fit, int noffset, char **desc) +{ +	int len; + +	*desc = (char *)fdt_getprop (fit, noffset, FIT_DESC_PROP, &len); +	if (*desc == NULL) { +		fit_get_debug (fit, noffset, FIT_DESC_PROP, len); +		return -1; +	} + +	return 0; +} + +/** + * fit_get_timestamp - get node timestamp property + * @fit: pointer to the FIT format image header + * @noffset: node offset + * @timestamp: pointer to the time_t, will hold read timestamp + * + * fit_get_timestamp() reads timestamp poperty from given node, if timestamp + * is found and has a correct size its value is retured in third call + * argument. + * + * returns: + *     0, on success + *     -1, on property read failure + *     -2, on wrong timestamp size + */ +int fit_get_timestamp (const void *fit, int noffset, time_t *timestamp) +{ +	int len; +	const void *data; + +	data = fdt_getprop (fit, noffset, FIT_TIMESTAMP_PROP, &len); +	if (data == NULL) { +		fit_get_debug (fit, noffset, FIT_TIMESTAMP_PROP, len); +		return -1; +	} +	if (len != sizeof (uint32_t)) { +		debug ("FIT timestamp with incorrect size of (%u)\n", len); +		return -2; +	} + +	*timestamp = uimage_to_cpu (*((uint32_t *)data)); +	return 0; +} + +/** + * fit_image_get_node - get node offset for component image of a given unit name + * @fit: pointer to the FIT format image header + * @image_uname: component image node unit name + * + * fit_image_get_node() finds a component image (withing the '/images' + * node) of a provided unit name. If image is found its node offset is + * returned to the caller. + * + * returns: + *     image node offset when found (>=0) + *     negative number on failure (FDT_ERR_* code) + */ +int fit_image_get_node (const void *fit, const char *image_uname) +{ +	int noffset, images_noffset; + +	images_noffset = fdt_path_offset (fit, FIT_IMAGES_PATH); +	if (images_noffset < 0) { +		debug ("Can't find images parent node '%s' (%s)\n", +			FIT_IMAGES_PATH, fdt_strerror (images_noffset)); +		return images_noffset; +	} + +	noffset = fdt_subnode_offset (fit, images_noffset, image_uname); +	if (noffset < 0) { +		debug ("Can't get node offset for image unit name: '%s' (%s)\n", +			image_uname, fdt_strerror (noffset)); +	} + +	return noffset; +} + +/** + * fit_image_get_os - get os id for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @os: pointer to the uint8_t, will hold os numeric id + * + * fit_image_get_os() finds os property in a given component image node. + * If the property is found, its (string) value is translated to the numeric + * id which is returned to the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_get_os (const void *fit, int noffset, uint8_t *os) +{ +	int len; +	const void *data; + +	/* Get OS name from property data */ +	data = fdt_getprop (fit, noffset, FIT_OS_PROP, &len); +	if (data == NULL) { +		fit_get_debug (fit, noffset, FIT_OS_PROP, len); +		*os = -1; +		return -1; +	} + +	/* Translate OS name to id */ +	*os = genimg_get_os_id (data); +	return 0; +} + +/** + * fit_image_get_arch - get arch id for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @arch: pointer to the uint8_t, will hold arch numeric id + * + * fit_image_get_arch() finds arch property in a given component image node. + * If the property is found, its (string) value is translated to the numeric + * id which is returned to the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_get_arch (const void *fit, int noffset, uint8_t *arch) +{ +	int len; +	const void *data; + +	/* Get architecture name from property data */ +	data = fdt_getprop (fit, noffset, FIT_ARCH_PROP, &len); +	if (data == NULL) { +		fit_get_debug (fit, noffset, FIT_ARCH_PROP, len); +		*arch = -1; +		return -1; +	} + +	/* Translate architecture name to id */ +	*arch = genimg_get_arch_id (data); +	return 0; +} + +/** + * fit_image_get_type - get type id for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @type: pointer to the uint8_t, will hold type numeric id + * + * fit_image_get_type() finds type property in a given component image node. + * If the property is found, its (string) value is translated to the numeric + * id which is returned to the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_get_type (const void *fit, int noffset, uint8_t *type) +{ +	int len; +	const void *data; + +	/* Get image type name from property data */ +	data = fdt_getprop (fit, noffset, FIT_TYPE_PROP, &len); +	if (data == NULL) { +		fit_get_debug (fit, noffset, FIT_TYPE_PROP, len); +		*type = -1; +		return -1; +	} + +	/* Translate image type name to id */ +	*type = genimg_get_type_id (data); +	return 0; +} + +/** + * fit_image_get_comp - get comp id for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @comp: pointer to the uint8_t, will hold comp numeric id + * + * fit_image_get_comp() finds comp property in a given component image node. + * If the property is found, its (string) value is translated to the numeric + * id which is returned to the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_get_comp (const void *fit, int noffset, uint8_t *comp) +{ +	int len; +	const void *data; + +	/* Get compression name from property data */ +	data = fdt_getprop (fit, noffset, FIT_COMP_PROP, &len); +	if (data == NULL) { +		fit_get_debug (fit, noffset, FIT_COMP_PROP, len); +		*comp = -1; +		return -1; +	} + +	/* Translate compression name to id */ +	*comp = genimg_get_comp_id (data); +	return 0; +} + +/** + * fit_image_get_load - get load address property for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @load: pointer to the uint32_t, will hold load address + * + * fit_image_get_load() finds load address property in a given component image node. + * If the property is found, its value is returned to the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_get_load (const void *fit, int noffset, ulong *load) +{ +	int len; +	const uint32_t *data; + +	data = fdt_getprop (fit, noffset, FIT_LOAD_PROP, &len); +	if (data == NULL) { +		fit_get_debug (fit, noffset, FIT_LOAD_PROP, len); +		return -1; +	} + +	*load = uimage_to_cpu (*data); +	return 0; +} + +/** + * fit_image_get_entry - get entry point address property for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @entry: pointer to the uint32_t, will hold entry point address + * + * fit_image_get_entry() finds entry point address property in a given component image node. + * If the property is found, its value is returned to the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_get_entry (const void *fit, int noffset, ulong *entry) +{ +	int len; +	const uint32_t *data; + +	data = fdt_getprop (fit, noffset, FIT_ENTRY_PROP, &len); +	if (data == NULL) { +		fit_get_debug (fit, noffset, FIT_ENTRY_PROP, len); +		return -1; +	} + +	*entry = uimage_to_cpu (*data); +	return 0; +} + +/** + * fit_image_get_data - get data property and its size for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @data: double pointer to void, will hold data property's data address + * @size: pointer to size_t, will hold data property's data size + * + * fit_image_get_data() finds data property in a given component image node. + * If the property is found its data start address and size are returned to + * the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_get_data (const void *fit, int noffset, +		const void **data, size_t *size) +{ +	int len; + +	*data = fdt_getprop (fit, noffset, FIT_DATA_PROP, &len); +	if (*data == NULL) { +		fit_get_debug (fit, noffset, FIT_DATA_PROP, len); +		*size = 0; +		return -1; +	} + +	*size = len; +	return 0; +} + +/** + * fit_image_hash_get_algo - get hash algorithm name + * @fit: pointer to the FIT format image header + * @noffset: hash node offset + * @algo: double pointer to char, will hold pointer to the algorithm name + * + * fit_image_hash_get_algo() finds hash algorithm property in a given hash node. + * If the property is found its data start address is returned to the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_hash_get_algo (const void *fit, int noffset, char **algo) +{ +	int len; + +	*algo = (char *)fdt_getprop (fit, noffset, FIT_ALGO_PROP, &len); +	if (*algo == NULL) { +		fit_get_debug (fit, noffset, FIT_ALGO_PROP, len); +		return -1; +	} + +	return 0; +} + +/** + * fit_image_hash_get_value - get hash value and length + * @fit: pointer to the FIT format image header + * @noffset: hash node offset + * @value: double pointer to uint8_t, will hold address of a hash value data + * @value_len: pointer to an int, will hold hash data length + * + * fit_image_hash_get_value() finds hash value property in a given hash node. + * If the property is found its data start address and size are returned to + * the caller. + * + * returns: + *     0, on success + *     -1, on failure + */ +int fit_image_hash_get_value (const void *fit, int noffset, uint8_t **value, +				int *value_len) +{ +	int len; + +	*value = (uint8_t *)fdt_getprop (fit, noffset, FIT_VALUE_PROP, &len); +	if (*value == NULL) { +		fit_get_debug (fit, noffset, FIT_VALUE_PROP, len); +		*value_len = 0; +		return -1; +	} + +	*value_len = len; +	return 0; +} + +/** + * fit_set_timestamp - set node timestamp property + * @fit: pointer to the FIT format image header + * @noffset: node offset + * @timestamp: timestamp value to be set + * + * fit_set_timestamp() attempts to set timestamp property in the requested + * node and returns operation status to the caller. + * + * returns: + *     0, on success + *     -1, on property read failure + */ +int fit_set_timestamp (void *fit, int noffset, time_t timestamp) +{ +	uint32_t t; +	int ret; + +	t = cpu_to_uimage (timestamp); +	ret = fdt_setprop (fit, noffset, FIT_TIMESTAMP_PROP, &t, +				sizeof (uint32_t)); +	if (ret) { +		printf ("Can't set '%s' property for '%s' node (%s)\n", +			FIT_TIMESTAMP_PROP, fit_get_name (fit, noffset, NULL), +			fdt_strerror (ret)); +		return -1; +	} + +	return 0; +} + +/** + * calculate_hash - calculate and return hash for provided input data + * @data: pointer to the input data + * @data_len: data length + * @algo: requested hash algorithm + * @value: pointer to the char, will hold hash value data (caller must + * allocate enough free space) + * value_len: length of the calculated hash + * + * calculate_hash() computes input data hash according to the requested algorithm. + * Resulting hash value is placed in caller provided 'value' buffer, length + * of the calculated hash is returned via value_len pointer argument. + * + * returns: + *     0, on success + *    -1, when algo is unsupported + */ +static int calculate_hash (const void *data, int data_len, const char *algo, +			uint8_t *value, int *value_len) +{ +	if (strcmp (algo, "crc32") == 0 ) { +		*((uint32_t *)value) = crc32 (0, data, data_len); +		*((uint32_t *)value) = cpu_to_uimage (*((uint32_t *)value)); +		*value_len = 4; +	} else if (strcmp (algo, "sha1") == 0 ) { +		sha1_csum ((unsigned char *) data, data_len, +				(unsigned char *) value); +		*value_len = 20; +	} else if (strcmp (algo, "md5") == 0 ) { +		printf ("MD5 not supported\n"); +		*value_len = 0; +	} else { +		debug ("Unsupported hash alogrithm\n"); +		return -1; +	} +	return 0; +} + +#ifdef USE_HOSTCC +/** + * fit_set_hashes - process FIT component image nodes and calculate hashes + * @fit: pointer to the FIT format image header + * + * fit_set_hashes() adds hash values for all component images in the FIT blob. + * Hashes are calculated for all component images which have hash subnodes + * with algorithm property set to one of the supported hash algorithms. + * + * returns + *     0, on success + *     libfdt error code, on failure + */ +int fit_set_hashes (void *fit) +{ +	int images_noffset; +	int noffset; +	int ndepth; +	int ret; + +	/* Find images parent node offset */ +	images_noffset = fdt_path_offset (fit, FIT_IMAGES_PATH); +	if (images_noffset < 0) { +		printf ("Can't find images parent node '%s' (%s)\n", +			FIT_IMAGES_PATH, fdt_strerror (images_noffset)); +		return images_noffset; +	} + +	/* Process its subnodes, print out component images details */ +	for (ndepth = 0, noffset = fdt_next_node (fit, images_noffset, &ndepth); +	     (noffset >= 0) && (ndepth > 0); +	     noffset = fdt_next_node (fit, noffset, &ndepth)) { +		if (ndepth == 1) { +			/* +			 * Direct child node of the images parent node, +			 * i.e. component image node. +			 */ +			ret = fit_image_set_hashes (fit, noffset); +			if (ret) +				return ret; +		} +	} + +	return 0; +} +/** + * fit_image_set_hashes - calculate/set hashes for given component image node + * @fit: pointer to the FIT format image header + * @image_noffset: requested component image node + * + * fit_image_set_hashes() adds hash values for an component image node. All + * existing hash subnodes are checked, if algorithm property is set to one of + * the supported hash algorithms, hash value is computed and corresponding + * hash node property is set, for example: + * + * Input component image node structure: + * + * o image@1 (at image_noffset) + *   | - data = [binary data] + *   o hash@1 + *     |- algo = "sha1" + * + * Output component image node structure: + * + * o image@1 (at image_noffset) + *   | - data = [binary data] + *   o hash@1 + *     |- algo = "sha1" + *     |- value = sha1(data) + * + * returns: + *     0 on sucess + *    <0 on failure + */ +int fit_image_set_hashes (void *fit, int image_noffset) +{ +	const void *data; +	size_t size; +	char *algo; +	uint8_t value[FIT_MAX_HASH_LEN]; +	int value_len; +	int noffset; +	int ndepth; + +	/* Get image data and data length */ +	if (fit_image_get_data (fit, image_noffset, &data, &size)) { +		printf ("Can't get image data/size\n"); +		return -1; +	} + +	/* Process all hash subnodes of the component image node */ +	for (ndepth = 0, noffset = fdt_next_node (fit, image_noffset, &ndepth); +	     (noffset >= 0) && (ndepth > 0); +	     noffset = fdt_next_node (fit, noffset, &ndepth)) { +		if (ndepth == 1) { +			/* Direct child node of the component image node */ + +			/* +			 * Check subnode name, must be equal to "hash". +			 * Multiple hash nodes require unique unit node +			 * names, e.g. hash@1, hash@2, etc. +			 */ +			if (strncmp (fit_get_name(fit, noffset, NULL), +						FIT_HASH_NODENAME, +						strlen(FIT_HASH_NODENAME)) != 0) { +				/* Not a hash subnode, skip it */ +				continue; +			} + +			if (fit_image_hash_get_algo (fit, noffset, &algo)) { +				printf ("Can't get hash algo property for " +					"'%s' hash node in '%s' image node\n", +					fit_get_name (fit, noffset, NULL), +					fit_get_name (fit, image_noffset, NULL)); +				return -1; +			} + +			if (calculate_hash (data, size, algo, value, &value_len)) { +				printf ("Unsupported hash algorithm (%s) for " +					"'%s' hash node in '%s' image node\n", +					algo, fit_get_name (fit, noffset, NULL), +					fit_get_name (fit, image_noffset, NULL)); +				return -1; +			} + +			if (fit_image_hash_set_value (fit, noffset, value, +							value_len)) { +				printf ("Can't set hash value for " +					"'%s' hash node in '%s' image node\n", +					fit_get_name (fit, noffset, NULL), +					fit_get_name (fit, image_noffset, NULL)); +				return -1; +			} +		} +	} + +	return 0; +} + +/** + * fit_image_hash_set_value - set hash value in requested has node + * @fit: pointer to the FIT format image header + * @noffset: hash node offset + * @value: hash value to be set + * @value_len: hash value length + * + * fit_image_hash_set_value() attempts to set hash value in a node at offset + * given and returns operation status to the caller. + * + * returns + *     0, on success + *     -1, on failure + */ +int fit_image_hash_set_value (void *fit, int noffset, uint8_t *value, +				int value_len) +{ +	int ret; + +	ret = fdt_setprop (fit, noffset, FIT_VALUE_PROP, value, value_len); +	if (ret) { +		printf ("Can't set hash '%s' property for '%s' node (%s)\n", +			FIT_VALUE_PROP, fit_get_name (fit, noffset, NULL), +			fdt_strerror (ret)); +		return -1; +	} + +	return 0; +} +#endif /* USE_HOSTCC */ + +/** + * fit_image_check_hashes - verify data intergity + * @fit: pointer to the FIT format image header + * @image_noffset: component image node offset + * + * fit_image_check_hashes() goes over component image hash nodes, + * re-calculates each data hash and compares with the value stored in hash + * node. + * + * returns: + *     1, if all hashes are valid + *     0, otherwise (or on error) + */ +int fit_image_check_hashes (const void *fit, int image_noffset) +{ +	const void	*data; +	size_t		size; +	char		*algo; +	uint8_t		*fit_value; +	int		fit_value_len; +	uint8_t		value[FIT_MAX_HASH_LEN]; +	int		value_len; +	int		noffset; +	int		ndepth; +	char		*err_msg = ""; + +	/* Get image data and data length */ +	if (fit_image_get_data (fit, image_noffset, &data, &size)) { +		printf ("Can't get image data/size\n"); +		return 0; +	} + +	/* Process all hash subnodes of the component image node */ +	for (ndepth = 0, noffset = fdt_next_node (fit, image_noffset, &ndepth); +	     (noffset >= 0) && (ndepth > 0); +	     noffset = fdt_next_node (fit, noffset, &ndepth)) { +		if (ndepth == 1) { +			/* Direct child node of the component image node */ + +			/* +			 * Check subnode name, must be equal to "hash". +			 * Multiple hash nodes require unique unit node +			 * names, e.g. hash@1, hash@2, etc. +			 */ +			if (strncmp (fit_get_name(fit, noffset, NULL), +					FIT_HASH_NODENAME, +					strlen(FIT_HASH_NODENAME)) != 0) +				continue; + +			if (fit_image_hash_get_algo (fit, noffset, &algo)) { +				err_msg = "Can't get hash algo property"; +				goto error; +			} +			printf ("%s", algo); + +			if (fit_image_hash_get_value (fit, noffset, &fit_value, +							&fit_value_len)) { +				err_msg = "Can't get hash value property"; +				goto error; +			} + +			if (calculate_hash (data, size, algo, value, &value_len)) { +				err_msg = "Unsupported hash algorithm"; +				goto error; +			} + +			if (value_len != fit_value_len) { +				err_msg = "Bad hash value len"; +				goto error; +			} else if (memcmp (value, fit_value, value_len) != 0) { +				err_msg = "Bad hash value"; +				goto error; +			} +			printf ("+ "); +		} +	} + +	return 1; + +error: +	printf ("%s for '%s' hash node in '%s' image node\n", +			err_msg, fit_get_name (fit, noffset, NULL), +			fit_get_name (fit, image_noffset, NULL)); +	return 0; +} + +/** + * fit_image_check_os - check whether image node is of a given os type + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @os: requested image os + * + * fit_image_check_os() reads image os property and compares its numeric + * id with the requested os. Comparison result is returned to the caller. + * + * returns: + *     1 if image is of given os type + *     0 otherwise (or on error) + */ +int fit_image_check_os (const void *fit, int noffset, uint8_t os) +{ +	uint8_t image_os; + +	if (fit_image_get_os (fit, noffset, &image_os)) +		return 0; +	return (os == image_os); +} + +/** + * fit_image_check_arch - check whether image node is of a given arch + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @arch: requested imagearch + * + * fit_image_check_arch() reads image arch property and compares its numeric + * id with the requested arch. Comparison result is returned to the caller. + * + * returns: + *     1 if image is of given arch + *     0 otherwise (or on error) + */ +int fit_image_check_arch (const void *fit, int noffset, uint8_t arch) +{ +	uint8_t image_arch; + +	if (fit_image_get_arch (fit, noffset, &image_arch)) +		return 0; +	return (arch == image_arch); +} + +/** + * fit_image_check_type - check whether image node is of a given type + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @type: requested image type + * + * fit_image_check_type() reads image type property and compares its numeric + * id with the requested type. Comparison result is returned to the caller. + * + * returns: + *     1 if image is of given type + *     0 otherwise (or on error) + */ +int fit_image_check_type (const void *fit, int noffset, uint8_t type) +{ +	uint8_t image_type; + +	if (fit_image_get_type (fit, noffset, &image_type)) +		return 0; +	return (type == image_type); +} + +/** + * fit_image_check_comp - check whether image node uses given compression + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @comp: requested image compression type + * + * fit_image_check_comp() reads image compression property and compares its + * numeric id with the requested compression type. Comparison result is + * returned to the caller. + * + * returns: + *     1 if image uses requested compression + *     0 otherwise (or on error) + */ +int fit_image_check_comp (const void *fit, int noffset, uint8_t comp) +{ +	uint8_t image_comp; + +	if (fit_image_get_comp (fit, noffset, &image_comp)) +		return 0; +	return (comp == image_comp); +} + +/** + * fit_check_format - sanity check FIT image format + * @fit: pointer to the FIT format image header + * + * fit_check_format() runs a basic sanity FIT image verification. + * Routine checks for mandatory properties, nodes, etc. + * + * returns: + *     1, on success + *     0, on failure + */ +int fit_check_format (const void *fit) +{ +	/* mandatory / node 'description' property */ +	if (fdt_getprop (fit, 0, FIT_DESC_PROP, NULL) == NULL) { +		debug ("Wrong FIT format: no description\n"); +		return 0; +	} + +#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC) +	/* mandatory / node 'timestamp' property */ +	if (fdt_getprop (fit, 0, FIT_TIMESTAMP_PROP, NULL) == NULL) { +		debug ("Wrong FIT format: no description\n"); +		return 0; +	} +#endif + +	/* mandatory subimages parent '/images' node */ +	if (fdt_path_offset (fit, FIT_IMAGES_PATH) < 0) { +		debug ("Wrong FIT format: no images parent node\n"); +		return 0; +	} + +	return 1; +} + +/** + * fit_conf_get_node - get node offset for configuration of a given unit name + * @fit: pointer to the FIT format image header + * @conf_uname: configuration node unit name + * + * fit_conf_get_node() finds a configuration (withing the '/configurations' + * parant node) of a provided unit name. If configuration is found its node offset + * is returned to the caller. + * + * When NULL is provided in second argument fit_conf_get_node() will search + * for a default configuration node instead. Default configuration node unit name + * is retrived from FIT_DEFAULT_PROP property of the '/configurations' node. + * + * returns: + *     configuration node offset when found (>=0) + *     negative number on failure (FDT_ERR_* code) + */ +int fit_conf_get_node (const void *fit, const char *conf_uname) +{ +	int noffset, confs_noffset; +	int len; + +	confs_noffset = fdt_path_offset (fit, FIT_CONFS_PATH); +	if (confs_noffset < 0) { +		debug ("Can't find configurations parent node '%s' (%s)\n", +			FIT_CONFS_PATH, fdt_strerror (confs_noffset)); +		return confs_noffset; +	} + +	if (conf_uname == NULL) { +		/* get configuration unit name from the default property */ +		debug ("No configuration specified, trying default...\n"); +		conf_uname = (char *)fdt_getprop (fit, confs_noffset, FIT_DEFAULT_PROP, &len); +		if (conf_uname == NULL) { +			fit_get_debug (fit, confs_noffset, FIT_DEFAULT_PROP, len); +			return len; +		} +		debug ("Found default configuration: '%s'\n", conf_uname); +	} + +	noffset = fdt_subnode_offset (fit, confs_noffset, conf_uname); +	if (noffset < 0) { +		debug ("Can't get node offset for configuration unit name: '%s' (%s)\n", +			conf_uname, fdt_strerror (noffset)); +	} + +	return noffset; +} + +static int __fit_conf_get_prop_node (const void *fit, int noffset, +		const char *prop_name) +{ +	char *uname; +	int len; + +	/* get kernel image unit name from configuration kernel property */ +	uname = (char *)fdt_getprop (fit, noffset, prop_name, &len); +	if (uname == NULL) +		return len; + +	return fit_image_get_node (fit, uname); +} + +/** + * fit_conf_get_kernel_node - get kernel image node offset that corresponds to + * a given configuration + * @fit: pointer to the FIT format image header + * @noffset: configuration node offset + * + * fit_conf_get_kernel_node() retrives kernel image node unit name from + * configuration FIT_KERNEL_PROP property and translates it to the node + * offset. + * + * returns: + *     image node offset when found (>=0) + *     negative number on failure (FDT_ERR_* code) + */ +int fit_conf_get_kernel_node (const void *fit, int noffset) +{ +	return __fit_conf_get_prop_node (fit, noffset, FIT_KERNEL_PROP); +} + +/** + * fit_conf_get_ramdisk_node - get ramdisk image node offset that corresponds to + * a given configuration + * @fit: pointer to the FIT format image header + * @noffset: configuration node offset + * + * fit_conf_get_ramdisk_node() retrives ramdisk image node unit name from + * configuration FIT_KERNEL_PROP property and translates it to the node + * offset. + * + * returns: + *     image node offset when found (>=0) + *     negative number on failure (FDT_ERR_* code) + */ +int fit_conf_get_ramdisk_node (const void *fit, int noffset) +{ +	return __fit_conf_get_prop_node (fit, noffset, FIT_RAMDISK_PROP); +} + +/** + * fit_conf_get_fdt_node - get fdt image node offset that corresponds to + * a given configuration + * @fit: pointer to the FIT format image header + * @noffset: configuration node offset + * + * fit_conf_get_fdt_node() retrives fdt image node unit name from + * configuration FIT_KERNEL_PROP property and translates it to the node + * offset. + * + * returns: + *     image node offset when found (>=0) + *     negative number on failure (FDT_ERR_* code) + */ +int fit_conf_get_fdt_node (const void *fit, int noffset) +{ +	return __fit_conf_get_prop_node (fit, noffset, FIT_FDT_PROP); +} + +/** + * fit_conf_print - prints out the FIT configuration details + * @fit: pointer to the FIT format image header + * @conf_noffset: offset of the configuration node + * @p: pointer to prefix string + * + * fit_conf_print() lists all mandatory properies for the processed + * configuration node. + * + * returns: + *     no returned results + */ +void fit_conf_print (const void *fit, int noffset, const char *p) +{ +	char *desc; +	char *uname; +	int ret; + +	/* Mandatory properties */ +	ret = fit_get_desc (fit, noffset, &desc); +	printf ("%s  Description:  ", p); +	if (ret) +		printf ("unavailable\n"); +	else +		printf ("%s\n", desc); + +	uname = (char *)fdt_getprop (fit, noffset, FIT_KERNEL_PROP, NULL); +	printf ("%s  Kernel:       ", p); +	if (uname == NULL) +		printf ("unavailable\n"); +	else +		printf ("%s\n", uname); + +	/* Optional properties */ +	uname = (char *)fdt_getprop (fit, noffset, FIT_RAMDISK_PROP, NULL); +	if (uname) +		printf ("%s  Init Ramdisk: %s\n", p, uname); + +	uname = (char *)fdt_getprop (fit, noffset, FIT_FDT_PROP, NULL); +	if (uname) +		printf ("%s  FDT:          %s\n", p, uname); +}  #endif /* CONFIG_FIT */ -#endif /* !USE_HOSTCC */ diff --git a/include/image.h b/include/image.h index ed795521d..704a3b442 100644 --- a/include/image.h +++ b/include/image.h @@ -40,6 +40,7 @@  #include <lmb.h>  #include <linux/string.h>  #include <asm/u-boot.h> +#endif /* USE_HOSTCC */  /* new uImage format support enabled by default */  #define CONFIG_FIT		1 @@ -51,7 +52,12 @@  #if defined(CONFIG_FIT) && !defined(CONFIG_OF_LIBFDT)  #error "CONFIG_OF_LIBFDT not enabled, required by CONFIG_FIT!"  #endif -#endif /* USE_HOSTCC */ + +#if defined(CONFIG_FIT) +#include <fdt.h> +#include <libfdt.h> +#include <fdt_support.h> +#endif  /*   * Operating System Codes @@ -412,16 +418,160 @@ static inline int image_check_target_arch (image_header_t *hdr)  	return 1;  } +#endif /* USE_HOSTCC */  /*******************************************************************/  /* New uImage format specific code (prefixed with fit_) */  /*******************************************************************/  #if defined(CONFIG_FIT) + +#define FIT_IMAGES_PATH		"/images" +#define FIT_CONFS_PATH		"/configurations" + +/* hash node */ +#define FIT_HASH_NODENAME	"hash" +#define FIT_ALGO_PROP		"algo" +#define FIT_VALUE_PROP		"value" + +/* image node */ +#define FIT_DATA_PROP		"data" +#define FIT_TIMESTAMP_PROP	"timestamp" +#define FIT_DESC_PROP		"description" +#define FIT_ARCH_PROP		"arch" +#define FIT_TYPE_PROP		"type" +#define FIT_OS_PROP		"os" +#define FIT_COMP_PROP		"compression" +#define FIT_ENTRY_PROP		"entry" +#define FIT_LOAD_PROP		"load" + +/* configuration node */ +#define FIT_KERNEL_PROP		"kernel" +#define FIT_RAMDISK_PROP	"ramdisk" +#define FIT_FDT_PROP		"fdt" +#define FIT_DEFAULT_PROP	"default" + +#define FIT_MAX_HASH_LEN	20	/* max(crc32_len(4), sha1_len(20)) */ + +/* cmdline argument format parsing */  inline int fit_parse_conf (const char *spec, ulong addr_curr,  		ulong *addr, const char **conf_name);  inline int fit_parse_subimage (const char *spec, ulong addr_curr,  		ulong *addr, const char **image_name); +inline void fit_print_contents (const void *fit); +inline void fit_print_contents_noindent (const void *fit); +void fit_image_print (const void *fit, int noffset, const char *p); +void fit_image_print_hash (const void *fit, int noffset, const char *p); + +/** + * fit_get_end - get FIT image size + * @fit: pointer to the FIT format image header + * + * returns: + *     size of the FIT image (blob) in memory + */ +static inline ulong fit_get_size (const void *fit) +{ +	return fdt_totalsize (fit); +} + +/** + * fit_get_end - get FIT image end + * @fit: pointer to the FIT format image header + * + * returns: + *     end address of the FIT image (blob) in memory + */ +static inline ulong fit_get_end (const void *fit) +{ +	return (ulong)fit + fdt_totalsize (fit); +} + +/** + * fit_get_name - get FIT node name + * @fit: pointer to the FIT format image header + * + * returns: + *     NULL, on error + *     pointer to node name, on success + */ +static inline const char *fit_get_name (const void *fit_hdr, +		int noffset, int *len) +{ +	return fdt_get_name (fit_hdr, noffset, len); +} + +int fit_get_desc (const void *fit, int noffset, char **desc); +int fit_get_timestamp (const void *fit, int noffset, time_t *timestamp); + +int fit_image_get_node (const void *fit, const char *image_uname); +int fit_image_get_os (const void *fit, int noffset, uint8_t *os); +int fit_image_get_arch (const void *fit, int noffset, uint8_t *arch); +int fit_image_get_type (const void *fit, int noffset, uint8_t *type); +int fit_image_get_comp (const void *fit, int noffset, uint8_t *comp); +int fit_image_get_load (const void *fit, int noffset, ulong *load); +int fit_image_get_entry (const void *fit, int noffset, ulong *entry); +int fit_image_get_data (const void *fit, int noffset, +				const void **data, size_t *size); + +int fit_image_hash_get_algo (const void *fit, int noffset, char **algo); +int fit_image_hash_get_value (const void *fit, int noffset, uint8_t **value, +				int *value_len); + +int fit_set_timestamp (void *fit, int noffset, time_t timestamp); +int fit_set_hashes (void *fit); +int fit_image_set_hashes (void *fit, int image_noffset); +int fit_image_hash_set_value (void *fit, int noffset, uint8_t *value, +				int value_len); + +int fit_image_check_hashes (const void *fit, int noffset); +int fit_image_check_os (const void *fit, int noffset, uint8_t os); +int fit_image_check_arch (const void *fit, int noffset, uint8_t arch); +int fit_image_check_type (const void *fit, int noffset, uint8_t type); +int fit_image_check_comp (const void *fit, int noffset, uint8_t comp); +int fit_check_format (const void *fit); + +int fit_conf_get_node (const void *fit, const char *conf_uname); +int fit_conf_get_kernel_node (const void *fit, int noffset); +int fit_conf_get_ramdisk_node (const void *fit, int noffset); +int fit_conf_get_fdt_node (const void *fit, int noffset); + +void fit_conf_print (const void *fit, int noffset, const char *p); + +#ifndef USE_HOSTCC +static inline int fit_image_check_target_arch (const void *fdt, int node) +{ +#if defined(__ARM__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_ARM)) +#elif defined(__avr32__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_AVR32)) +#elif defined(__bfin__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_BLACKFIN)) +#elif defined(__I386__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_I386)) +#elif defined(__M68K__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_M68K)) +#elif defined(__microblaze__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_MICROBLAZE)) +#elif defined(__mips__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_MIPS)) +#elif defined(__nios__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_NIOS)) +#elif defined(__nios2__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_NIOS2)) +#elif defined(__PPC__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_PPC)) +#elif defined(__sh__) +	if (!fit_image_check_arch (fdt, node, IH_ARCH_SH)) +#else +# error Unknown CPU type +#endif +		return 0; + +	return 1; +} +#endif /* USE_HOSTCC */ +  #ifdef CONFIG_FIT_VERBOSE  #define fit_unsupported(msg)	printf ("! %s:%d " \  				"FIT images not supported for '%s'\n", \ @@ -436,6 +586,5 @@ inline int fit_parse_subimage (const char *spec, ulong addr_curr,  #define fit_unsupported_reset(msg)  #endif /* CONFIG_FIT_VERBOSE */  #endif /* CONFIG_FIT */ -#endif /* USE_HOSTCC */  #endif	/* __IMAGE_H__ */ diff --git a/tools/mkimage.h b/tools/mkimage.h index cdd52bc9c..41cd156fa 100644 --- a/tools/mkimage.h +++ b/tools/mkimage.h @@ -35,6 +35,14 @@  #include <sha1.h>  #include "fdt_host.h" +#define MKIMAGE_DEBUG + +#ifdef MKIMAGE_DEBUG +#define debug(fmt,args...)	printf (fmt ,##args) +#else +#define debug(fmt,args...) +#endif /* MKIMAGE_DEBUG */ +  #if defined(__BEOS__) || defined(__NetBSD__) || defined(__APPLE__)  #include <inttypes.h>  #endif |