[U-Boot] [PATCH v4 1/2] fit: Support compression for non-kernel components (e.g. FDT)

Julius Werner jwerner at chromium.org
Wed May 15 22:29:57 UTC 2019


This patch adds support for compressing non-kernel image nodes in a FIT
image (kernel nodes could already be compressed previously). This can
reduce the size of FIT images and therefore improve boot times
(especially when an image bundles many different kernel FDTs). The
images will automatically be decompressed on load.

This patch does not support extracting compatible strings from
compressed FDTs, so it's not very helpful in conjunction with
CONFIG_FIT_BEST_MATCH yet, but it can already be used in environments
that select the configuration to load explicitly.

Signed-off-by: Julius Werner <jwerner at chromium.org>
---
 - Changes for v2:
   - Changed from only supporting compressed FDTs to supporting all
     non-kernel image node types.
 - Changes for v3:
   - Fixed up some debug output that was still written for v1.
   - Fixed a mistake with handling FIT_LOAD_OPTIONAL_NON_ZERO when
     'load' was 0 (i.e. unset).
   - Added compression test case to the test_fit pytest.
 - No changes for v4

 common/image-fit.c        | 86 +++++++++++++++++++++++----------------
 test/py/tests/test_fit.py | 29 +++++++++++--
 2 files changed, 77 insertions(+), 38 deletions(-)

diff --git a/common/image-fit.c b/common/image-fit.c
index ac901e131c..469c5c8f49 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -22,6 +22,7 @@
 DECLARE_GLOBAL_DATA_PTR;
 #endif /* !USE_HOSTCC*/
 
+#include <bootm.h>
 #include <image.h>
 #include <bootstage.h>
 #include <u-boot/crc.h>
@@ -1576,6 +1577,13 @@ int fit_conf_find_compat(const void *fit, const void *fdt)
 			      kfdt_name);
 			continue;
 		}
+
+		if (!fit_image_check_comp(fit, kfdt_noffset, IH_COMP_NONE)) {
+			debug("Can't extract compat from \"%s\" (compressed)\n",
+			      kfdt_name);
+			continue;
+		}
+
 		/*
 		 * Get a pointer to this configuration's fdt.
 		 */
@@ -1795,11 +1803,12 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 	const char *fit_uname_config;
 	const char *fit_base_uname_config;
 	const void *fit;
-	const void *buf;
+	void *buf;
+	void *loadbuf;
 	size_t size;
 	int type_ok, os_ok;
-	ulong load, data, len;
-	uint8_t os;
+	ulong load, load_end, data, len;
+	uint8_t os, comp;
 #ifndef USE_HOSTCC
 	uint8_t os_arch;
 #endif
@@ -1895,12 +1904,6 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 	images->os.arch = os_arch;
 #endif
 
-	if (image_type == IH_TYPE_FLATDT &&
-	    !fit_image_check_comp(fit, noffset, IH_COMP_NONE)) {
-		puts("FDT image is compressed");
-		return -EPROTONOSUPPORT;
-	}
-
 	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
 	type_ok = fit_image_check_type(fit, noffset, image_type) ||
 		  fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE) ||
@@ -1931,7 +1934,8 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK);
 
 	/* get image data address and length */
-	if (fit_image_get_data_and_size(fit, noffset, &buf, &size)) {
+	if (fit_image_get_data_and_size(fit, noffset,
+					(const void **)&buf, &size)) {
 		printf("Could not find %s subimage data!\n", prop_name);
 		bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA);
 		return -ENOENT;
@@ -1939,30 +1943,15 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 
 #if !defined(USE_HOSTCC) && defined(CONFIG_FIT_IMAGE_POST_PROCESS)
 	/* perform any post-processing on the image data */
-	board_fit_image_post_process((void **)&buf, &size);
+	board_fit_image_post_process(&buf, &size);
 #endif
 
 	len = (ulong)size;
 
-	/* verify that image data is a proper FDT blob */
-	if (image_type == IH_TYPE_FLATDT && fdt_check_header(buf)) {
-		puts("Subimage data is not a FDT");
-		return -ENOEXEC;
-	}
-
 	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK);
 
-	/*
-	 * Work-around for eldk-4.2 which gives this warning if we try to
-	 * cast in the unmap_sysmem() call:
-	 * warning: initialization discards qualifiers from pointer target type
-	 */
-	{
-		void *vbuf = (void *)buf;
-
-		data = map_to_sysmem(vbuf);
-	}
-
+	data = map_to_sysmem(buf);
+	load = data;
 	if (load_op == FIT_LOAD_IGNORED) {
 		/* Don't load */
 	} else if (fit_image_get_load(fit, noffset, &load)) {
@@ -1974,8 +1963,6 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 		}
 	} else if (load_op != FIT_LOAD_OPTIONAL_NON_ZERO || load) {
 		ulong image_start, image_end;
-		ulong load_end;
-		void *dst;
 
 		/*
 		 * move image data to the load address,
@@ -1993,14 +1980,45 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 
 		printf("   Loading %s from 0x%08lx to 0x%08lx\n",
 		       prop_name, data, load);
+	} else {
+		load = data;	/* No load address specified */
+	}
+
+	comp = IH_COMP_NONE;
+	loadbuf = buf;
+	/* Kernel images get decompressed later in bootm_load_os(). */
+	if (!(image_type == IH_TYPE_KERNEL ||
+	      image_type == IH_TYPE_KERNEL_NOLOAD) &&
+	    !fit_image_get_comp(fit, noffset, &comp) &&
+	    comp != IH_COMP_NONE) {
+		ulong max_decomp_len = len * 20;
+		if (load == data) {
+			loadbuf = malloc(max_decomp_len);
+			load = map_to_sysmem(loadbuf);
+		} else {
+			loadbuf = map_sysmem(load, max_decomp_len);
+		}
+		if (bootm_decomp_image(comp, load, data, image_type,
+				loadbuf, buf, len, max_decomp_len, &load_end)) {
+			printf("Error decompressing %s\n", prop_name);
 
-		dst = map_sysmem(load, len);
-		memmove(dst, buf, len);
-		data = load;
+			return -ENOEXEC;
+		}
+		len = load_end - load;
+	} else if (load != data) {
+		loadbuf = map_sysmem(load, len);
+		memcpy(loadbuf, buf, len);
 	}
+
+	/* verify that image data is a proper FDT blob */
+	if (image_type == IH_TYPE_FLATDT && fdt_check_header(loadbuf)) {
+		puts("Subimage data is not a FDT");
+		return -ENOEXEC;
+	}
+
 	bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD);
 
-	*datap = data;
+	*datap = load;
 	*lenp = len;
 	if (fit_unamep)
 		*fit_unamep = (char *)fit_uname;
diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py
index 49d6fea571..8009d2907b 100755
--- a/test/py/tests/test_fit.py
+++ b/test/py/tests/test_fit.py
@@ -24,7 +24,7 @@ base_its = '''
                         type = "kernel";
                         arch = "sandbox";
                         os = "linux";
-                        compression = "none";
+                        compression = "%(compression)s";
                         load = <0x40000>;
                         entry = <0x8>;
                 };
@@ -39,11 +39,11 @@ base_its = '''
                 };
                 fdt at 1 {
                         description = "snow";
-                        data = /incbin/("u-boot.dtb");
+                        data = /incbin/("%(fdt)s");
                         type = "flat_dt";
                         arch = "sandbox";
                         %(fdt_load)s
-                        compression = "none";
+                        compression = "%(compression)s";
                         signature at 1 {
                                 algo = "sha1,rsa2048";
                                 key-name-hint = "dev";
@@ -56,7 +56,7 @@ base_its = '''
                         arch = "sandbox";
                         os = "linux";
                         %(ramdisk_load)s
-                        compression = "none";
+                        compression = "%(compression)s";
                 };
                 ramdisk at 2 {
                         description = "snow";
@@ -221,6 +221,10 @@ def test_fit(u_boot_console):
             print(data, file=fd)
         return fname
 
+    def make_compressed(filename):
+        util.run_and_log(cons, ['gzip', '-f', '-k', filename])
+        return filename + '.gz'
+
     def find_matching(text, match):
         """Find a match in a line of text, and return the unmatched line portion
 
@@ -312,6 +316,7 @@ def test_fit(u_boot_console):
         loadables1 = make_kernel('test-loadables1.bin', 'lenrek')
         loadables2 = make_ramdisk('test-loadables2.bin', 'ksidmar')
         kernel_out = make_fname('kernel-out.bin')
+        fdt = make_fname('u-boot.dtb')
         fdt_out = make_fname('fdt-out.dtb')
         ramdisk_out = make_fname('ramdisk-out.bin')
         loadables1_out = make_fname('loadables1-out.bin')
@@ -326,6 +331,7 @@ def test_fit(u_boot_console):
             'kernel_addr' : 0x40000,
             'kernel_size' : filesize(kernel),
 
+            'fdt' : fdt,
             'fdt_out' : fdt_out,
             'fdt_addr' : 0x80000,
             'fdt_size' : filesize(control_dtb),
@@ -351,6 +357,7 @@ def test_fit(u_boot_console):
             'loadables2_load' : '',
 
             'loadables_config' : '',
+            'compression' : 'none',
         }
 
         # Make a basic FIT and a script to load it
@@ -417,6 +424,20 @@ def test_fit(u_boot_console):
             check_equal(loadables2, loadables2_out,
                         'Loadables2 (ramdisk) not loaded')
 
+        # Kernel, FDT and Ramdisk all compressed
+        with cons.log.section('(Kernel + FDT + Ramdisk) compressed'):
+            params['compression'] = 'gzip'
+            params['kernel'] = make_compressed(kernel)
+            params['fdt'] = make_compressed(fdt)
+            params['ramdisk'] = make_compressed(ramdisk)
+            fit = make_fit(mkimage, params)
+            cons.restart_uboot()
+            output = cons.run_command_list(cmd.splitlines())
+            check_equal(kernel, kernel_out, 'Kernel not loaded')
+            check_equal(control_dtb, fdt_out, 'FDT not loaded')
+            check_equal(ramdisk, ramdisk_out, 'Ramdisk not loaded')
+
+
     cons = u_boot_console
     try:
         # We need to use our own device tree file. Remember to restore it
-- 
2.20.1



More information about the U-Boot mailing list