diff options
author | Simon Glass <sjg@chromium.org> | 2018-09-14 13:57:26 +0300 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2018-09-29 20:49:32 +0300 |
commit | 83d73c2f7c471c1a7e5a9a2bf0de287491408b2d (patch) | |
tree | 0f97947d81d656fc25afe2714e2938a6451459cf | |
parent | 04187a845c86215da0e3ad680cdcf2fc7515b99a (diff) | |
download | u-boot-83d73c2f7c471c1a7e5a9a2bf0de287491408b2d.tar.xz |
binman: Support compressed entries
Add support for compressing blob entries. This can help reduce image sizes
for many types of data. It requires that the firmware be able to
decompress the data at run-time.
Signed-off-by: Simon Glass <sjg@chromium.org>
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | tools/binman/README | 16 | ||||
-rw-r--r-- | tools/binman/README.entries | 7 | ||||
-rw-r--r-- | tools/binman/etype/blob.py | 49 | ||||
-rw-r--r-- | tools/binman/ftest.py | 31 | ||||
-rw-r--r-- | tools/binman/test/83_compress.dts | 11 |
6 files changed, 106 insertions, 9 deletions
diff --git a/.travis.yml b/.travis.yml index ea3b20e063..2b759c9d68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ addons: - wget - device-tree-compiler - lzop + - liblz4-tool before_install: - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y diff --git a/tools/binman/README b/tools/binman/README index 10dfe5766d..d6871946ab 100644 --- a/tools/binman/README +++ b/tools/binman/README @@ -593,6 +593,22 @@ the device tree. These can be used by U-Boot at run-time to find the location of each entry. +Compression +----------- + +Binman support compression for 'blob' entries (those of type 'blob' and +derivatives). To enable this for an entry, add a 'compression' property: + + blob { + filename = "datafile"; + compression = "lz4"; + }; + +The entry will then contain the compressed data, using the 'lz4' compression +algorithm. Currently this is the only one that is supported. + + + Map files --------- diff --git a/tools/binman/README.entries b/tools/binman/README.entries index 091fb5ce2b..2cf7dc0338 100644 --- a/tools/binman/README.entries +++ b/tools/binman/README.entries @@ -19,11 +19,18 @@ class by other entry types. Properties / Entry arguments: - filename: Filename of file to read into entry + - compress: Compression algorithm to use: + none: No compression + lz4: Use lz4 compression (via 'lz4' command-line utility) This entry reads data from a file and places it in the entry. The default filename is often specified specified by the subclass. See for example the 'u_boot' entry which provides the filename 'u-boot.bin'. +If compression is enabled, an extra 'uncomp-size' property is written to +the node (if enabled with -u) which provides the uncompressed size of the +data. + Entry: blob-dtb: A blob that holds a device tree diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py index 3f46eecf30..642a0e482a 100644 --- a/tools/binman/etype/blob.py +++ b/tools/binman/etype/blob.py @@ -7,6 +7,7 @@ from entry import Entry import fdt_util +import state import tools class Entry_blob(Entry): @@ -17,14 +18,23 @@ class Entry_blob(Entry): Properties / Entry arguments: - filename: Filename of file to read into entry + - compress: Compression algorithm to use: + none: No compression + lz4: Use lz4 compression (via 'lz4' command-line utility) This entry reads data from a file and places it in the entry. The default filename is often specified specified by the subclass. See for example the 'u_boot' entry which provides the filename 'u-boot.bin'. + + If compression is enabled, an extra 'uncomp-size' property is written to + the node (if enabled with -u) which provides the uncompressed size of the + data. """ def __init__(self, section, etype, node): Entry.__init__(self, section, etype, node) - self._filename = fdt_util.GetString(self._node, "filename", self.etype) + self._filename = fdt_util.GetString(self._node, 'filename', self.etype) + self._compress = fdt_util.GetString(self._node, 'compress', 'none') + self._uncompressed_size = None def ObtainContents(self): self._filename = self.GetDefaultFilename() @@ -33,15 +43,36 @@ class Entry_blob(Entry): return True def ReadBlobContents(self): - with open(self._pathname) as fd: - # We assume the data is small enough to fit into memory. If this - # is used for large filesystem image that might not be true. - # In that case, Image.BuildImage() could be adjusted to use a - # new Entry method which can read in chunks. Then we could copy - # the data in chunks and avoid reading it all at once. For now - # this seems like an unnecessary complication. - self.SetContents(fd.read()) + # We assume the data is small enough to fit into memory. If this + # is used for large filesystem image that might not be true. + # In that case, Image.BuildImage() could be adjusted to use a + # new Entry method which can read in chunks. Then we could copy + # the data in chunks and avoid reading it all at once. For now + # this seems like an unnecessary complication. + data = tools.ReadFile(self._pathname) + if self._compress == 'lz4': + self._uncompressed_size = len(data) + ''' + import lz4 # Import this only if needed (python-lz4 dependency) + + try: + data = lz4.frame.compress(data) + except AttributeError: + data = lz4.compress(data) + ''' + data = tools.Run('lz4', '-c', self._pathname, ) + self.SetContents(data) return True def GetDefaultFilename(self): return self._filename + + def AddMissingProperties(self): + Entry.AddMissingProperties(self) + if self._compress != 'none': + state.AddZeroProp(self._node, 'uncomp-size') + + def SetCalculatedProperties(self): + Entry.SetCalculatedProperties(self) + if self._uncompressed_size is not None: + state.SetInt(self._node, 'uncomp-size', self._uncompressed_size) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 6bfef7b63a..1c3c46fc23 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -54,6 +54,7 @@ CROS_EC_RW_DATA = 'ecrw' GBB_DATA = 'gbbd' BMPBLK_DATA = 'bmp' VBLOCK_DATA = 'vblk' +COMPRESS_DATA = 'data to compress' class TestFunctional(unittest.TestCase): @@ -116,6 +117,8 @@ class TestFunctional(unittest.TestCase): with open(self.TestFile('descriptor.bin')) as fd: TestFunctional._MakeInputFile('descriptor.bin', fd.read()) + TestFunctional._MakeInputFile('compress', COMPRESS_DATA) + @classmethod def tearDownClass(self): """Remove the temporary input directory and its contents""" @@ -1505,6 +1508,34 @@ class TestFunctional(unittest.TestCase): finally: self._ResetDtbs() + def _decompress(self, data): + out = os.path.join(self._indir, 'lz4.tmp') + with open(out, 'wb') as fd: + fd.write(data) + return tools.Run('lz4', '-dc', out) + ''' + try: + orig = lz4.frame.decompress(data) + except AttributeError: + orig = lz4.decompress(data) + ''' + + def testCompress(self): + """Test compression of blobs""" + data, _, _, out_dtb_fname = self._DoReadFileDtb('83_compress.dts', + use_real_dtb=True, update_dtb=True) + dtb = fdt.Fdt(out_dtb_fname) + dtb.Scan() + props = self._GetPropTree(dtb, ['size', 'uncomp-size']) + orig = self._decompress(data) + self.assertEquals(COMPRESS_DATA, orig) + expected = { + 'blob:uncomp-size': len(COMPRESS_DATA), + 'blob:size': len(data), + 'size': len(data), + } + self.assertEqual(expected, props) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/83_compress.dts b/tools/binman/test/83_compress.dts new file mode 100644 index 0000000000..07813bdeaa --- /dev/null +++ b/tools/binman/test/83_compress.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + blob { + filename = "compress"; + compress = "lz4"; + }; + }; +}; |