mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	binman: Support adding files
In some cases it is useful to add a group of files to the image and be able to access them at run-time. Of course it is possible to generate the binman config file with a set of blobs each with a filename. But for convenience, add an entry type which can do this. Add required support (for adding nodes and string properties) into the state module. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
		| @@ -71,6 +71,21 @@ updating the EC on startup via software sync. | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Entry: files: Entry containing a set of files | ||||||
|  | --------------------------------------------- | ||||||
|  |  | ||||||
|  | Properties / Entry arguments: | ||||||
|  |     - pattern: Filename pattern to match the files to include | ||||||
|  |     - compress: Compression algorithm to use: | ||||||
|  |         none: No compression | ||||||
|  |         lz4: Use lz4 compression (via 'lz4' command-line utility) | ||||||
|  |  | ||||||
|  | This entry reads a number of files and places each in a separate sub-entry | ||||||
|  | within this entry. To access these you need to enable device-tree updates | ||||||
|  | at run-time so you can obtain the file positions. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Entry: fill: An entry which is filled to a particular byte value | Entry: fill: An entry which is filled to a particular byte value | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -103,6 +103,10 @@ class Section(object): | |||||||
|     def SetOffset(self, offset): |     def SetOffset(self, offset): | ||||||
|         self._offset = offset |         self._offset = offset | ||||||
|  |  | ||||||
|  |     def ExpandEntries(self): | ||||||
|  |         for entry in self._entries.values(): | ||||||
|  |             entry.ExpandEntries() | ||||||
|  |  | ||||||
|     def AddMissingProperties(self): |     def AddMissingProperties(self): | ||||||
|         """Add new properties to the device tree as needed for this entry""" |         """Add new properties to the device tree as needed for this entry""" | ||||||
|         for prop in ['offset', 'size', 'image-pos']: |         for prop in ['offset', 'size', 'image-pos']: | ||||||
|   | |||||||
| @@ -146,6 +146,7 @@ def Binman(options, args): | |||||||
|             # without changing the device-tree size, thus ensuring that our |             # without changing the device-tree size, thus ensuring that our | ||||||
|             # entry offsets remain the same. |             # entry offsets remain the same. | ||||||
|             for image in images.values(): |             for image in images.values(): | ||||||
|  |                 image.ExpandEntries() | ||||||
|                 if options.update_fdt: |                 if options.update_fdt: | ||||||
|                     image.AddMissingProperties() |                     image.AddMissingProperties() | ||||||
|                 image.ProcessFdt(dtb) |                 image.ProcessFdt(dtb) | ||||||
|   | |||||||
| @@ -179,6 +179,9 @@ class Entry(object): | |||||||
|             return Set([fname]) |             return Set([fname]) | ||||||
|         return Set() |         return Set() | ||||||
|  |  | ||||||
|  |     def ExpandEntries(self): | ||||||
|  |         pass | ||||||
|  |  | ||||||
|     def AddMissingProperties(self): |     def AddMissingProperties(self): | ||||||
|         """Add new properties to the device tree as needed for this entry""" |         """Add new properties to the device tree as needed for this entry""" | ||||||
|         for prop in ['offset', 'size', 'image-pos']: |         for prop in ['offset', 'size', 'image-pos']: | ||||||
|   | |||||||
							
								
								
									
										57
									
								
								tools/binman/etype/files.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								tools/binman/etype/files.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | # Copyright (c) 2018 Google, Inc | ||||||
|  | # Written by Simon Glass <sjg@chromium.org> | ||||||
|  | # | ||||||
|  | # Entry-type module for a set of files which are placed in individual | ||||||
|  | # sub-entries | ||||||
|  | # | ||||||
|  |  | ||||||
|  | import glob | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | from section import Entry_section | ||||||
|  | import fdt_util | ||||||
|  | import state | ||||||
|  | import tools | ||||||
|  |  | ||||||
|  | import bsection | ||||||
|  |  | ||||||
|  | class Entry_files(Entry_section): | ||||||
|  |     """Entry containing a set of files | ||||||
|  |  | ||||||
|  |     Properties / Entry arguments: | ||||||
|  |         - pattern: Filename pattern to match the files to include | ||||||
|  |         - compress: Compression algorithm to use: | ||||||
|  |             none: No compression | ||||||
|  |             lz4: Use lz4 compression (via 'lz4' command-line utility) | ||||||
|  |  | ||||||
|  |     This entry reads a number of files and places each in a separate sub-entry | ||||||
|  |     within this entry. To access these you need to enable device-tree updates | ||||||
|  |     at run-time so you can obtain the file positions. | ||||||
|  |     """ | ||||||
|  |     def __init__(self, section, etype, node): | ||||||
|  |         Entry_section.__init__(self, section, etype, node) | ||||||
|  |         self._pattern = fdt_util.GetString(self._node, 'pattern') | ||||||
|  |         if not self._pattern: | ||||||
|  |             self.Raise("Missing 'pattern' property") | ||||||
|  |         self._compress = fdt_util.GetString(self._node, 'compress', 'none') | ||||||
|  |         self._require_matches = fdt_util.GetBool(self._node, | ||||||
|  |                                                 'require-matches') | ||||||
|  |  | ||||||
|  |     def ExpandEntries(self): | ||||||
|  |         files = tools.GetInputFilenameGlob(self._pattern) | ||||||
|  |         if self._require_matches and not files: | ||||||
|  |             self.Raise("Pattern '%s' matched no files" % self._pattern) | ||||||
|  |         for fname in files: | ||||||
|  |             if not os.path.isfile(fname): | ||||||
|  |                 continue | ||||||
|  |             name = os.path.basename(fname) | ||||||
|  |             subnode = self._node.FindNode(name) | ||||||
|  |             if not subnode: | ||||||
|  |                 subnode = state.AddSubnode(self._node, name) | ||||||
|  |             state.AddString(subnode, 'type', 'blob') | ||||||
|  |             state.AddString(subnode, 'filename', fname) | ||||||
|  |             state.AddString(subnode, 'compress', self._compress) | ||||||
|  |  | ||||||
|  |         # Read entries again, now that we have some | ||||||
|  |         self._section._ReadEntries() | ||||||
| @@ -54,6 +54,8 @@ CROS_EC_RW_DATA       = 'ecrw' | |||||||
| GBB_DATA              = 'gbbd' | GBB_DATA              = 'gbbd' | ||||||
| BMPBLK_DATA           = 'bmp' | BMPBLK_DATA           = 'bmp' | ||||||
| VBLOCK_DATA           = 'vblk' | VBLOCK_DATA           = 'vblk' | ||||||
|  | FILES_DATA            = ("sorry I'm late\nOh, don't bother apologising, I'm " + | ||||||
|  |                          "sorry you're alive\n") | ||||||
| COMPRESS_DATA         = 'data to compress' | COMPRESS_DATA         = 'data to compress' | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -117,6 +119,9 @@ class TestFunctional(unittest.TestCase): | |||||||
|         with open(self.TestFile('descriptor.bin')) as fd: |         with open(self.TestFile('descriptor.bin')) as fd: | ||||||
|             TestFunctional._MakeInputFile('descriptor.bin', fd.read()) |             TestFunctional._MakeInputFile('descriptor.bin', fd.read()) | ||||||
|  |  | ||||||
|  |         shutil.copytree(self.TestFile('files'), | ||||||
|  |                         os.path.join(self._indir, 'files')) | ||||||
|  |  | ||||||
|         TestFunctional._MakeInputFile('compress', COMPRESS_DATA) |         TestFunctional._MakeInputFile('compress', COMPRESS_DATA) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
| @@ -1536,6 +1541,44 @@ class TestFunctional(unittest.TestCase): | |||||||
|             } |             } | ||||||
|         self.assertEqual(expected, props) |         self.assertEqual(expected, props) | ||||||
|  |  | ||||||
|  |     def testFiles(self): | ||||||
|  |         """Test bringing in multiple files""" | ||||||
|  |         data = self._DoReadFile('84_files.dts') | ||||||
|  |         self.assertEqual(FILES_DATA, data) | ||||||
|  |  | ||||||
|  |     def testFilesCompress(self): | ||||||
|  |         """Test bringing in multiple files and compressing them""" | ||||||
|  |         data = self._DoReadFile('85_files_compress.dts') | ||||||
|  |  | ||||||
|  |         image = control.images['image'] | ||||||
|  |         entries = image.GetEntries() | ||||||
|  |         files = entries['files'] | ||||||
|  |         entries = files._section._entries | ||||||
|  |  | ||||||
|  |         orig = '' | ||||||
|  |         for i in range(1, 3): | ||||||
|  |             key = '%d.dat' % i | ||||||
|  |             start = entries[key].image_pos | ||||||
|  |             len = entries[key].size | ||||||
|  |             chunk = data[start:start + len] | ||||||
|  |             orig += self._decompress(chunk) | ||||||
|  |  | ||||||
|  |         self.assertEqual(FILES_DATA, orig) | ||||||
|  |  | ||||||
|  |     def testFilesMissing(self): | ||||||
|  |         """Test missing files""" | ||||||
|  |         with self.assertRaises(ValueError) as e: | ||||||
|  |             data = self._DoReadFile('86_files_none.dts') | ||||||
|  |         self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched " | ||||||
|  |                       'no files', str(e.exception)) | ||||||
|  |  | ||||||
|  |     def testFilesNoPattern(self): | ||||||
|  |         """Test missing files""" | ||||||
|  |         with self.assertRaises(ValueError) as e: | ||||||
|  |             data = self._DoReadFile('87_files_no_pattern.dts') | ||||||
|  |         self.assertIn("Node '/binman/files': Missing 'pattern' property", | ||||||
|  |                       str(e.exception)) | ||||||
|  |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     unittest.main() |     unittest.main() | ||||||
|   | |||||||
| @@ -58,6 +58,15 @@ class Image: | |||||||
|         """Get the set of device tree files used by this image""" |         """Get the set of device tree files used by this image""" | ||||||
|         return self._section.GetFdtSet() |         return self._section.GetFdtSet() | ||||||
|  |  | ||||||
|  |     def ExpandEntries(self): | ||||||
|  |         """Expand out any entries which have calculated sub-entries | ||||||
|  |  | ||||||
|  |         Some entries are expanded out at runtime, e.g. 'files', which produces | ||||||
|  |         a section containing a list of files. Process these entries so that | ||||||
|  |         this information is added to the device tree. | ||||||
|  |         """ | ||||||
|  |         self._section.ExpandEntries() | ||||||
|  |  | ||||||
|     def AddMissingProperties(self): |     def AddMissingProperties(self): | ||||||
|         """Add properties that are not present in the device tree |         """Add properties that are not present in the device tree | ||||||
|  |  | ||||||
|   | |||||||
| @@ -189,6 +189,33 @@ def AddZeroProp(node, prop): | |||||||
|     for n in GetUpdateNodes(node): |     for n in GetUpdateNodes(node): | ||||||
|         n.AddZeroProp(prop) |         n.AddZeroProp(prop) | ||||||
|  |  | ||||||
|  | def AddSubnode(node, name): | ||||||
|  |     """Add a new subnode to a node in affected device trees | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         node: Node to add to | ||||||
|  |         name: name of node to add | ||||||
|  |  | ||||||
|  |     Returns: | ||||||
|  |         New subnode that was created in main tree | ||||||
|  |     """ | ||||||
|  |     first = None | ||||||
|  |     for n in GetUpdateNodes(node): | ||||||
|  |         subnode = n.AddSubnode(name) | ||||||
|  |         if not first: | ||||||
|  |             first = subnode | ||||||
|  |     return first | ||||||
|  |  | ||||||
|  | def AddString(node, prop, value): | ||||||
|  |     """Add a new string property to affected device trees | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         prop_name: Name of property | ||||||
|  |         value: String value (which will be \0-terminated in the DT) | ||||||
|  |     """ | ||||||
|  |     for n in GetUpdateNodes(node): | ||||||
|  |         n.AddString(prop, value) | ||||||
|  |  | ||||||
| def SetInt(node, prop, value): | def SetInt(node, prop, value): | ||||||
|     """Update an integer property in affected device trees with an integer value |     """Update an integer property in affected device trees with an integer value | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								tools/binman/test/84_files.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tools/binman/test/84_files.dts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | /dts-v1/; | ||||||
|  |  | ||||||
|  | / { | ||||||
|  | 	binman { | ||||||
|  | 		files { | ||||||
|  | 			pattern = "files/*.dat"; | ||||||
|  | 			compress = "none"; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
							
								
								
									
										11
									
								
								tools/binman/test/85_files_compress.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tools/binman/test/85_files_compress.dts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | /dts-v1/; | ||||||
|  |  | ||||||
|  | / { | ||||||
|  | 	binman { | ||||||
|  | 		files { | ||||||
|  | 			pattern = "files/*.dat"; | ||||||
|  | 			compress = "lz4"; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
							
								
								
									
										12
									
								
								tools/binman/test/86_files_none.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tools/binman/test/86_files_none.dts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | /dts-v1/; | ||||||
|  |  | ||||||
|  | / { | ||||||
|  | 	binman { | ||||||
|  | 		files { | ||||||
|  | 			pattern = "files/*.none"; | ||||||
|  | 			compress = "none"; | ||||||
|  | 			require-matches; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
							
								
								
									
										11
									
								
								tools/binman/test/87_files_no_pattern.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tools/binman/test/87_files_no_pattern.dts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | /dts-v1/; | ||||||
|  |  | ||||||
|  | / { | ||||||
|  | 	binman { | ||||||
|  | 		files { | ||||||
|  | 			compress = "none"; | ||||||
|  | 			require-matches; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
							
								
								
									
										1
									
								
								tools/binman/test/files/1.dat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tools/binman/test/files/1.dat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | sorry I'm late | ||||||
							
								
								
									
										1
									
								
								tools/binman/test/files/2.dat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tools/binman/test/files/2.dat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | Oh, don't bother apologising, I'm sorry you're alive | ||||||
							
								
								
									
										0
									
								
								tools/binman/test/files/ignored_dir.dat/ignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tools/binman/test/files/ignored_dir.dat/ignore
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								tools/binman/test/files/not-this-one
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tools/binman/test/files/not-this-one
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | this does not have a .dat extenion | ||||||
| @@ -4,6 +4,7 @@ | |||||||
| # | # | ||||||
|  |  | ||||||
| import command | import command | ||||||
|  | import glob | ||||||
| import os | import os | ||||||
| import shutil | import shutil | ||||||
| import tempfile | import tempfile | ||||||
| @@ -123,6 +124,23 @@ def GetInputFilename(fname): | |||||||
|     raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" % |     raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" % | ||||||
|                      (fname, ','.join(indir), os.getcwd())) |                      (fname, ','.join(indir), os.getcwd())) | ||||||
|  |  | ||||||
|  | def GetInputFilenameGlob(pattern): | ||||||
|  |     """Return a list of filenames for use as input. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         pattern: Filename pattern to search for | ||||||
|  |  | ||||||
|  |     Returns: | ||||||
|  |         A list of matching files in all input directories | ||||||
|  |     """ | ||||||
|  |     if not indir: | ||||||
|  |         return glob.glob(fname) | ||||||
|  |     files = [] | ||||||
|  |     for dirname in indir: | ||||||
|  |         pathname = os.path.join(dirname, pattern) | ||||||
|  |         files += glob.glob(pathname) | ||||||
|  |     return sorted(files) | ||||||
|  |  | ||||||
| def Align(pos, align): | def Align(pos, align): | ||||||
|     if align: |     if align: | ||||||
|         mask = align - 1 |         mask = align - 1 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user