Skip to content

Commit

Permalink
fit: Support compression for non-kernel components (e.g. FDT)
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
Reviewed-by: Simon Goldschmidt <[email protected]>
  • Loading branch information
jwerner-chromium authored and trini committed Jul 29, 2019
1 parent 2090854 commit b1307f8
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 38 deletions.
86 changes: 52 additions & 34 deletions common/image-fit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) ||
Expand Down Expand Up @@ -1931,38 +1934,24 @@ 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;
}

#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)) {
Expand All @@ -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,
Expand All @@ -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 (image_decomp(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;
Expand Down
29 changes: 25 additions & 4 deletions test/py/tests/test_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
type = "kernel";
arch = "sandbox";
os = "linux";
compression = "none";
compression = "%(compression)s";
load = <0x40000>;
entry = <0x8>;
};
Expand All @@ -39,11 +39,11 @@
};
fdt@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@1 {
algo = "sha1,rsa2048";
key-name-hint = "dev";
Expand All @@ -56,7 +56,7 @@
arch = "sandbox";
os = "linux";
%(ramdisk_load)s
compression = "none";
compression = "%(compression)s";
};
ramdisk@2 {
description = "snow";
Expand Down Expand Up @@ -221,6 +221,10 @@ def make_ramdisk(filename, text):
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
Expand Down Expand Up @@ -312,6 +316,7 @@ def run_fit_test(mkimage):
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')
Expand All @@ -326,6 +331,7 @@ def run_fit_test(mkimage):
'kernel_addr' : 0x40000,
'kernel_size' : filesize(kernel),

'fdt' : fdt,
'fdt_out' : fdt_out,
'fdt_addr' : 0x80000,
'fdt_size' : filesize(control_dtb),
Expand All @@ -351,6 +357,7 @@ def run_fit_test(mkimage):
'loadables2_load' : '',

'loadables_config' : '',
'compression' : 'none',
}

# Make a basic FIT and a script to load it
Expand Down Expand Up @@ -417,6 +424,20 @@ def run_fit_test(mkimage):
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
Expand Down

0 comments on commit b1307f8

Please sign in to comment.