diff mbox

[U-Boot,3/4] dumpimage: fit: extract FIT images

Message ID 1421297683-6989-3-git-send-email-guilherme.maciel.ferreira@gmail.com
State Accepted
Delegated to: Tom Rini
Headers show

Commit Message

Guilherme Maciel Ferreira Jan. 15, 2015, 4:54 a.m. UTC
The dumpimage is able to extract components contained in a FIT image:

  $ ./dumpimage -T flat_dt -i CONTAINER.ITB -p INDEX FILE

The CONTAINER.ITB is a regular FIT container file. The INDEX is the poisition
of the sub-image to be retrieved, and FILE is the file (path+name) to save the
extracted sub-image.

For example, given the following kernel.its to build a kernel.itb:

  /dts-v1/;
  / {
      ...
      images {
        kernel@1 {
          description = "Kernel 2.6.32-34";
          data = /incbin/("/boot/vmlinuz-2.6.32-34-generic");
          type = "kernel";
          arch = "ppc";
          os = "linux";
          compression = "gzip";
          load = <00000000>;
          entry = <00000000>;
          hash@1 {
            algo = "md5";
          };
        };
        ...
      };
      ...
    };

The dumpimage can extract the 'kernel@1' node through the following command:

  $ ./dumpimage -T flat_dt -i kernel.itb -p 0 kernel
  Extracted:
   Image 0 (kernel@1)
    Description:  Kernel 2.6.32-34
    Created:      Wed Oct 22 15:50:26 2014
    Type:         Kernel Image
    Compression:  gzip compressed
    Data Size:    4040128 Bytes = 3945.44 kB = 3.85 MB
    Architecture: PowerPC
    OS:           Linux
    Load Address: 0x00000000
    Entry Point:  0x00000000
    Hash algo:    md5
    Hash value:   22352ad39bdc03e2e50f9cc28c1c3652

Which results in the file 'kernel' being exactly the same as '/boot/vmlinuz-2.6.32-34-generic'.

Signed-off-by: Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
---
 common/image-fit.c            |   30 +++++++++++++-
 include/image.h               |    1 +
 test/image/test-imagetools.sh |   83 ++++++++++++++++++++++++++++++++++++-
 tools/fit_image.c             |   93 ++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 204 insertions(+), 3 deletions(-)

Comments

Tom Rini Feb. 2, 2015, 6:58 p.m. UTC | #1
On Thu, Jan 15, 2015 at 02:54:42AM -0200, Guilherme Maciel Ferreira wrote:

> The dumpimage is able to extract components contained in a FIT image:
> 
>   $ ./dumpimage -T flat_dt -i CONTAINER.ITB -p INDEX FILE
> 
> The CONTAINER.ITB is a regular FIT container file. The INDEX is the poisition
> of the sub-image to be retrieved, and FILE is the file (path+name) to save the
> extracted sub-image.
> 
> For example, given the following kernel.its to build a kernel.itb:
> 
>   /dts-v1/;
>   / {
>       ...
>       images {
>         kernel@1 {
>           description = "Kernel 2.6.32-34";
>           data = /incbin/("/boot/vmlinuz-2.6.32-34-generic");
>           type = "kernel";
>           arch = "ppc";
>           os = "linux";
>           compression = "gzip";
>           load = <00000000>;
>           entry = <00000000>;
>           hash@1 {
>             algo = "md5";
>           };
>         };
>         ...
>       };
>       ...
>     };
> 
> The dumpimage can extract the 'kernel@1' node through the following command:
> 
>   $ ./dumpimage -T flat_dt -i kernel.itb -p 0 kernel
>   Extracted:
>    Image 0 (kernel@1)
>     Description:  Kernel 2.6.32-34
>     Created:      Wed Oct 22 15:50:26 2014
>     Type:         Kernel Image
>     Compression:  gzip compressed
>     Data Size:    4040128 Bytes = 3945.44 kB = 3.85 MB
>     Architecture: PowerPC
>     OS:           Linux
>     Load Address: 0x00000000
>     Entry Point:  0x00000000
>     Hash algo:    md5
>     Hash value:   22352ad39bdc03e2e50f9cc28c1c3652
> 
> Which results in the file 'kernel' being exactly the same as '/boot/vmlinuz-2.6.32-34-generic'.
> 
> Signed-off-by: Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>

Applied to u-boot/master, thanks!
diff mbox

Patch

diff --git a/common/image-fit.c b/common/image-fit.c
index 4ffc5aa..aaf3a81 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -112,6 +112,33 @@  static void fit_get_debug(const void *fit, int noffset,
 	      fdt_strerror(err));
 }
 
+/**
+ * fit_get_subimage_count - get component (sub-image) count
+ * @fit: pointer to the FIT format image header
+ * @images_noffset: offset of images node
+ *
+ * returns:
+ *     number of image components
+ */
+int fit_get_subimage_count(const void *fit, int images_noffset)
+{
+	int noffset;
+	int ndepth;
+	int count = 0;
+
+	/* 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) {
+			count++;
+		}
+	}
+
+	return count;
+}
+
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT)
 /**
  * fit_print_contents - prints out the contents of the FIT format image
@@ -423,7 +450,8 @@  void fit_image_print(const void *fit, int image_noffset, const char *p)
 		}
 	}
 }
-#endif
+
+#endif /* !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT) */
 
 /**
  * fit_get_desc - get node description property
diff --git a/include/image.h b/include/image.h
index aa748fa..f236fdd 100644
--- a/include/image.h
+++ b/include/image.h
@@ -750,6 +750,7 @@  int fit_parse_conf(const char *spec, ulong addr_curr,
 int fit_parse_subimage(const char *spec, ulong addr_curr,
 		ulong *addr, const char **image_name);
 
+int fit_get_subimage_count(const void *fit, int images_noffset);
 void fit_print_contents(const void *fit);
 void fit_image_print(const void *fit, int noffset, const char *p);
 
diff --git a/test/image/test-imagetools.sh b/test/image/test-imagetools.sh
index 8aaaade..952f975 100755
--- a/test/image/test-imagetools.sh
+++ b/test/image/test-imagetools.sh
@@ -16,6 +16,8 @@  BASEDIR=sandbox
 SRCDIR=${BASEDIR}/boot
 IMAGE_NAME="v1.0-test"
 IMAGE_MULTI=linux.img
+IMAGE_FIT_ITS=linux.its
+IMAGE_FIT_ITB=linux.itb
 DATAFILE0=vmlinuz
 DATAFILE1=initrd.img
 DATAFILE2=System.map
@@ -34,7 +36,10 @@  cleanup()
 	for file in ${DATAFILES}; do
 		rm -f ${file} ${SRCDIR}/${file}
 	done
-	rm -f ${IMAGE_MULTI} ${DUMPIMAGE_LIST} ${MKIMAGE_LIST} ${TEST_OUT}
+	rm -f ${IMAGE_MULTI}
+	rm -f ${DUMPIMAGE_LIST}
+	rm -f ${MKIMAGE_LIST}
+	rm -f ${TEST_OUT}
 	rmdir ${SRCDIR}
 }
 
@@ -105,6 +110,70 @@  extract_multi_image()
 	echo "done."
 }
 
+# Write files into a FIT image
+create_fit_image()
+{
+	echo " \
+	/dts-v1/; \
+	/ { \
+	    description = \"FIT image\"; \
+	    #address-cells = <1>; \
+	\
+	    images { \
+	        kernel@1 { \
+	            description = \"kernel\"; \
+	            data = /incbin/(\"${DATAFILE0}\"); \
+	            type = \"kernel\"; \
+	            arch = \"sandbox\"; \
+	            os = \"linux\"; \
+	            compression = \"gzip\"; \
+	            load = <0x40000>; \
+	            entry = <0x8>; \
+	        }; \
+	        ramdisk@1 { \
+	            description = \"filesystem\"; \
+	            data = /incbin/(\"${DATAFILE1}\"); \
+	            type = \"ramdisk\"; \
+	            arch = \"sandbox\"; \
+	            os = \"linux\"; \
+	            compression = \"none\"; \
+	            load = <0x80000>; \
+	            entry = <0x16>; \
+	        }; \
+	        fdt@1 { \
+	            description = \"device tree\"; \
+	            data = /incbin/(\"${DATAFILE2}\"); \
+	            type = \"flat_dt\"; \
+	            arch = \"sandbox\"; \
+	            compression = \"none\"; \
+	        }; \
+	    }; \
+	    configurations { \
+	        default = \"conf@1\"; \
+	        conf@1 { \
+	            kernel = \"kernel@1\"; \
+	            fdt = \"fdt@1\"; \
+	        }; \
+	    }; \
+	}; \
+	" > ${IMAGE_FIT_ITS}
+
+	echo -e "\nBuilding FIT image..."
+	do_cmd ${MKIMAGE} -f ${IMAGE_FIT_ITS} ${IMAGE_FIT_ITB}
+	echo "done."
+}
+
+# Extract files from a FIT image
+extract_fit_image()
+{
+	echo -e "\nExtracting FIT image contents..."
+	do_cmd ${DUMPIMAGE} -T flat_dt -i ${IMAGE_FIT_ITB} -p 0 ${DATAFILE0}
+	do_cmd ${DUMPIMAGE} -T flat_dt -i ${IMAGE_FIT_ITB} -p 1 ${DATAFILE1}
+	do_cmd ${DUMPIMAGE} -T flat_dt -i ${IMAGE_FIT_ITB} -p 2 ${DATAFILE2}
+	do_cmd ${DUMPIMAGE} -T flat_dt -i ${IMAGE_FIT_ITB} -p 2 ${DATAFILE2} -o ${TEST_OUT}
+	echo "done."
+}
+
 # List the contents of a file
 # Args:
 #    image filename
@@ -136,6 +205,18 @@  main()
 	list_image ${IMAGE_MULTI}
 	assert_equal ${DUMPIMAGE_LIST} ${MKIMAGE_LIST}
 
+	# Compress and extract FIT images, compare the result
+	create_fit_image
+	extract_fit_image
+	for file in ${DATAFILES}; do
+		assert_equal ${file} ${SRCDIR}/${file}
+	done
+	assert_equal ${TEST_OUT} ${DATAFILE2}
+
+	# List contents of FIT image and compares output from tools
+	list_image ${IMAGE_FIT_ITB}
+	assert_equal ${DUMPIMAGE_LIST} ${MKIMAGE_LIST}
+
 	# Remove files created
 	cleanup
 
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 5712842..eb2a25e 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -155,6 +155,97 @@  err_system:
 	return -1;
 }
 
+/**
+ * fit_image_extract - extract a FIT component image
+ * @fit: pointer to the FIT format image header
+ * @image_noffset: offset of the component image node
+ * @file_name: name of the file to store the FIT sub-image
+ *
+ * returns:
+ *     zero in case of success or a negative value if fail.
+ */
+static int fit_image_extract(
+	const void *fit,
+	int image_noffset,
+	const char *file_name)
+{
+	const void *file_data;
+	size_t file_size = 0;
+
+	/* get the "data" property of component at offset "image_noffset" */
+	fit_image_get_data(fit, image_noffset, &file_data, &file_size);
+
+	/* save the "file_data" into the file specified by "file_name" */
+	return imagetool_save_subimage(file_name, (ulong) file_data, file_size);
+}
+
+/**
+ * fit_extract_contents - retrieve a sub-image component from the FIT image
+ * @ptr: pointer to the FIT format image header
+ * @params: command line parameters
+ *
+ * returns:
+ *     zero in case of success or a negative value if fail.
+ */
+static int fit_extract_contents(void *ptr, struct image_tool_params *params)
+{
+	int images_noffset;
+	int noffset;
+	int ndepth;
+	const void *fit = ptr;
+	int count = 0;
+	const char *p;
+
+	/* Indent string is defined in header image.h */
+	p = IMAGE_INDENT_STRING;
+
+	if (!fit_check_format(fit)) {
+		printf("Bad FIT image format\n");
+		return -1;
+	}
+
+	/* 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 -1;
+	}
+
+	/* Avoid any overrun */
+	count = fit_get_subimage_count(fit, images_noffset);
+	if ((params->pflag < 0) || (count <= params->pflag)) {
+		printf("No such component at '%d'\n", params->pflag);
+		return -1;
+	}
+
+	/* Process its subnodes, extract the desired component from image */
+	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.
+			 */
+			if (params->pflag == count) {
+				printf("Extracted:\n%s Image %u (%s)\n", p,
+				       count, fit_get_name(fit, noffset, NULL));
+
+				fit_image_print(fit, noffset, p);
+
+				return fit_image_extract(fit, noffset,
+						params->outfile);
+			}
+
+			count++;
+		}
+	}
+
+	return 0;
+}
+
 static int fit_check_params(struct image_tool_params *params)
 {
 	return	((params->dflag && (params->fflag || params->lflag)) ||
@@ -171,7 +262,7 @@  U_BOOT_IMAGE_TYPE(
 	fit_verify_header,
 	fit_print_contents,
 	NULL,
-	NULL,
+	fit_extract_contents,
 	fit_check_image_types,
 	fit_handle_file,
 	NULL /* FIT images use DTB header */