diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile | 3 | ||||
-rw-r--r-- | tools/binman/elf.py | 6 | ||||
-rw-r--r-- | tools/binman/etype/fmap.py | 2 | ||||
-rw-r--r-- | tools/binman/fdt_test.py | 14 | ||||
-rw-r--r-- | tools/binman/fmap_util.py | 3 | ||||
-rw-r--r-- | tools/buildman/builderthread.py | 14 | ||||
-rw-r--r-- | tools/concurrencytest/concurrencytest.py | 4 | ||||
-rw-r--r-- | tools/dtoc/dtb_platdata.py | 643 | ||||
-rw-r--r-- | tools/dtoc/dtoc_test_scan_drivers.cxx | 2 | ||||
-rw-r--r-- | tools/dtoc/dtoc_test_simple.dts | 5 | ||||
-rw-r--r-- | tools/dtoc/fdt.py | 58 | ||||
-rwxr-xr-x | tools/dtoc/main.py | 49 | ||||
-rw-r--r-- | tools/dtoc/src_scan.py | 185 | ||||
-rwxr-xr-x | tools/dtoc/test_dtoc.py | 539 | ||||
-rwxr-xr-x | tools/dtoc/test_fdt.py | 34 | ||||
-rw-r--r-- | tools/dtoc/test_src_scan.py | 107 | ||||
-rw-r--r-- | tools/mkeficapsule.c | 446 | ||||
-rw-r--r-- | tools/patman/control.py | 6 | ||||
-rw-r--r-- | tools/patman/func_test.py | 19 | ||||
-rw-r--r-- | tools/patman/gitutil.py | 9 | ||||
-rwxr-xr-x | tools/patman/main.py | 2 | ||||
-rw-r--r-- | tools/patman/series.py | 4 | ||||
-rw-r--r-- | tools/patman/settings.py | 12 | ||||
-rw-r--r-- | tools/patman/test_checkpatch.py | 28 | ||||
-rw-r--r-- | tools/patman/tools.py | 93 | ||||
-rwxr-xr-x | tools/zynqmp_pm_cfg_obj_convert.py | 2 |
26 files changed, 1501 insertions, 788 deletions
diff --git a/tools/Makefile b/tools/Makefile index 253a6b9706..14fb0ed98f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -221,6 +221,9 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include +mkeficapsule-objs := mkeficapsule.o $(LIBFDT_OBJS) +hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule + # We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of # exceptions for files that aren't complaint. diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 5e566e56cb..249074a334 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -158,9 +158,9 @@ def MakeElf(elf_fname, text, data): # Spilt the text into two parts so that we can make the entry point two # bytes after the start of the text section - text_bytes1 = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in text[:2]] - text_bytes2 = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in text[2:]] - data_bytes = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in data] + text_bytes1 = ['\t.byte\t%#x' % byte for byte in text[:2]] + text_bytes2 = ['\t.byte\t%#x' % byte for byte in text[2:]] + data_bytes = ['\t.byte\t%#x' % byte for byte in data] with open(s_file, 'w') as fd: print('''/* Auto-generated C program to produce an ELF file for testing */ diff --git a/tools/binman/etype/fmap.py b/tools/binman/etype/fmap.py index 3e9b815d11..fe81c6f64a 100644 --- a/tools/binman/etype/fmap.py +++ b/tools/binman/etype/fmap.py @@ -52,7 +52,7 @@ class Entry_fmap(Entry): if pos is not None: pos -= entry.section.GetRootSkipAtStart() areas.append(fmap_util.FmapArea(pos or 0, entry.size or 0, - tools.FromUnicode(entry.name), 0)) + entry.name, 0)) entries = self.GetImage().GetEntries() areas = [] diff --git a/tools/binman/fdt_test.py b/tools/binman/fdt_test.py index c491d40e9e..3e12540f62 100644 --- a/tools/binman/fdt_test.py +++ b/tools/binman/fdt_test.py @@ -50,37 +50,37 @@ class TestFdt(unittest.TestCase): self.assertEquals('me.bin', val) prop = node.props['intval'] - self.assertEquals(fdt.TYPE_INT, prop.type) + self.assertEquals(fdt.Type.INT, prop.type) self.assertEquals(3, fdt_util.GetInt(node, 'intval')) prop = node.props['intarray'] - self.assertEquals(fdt.TYPE_INT, prop.type) + self.assertEquals(fdt.Type.INT, prop.type) self.assertEquals(list, type(prop.value)) self.assertEquals(2, len(prop.value)) self.assertEquals([5, 6], [fdt_util.fdt32_to_cpu(val) for val in prop.value]) prop = node.props['byteval'] - self.assertEquals(fdt.TYPE_BYTE, prop.type) + self.assertEquals(fdt.Type.BYTE, prop.type) self.assertEquals(chr(8), prop.value) prop = node.props['bytearray'] - self.assertEquals(fdt.TYPE_BYTE, prop.type) + self.assertEquals(fdt.Type.BYTE, prop.type) self.assertEquals(list, type(prop.value)) self.assertEquals(str, type(prop.value[0])) self.assertEquals(3, len(prop.value)) self.assertEquals([chr(1), '#', '4'], prop.value) prop = node.props['longbytearray'] - self.assertEquals(fdt.TYPE_INT, prop.type) + self.assertEquals(fdt.Type.INT, prop.type) self.assertEquals(0x090a0b0c, fdt_util.GetInt(node, 'longbytearray')) prop = node.props['stringval'] - self.assertEquals(fdt.TYPE_STRING, prop.type) + self.assertEquals(fdt.Type.STRING, prop.type) self.assertEquals('message2', fdt_util.GetString(node, 'stringval')) prop = node.props['stringarray'] - self.assertEquals(fdt.TYPE_STRING, prop.type) + self.assertEquals(fdt.Type.STRING, prop.type) self.assertEquals(list, type(prop.value)) self.assertEquals(3, len(prop.value)) self.assertEquals(['another', 'multi-word', 'message'], prop.value) diff --git a/tools/binman/fmap_util.py b/tools/binman/fmap_util.py index 25fe60a9cc..b03fc28fbb 100644 --- a/tools/binman/fmap_util.py +++ b/tools/binman/fmap_util.py @@ -111,8 +111,7 @@ def EncodeFmap(image_size, name, areas): ConvertName(names, params) return struct.pack(fmt, *params) - values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, - tools.FromUnicode(name), len(areas)) + values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas)) blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values) for area in areas: blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area) diff --git a/tools/buildman/builderthread.py b/tools/buildman/builderthread.py index 48fcd6cf7e..d664868582 100644 --- a/tools/buildman/builderthread.py +++ b/tools/buildman/builderthread.py @@ -13,6 +13,7 @@ from patman import command from patman import gitutil RETURN_CODE_RETRY = -1 +BASE_ELF_FILENAMES = ['u-boot', 'spl/u-boot-spl', 'tpl/u-boot-tpl'] def Mkdir(dirname, parents = False): """Make a directory if it doesn't already exist. @@ -240,6 +241,17 @@ class BuilderThread(threading.Thread): args.extend(self.builder.toolchains.GetMakeArguments(brd)) args.extend(self.toolchain.MakeArgs()) + # Remove any output targets. Since we use a build directory that + # was previously used by another board, it may have produced an + # SPL image. If we don't remove it (i.e. see do_config and + # self.mrproper below) then it will appear to be the output of + # this build, even if it does not produce SPL images. + build_dir = self.builder.GetBuildDir(commit_upto, brd.target) + for elf in BASE_ELF_FILENAMES: + fname = os.path.join(out_dir, elf) + if os.path.exists(fname): + os.remove(fname) + # If we need to reconfigure, do that now if do_config: config_out = '' @@ -335,7 +347,7 @@ class BuilderThread(threading.Thread): for var in sorted(env.keys()): print('%s="%s"' % (var, env[var]), file=fd) lines = [] - for fname in ['u-boot', 'spl/u-boot-spl']: + for fname in BASE_ELF_FILENAMES: cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname] nm_result = command.RunPipe([cmd], capture=True, capture_stderr=True, cwd=result.out_dir, diff --git a/tools/concurrencytest/concurrencytest.py b/tools/concurrencytest/concurrencytest.py index 418d7eed21..5e88b94f41 100644 --- a/tools/concurrencytest/concurrencytest.py +++ b/tools/concurrencytest/concurrencytest.py @@ -68,7 +68,7 @@ def fork_for_tests(concurrency_num=CPU_COUNT): pid = os.fork() if pid == 0: try: - stream = os.fdopen(c2pwrite, 'wb', 1) + stream = os.fdopen(c2pwrite, 'wb') os.close(c2pread) # Leave stderr and stdout open so we can see test noise # Close stdin so that the child goes away if it decides to @@ -92,7 +92,7 @@ def fork_for_tests(concurrency_num=CPU_COUNT): os._exit(0) else: os.close(c2pwrite) - stream = os.fdopen(c2pread, 'rb', 1) + stream = os.fdopen(c2pread, 'rb') test = ProtocolTestCase(stream) result.append(test) return result diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 9b27aecc14..b7abaed67a 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -9,19 +9,24 @@ This supports converting device tree data to C structures definitions and static data. + +See doc/driver-model/of-plat.rst for more informaiton """ import collections import copy +from enum import IntEnum import os import re import sys from dtoc import fdt from dtoc import fdt_util -from patman import tools +from dtoc import src_scan +from dtoc.src_scan import conv_name_to_c -# When we see these properties we ignore them - i.e. do not create a structure member +# When we see these properties we ignore them - i.e. do not create a structure +# member PROP_IGNORE_LIST = [ '#address-cells', '#gpio-cells', @@ -35,18 +40,29 @@ PROP_IGNORE_LIST = [ 'u-boot,dm-spl', ] -# C type declarations for the tyues we support +# C type declarations for the types we support TYPE_NAMES = { - fdt.TYPE_INT: 'fdt32_t', - fdt.TYPE_BYTE: 'unsigned char', - fdt.TYPE_STRING: 'const char *', - fdt.TYPE_BOOL: 'bool', - fdt.TYPE_INT64: 'fdt64_t', + fdt.Type.INT: 'fdt32_t', + fdt.Type.BYTE: 'unsigned char', + fdt.Type.STRING: 'const char *', + fdt.Type.BOOL: 'bool', + fdt.Type.INT64: 'fdt64_t', } STRUCT_PREFIX = 'dtd_' VAL_PREFIX = 'dtv_' +class Ftype(IntEnum): + SOURCE, HEADER = range(2) + + +# This holds information about each type of output file dtoc can create +# type: Type of file (Ftype) +# fname: Filename excluding directory, e.g. 'dt-plat.c' +# hdr_comment: Comment explaining the purpose of the file +OutputFile = collections.namedtuple('OutputFile', + ['ftype', 'fname', 'method', 'hdr_comment']) + # This holds information about a property which includes phandles. # # max_args: integer: Maximum number or arguments that any phandle uses (int). @@ -62,32 +78,15 @@ PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args']) PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name']) -def conv_name_to_c(name): - """Convert a device-tree name to a C identifier - - This uses multiple replace() calls instead of re.sub() since it is faster - (400ms for 1m calls versus 1000ms for the 're' version). - - Args: - name: Name to convert - Return: - String containing the C version of this name - """ - new = name.replace('@', '_at_') - new = new.replace('-', '_') - new = new.replace(',', '_') - new = new.replace('.', '_') - return new - def tab_to(num_tabs, line): """Append tabs to a line of text to reach a tab stop. Args: - num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.) - line: Line of text to append to + num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.) + line (str): Line of text to append to Returns: - line with the correct number of tabs appeneded. If the line already + str: line with the correct number of tabs appeneded. If the line already extends past that tab stop then a single space is appended. """ if len(line) >= num_tabs * 8: @@ -103,37 +102,29 @@ def get_value(ftype, value): For booleans this return 'true' Args: - type: Data type (fdt_util) - value: Data value, as a string of bytes + ftype (fdt.Type): Data type (fdt_util) + value (bytes): Data value, as a string of bytes + + Returns: + str: String representation of the value """ - if ftype == fdt.TYPE_INT: - return '%#x' % fdt_util.fdt32_to_cpu(value) - elif ftype == fdt.TYPE_BYTE: - return '%#x' % tools.ToByte(value[0]) - elif ftype == fdt.TYPE_STRING: + if ftype == fdt.Type.INT: + val = '%#x' % fdt_util.fdt32_to_cpu(value) + elif ftype == fdt.Type.BYTE: + char = value[0] + val = '%#x' % (ord(char) if isinstance(char, str) else char) + elif ftype == fdt.Type.STRING: # Handle evil ACPI backslashes by adding another backslash before them. # So "\\_SB.GPO0" in the device tree effectively stays like that in C - return '"%s"' % value.replace('\\', '\\\\') - elif ftype == fdt.TYPE_BOOL: - return 'true' - elif ftype == fdt.TYPE_INT64: - return '%#x' % value - -def get_compat_name(node): - """Get the node's list of compatible string as a C identifiers - - Args: - node: Node object to check - Return: - List of C identifiers for all the compatible strings - """ - compat = node.props['compatible'].value - if not isinstance(compat, list): - compat = [compat] - return [conv_name_to_c(c) for c in compat] + val = '"%s"' % value.replace('\\', '\\\\') + elif ftype == fdt.Type.BOOL: + val = 'true' + else: # ftype == fdt.Type.INT64: + val = '%#x' % value + return val -class DtbPlatdata(object): +class DtbPlatdata(): """Provide a means to convert device tree binary data to platform data The output of this process is C structures which can be used in space- @@ -141,89 +132,103 @@ class DtbPlatdata(object): code is not affordable. Properties: + _scan: Scan object, for scanning and reporting on useful information + from the U-Boot source code _fdt: Fdt object, referencing the device tree _dtb_fname: Filename of the input device tree binary file _valid_nodes: A list of Node object with compatible strings. The list is ordered by conv_name_to_c(node.name) _include_disabled: true to include nodes marked status = "disabled" _outfile: The current output file (sys.stdout or a real file) - _warning_disabled: true to disable warnings about driver names not found _lines: Stashed list of output lines for outputting in the future - _drivers: List of valid driver names found in drivers/ - _driver_aliases: Dict that holds aliases for driver names - key: Driver alias declared with - U_BOOT_DRIVER_ALIAS(driver_alias, driver_name) - value: Driver name declared with U_BOOT_DRIVER(driver_name) - _drivers_additional: List of additional drivers to use during scanning + _dirname: Directory to hold output files, or None for none (all files + go to stdout) + _struct_data (dict): OrderedDict of dtplat structures to output + key (str): Node name, as a C identifier + value: dict containing structure fields: + key (str): Field name + value: Prop object with field information + _basedir (str): Base directory of source tree """ - def __init__(self, dtb_fname, include_disabled, warning_disabled, - drivers_additional=[]): + def __init__(self, scan, dtb_fname, include_disabled): + self._scan = scan self._fdt = None self._dtb_fname = dtb_fname self._valid_nodes = None self._include_disabled = include_disabled self._outfile = None - self._warning_disabled = warning_disabled self._lines = [] - self._drivers = [] - self._driver_aliases = {} - self._drivers_additional = drivers_additional + self._dirnames = [None] * len(Ftype) + self._struct_data = collections.OrderedDict() + self._basedir = None - def get_normalized_compat_name(self, node): - """Get a node's normalized compat name + def setup_output_dirs(self, output_dirs): + """Set up the output directories - Returns a valid driver name by retrieving node's list of compatible - string as a C identifier and performing a check against _drivers - and a lookup in driver_aliases printing a warning in case of failure. + This should be done before setup_output() is called Args: - node: Node object to check - Return: - Tuple: - Driver name associated with the first compatible string - List of C identifiers for all the other compatible strings - (possibly empty) - In case of no match found, the return will be the same as - get_compat_name() + output_dirs (tuple of str): + Directory to use for C output files. + Use None to write files relative current directory + Directory to use for H output files. + Defaults to the C output dir """ - compat_list_c = get_compat_name(node) - - for compat_c in compat_list_c: - if not compat_c in self._drivers: - compat_c = self._driver_aliases.get(compat_c) - if not compat_c: - continue - - aliases_c = compat_list_c - if compat_c in aliases_c: - aliases_c.remove(compat_c) - return compat_c, aliases_c - - if not self._warning_disabled: - print('WARNING: the driver %s was not found in the driver list' - % (compat_list_c[0])) - - return compat_list_c[0], compat_list_c[1:] - - def setup_output(self, fname): + def process_dir(ftype, dirname): + if dirname: + os.makedirs(dirname, exist_ok=True) + self._dirnames[ftype] = dirname + + if output_dirs: + c_dirname = output_dirs[0] + h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname + process_dir(Ftype.SOURCE, c_dirname) + process_dir(Ftype.HEADER, h_dirname) + + def setup_output(self, ftype, fname): """Set up the output destination Once this is done, future calls to self.out() will output to this - file. + file. The file used is as follows: + + self._dirnames[ftype] is None: output to fname, or stdout if None + self._dirnames[ftype] is not None: output to fname in that directory + + Calling this function multiple times will close the old file and open + the new one. If they are the same file, nothing happens and output will + continue to the same file. Args: - fname: Filename to send output to, or '-' for stdout + ftype (str): Type of file to create ('c' or 'h') + fname (str): Filename to send output to. If there is a directory in + self._dirnames for this file type, it will be put in that + directory """ - if fname == '-': - self._outfile = sys.stdout + dirname = self._dirnames[ftype] + if dirname: + pathname = os.path.join(dirname, fname) + if self._outfile: + self._outfile.close() + self._outfile = open(pathname, 'w') + elif fname: + if not self._outfile: + self._outfile = open(fname, 'w') else: - self._outfile = open(fname, 'w') + self._outfile = sys.stdout + + def finish_output(self): + """Finish outputing to a file + + This closes the output file, if one is in use + """ + if self._outfile != sys.stdout: + self._outfile.close() def out(self, line): """Output a string to the output file Args: - line: String to output + line (str): String to output """ self._outfile.write(line) @@ -231,7 +236,7 @@ class DtbPlatdata(object): """Buffer up a string to send later Args: - line: String to add to our 'buffer' list + line (str): String to add to our 'buffer' list """ self._lines.append(line) @@ -239,21 +244,26 @@ class DtbPlatdata(object): """Get the contents of the output buffer, and clear it Returns: - The output buffer, which is then cleared for future use + list(str): The output buffer, which is then cleared for future use """ lines = self._lines self._lines = [] return lines - def out_header(self): - """Output a message indicating that this is an auto-generated file""" + def out_header(self, outfile): + """Output a message indicating that this is an auto-generated file + + Args: + outfile: OutputFile describing the file being generated + """ self.out('''/* * DO NOT MODIFY * - * This file was generated by dtoc from a .dtb (device tree binary) file. + * %s. + * This was generated by dtoc from a .dtb (device tree binary) file. */ -''') +''' % outfile.hdr_comment) def get_phandle_argc(self, prop, node_name): """Check if a node contains phandles @@ -262,9 +272,14 @@ class DtbPlatdata(object): or not. As an interim measure, use a list of known property names. Args: - prop: Prop object to check - Return: - Number of argument cells is this is a phandle, else None + prop (fdt.Prop): Prop object to check + node_name (str): Node name, only used for raising an error + Returns: + int or None: Number of argument cells is this is a phandle, + else None + Raises: + ValueError: if the phandle cannot be parsed or the required property + is not present """ if prop.name in ['clocks', 'cd-gpios']: if not isinstance(prop.value, list): @@ -293,7 +308,7 @@ class DtbPlatdata(object): break if not cells: raise ValueError("Node '%s' has no cells property" % - (target.name)) + (target.name)) num_args = fdt_util.fdt32_to_cpu(cells.value) max_args = max(max_args, num_args) args.append(num_args) @@ -301,62 +316,6 @@ class DtbPlatdata(object): return PhandleInfo(max_args, args) return None - def scan_driver(self, fn): - """Scan a driver file to build a list of driver names and aliases - - This procedure will populate self._drivers and self._driver_aliases - - Args - fn: Driver filename to scan - """ - with open(fn, encoding='utf-8') as fd: - try: - buff = fd.read() - except UnicodeDecodeError: - # This seems to happen on older Python versions - print("Skipping file '%s' due to unicode error" % fn) - return - - # The following re will search for driver names declared as - # U_BOOT_DRIVER(driver_name) - drivers = re.findall('U_BOOT_DRIVER\((.*)\)', buff) - - for driver in drivers: - self._drivers.append(driver) - - # The following re will search for driver aliases declared as - # U_BOOT_DRIVER_ALIAS(alias, driver_name) - driver_aliases = re.findall('U_BOOT_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)', - buff) - - for alias in driver_aliases: # pragma: no cover - if len(alias) != 2: - continue - self._driver_aliases[alias[1]] = alias[0] - - def scan_drivers(self): - """Scan the driver folders to build a list of driver names and aliases - - This procedure will populate self._drivers and self._driver_aliases - - """ - basedir = sys.argv[0].replace('tools/dtoc/dtoc', '') - if basedir == '': - basedir = './' - for (dirpath, dirnames, filenames) in os.walk(basedir): - for fn in filenames: - if not fn.endswith('.c'): - continue - self.scan_driver(dirpath + '/' + fn) - - for fn in self._drivers_additional: - if not isinstance(fn, str) or len(fn) == 0: - continue - if fn[0] == '/': - self.scan_driver(fn) - else: - self.scan_driver(basedir + '/' + fn) - def scan_dtb(self): """Scan the device tree to obtain a tree of nodes and properties @@ -371,8 +330,8 @@ class DtbPlatdata(object): This adds each node to self._valid_nodes. Args: - root: Root node for scan - valid_nodes: List of Node objects to add to + root (Node): Root node for scan + valid_nodes (list of Node): List of Node objects to add to """ for node in root.subnodes: if 'compatible' in node.props: @@ -403,7 +362,7 @@ class DtbPlatdata(object): """Get the number of cells in addresses and sizes for this node Args: - node: Node to check + node (fdt.None): Node to check Returns: Tuple: @@ -411,15 +370,15 @@ class DtbPlatdata(object): Number of size cells for this node """ parent = node.parent - na, ns = 2, 2 + num_addr, num_size = 2, 2 if parent: - na_prop = parent.props.get('#address-cells') - ns_prop = parent.props.get('#size-cells') - if na_prop: - na = fdt_util.fdt32_to_cpu(na_prop.value) - if ns_prop: - ns = fdt_util.fdt32_to_cpu(ns_prop.value) - return na, ns + addr_prop = parent.props.get('#address-cells') + size_prop = parent.props.get('#size-cells') + if addr_prop: + num_addr = fdt_util.fdt32_to_cpu(addr_prop.value) + if size_prop: + num_size = fdt_util.fdt32_to_cpu(size_prop.value) + return num_addr, num_size def scan_reg_sizes(self): """Scan for 64-bit 'reg' properties and update the values @@ -432,30 +391,31 @@ class DtbPlatdata(object): reg = node.props.get('reg') if not reg: continue - na, ns = self.get_num_cells(node) - total = na + ns + num_addr, num_size = self.get_num_cells(node) + total = num_addr + num_size - if reg.type != fdt.TYPE_INT: + if reg.type != fdt.Type.INT: raise ValueError("Node '%s' reg property is not an int" % node.name) if len(reg.value) % total: - raise ValueError("Node '%s' reg property has %d cells " - 'which is not a multiple of na + ns = %d + %d)' % - (node.name, len(reg.value), na, ns)) - reg.na = na - reg.ns = ns - if na != 1 or ns != 1: - reg.type = fdt.TYPE_INT64 + raise ValueError( + "Node '%s' reg property has %d cells " + 'which is not a multiple of na + ns = %d + %d)' % + (node.name, len(reg.value), num_addr, num_size)) + reg.num_addr = num_addr + reg.num_size = num_size + if num_addr != 1 or num_size != 1: + reg.type = fdt.Type.INT64 i = 0 new_value = [] val = reg.value if not isinstance(val, list): val = [val] while i < len(val): - addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na) - i += na - size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns) - i += ns + addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr) + i += num_addr + size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size) + i += num_size new_value += [addr, size] reg.value = new_value @@ -470,16 +430,11 @@ class DtbPlatdata(object): Once the widest property is determined, all other properties are updated to match that width. - Returns: - dict containing structures: - key (str): Node name, as a C identifier - value: dict containing structure fields: - key (str): Field name - value: Prop object with field information + The results are written to self._struct_data """ - structs = collections.OrderedDict() + structs = self._struct_data for node in self._valid_nodes: - node_name, _ = self.get_normalized_compat_name(node) + node_name, _ = self._scan.get_normalized_compat_name(node) fields = {} # Get a list of all the valid properties in this node. @@ -501,16 +456,12 @@ class DtbPlatdata(object): else: structs[node_name] = fields - upto = 0 for node in self._valid_nodes: - node_name, _ = self.get_normalized_compat_name(node) + node_name, _ = self._scan.get_normalized_compat_name(node) struct = structs[node_name] for name, prop in node.props.items(): if name not in PROP_IGNORE_LIST and name[0] != '#': prop.Widen(struct[name]) - upto += 1 - - return structs def scan_phandles(self): """Figure out what phandles each node uses @@ -540,22 +491,14 @@ class DtbPlatdata(object): pos += 1 + args - def generate_structs(self, structs): + def generate_structs(self): """Generate struct defintions for the platform data This writes out the body of a header file consisting of structure definitions for node in self._valid_nodes. See the documentation in doc/driver-model/of-plat.rst for more information. - - Args: - structs: dict containing structures: - key (str): Node name, as a C identifier - value: dict containing structure fields: - key (str): Field name - value: Prop object with field information - """ - self.out_header() + structs = self._struct_data self.out('#include <stdbool.h>\n') self.out('#include <linux/libfdt.h>\n') @@ -580,154 +523,198 @@ class DtbPlatdata(object): self.out(';\n') self.out('};\n') - def output_node(self, node): - """Output the C code for a node + def _output_list(self, node, prop): + """Output the C code for a devicetree property that holds a list Args: - node: node to output + node (fdt.Node): Node to output + prop (fdt.Prop): Prop to output """ - def _output_list(node, prop): - """Output the C code for a devicetree property that holds a list - - Args: - node (fdt.Node): Node to output - prop (fdt.Prop): Prop to output - """ - self.buf('{') - vals = [] - # For phandles, output a reference to the platform data - # of the target node. - info = self.get_phandle_argc(prop, node.name) - if info: - # Process the list as pairs of (phandle, id) - pos = 0 - item = 0 - for args in info.args: - phandle_cell = prop.value[pos] - phandle = fdt_util.fdt32_to_cpu(phandle_cell) - target_node = self._fdt.phandle_to_node[phandle] - name = conv_name_to_c(target_node.name) - arg_values = [] - for i in range(args): - arg_values.append( - str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i]))) - pos += 1 + args - vals.append('\t{%d, {%s}}' % (target_node.idx, - ', '.join(arg_values))) - item += 1 - for val in vals: - self.buf('\n\t\t%s,' % val) - else: - for val in prop.value: - vals.append(get_value(prop.type, val)) + self.buf('{') + vals = [] + # For phandles, output a reference to the platform data + # of the target node. + info = self.get_phandle_argc(prop, node.name) + if info: + # Process the list as pairs of (phandle, id) + pos = 0 + for args in info.args: + phandle_cell = prop.value[pos] + phandle = fdt_util.fdt32_to_cpu(phandle_cell) + target_node = self._fdt.phandle_to_node[phandle] + arg_values = [] + for i in range(args): + arg_values.append( + str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i]))) + pos += 1 + args + vals.append('\t{%d, {%s}}' % (target_node.idx, + ', '.join(arg_values))) + for val in vals: + self.buf('\n\t\t%s,' % val) + else: + for val in prop.value: + vals.append(get_value(prop.type, val)) - # Put 8 values per line to avoid very long lines. - for i in range(0, len(vals), 8): - if i: - self.buf(',\n\t\t') - self.buf(', '.join(vals[i:i + 8])) - self.buf('}') + # Put 8 values per line to avoid very long lines. + for i in range(0, len(vals), 8): + if i: + self.buf(',\n\t\t') + self.buf(', '.join(vals[i:i + 8])) + self.buf('}') - struct_name, _ = self.get_normalized_compat_name(node) - var_name = conv_name_to_c(node.name) - self.buf('/* Node %s index %d */\n' % (node.path, node.idx)) - self.buf('static struct %s%s %s%s = {\n' % - (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) - for pname in sorted(node.props): - prop = node.props[pname] - if pname in PROP_IGNORE_LIST or pname[0] == '#': - continue - member_name = conv_name_to_c(prop.name) - self.buf('\t%s= ' % tab_to(3, '.' + member_name)) + def _declare_device(self, var_name, struct_name, node_parent): + """Add a device declaration to the output - # Special handling for lists - if isinstance(prop.value, list): - _output_list(node, prop) - else: - self.buf(get_value(prop.type, prop.value)) - self.buf(',\n') - self.buf('};\n') + This declares a U_BOOT_DRVINFO() for the device being processed - # Add a device declaration - self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name) + Args: + var_name (str): C name for the node + struct_name (str): Name for the dt struct associated with the node + node_parent (Node): Parent of the node (or None if none) + """ + self.buf('U_BOOT_DRVINFO(%s) = {\n' % var_name) self.buf('\t.name\t\t= "%s",\n' % struct_name) - self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) - self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name)) + self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, var_name)) + self.buf('\t.plat_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name)) idx = -1 - if node.parent and node.parent in self._valid_nodes: - idx = node.parent.idx + if node_parent and node_parent in self._valid_nodes: + idx = node_parent.idx self.buf('\t.parent_idx\t= %d,\n' % idx) self.buf('};\n') self.buf('\n') + def _output_prop(self, node, prop): + """Output a line containing the value of a struct member + + Args: + node (Node): Node being output + prop (Prop): Prop object to output + """ + if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#': + return + member_name = conv_name_to_c(prop.name) + self.buf('\t%s= ' % tab_to(3, '.' + member_name)) + + # Special handling for lists + if isinstance(prop.value, list): + self._output_list(node, prop) + else: + self.buf(get_value(prop.type, prop.value)) + self.buf(',\n') + + def _output_values(self, var_name, struct_name, node): + """Output the definition of a device's struct values + + Args: + var_name (str): C name for the node + struct_name (str): Name for the dt struct associated with the node + node (Node): Node being output + """ + self.buf('static struct %s%s %s%s = {\n' % + (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) + for pname in sorted(node.props): + self._output_prop(node, node.props[pname]) + self.buf('};\n') + + def output_node(self, node): + """Output the C code for a node + + Args: + node (fdt.Node): node to output + """ + struct_name, _ = self._scan.get_normalized_compat_name(node) + var_name = conv_name_to_c(node.name) + self.buf('/* Node %s index %d */\n' % (node.path, node.idx)) + + self._output_values(var_name, struct_name, node) + self._declare_device(var_name, struct_name, node.parent) + self.out(''.join(self.get_buf())) - def generate_tables(self): + def generate_plat(self): """Generate device defintions for the platform data This writes out C platform data initialisation data and - U_BOOT_DEVICE() declarations for each valid node. Where a node has + U_BOOT_DRVINFO() declarations for each valid node. Where a node has multiple compatible strings, a #define is used to make them equivalent. See the documentation in doc/driver-model/of-plat.rst for more information. """ - self.out_header() - self.out('/* Allow use of U_BOOT_DEVICE() in this file */\n') - self.out('#define DT_PLATDATA_C\n') + self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n') + self.out('#define DT_PLAT_C\n') self.out('\n') self.out('#include <common.h>\n') self.out('#include <dm.h>\n') self.out('#include <dt-structs.h>\n') self.out('\n') - nodes_to_output = list(self._valid_nodes) - - # Keep outputing nodes until there is none left - while nodes_to_output: - node = nodes_to_output[0] - # Output all the node's dependencies first - for req_node in node.phandles: - if req_node in nodes_to_output: - self.output_node(req_node) - nodes_to_output.remove(req_node) - self.output_node(node) - nodes_to_output.remove(node) - # Define dm_populate_phandle_data() which will add the linking between - # nodes using DM_GET_DEVICE - # dtv_dmc_at_xxx.clocks[0].node = DM_GET_DEVICE(clock_controller_at_xxx) - self.buf('void dm_populate_phandle_data(void) {\n') - self.buf('}\n') + for node in self._valid_nodes: + self.output_node(node) self.out(''.join(self.get_buf())) -def run_steps(args, dtb_file, include_disabled, output, warning_disabled=False, - drivers_additional=[]): + +# Types of output file we understand +# key: Command used to generate this file +# value: OutputFile for this command +OUTPUT_FILES = { + 'struct': + OutputFile(Ftype.HEADER, 'dt-structs-gen.h', + DtbPlatdata.generate_structs, + 'Defines the structs used to hold devicetree data'), + 'platdata': + OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat, + 'Declares the U_BOOT_DRIVER() records and platform data'), + } + + +def run_steps(args, dtb_file, include_disabled, output, output_dirs, + warning_disabled=False, drivers_additional=None, basedir=None): """Run all the steps of the dtoc tool Args: - args: List of non-option arguments provided to the problem - dtb_file: Filename of dtb file to process - include_disabled: True to include disabled nodes - output: Name of output file + args (list): List of non-option arguments provided to the problem + dtb_file (str): Filename of dtb file to process + include_disabled (bool): True to include disabled nodes + output (str): Name of output file (None for stdout) + output_dirs (tuple of str): + Directory to put C output files + Directory to put H output files + warning_disabled (bool): True to avoid showing warnings about missing + drivers + drivers_additional (list): List of additional drivers to use during + scanning + basedir (str): Base directory of U-Boot source code. Defaults to the + grandparent of this file's directory + Raises: + ValueError: if args has no command, or an unknown command """ if not args: - raise ValueError('Please specify a command: struct, platdata') + raise ValueError('Please specify a command: struct, platdata, all') + if output and output_dirs and any(output_dirs): + raise ValueError('Must specify either output or output_dirs, not both') - plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled, drivers_additional) - plat.scan_drivers() + scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional) + plat = DtbPlatdata(scan, dtb_file, include_disabled) + scan.scan_drivers() plat.scan_dtb() plat.scan_tree() plat.scan_reg_sizes() - plat.setup_output(output) - structs = plat.scan_structs() + plat.setup_output_dirs(output_dirs) + plat.scan_structs() plat.scan_phandles() - for cmd in args[0].split(','): - if cmd == 'struct': - plat.generate_structs(structs) - elif cmd == 'platdata': - plat.generate_tables() - else: - raise ValueError("Unknown command '%s': (use: struct, platdata)" % - cmd) + cmds = args[0].split(',') + if 'all' in cmds: + cmds = sorted(OUTPUT_FILES.keys()) + for cmd in cmds: + outfile = OUTPUT_FILES.get(cmd) + if not outfile: + raise ValueError("Unknown command '%s': (use: %s)" % + (cmd, ', '.join(sorted(OUTPUT_FILES.keys())))) + plat.setup_output(outfile.ftype, + outfile.fname if output_dirs else output) + plat.out_header(outfile) + outfile.method(plat) + plat.finish_output() diff --git a/tools/dtoc/dtoc_test_scan_drivers.cxx b/tools/dtoc/dtoc_test_scan_drivers.cxx index 557c692ba2..f448767670 100644 --- a/tools/dtoc/dtoc_test_scan_drivers.cxx +++ b/tools/dtoc/dtoc_test_scan_drivers.cxx @@ -1 +1 @@ -U_BOOT_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2) +DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2) diff --git a/tools/dtoc/dtoc_test_simple.dts b/tools/dtoc/dtoc_test_simple.dts index fd168cb593..1c87b89192 100644 --- a/tools/dtoc/dtoc_test_simple.dts +++ b/tools/dtoc/dtoc_test_simple.dts @@ -44,11 +44,6 @@ longbytearray = [09 0a 0b 0c 0d 0e 0f 10]; }; - spl-test4 { - u-boot,dm-pre-reloc; - compatible = "sandbox,spl-test.2"; - }; - i2c@0 { compatible = "sandbox,i2c-test"; u-boot,dm-pre-reloc; diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index 03b86773d5..4a78c73725 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -5,6 +5,7 @@ # Written by Simon Glass <sjg@chromium.org> # +from enum import IntEnum import struct import sys @@ -22,7 +23,25 @@ from patman import tools # so it is fairly efficient. # A list of types we support -(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, TYPE_INT64) = range(5) +class Type(IntEnum): + (BYTE, INT, STRING, BOOL, INT64) = range(5) + + def is_wider_than(self, other): + """Check if another type is 'wider' than this one + + A wider type is one that holds more information than an earlier one, + similar to the concept of type-widening in C. + + This uses a simple arithmetic comparison, since type values are in order + from narrowest (BYTE) to widest (INT64). + + Args: + other: Other type to compare against + + Return: + True if the other type is wider + """ + return self.value > other.value def CheckErr(errnum, msg): if errnum: @@ -41,9 +60,9 @@ def BytesToValue(data): Type of data Data, either a single element or a list of elements. Each element is one of: - TYPE_STRING: str/bytes value from the property - TYPE_INT: a byte-swapped integer stored as a 4-byte str/bytes - TYPE_BYTE: a byte stored as a single-byte str/bytes + Type.STRING: str/bytes value from the property + Type.INT: a byte-swapped integer stored as a 4-byte str/bytes + Type.BYTE: a byte stored as a single-byte str/bytes """ data = bytes(data) size = len(data) @@ -63,21 +82,21 @@ def BytesToValue(data): is_string = False if is_string: if count == 1: - return TYPE_STRING, strings[0].decode() + return Type.STRING, strings[0].decode() else: - return TYPE_STRING, [s.decode() for s in strings[:-1]] + return Type.STRING, [s.decode() for s in strings[:-1]] if size % 4: if size == 1: - return TYPE_BYTE, tools.ToChar(data[0]) + return Type.BYTE, chr(data[0]) else: - return TYPE_BYTE, [tools.ToChar(ch) for ch in list(data)] + return Type.BYTE, [chr(ch) for ch in list(data)] val = [] for i in range(0, size, 4): val.append(data[i:i + 4]) if size == 4: - return TYPE_INT, val[0] + return Type.INT, val[0] else: - return TYPE_INT, val + return Type.INT, val class Prop: @@ -97,7 +116,7 @@ class Prop: self.bytes = bytes(data) self.dirty = False if not data: - self.type = TYPE_BOOL + self.type = Type.BOOL self.value = True return self.type, self.value = BytesToValue(bytes(data)) @@ -128,15 +147,14 @@ class Prop: update the current property to be like the second, since it is less specific. """ - if newprop.type < self.type: - # Special handling to convert an int into bytes - if self.type == TYPE_INT and newprop.type == TYPE_BYTE: + if self.type.is_wider_than(newprop.type): + if self.type == Type.INT and newprop.type == Type.BYTE: if type(self.value) == list: new_value = [] for val in self.value: - new_value += [tools.ToChar(by) for by in val] + new_value += [chr(by) for by in val] else: - new_value = [tools.ToChar(by) for by in self.value] + new_value = [chr(by) for by in self.value] self.value = new_value self.type = newprop.type @@ -155,11 +173,11 @@ class Prop: Returns: A single value of the given type """ - if type == TYPE_BYTE: + if type == Type.BYTE: return chr(0) - elif type == TYPE_INT: + elif type == Type.INT: return struct.pack('>I', 0); - elif type == TYPE_STRING: + elif type == Type.STRING: return '' else: return True @@ -184,7 +202,7 @@ class Prop: """ self.bytes = struct.pack('>I', val); self.value = self.bytes - self.type = TYPE_INT + self.type = Type.INT self.dirty = True def SetData(self, bytes): diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py index b94d9c301f..b0ad0f3952 100755 --- a/tools/dtoc/main.py +++ b/tools/dtoc/main.py @@ -13,11 +13,7 @@ having to link against libfdt. By putting the data from the device tree into C structures, normal C code can be used. This helps to reduce the size of the compiled program. -Dtoc produces two output files: - - dt-structs.h - contains struct definitions - dt-platdata.c - contains data from the device tree using the struct - definitions, as well as U-Boot driver definitions. +Dtoc produces several output files - see OUTPUT_FILES in dtb_platdata.py This tool is used in U-Boot to provide device tree data to SPL without increasing the code size of SPL. This supports the CONFIG_SPL_OF_PLATDATA @@ -42,37 +38,27 @@ sys.path.insert(0, os.path.join(our_path, from dtoc import dtb_platdata from patman import test_util -def run_tests(args): +def run_tests(processes, args): """Run all the test we have for dtoc Args: + processes: Number of processes to use to run tests (None=same as #CPUs) args: List of positional args provided to dtoc. This can hold a test name to execute (as in 'dtoc -t test_empty_file', for example) """ - import test_dtoc + from dtoc import test_src_scan + from dtoc import test_dtoc result = unittest.TestResult() sys.argv = [sys.argv[0]] test_name = args and args[0] or None - for module in (test_dtoc.TestDtoc,): - if test_name: - try: - suite = unittest.TestLoader().loadTestsFromName(test_name, module) - except AttributeError: - continue - else: - suite = unittest.TestLoader().loadTestsFromTestCase(module) - suite.run(result) - - print(result) - for _, err in result.errors: - print(err) - for _, err in result.failures: - print(err) - if result.errors or result.failures: - print('dtoc tests FAILED') - return 1 - return 0 + + test_util.RunTestSuites( + result, debug=True, verbosity=1, test_preserve_dirs=False, + processes=processes, test_name=test_name, toolpath=[], + test_class_list=[test_dtoc.TestDtoc,test_src_scan.TestSrcScan]) + + return test_util.ReportResult('binman', test_name, result) def RunTestCoverage(): """Run the tests and check that we get 100% coverage""" @@ -87,11 +73,15 @@ if __name__ != '__main__': parser = OptionParser() parser.add_option('-B', '--build-dir', type='string', default='b', help='Directory containing the build output') +parser.add_option('-c', '--c-output-dir', action='store', + help='Select output directory for C files') +parser.add_option('-C', '--h-output-dir', action='store', + help='Select output directory for H files (defaults to --c-output-di)') parser.add_option('-d', '--dtb-file', action='store', help='Specify the .dtb input file') parser.add_option('--include-disabled', action='store_true', help='Include disabled nodes') -parser.add_option('-o', '--output', action='store', default='-', +parser.add_option('-o', '--output', action='store', help='Select output filename') parser.add_option('-P', '--processes', type=int, help='set number of processes to use for running tests') @@ -103,7 +93,7 @@ parser.add_option('-T', '--test-coverage', action='store_true', # Run our meagre tests if options.test: - ret_code = run_tests(args) + ret_code = run_tests(options.processes, args) sys.exit(ret_code) elif options.test_coverage: @@ -111,4 +101,5 @@ elif options.test_coverage: else: dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled, - options.output) + options.output, + [options.c_output_dir, options.h_output_dir]) diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py new file mode 100644 index 0000000000..f63c9fc166 --- /dev/null +++ b/tools/dtoc/src_scan.py @@ -0,0 +1,185 @@ +#!/usr/bin/python +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2017 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# + +"""Scanning of U-Boot source for drivers and structs + +This scans the source tree to find out things about all instances of +U_BOOT_DRIVER(), UCLASS_DRIVER and all struct declarations in header files. + +See doc/driver-model/of-plat.rst for more informaiton +""" + +import os +import re +import sys + + +def conv_name_to_c(name): + """Convert a device-tree name to a C identifier + + This uses multiple replace() calls instead of re.sub() since it is faster + (400ms for 1m calls versus 1000ms for the 're' version). + + Args: + name (str): Name to convert + Return: + str: String containing the C version of this name + """ + new = name.replace('@', '_at_') + new = new.replace('-', '_') + new = new.replace(',', '_') + new = new.replace('.', '_') + return new + +def get_compat_name(node): + """Get the node's list of compatible string as a C identifiers + + Args: + node (fdt.Node): Node object to check + Return: + list of str: List of C identifiers for all the compatible strings + """ + compat = node.props['compatible'].value + if not isinstance(compat, list): + compat = [compat] + return [conv_name_to_c(c) for c in compat] + + +class Driver: + """Information about a driver in U-Boot + + Attributes: + name: Name of driver. For U_BOOT_DRIVER(x) this is 'x' + """ + def __init__(self, name): + self.name = name + + def __eq__(self, other): + return self.name == other.name + + def __repr__(self): + return "Driver(name='%s')" % self.name + + +class Scanner: + """Scanning of the U-Boot source tree + + Properties: + _basedir (str): Base directory of U-Boot source code. Defaults to the + grandparent of this file's directory + _drivers: Dict of valid driver names found in drivers/ + key: Driver name + value: Driver for that driver + _driver_aliases: Dict that holds aliases for driver names + key: Driver alias declared with + DM_DRIVER_ALIAS(driver_alias, driver_name) + value: Driver name declared with U_BOOT_DRIVER(driver_name) + _warning_disabled: true to disable warnings about driver names not found + _drivers_additional (list or str): List of additional drivers to use + during scanning + """ + def __init__(self, basedir, warning_disabled, drivers_additional): + """Set up a new Scanner + """ + if not basedir: + basedir = sys.argv[0].replace('tools/dtoc/dtoc', '') + if basedir == '': + basedir = './' + self._basedir = basedir + self._drivers = {} + self._driver_aliases = {} + self._drivers_additional = drivers_additional or [] + self._warning_disabled = warning_disabled + + def get_normalized_compat_name(self, node): + """Get a node's normalized compat name + + Returns a valid driver name by retrieving node's list of compatible + string as a C identifier and performing a check against _drivers + and a lookup in driver_aliases printing a warning in case of failure. + + Args: + node (Node): Node object to check + Return: + Tuple: + Driver name associated with the first compatible string + List of C identifiers for all the other compatible strings + (possibly empty) + In case of no match found, the return will be the same as + get_compat_name() + """ + compat_list_c = get_compat_name(node) + + for compat_c in compat_list_c: + if not compat_c in self._drivers.keys(): + compat_c = self._driver_aliases.get(compat_c) + if not compat_c: + continue + + aliases_c = compat_list_c + if compat_c in aliases_c: + aliases_c.remove(compat_c) + return compat_c, aliases_c + + if not self._warning_disabled: + print('WARNING: the driver %s was not found in the driver list' + % (compat_list_c[0])) + + return compat_list_c[0], compat_list_c[1:] + + def scan_driver(self, fname): + """Scan a driver file to build a list of driver names and aliases + + This procedure will populate self._drivers and self._driver_aliases + + Args + fname: Driver filename to scan + """ + with open(fname, encoding='utf-8') as inf: + try: + buff = inf.read() + except UnicodeDecodeError: + # This seems to happen on older Python versions + print("Skipping file '%s' due to unicode error" % fname) + return + + # The following re will search for driver names declared as + # U_BOOT_DRIVER(driver_name) + drivers = re.findall(r'U_BOOT_DRIVER\((.*)\)', buff) + + for driver in drivers: + self._drivers[driver] = Driver(driver) + + # The following re will search for driver aliases declared as + # DM_DRIVER_ALIAS(alias, driver_name) + driver_aliases = re.findall( + r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)', + buff) + + for alias in driver_aliases: # pragma: no cover + if len(alias) != 2: + continue + self._driver_aliases[alias[1]] = alias[0] + + def scan_drivers(self): + """Scan the driver folders to build a list of driver names and aliases + + This procedure will populate self._drivers and self._driver_aliases + """ + for (dirpath, _, filenames) in os.walk(self._basedir): + for fname in filenames: + if not fname.endswith('.c'): + continue + self.scan_driver(dirpath + '/' + fname) + + for fname in self._drivers_additional: + if not isinstance(fname, str) or len(fname) == 0: + continue + if fname[0] == '/': + self.scan_driver(fname) + else: + self.scan_driver(self._basedir + '/' + fname) diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index a5836e04b7..d961d67b8f 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -10,29 +10,29 @@ tool. """ import collections +import glob import os import struct -import sys -import tempfile import unittest -from dtoc import dtb_platdata -from dtb_platdata import conv_name_to_c -from dtb_platdata import get_compat_name from dtb_platdata import get_value from dtb_platdata import tab_to +from dtoc import dtb_platdata from dtoc import fdt from dtoc import fdt_util +from dtoc.src_scan import conv_name_to_c +from dtoc.src_scan import get_compat_name from patman import test_util from patman import tools -our_path = os.path.dirname(os.path.realpath(__file__)) +OUR_PATH = os.path.dirname(os.path.realpath(__file__)) HEADER = '''/* * DO NOT MODIFY * - * This file was generated by dtoc from a .dtb (device tree binary) file. + * Defines the structs used to hold devicetree data. + * This was generated by dtoc from a .dtb (device tree binary) file. */ #include <stdbool.h> @@ -41,33 +41,33 @@ HEADER = '''/* C_HEADER = '''/* * DO NOT MODIFY * - * This file was generated by dtoc from a .dtb (device tree binary) file. + * Declares the U_BOOT_DRIVER() records and platform data. + * This was generated by dtoc from a .dtb (device tree binary) file. */ -/* Allow use of U_BOOT_DEVICE() in this file */ -#define DT_PLATDATA_C +/* Allow use of U_BOOT_DRVINFO() in this file */ +#define DT_PLAT_C #include <common.h> #include <dm.h> #include <dt-structs.h> ''' -C_EMPTY_POPULATE_PHANDLE_DATA = '''void dm_populate_phandle_data(void) { -} -''' - +# This is a test so is allowed to access private things in the module it is +# testing +# pylint: disable=W0212 def get_dtb_file(dts_fname, capture_stderr=False): """Compile a .dts file to a .dtb Args: - dts_fname: Filename of .dts file in the current directory - capture_stderr: True to capture and discard stderr output + dts_fname (str): Filename of .dts file in the current directory + capture_stderr (bool): True to capture and discard stderr output Returns: - Filename of compiled file in output directory + str: Filename of compiled file in output directory """ - return fdt_util.EnsureCompiled(os.path.join(our_path, dts_fname), + return fdt_util.EnsureCompiled(os.path.join(OUR_PATH, dts_fname), capture_stderr=capture_stderr) @@ -80,20 +80,21 @@ class TestDtoc(unittest.TestCase): @classmethod def tearDownClass(cls): - tools._RemoveOutputDir() + tools.FinaliseOutputDir() - def _WritePythonString(self, fname, data): + @staticmethod + def _write_python_string(fname, data): """Write a string with tabs expanded as done in this Python file Args: - fname: Filename to write to - data: Raw string to convert + fname (str): Filename to write to + data (str): Raw string to convert """ data = data.replace('\t', '\\t') - with open(fname, 'w') as fd: - fd.write(data) + with open(fname, 'w') as fout: + fout.write(data) - def _CheckStrings(self, expected, actual): + def _check_strings(self, expected, actual): """Check that a string matches its expected value If the strings do not match, they are written to the /tmp directory in @@ -101,18 +102,25 @@ class TestDtoc(unittest.TestCase): easy comparison and update of the tests. Args: - expected: Expected string - actual: Actual string + expected (str): Expected string + actual (str): Actual string """ if expected != actual: - self._WritePythonString('/tmp/binman.expected', expected) - self._WritePythonString('/tmp/binman.actual', actual) + self._write_python_string('/tmp/binman.expected', expected) + self._write_python_string('/tmp/binman.actual', actual) print('Failures written to /tmp/binman.{expected,actual}') - self.assertEquals(expected, actual) + self.assertEqual(expected, actual) + @staticmethod + def run_test(args, dtb_file, output): + """Run a test using dtoc - def run_test(self, args, dtb_file, output): - dtb_platdata.run_steps(args, dtb_file, False, output, True) + Args: + args (list of str): List of arguments for dtoc + dtb_file (str): Filename of .dtb file + output (str): Filename of output file + """ + dtb_platdata.run_steps(args, dtb_file, False, output, [], True) def test_name(self): """Test conversion of device tree names to C identifiers""" @@ -134,13 +142,13 @@ class TestDtoc(unittest.TestCase): def test_get_value(self): """Test operation of get_value() function""" self.assertEqual('0x45', - get_value(fdt.TYPE_INT, struct.pack('>I', 0x45))) + get_value(fdt.Type.INT, struct.pack('>I', 0x45))) self.assertEqual('0x45', - get_value(fdt.TYPE_BYTE, struct.pack('<I', 0x45))) + get_value(fdt.Type.BYTE, struct.pack('<I', 0x45))) self.assertEqual('0x0', - get_value(fdt.TYPE_BYTE, struct.pack('>I', 0x45))) - self.assertEqual('"test"', get_value(fdt.TYPE_STRING, 'test')) - self.assertEqual('true', get_value(fdt.TYPE_BOOL, None)) + get_value(fdt.Type.BYTE, struct.pack('>I', 0x45))) + self.assertEqual('"test"', get_value(fdt.Type.STRING, 'test')) + self.assertEqual('true', get_value(fdt.Type.BOOL, None)) def test_get_compat_name(self): """Test operation of get_compat_name() function""" @@ -160,7 +168,7 @@ class TestDtoc(unittest.TestCase): prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third']) node = Node({'compatible': prop}) self.assertEqual((['rockchip_rk3399_sdhci_5_1', - 'arasan_sdhci_5_1', 'third']), + 'arasan_sdhci_5_1', 'third']), get_compat_name(node)) def test_empty_file(self): @@ -175,17 +183,9 @@ class TestDtoc(unittest.TestCase): self.run_test(['platdata'], dtb_file, output) with open(output) as infile: lines = infile.read().splitlines() - self.assertEqual(C_HEADER.splitlines() + [''] + - C_EMPTY_POPULATE_PHANDLE_DATA.splitlines(), lines) + self.assertEqual(C_HEADER.splitlines() + [''], lines) - def test_simple(self): - """Test output from some simple nodes with various types of data""" - dtb_file = get_dtb_file('dtoc_test_simple.dts') - output = tools.GetOutputFilename('output') - self.run_test(['struct'], dtb_file, output) - with open(output) as infile: - data = infile.read() - self._CheckStrings(HEADER + ''' + struct_text = HEADER + ''' struct dtd_sandbox_i2c_test { }; struct dtd_sandbox_pmic_test { @@ -204,21 +204,16 @@ struct dtd_sandbox_spl_test { \tconst char *\tstringarray[3]; \tconst char *\tstringval; }; -struct dtd_sandbox_spl_test_2 { -}; -''', data) +''' - self.run_test(['platdata'], dtb_file, output) - with open(output) as infile: - data = infile.read() - self._CheckStrings(C_HEADER + ''' + platdata_text = C_HEADER + ''' /* Node /i2c@0 index 0 */ static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = { }; -U_BOOT_DEVICE(i2c_at_0) = { +U_BOOT_DRVINFO(i2c_at_0) = { \t.name\t\t= "sandbox_i2c_test", -\t.platdata\t= &dtv_i2c_at_0, -\t.platdata_size\t= sizeof(dtv_i2c_at_0), +\t.plat\t= &dtv_i2c_at_0, +\t.plat_size\t= sizeof(dtv_i2c_at_0), \t.parent_idx\t= -1, }; @@ -227,10 +222,10 @@ static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = { \t.low_power\t\t= true, \t.reg\t\t\t= {0x9, 0x0}, }; -U_BOOT_DEVICE(pmic_at_9) = { +U_BOOT_DRVINFO(pmic_at_9) = { \t.name\t\t= "sandbox_pmic_test", -\t.platdata\t= &dtv_pmic_at_9, -\t.platdata_size\t= sizeof(dtv_pmic_at_9), +\t.plat\t= &dtv_pmic_at_9, +\t.plat_size\t= sizeof(dtv_pmic_at_9), \t.parent_idx\t= 0, }; @@ -247,10 +242,10 @@ static struct dtd_sandbox_spl_test dtv_spl_test = { \t.stringarray\t\t= {"multi-word", "message", ""}, \t.stringval\t\t= "message", }; -U_BOOT_DEVICE(spl_test) = { +U_BOOT_DRVINFO(spl_test) = { \t.name\t\t= "sandbox_spl_test", -\t.platdata\t= &dtv_spl_test, -\t.platdata_size\t= sizeof(dtv_spl_test), +\t.plat\t= &dtv_spl_test, +\t.plat_size\t= sizeof(dtv_spl_test), \t.parent_idx\t= -1, }; @@ -266,10 +261,10 @@ static struct dtd_sandbox_spl_test dtv_spl_test2 = { \t.stringarray\t\t= {"another", "multi-word", "message"}, \t.stringval\t\t= "message2", }; -U_BOOT_DEVICE(spl_test2) = { +U_BOOT_DRVINFO(spl_test2) = { \t.name\t\t= "sandbox_spl_test", -\t.platdata\t= &dtv_spl_test2, -\t.platdata_size\t= sizeof(dtv_spl_test2), +\t.plat\t= &dtv_spl_test2, +\t.plat_size\t= sizeof(dtv_spl_test2), \t.parent_idx\t= -1, }; @@ -279,24 +274,35 @@ static struct dtd_sandbox_spl_test dtv_spl_test3 = { \t\t0x0}, \t.stringarray\t\t= {"one", "", ""}, }; -U_BOOT_DEVICE(spl_test3) = { +U_BOOT_DRVINFO(spl_test3) = { \t.name\t\t= "sandbox_spl_test", -\t.platdata\t= &dtv_spl_test3, -\t.platdata_size\t= sizeof(dtv_spl_test3), +\t.plat\t= &dtv_spl_test3, +\t.plat_size\t= sizeof(dtv_spl_test3), \t.parent_idx\t= -1, }; -/* Node /spl-test4 index 5 */ -static struct dtd_sandbox_spl_test_2 dtv_spl_test4 = { -}; -U_BOOT_DEVICE(spl_test4) = { -\t.name\t\t= "sandbox_spl_test_2", -\t.platdata\t= &dtv_spl_test4, -\t.platdata_size\t= sizeof(dtv_spl_test4), -\t.parent_idx\t= -1, -}; +''' -''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) + def test_simple(self): + """Test output from some simple nodes with various types of data""" + dtb_file = get_dtb_file('dtoc_test_simple.dts') + output = tools.GetOutputFilename('output') + self.run_test(['struct'], dtb_file, output) + with open(output) as infile: + data = infile.read() + + self._check_strings(self.struct_text, data) + + self.run_test(['platdata'], dtb_file, output) + with open(output) as infile: + data = infile.read() + + self._check_strings(self.platdata_text, data) + + # Try the 'all' command + self.run_test(['all'], dtb_file, output) + data = tools.ReadFile(output, binary=False) + self._check_strings(self.platdata_text + self.struct_text, data) def test_driver_alias(self): """Test output from a device tree file with a driver alias""" @@ -305,7 +311,7 @@ U_BOOT_DEVICE(spl_test4) = { self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_sandbox_gpio { \tconst char *\tgpio_bank_name; \tbool\t\tgpio_controller; @@ -316,54 +322,50 @@ struct dtd_sandbox_gpio { self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /gpios@0 index 0 */ static struct dtd_sandbox_gpio dtv_gpios_at_0 = { \t.gpio_bank_name\t\t= "a", \t.gpio_controller\t= true, \t.sandbox_gpio_count\t= 0x14, }; -U_BOOT_DEVICE(gpios_at_0) = { +U_BOOT_DRVINFO(gpios_at_0) = { \t.name\t\t= "sandbox_gpio", -\t.platdata\t= &dtv_gpios_at_0, -\t.platdata_size\t= sizeof(dtv_gpios_at_0), +\t.plat\t= &dtv_gpios_at_0, +\t.plat_size\t= sizeof(dtv_gpios_at_0), \t.parent_idx\t= -1, }; -void dm_populate_phandle_data(void) { -} ''', data) def test_invalid_driver(self): """Test output from a device tree file with an invalid driver""" dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts') output = tools.GetOutputFilename('output') - with test_util.capture_sys_output() as (stdout, stderr): - dtb_platdata.run_steps(['struct'], dtb_file, False, output) + with test_util.capture_sys_output() as _: + dtb_platdata.run_steps(['struct'], dtb_file, False, output, []) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_invalid { }; ''', data) - with test_util.capture_sys_output() as (stdout, stderr): - dtb_platdata.run_steps(['platdata'], dtb_file, False, output) + with test_util.capture_sys_output() as _: + dtb_platdata.run_steps(['platdata'], dtb_file, False, output, []) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /spl-test index 0 */ static struct dtd_invalid dtv_spl_test = { }; -U_BOOT_DEVICE(spl_test) = { +U_BOOT_DRVINFO(spl_test) = { \t.name\t\t= "invalid", -\t.platdata\t= &dtv_spl_test, -\t.platdata_size\t= sizeof(dtv_spl_test), +\t.plat\t= &dtv_spl_test, +\t.plat_size\t= sizeof(dtv_spl_test), \t.parent_idx\t= -1, }; -void dm_populate_phandle_data(void) { -} ''', data) def test_phandle(self): @@ -373,7 +375,7 @@ void dm_populate_phandle_data(void) { self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_source { \tstruct phandle_2_arg clocks[4]; }; @@ -385,15 +387,15 @@ struct dtd_target { self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /phandle2-target index 0 */ static struct dtd_target dtv_phandle2_target = { \t.intval\t\t\t= 0x1, }; -U_BOOT_DEVICE(phandle2_target) = { +U_BOOT_DRVINFO(phandle2_target) = { \t.name\t\t= "target", -\t.platdata\t= &dtv_phandle2_target, -\t.platdata_size\t= sizeof(dtv_phandle2_target), +\t.plat\t= &dtv_phandle2_target, +\t.plat_size\t= sizeof(dtv_phandle2_target), \t.parent_idx\t= -1, }; @@ -401,21 +403,10 @@ U_BOOT_DEVICE(phandle2_target) = { static struct dtd_target dtv_phandle3_target = { \t.intval\t\t\t= 0x2, }; -U_BOOT_DEVICE(phandle3_target) = { +U_BOOT_DRVINFO(phandle3_target) = { \t.name\t\t= "target", -\t.platdata\t= &dtv_phandle3_target, -\t.platdata_size\t= sizeof(dtv_phandle3_target), -\t.parent_idx\t= -1, -}; - -/* Node /phandle-target index 4 */ -static struct dtd_target dtv_phandle_target = { -\t.intval\t\t\t= 0x0, -}; -U_BOOT_DEVICE(phandle_target) = { -\t.name\t\t= "target", -\t.platdata\t= &dtv_phandle_target, -\t.platdata_size\t= sizeof(dtv_phandle_target), +\t.plat\t= &dtv_phandle3_target, +\t.plat_size\t= sizeof(dtv_phandle3_target), \t.parent_idx\t= -1, }; @@ -427,10 +418,10 @@ static struct dtd_source dtv_phandle_source = { \t\t\t{1, {12, 13}}, \t\t\t{4, {}},}, }; -U_BOOT_DEVICE(phandle_source) = { +U_BOOT_DRVINFO(phandle_source) = { \t.name\t\t= "source", -\t.platdata\t= &dtv_phandle_source, -\t.platdata_size\t= sizeof(dtv_phandle_source), +\t.plat\t= &dtv_phandle_source, +\t.plat_size\t= sizeof(dtv_phandle_source), \t.parent_idx\t= -1, }; @@ -439,15 +430,24 @@ static struct dtd_source dtv_phandle_source2 = { \t.clocks\t\t\t= { \t\t\t{4, {}},}, }; -U_BOOT_DEVICE(phandle_source2) = { +U_BOOT_DRVINFO(phandle_source2) = { \t.name\t\t= "source", -\t.platdata\t= &dtv_phandle_source2, -\t.platdata_size\t= sizeof(dtv_phandle_source2), +\t.plat\t= &dtv_phandle_source2, +\t.plat_size\t= sizeof(dtv_phandle_source2), +\t.parent_idx\t= -1, +}; + +/* Node /phandle-target index 4 */ +static struct dtd_target dtv_phandle_target = { +\t.intval\t\t\t= 0x0, +}; +U_BOOT_DRVINFO(phandle_target) = { +\t.name\t\t= "target", +\t.plat\t= &dtv_phandle_target, +\t.plat_size\t= sizeof(dtv_phandle_target), \t.parent_idx\t= -1, }; -void dm_populate_phandle_data(void) { -} ''', data) def test_phandle_single(self): @@ -457,7 +457,7 @@ void dm_populate_phandle_data(void) { self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_source { \tstruct phandle_0_arg clocks[1]; }; @@ -473,49 +473,47 @@ struct dtd_target { self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' -/* Node /phandle-target index 1 */ -static struct dtd_target dtv_phandle_target = { -}; -U_BOOT_DEVICE(phandle_target) = { -\t.name\t\t= "target", -\t.platdata\t= &dtv_phandle_target, -\t.platdata_size\t= sizeof(dtv_phandle_target), -\t.parent_idx\t= -1, -}; - + self._check_strings(C_HEADER + ''' /* Node /phandle-source2 index 0 */ static struct dtd_source dtv_phandle_source2 = { \t.clocks\t\t\t= { \t\t\t{1, {}},}, }; -U_BOOT_DEVICE(phandle_source2) = { +U_BOOT_DRVINFO(phandle_source2) = { \t.name\t\t= "source", -\t.platdata\t= &dtv_phandle_source2, -\t.platdata_size\t= sizeof(dtv_phandle_source2), +\t.plat\t= &dtv_phandle_source2, +\t.plat_size\t= sizeof(dtv_phandle_source2), +\t.parent_idx\t= -1, +}; + +/* Node /phandle-target index 1 */ +static struct dtd_target dtv_phandle_target = { +}; +U_BOOT_DRVINFO(phandle_target) = { +\t.name\t\t= "target", +\t.plat\t= &dtv_phandle_target, +\t.plat_size\t= sizeof(dtv_phandle_target), \t.parent_idx\t= -1, }; -void dm_populate_phandle_data(void) { -} ''', data) def test_phandle_cd_gpio(self): """Test that phandle targets are generated when unsing cd-gpios""" dtb_file = get_dtb_file('dtoc_test_phandle_cd_gpios.dts') output = tools.GetOutputFilename('output') - dtb_platdata.run_steps(['platdata'], dtb_file, False, output, True) + dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [], True) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /phandle2-target index 0 */ static struct dtd_target dtv_phandle2_target = { \t.intval\t\t\t= 0x1, }; -U_BOOT_DEVICE(phandle2_target) = { +U_BOOT_DRVINFO(phandle2_target) = { \t.name\t\t= "target", -\t.platdata\t= &dtv_phandle2_target, -\t.platdata_size\t= sizeof(dtv_phandle2_target), +\t.plat\t= &dtv_phandle2_target, +\t.plat_size\t= sizeof(dtv_phandle2_target), \t.parent_idx\t= -1, }; @@ -523,21 +521,10 @@ U_BOOT_DEVICE(phandle2_target) = { static struct dtd_target dtv_phandle3_target = { \t.intval\t\t\t= 0x2, }; -U_BOOT_DEVICE(phandle3_target) = { -\t.name\t\t= "target", -\t.platdata\t= &dtv_phandle3_target, -\t.platdata_size\t= sizeof(dtv_phandle3_target), -\t.parent_idx\t= -1, -}; - -/* Node /phandle-target index 4 */ -static struct dtd_target dtv_phandle_target = { -\t.intval\t\t\t= 0x0, -}; -U_BOOT_DEVICE(phandle_target) = { +U_BOOT_DRVINFO(phandle3_target) = { \t.name\t\t= "target", -\t.platdata\t= &dtv_phandle_target, -\t.platdata_size\t= sizeof(dtv_phandle_target), +\t.plat\t= &dtv_phandle3_target, +\t.plat_size\t= sizeof(dtv_phandle3_target), \t.parent_idx\t= -1, }; @@ -549,10 +536,10 @@ static struct dtd_source dtv_phandle_source = { \t\t\t{1, {12, 13}}, \t\t\t{4, {}},}, }; -U_BOOT_DEVICE(phandle_source) = { +U_BOOT_DRVINFO(phandle_source) = { \t.name\t\t= "source", -\t.platdata\t= &dtv_phandle_source, -\t.platdata_size\t= sizeof(dtv_phandle_source), +\t.plat\t= &dtv_phandle_source, +\t.plat_size\t= sizeof(dtv_phandle_source), \t.parent_idx\t= -1, }; @@ -561,15 +548,24 @@ static struct dtd_source dtv_phandle_source2 = { \t.cd_gpios\t\t= { \t\t\t{4, {}},}, }; -U_BOOT_DEVICE(phandle_source2) = { +U_BOOT_DRVINFO(phandle_source2) = { \t.name\t\t= "source", -\t.platdata\t= &dtv_phandle_source2, -\t.platdata_size\t= sizeof(dtv_phandle_source2), +\t.plat\t= &dtv_phandle_source2, +\t.plat_size\t= sizeof(dtv_phandle_source2), +\t.parent_idx\t= -1, +}; + +/* Node /phandle-target index 4 */ +static struct dtd_target dtv_phandle_target = { +\t.intval\t\t\t= 0x0, +}; +U_BOOT_DRVINFO(phandle_target) = { +\t.name\t\t= "target", +\t.plat\t= &dtv_phandle_target, +\t.plat_size\t= sizeof(dtv_phandle_target), \t.parent_idx\t= -1, }; -void dm_populate_phandle_data(void) { -} ''', data) def test_phandle_bad(self): @@ -577,20 +573,20 @@ void dm_populate_phandle_data(void) { dtb_file = get_dtb_file('dtoc_test_phandle_bad.dts', capture_stderr=True) output = tools.GetOutputFilename('output') - with self.assertRaises(ValueError) as e: + with self.assertRaises(ValueError) as exc: self.run_test(['struct'], dtb_file, output) self.assertIn("Cannot parse 'clocks' in node 'phandle-source'", - str(e.exception)) + str(exc.exception)) def test_phandle_bad2(self): """Test a phandle target missing its #*-cells property""" dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts', capture_stderr=True) output = tools.GetOutputFilename('output') - with self.assertRaises(ValueError) as e: + with self.assertRaises(ValueError) as exc: self.run_test(['struct'], dtb_file, output) self.assertIn("Node 'phandle-target' has no cells property", - str(e.exception)) + str(exc.exception)) def test_addresses64(self): """Test output from a node with a 'reg' property with na=2, ns=2""" @@ -599,7 +595,7 @@ void dm_populate_phandle_data(void) { self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_test1 { \tfdt64_t\t\treg[2]; }; @@ -614,15 +610,15 @@ struct dtd_test3 { self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /test1 index 0 */ static struct dtd_test1 dtv_test1 = { \t.reg\t\t\t= {0x1234, 0x5678}, }; -U_BOOT_DEVICE(test1) = { +U_BOOT_DRVINFO(test1) = { \t.name\t\t= "test1", -\t.platdata\t= &dtv_test1, -\t.platdata_size\t= sizeof(dtv_test1), +\t.plat\t= &dtv_test1, +\t.plat_size\t= sizeof(dtv_test1), \t.parent_idx\t= -1, }; @@ -630,10 +626,10 @@ U_BOOT_DEVICE(test1) = { static struct dtd_test2 dtv_test2 = { \t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654}, }; -U_BOOT_DEVICE(test2) = { +U_BOOT_DRVINFO(test2) = { \t.name\t\t= "test2", -\t.platdata\t= &dtv_test2, -\t.platdata_size\t= sizeof(dtv_test2), +\t.plat\t= &dtv_test2, +\t.plat_size\t= sizeof(dtv_test2), \t.parent_idx\t= -1, }; @@ -641,14 +637,14 @@ U_BOOT_DEVICE(test2) = { static struct dtd_test3 dtv_test3 = { \t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3}, }; -U_BOOT_DEVICE(test3) = { +U_BOOT_DRVINFO(test3) = { \t.name\t\t= "test3", -\t.platdata\t= &dtv_test3, -\t.platdata_size\t= sizeof(dtv_test3), +\t.plat\t= &dtv_test3, +\t.plat_size\t= sizeof(dtv_test3), \t.parent_idx\t= -1, }; -''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) +''', data) def test_addresses32(self): """Test output from a node with a 'reg' property with na=1, ns=1""" @@ -657,7 +653,7 @@ U_BOOT_DEVICE(test3) = { self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_test1 { \tfdt32_t\t\treg[2]; }; @@ -669,15 +665,15 @@ struct dtd_test2 { self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /test1 index 0 */ static struct dtd_test1 dtv_test1 = { \t.reg\t\t\t= {0x1234, 0x5678}, }; -U_BOOT_DEVICE(test1) = { +U_BOOT_DRVINFO(test1) = { \t.name\t\t= "test1", -\t.platdata\t= &dtv_test1, -\t.platdata_size\t= sizeof(dtv_test1), +\t.plat\t= &dtv_test1, +\t.plat_size\t= sizeof(dtv_test1), \t.parent_idx\t= -1, }; @@ -685,14 +681,14 @@ U_BOOT_DEVICE(test1) = { static struct dtd_test2 dtv_test2 = { \t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3}, }; -U_BOOT_DEVICE(test2) = { +U_BOOT_DRVINFO(test2) = { \t.name\t\t= "test2", -\t.platdata\t= &dtv_test2, -\t.platdata_size\t= sizeof(dtv_test2), +\t.plat\t= &dtv_test2, +\t.plat_size\t= sizeof(dtv_test2), \t.parent_idx\t= -1, }; -''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) +''', data) def test_addresses64_32(self): """Test output from a node with a 'reg' property with na=2, ns=1""" @@ -701,7 +697,7 @@ U_BOOT_DEVICE(test2) = { self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_test1 { \tfdt64_t\t\treg[2]; }; @@ -716,15 +712,15 @@ struct dtd_test3 { self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /test1 index 0 */ static struct dtd_test1 dtv_test1 = { \t.reg\t\t\t= {0x123400000000, 0x5678}, }; -U_BOOT_DEVICE(test1) = { +U_BOOT_DRVINFO(test1) = { \t.name\t\t= "test1", -\t.platdata\t= &dtv_test1, -\t.platdata_size\t= sizeof(dtv_test1), +\t.plat\t= &dtv_test1, +\t.plat_size\t= sizeof(dtv_test1), \t.parent_idx\t= -1, }; @@ -732,10 +728,10 @@ U_BOOT_DEVICE(test1) = { static struct dtd_test2 dtv_test2 = { \t.reg\t\t\t= {0x1234567890123456, 0x98765432}, }; -U_BOOT_DEVICE(test2) = { +U_BOOT_DRVINFO(test2) = { \t.name\t\t= "test2", -\t.platdata\t= &dtv_test2, -\t.platdata_size\t= sizeof(dtv_test2), +\t.plat\t= &dtv_test2, +\t.plat_size\t= sizeof(dtv_test2), \t.parent_idx\t= -1, }; @@ -743,14 +739,14 @@ U_BOOT_DEVICE(test2) = { static struct dtd_test3 dtv_test3 = { \t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3}, }; -U_BOOT_DEVICE(test3) = { +U_BOOT_DRVINFO(test3) = { \t.name\t\t= "test3", -\t.platdata\t= &dtv_test3, -\t.platdata_size\t= sizeof(dtv_test3), +\t.plat\t= &dtv_test3, +\t.plat_size\t= sizeof(dtv_test3), \t.parent_idx\t= -1, }; -''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) +''', data) def test_addresses32_64(self): """Test output from a node with a 'reg' property with na=1, ns=2""" @@ -759,7 +755,7 @@ U_BOOT_DEVICE(test3) = { self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_test1 { \tfdt64_t\t\treg[2]; }; @@ -774,15 +770,15 @@ struct dtd_test3 { self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /test1 index 0 */ static struct dtd_test1 dtv_test1 = { \t.reg\t\t\t= {0x1234, 0x567800000000}, }; -U_BOOT_DEVICE(test1) = { +U_BOOT_DRVINFO(test1) = { \t.name\t\t= "test1", -\t.platdata\t= &dtv_test1, -\t.platdata_size\t= sizeof(dtv_test1), +\t.plat\t= &dtv_test1, +\t.plat_size\t= sizeof(dtv_test1), \t.parent_idx\t= -1, }; @@ -790,10 +786,10 @@ U_BOOT_DEVICE(test1) = { static struct dtd_test2 dtv_test2 = { \t.reg\t\t\t= {0x12345678, 0x9876543210987654}, }; -U_BOOT_DEVICE(test2) = { +U_BOOT_DRVINFO(test2) = { \t.name\t\t= "test2", -\t.platdata\t= &dtv_test2, -\t.platdata_size\t= sizeof(dtv_test2), +\t.plat\t= &dtv_test2, +\t.plat_size\t= sizeof(dtv_test2), \t.parent_idx\t= -1, }; @@ -801,34 +797,35 @@ U_BOOT_DEVICE(test2) = { static struct dtd_test3 dtv_test3 = { \t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3}, }; -U_BOOT_DEVICE(test3) = { +U_BOOT_DRVINFO(test3) = { \t.name\t\t= "test3", -\t.platdata\t= &dtv_test3, -\t.platdata_size\t= sizeof(dtv_test3), +\t.plat\t= &dtv_test3, +\t.plat_size\t= sizeof(dtv_test3), \t.parent_idx\t= -1, }; -''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) +''', data) def test_bad_reg(self): """Test that a reg property with an invalid type generates an error""" # Capture stderr since dtc will emit warnings for this file dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True) output = tools.GetOutputFilename('output') - with self.assertRaises(ValueError) as e: + with self.assertRaises(ValueError) as exc: self.run_test(['struct'], dtb_file, output) self.assertIn("Node 'spl-test' reg property is not an int", - str(e.exception)) + str(exc.exception)) def test_bad_reg2(self): """Test that a reg property with an invalid cell count is detected""" # Capture stderr since dtc will emit warnings for this file dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True) output = tools.GetOutputFilename('output') - with self.assertRaises(ValueError) as e: + with self.assertRaises(ValueError) as exc: self.run_test(['struct'], dtb_file, output) - self.assertIn("Node 'spl-test' reg property has 3 cells which is not a multiple of na + ns = 1 + 1)", - str(e.exception)) + self.assertIn( + "Node 'spl-test' reg property has 3 cells which is not a multiple of na + ns = 1 + 1)", + str(exc.exception)) def test_add_prop(self): """Test that a subequent node can add a new property to a struct""" @@ -837,7 +834,7 @@ U_BOOT_DEVICE(test3) = { self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(HEADER + ''' + self._check_strings(HEADER + ''' struct dtd_sandbox_spl_test { \tfdt32_t\t\tintarray; \tfdt32_t\t\tintval; @@ -847,15 +844,15 @@ struct dtd_sandbox_spl_test { self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() - self._CheckStrings(C_HEADER + ''' + self._check_strings(C_HEADER + ''' /* Node /spl-test index 0 */ static struct dtd_sandbox_spl_test dtv_spl_test = { \t.intval\t\t\t= 0x1, }; -U_BOOT_DEVICE(spl_test) = { +U_BOOT_DRVINFO(spl_test) = { \t.name\t\t= "sandbox_spl_test", -\t.platdata\t= &dtv_spl_test, -\t.platdata_size\t= sizeof(dtv_spl_test), +\t.plat\t= &dtv_spl_test, +\t.plat_size\t= sizeof(dtv_spl_test), \t.parent_idx\t= -1, }; @@ -863,58 +860,70 @@ U_BOOT_DEVICE(spl_test) = { static struct dtd_sandbox_spl_test dtv_spl_test2 = { \t.intarray\t\t= 0x5, }; -U_BOOT_DEVICE(spl_test2) = { +U_BOOT_DRVINFO(spl_test2) = { \t.name\t\t= "sandbox_spl_test", -\t.platdata\t= &dtv_spl_test2, -\t.platdata_size\t= sizeof(dtv_spl_test2), +\t.plat\t= &dtv_spl_test2, +\t.plat_size\t= sizeof(dtv_spl_test2), \t.parent_idx\t= -1, }; -''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) +''', data) - def testStdout(self): + def test_stdout(self): """Test output to stdout""" dtb_file = get_dtb_file('dtoc_test_simple.dts') - with test_util.capture_sys_output() as (stdout, stderr): - self.run_test(['struct'], dtb_file, '-') + with test_util.capture_sys_output() as (stdout, _): + self.run_test(['struct'], dtb_file, None) + self._check_strings(self.struct_text, stdout.getvalue()) - def testNoCommand(self): + def test_multi_to_file(self): + """Test output of multiple pieces to a single file""" + dtb_file = get_dtb_file('dtoc_test_simple.dts') + output = tools.GetOutputFilename('output') + self.run_test(['all'], dtb_file, output) + data = tools.ReadFile(output, binary=False) + self._check_strings(self.platdata_text + self.struct_text, data) + + def test_no_command(self): """Test running dtoc without a command""" - with self.assertRaises(ValueError) as e: + with self.assertRaises(ValueError) as exc: self.run_test([], '', '') self.assertIn("Please specify a command: struct, platdata", - str(e.exception)) + str(exc.exception)) - def testBadCommand(self): + def test_bad_command(self): """Test running dtoc with an invalid command""" dtb_file = get_dtb_file('dtoc_test_simple.dts') output = tools.GetOutputFilename('output') - with self.assertRaises(ValueError) as e: + with self.assertRaises(ValueError) as exc: self.run_test(['invalid-cmd'], dtb_file, output) - self.assertIn("Unknown command 'invalid-cmd': (use: struct, platdata)", - str(e.exception)) - - def testScanDrivers(self): - """Test running dtoc with additional drivers to scan""" - dtb_file = get_dtb_file('dtoc_test_simple.dts') - output = tools.GetOutputFilename('output') - with test_util.capture_sys_output() as (stdout, stderr): - dtb_platdata.run_steps(['struct'], dtb_file, False, output, True, - [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx']) - - def testUnicodeError(self): - """Test running dtoc with an invalid unicode file + self.assertIn("Unknown command 'invalid-cmd': (use: platdata, struct)", + str(exc.exception)) + + def test_output_conflict(self): + """Test a conflict between and output dirs and output file""" + with self.assertRaises(ValueError) as exc: + dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], True) + self.assertIn("Must specify either output or output_dirs, not both", + str(exc.exception)) + + def test_output_dirs(self): + """Test outputting files to a directory""" + # Remove the directory so that files from other tests are not there + tools._RemoveOutputDir() + tools.PrepareOutputDir(None) - To be able to perform this test without adding a weird text file which - would produce issues when using checkpatch.pl or patman, generate the - file at runtime and then process it. - """ + # This should create the .dts and .dtb in the output directory dtb_file = get_dtb_file('dtoc_test_simple.dts') - output = tools.GetOutputFilename('output') - driver_fn = '/tmp/' + next(tempfile._get_candidate_names()) - with open(driver_fn, 'wb+') as df: - df.write(b'\x81') - - with test_util.capture_sys_output() as (stdout, stderr): - dtb_platdata.run_steps(['struct'], dtb_file, False, output, True, - [driver_fn]) + outdir = tools.GetOutputDir() + fnames = glob.glob(outdir + '/*') + self.assertEqual(2, len(fnames)) + + dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], True) + fnames = glob.glob(outdir + '/*') + self.assertEqual(4, len(fnames)) + + leafs = set(os.path.basename(fname) for fname in fnames) + self.assertEqual( + {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb'}, + leafs) diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py index cfe3e04c7a..dc6943f733 100755 --- a/tools/dtoc/test_fdt.py +++ b/tools/dtoc/test_fdt.py @@ -19,7 +19,7 @@ sys.path.insert(1, os.path.join(our_path, '..')) from dtoc import fdt from dtoc import fdt_util from dtoc.fdt_util import fdt32_to_cpu -from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, BytesToValue +from fdt import Type, BytesToValue import libfdt from patman import command from patman import test_util @@ -46,7 +46,7 @@ def _GetPropertyValue(dtb, node, prop_name): # Add 12, which is sizeof(struct fdt_property), to get to start of data offset = prop.GetOffset() + 12 data = dtb.GetContents()[offset:offset + len(prop.value)] - return prop, [tools.ToChar(x) for x in data] + return prop, [chr(x) for x in data] class TestFdt(unittest.TestCase): @@ -127,7 +127,7 @@ class TestFdt(unittest.TestCase): def testBytesToValue(self): self.assertEqual(BytesToValue(b'this\0is\0'), - (TYPE_STRING, ['this', 'is'])) + (Type.STRING, ['this', 'is'])) class TestNode(unittest.TestCase): """Test operation of the Node class""" @@ -249,46 +249,46 @@ class TestProp(unittest.TestCase): def testMakeProp(self): """Test we can convert all the the types that are supported""" prop = self._ConvertProp('boolval') - self.assertEqual(fdt.TYPE_BOOL, prop.type) + self.assertEqual(Type.BOOL, prop.type) self.assertEqual(True, prop.value) prop = self._ConvertProp('intval') - self.assertEqual(fdt.TYPE_INT, prop.type) + self.assertEqual(Type.INT, prop.type) self.assertEqual(1, fdt32_to_cpu(prop.value)) prop = self._ConvertProp('intarray') - self.assertEqual(fdt.TYPE_INT, prop.type) + self.assertEqual(Type.INT, prop.type) val = [fdt32_to_cpu(val) for val in prop.value] self.assertEqual([2, 3, 4], val) prop = self._ConvertProp('byteval') - self.assertEqual(fdt.TYPE_BYTE, prop.type) + self.assertEqual(Type.BYTE, prop.type) self.assertEqual(5, ord(prop.value)) prop = self._ConvertProp('longbytearray') - self.assertEqual(fdt.TYPE_BYTE, prop.type) + self.assertEqual(Type.BYTE, prop.type) val = [ord(val) for val in prop.value] self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val) prop = self._ConvertProp('stringval') - self.assertEqual(fdt.TYPE_STRING, prop.type) + self.assertEqual(Type.STRING, prop.type) self.assertEqual('message', prop.value) prop = self._ConvertProp('stringarray') - self.assertEqual(fdt.TYPE_STRING, prop.type) + self.assertEqual(Type.STRING, prop.type) self.assertEqual(['multi-word', 'message'], prop.value) prop = self._ConvertProp('notstring') - self.assertEqual(fdt.TYPE_BYTE, prop.type) + self.assertEqual(Type.BYTE, prop.type) val = [ord(val) for val in prop.value] self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val) def testGetEmpty(self): """Tests the GetEmpty() function for the various supported types""" - self.assertEqual(True, fdt.Prop.GetEmpty(fdt.TYPE_BOOL)) - self.assertEqual(chr(0), fdt.Prop.GetEmpty(fdt.TYPE_BYTE)) - self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(fdt.TYPE_INT)) - self.assertEqual('', fdt.Prop.GetEmpty(fdt.TYPE_STRING)) + self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL)) + self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE)) + self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT)) + self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING)) def testGetOffset(self): """Test we can get the offset of a property""" @@ -304,13 +304,13 @@ class TestProp(unittest.TestCase): # No action prop2 = node2.props['intval'] prop.Widen(prop2) - self.assertEqual(fdt.TYPE_INT, prop.type) + self.assertEqual(Type.INT, prop.type) self.assertEqual(1, fdt32_to_cpu(prop.value)) # Convert singla value to array prop2 = self.node.props['intarray'] prop.Widen(prop2) - self.assertEqual(fdt.TYPE_INT, prop.type) + self.assertEqual(Type.INT, prop.type) self.assertTrue(isinstance(prop.value, list)) # A 4-byte array looks like a single integer. When widened by a longer diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py new file mode 100644 index 0000000000..7d686530d6 --- /dev/null +++ b/tools/dtoc/test_src_scan.py @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2020 Google LLC +# + +"""Tests for the src_scan module + +This includes unit tests for scanning of the source code +""" + +import os +import shutil +import tempfile +import unittest +from unittest import mock + +from dtoc import src_scan +from patman import test_util +from patman import tools + +# This is a test so is allowed to access private things in the module it is +# testing +# pylint: disable=W0212 + +class TestSrcScan(unittest.TestCase): + """Tests for src_scan""" + @classmethod + def setUpClass(cls): + tools.PrepareOutputDir(None) + + @classmethod + def tearDownClass(cls): + tools.FinaliseOutputDir() + + def test_simple(self): + """Simple test of scanning drivers""" + scan = src_scan.Scanner(None, True, None) + scan.scan_drivers() + self.assertIn('sandbox_gpio', scan._drivers) + self.assertIn('sandbox_gpio_alias', scan._driver_aliases) + self.assertEqual('sandbox_gpio', + scan._driver_aliases['sandbox_gpio_alias']) + self.assertNotIn('sandbox_gpio_alias2', scan._driver_aliases) + + def test_additional(self): + """Test with additional drivers to scan""" + scan = src_scan.Scanner( + None, True, [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx']) + scan.scan_drivers() + self.assertIn('sandbox_gpio_alias2', scan._driver_aliases) + self.assertEqual('sandbox_gpio', + scan._driver_aliases['sandbox_gpio_alias2']) + + def test_unicode_error(self): + """Test running dtoc with an invalid unicode file + + To be able to perform this test without adding a weird text file which + would produce issues when using checkpatch.pl or patman, generate the + file at runtime and then process it. + """ + driver_fn = '/tmp/' + next(tempfile._get_candidate_names()) + with open(driver_fn, 'wb+') as fout: + fout.write(b'\x81') + + scan = src_scan.Scanner(None, True, [driver_fn]) + with test_util.capture_sys_output() as (stdout, _): + scan.scan_drivers() + self.assertRegex(stdout.getvalue(), + r"Skipping file '.*' due to unicode error\s*") + + def test_driver(self): + """Test the Driver class""" + drv1 = src_scan.Driver('fred') + drv2 = src_scan.Driver('mary') + drv3 = src_scan.Driver('fred') + self.assertEqual("Driver(name='fred')", str(drv1)) + self.assertEqual(drv1, drv3) + self.assertNotEqual(drv1, drv2) + self.assertNotEqual(drv2, drv3) + + def test_scan_dirs(self): + """Test scanning of source directories""" + def add_file(fname): + pathname = os.path.join(indir, fname) + dirname = os.path.dirname(pathname) + os.makedirs(dirname, exist_ok=True) + tools.WriteFile(pathname, '', binary=False) + fname_list.append(pathname) + + try: + indir = tempfile.mkdtemp(prefix='dtoc.') + + fname_list = [] + add_file('fname.c') + add_file('dir/fname2.c') + + # Mock out scan_driver and check that it is called with the + # expected files + with mock.patch.object(src_scan.Scanner, "scan_driver") as mocked: + scan = src_scan.Scanner(indir, True, None) + scan.scan_drivers() + self.assertEqual(2, len(mocked.mock_calls)) + self.assertEqual(mock.call(fname_list[0]), + mocked.mock_calls[0]) + self.assertEqual(mock.call(fname_list[1]), + mocked.mock_calls[1]) + finally: + shutil.rmtree(indir) diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c new file mode 100644 index 0000000000..270943fc90 --- /dev/null +++ b/tools/mkeficapsule.c @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Linaro Limited + * Author: AKASHI Takahiro + */ + +#include <errno.h> +#include <getopt.h> +#include <malloc.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <linux/types.h> + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "fdt_host.h" + +typedef __u8 u8; +typedef __u16 u16; +typedef __u32 u32; +typedef __u64 u64; +typedef __s16 s16; +typedef __s32 s32; + +#define aligned_u64 __aligned_u64 + +#define SIGNATURE_NODENAME "signature" +#define OVERLAY_NODENAME "__overlay__" + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +#include <efi.h> +#include <efi_api.h> + +static const char *tool_name = "mkeficapsule"; + +efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; +efi_guid_t efi_guid_image_type_uboot_fit = + EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; +efi_guid_t efi_guid_image_type_uboot_raw = + EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; + +static struct option options[] = { + {"fit", required_argument, NULL, 'f'}, + {"raw", required_argument, NULL, 'r'}, + {"index", required_argument, NULL, 'i'}, + {"instance", required_argument, NULL, 'I'}, + {"dtb", required_argument, NULL, 'D'}, + {"public key", required_argument, NULL, 'K'}, + {"overlay", no_argument, NULL, 'O'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0}, +}; + +static void print_usage(void) +{ + printf("Usage: %s [options] <output file>\n" + "Options:\n" + + "\t--fit <fit image> new FIT image file\n" + "\t--raw <raw image> new raw image file\n" + "\t--index <index> update image index\n" + "\t--instance <instance> update hardware instance\n" + "\t--public-key <key file> public key esl file\n" + "\t--dtb <dtb file> dtb file\n" + "\t--overlay the dtb file is an overlay\n" + "\t--help print a help message\n", + tool_name); +} + +static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size, + bool overlay) +{ + int parent; + int ov_node; + int frag_node; + int ret = 0; + + if (overlay) { + /* + * The signature would be stored in the + * first fragment node of the overlay + */ + frag_node = fdt_first_subnode(dptr, 0); + if (frag_node == -FDT_ERR_NOTFOUND) { + fprintf(stderr, + "Couldn't find the fragment node: %s\n", + fdt_strerror(frag_node)); + goto done; + } + + ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME); + if (ov_node == -FDT_ERR_NOTFOUND) { + fprintf(stderr, + "Couldn't find the __overlay__ node: %s\n", + fdt_strerror(ov_node)); + goto done; + } + } else { + ov_node = 0; + } + + parent = fdt_subnode_offset(dptr, ov_node, SIGNATURE_NODENAME); + if (parent == -FDT_ERR_NOTFOUND) { + parent = fdt_add_subnode(dptr, ov_node, SIGNATURE_NODENAME); + if (parent < 0) { + ret = parent; + if (ret != -FDT_ERR_NOSPACE) { + fprintf(stderr, + "Couldn't create signature node: %s\n", + fdt_strerror(parent)); + } + } + } + if (ret) + goto done; + + /* Write the key to the FDT node */ + ret = fdt_setprop(dptr, parent, "capsule-key", + sptr, key_size); + +done: + if (ret) + ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; + + return ret; +} + +static int add_public_key(const char *pkey_file, const char *dtb_file, + bool overlay) +{ + int ret; + int srcfd = 0; + int destfd = 0; + void *sptr = NULL; + void *dptr = NULL; + off_t src_size; + struct stat pub_key; + struct stat dtb; + + /* Find out the size of the public key */ + srcfd = open(pkey_file, O_RDONLY); + if (srcfd == -1) { + fprintf(stderr, "%s: Can't open %s: %s\n", + __func__, pkey_file, strerror(errno)); + goto err; + } + + ret = fstat(srcfd, &pub_key); + if (ret == -1) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + __func__, pkey_file, strerror(errno)); + goto err; + } + + src_size = pub_key.st_size; + + /* mmap the public key esl file */ + sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0); + if ((sptr == MAP_FAILED) || (errno != 0)) { + fprintf(stderr, "%s: Failed to mmap %s:%s\n", + __func__, pkey_file, strerror(errno)); + goto err; + } + + /* Open the dest FDT */ + destfd = open(dtb_file, O_RDWR); + if (destfd == -1) { + fprintf(stderr, "%s: Can't open %s: %s\n", + __func__, dtb_file, strerror(errno)); + goto err; + } + + ret = fstat(destfd, &dtb); + if (ret == -1) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + __func__, dtb_file, strerror(errno)); + goto err; + } + + dtb.st_size += src_size + 0x30; + if (ftruncate(destfd, dtb.st_size)) { + fprintf(stderr, "%s: Can't expand %s: %s\n", + __func__, dtb_file, strerror(errno)); + goto err;; + } + + errno = 0; + /* mmap the dtb file */ + dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, + destfd, 0); + if ((dptr == MAP_FAILED) || (errno != 0)) { + fprintf(stderr, "%s: Failed to mmap %s:%s\n", + __func__, dtb_file, strerror(errno)); + goto err; + } + + if (fdt_check_header(dptr)) { + fprintf(stderr, "%s: Invalid FDT header\n", __func__); + goto err; + } + + ret = fdt_open_into(dptr, dptr, dtb.st_size); + if (ret) { + fprintf(stderr, "%s: Cannot expand FDT: %s\n", + __func__, fdt_strerror(ret)); + goto err; + } + + /* Copy the esl file to the expanded FDT */ + ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay); + if (ret < 0) { + fprintf(stderr, "%s: Unable to add public key to the FDT\n", + __func__); + goto err; + } + + return 0; + +err: + if (sptr) + munmap(sptr, src_size); + + if (dptr) + munmap(dptr, dtb.st_size); + + if (srcfd >= 0) + close(srcfd); + + if (destfd >= 0) + close(destfd); + + return -1; +} + +static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + unsigned long index, unsigned long instance) +{ + struct efi_capsule_header header; + struct efi_firmware_management_capsule_header capsule; + struct efi_firmware_management_capsule_image_header image; + FILE *f, *g; + struct stat bin_stat; + u8 *data; + size_t size; + u64 offset; + +#ifdef DEBUG + printf("For output: %s\n", path); + printf("\tbin: %s\n\ttype: %pUl\n" bin, guid); + printf("\tindex: %ld\n\tinstance: %ld\n", index, instance); +#endif + + g = fopen(bin, "r"); + if (!g) { + printf("cannot open %s\n", bin); + return -1; + } + if (stat(bin, &bin_stat) < 0) { + printf("cannot determine the size of %s\n", bin); + goto err_1; + } + data = malloc(bin_stat.st_size); + if (!data) { + printf("cannot allocate memory: %lx\n", bin_stat.st_size); + goto err_1; + } + f = fopen(path, "w"); + if (!f) { + printf("cannot open %s\n", path); + goto err_2; + } + header.capsule_guid = efi_guid_fm_capsule; + header.header_size = sizeof(header); + /* TODO: The current implementation ignores flags */ + header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET; + header.capsule_image_size = sizeof(header) + + sizeof(capsule) + sizeof(u64) + + sizeof(image) + + bin_stat.st_size; + + size = fwrite(&header, 1, sizeof(header), f); + if (size < sizeof(header)) { + printf("write failed (%lx)\n", size); + goto err_3; + } + + capsule.version = 0x00000001; + capsule.embedded_driver_count = 0; + capsule.payload_item_count = 1; + size = fwrite(&capsule, 1, sizeof(capsule), f); + if (size < (sizeof(capsule))) { + printf("write failed (%lx)\n", size); + goto err_3; + } + offset = sizeof(capsule) + sizeof(u64); + size = fwrite(&offset, 1, sizeof(offset), f); + if (size < sizeof(offset)) { + printf("write failed (%lx)\n", size); + goto err_3; + } + + image.version = 0x00000003; + memcpy(&image.update_image_type_id, guid, sizeof(*guid)); + image.update_image_index = index; + image.update_image_size = bin_stat.st_size; + image.update_vendor_code_size = 0; /* none */ + image.update_hardware_instance = instance; + image.image_capsule_support = 0; + + size = fwrite(&image, 1, sizeof(image), f); + if (size < sizeof(image)) { + printf("write failed (%lx)\n", size); + goto err_3; + } + size = fread(data, 1, bin_stat.st_size, g); + if (size < bin_stat.st_size) { + printf("read failed (%lx)\n", size); + goto err_3; + } + size = fwrite(data, 1, bin_stat.st_size, f); + if (size < bin_stat.st_size) { + printf("write failed (%lx)\n", size); + goto err_3; + } + + fclose(f); + fclose(g); + free(data); + + return 0; + +err_3: + fclose(f); +err_2: + free(data); +err_1: + fclose(g); + + return -1; +} + +/* + * Usage: + * $ mkeficapsule -f <firmware binary> <output file> + */ +int main(int argc, char **argv) +{ + char *file; + char *pkey_file; + char *dtb_file; + efi_guid_t *guid; + unsigned long index, instance; + int c, idx; + int ret; + bool overlay = false; + + file = NULL; + pkey_file = NULL; + dtb_file = NULL; + guid = NULL; + index = 0; + instance = 0; + for (;;) { + c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx); + if (c == -1) + break; + + switch (c) { + case 'f': + if (file) { + printf("Image already specified\n"); + return -1; + } + file = optarg; + guid = &efi_guid_image_type_uboot_fit; + break; + case 'r': + if (file) { + printf("Image already specified\n"); + return -1; + } + file = optarg; + guid = &efi_guid_image_type_uboot_raw; + break; + case 'i': + index = strtoul(optarg, NULL, 0); + break; + case 'I': + instance = strtoul(optarg, NULL, 0); + break; + case 'K': + if (pkey_file) { + printf("Public Key already specified\n"); + return -1; + } + pkey_file = optarg; + break; + case 'D': + if (dtb_file) { + printf("DTB file already specified\n"); + return -1; + } + dtb_file = optarg; + break; + case 'O': + overlay = true; + break; + case 'h': + print_usage(); + return 0; + } + } + + /* need a fit image file or raw image file */ + if (!file && !pkey_file && !dtb_file) { + printf("%s: %d\n", __func__, __LINE__); + print_usage(); + return -1; + } + + if (pkey_file && dtb_file) { + ret = add_public_key(pkey_file, dtb_file, overlay); + if (ret == -1) { + printf("Adding public key to the dtb failed\n"); + return -1; + } else { + return 0; + } + } + + if (create_fwbin(argv[optind], file, guid, index, instance) + < 0) { + printf("Creating firmware capsule failed\n"); + return -1; + } + + return 0; +} diff --git a/tools/patman/control.py b/tools/patman/control.py index 2330682df4..ee9717cbf6 100644 --- a/tools/patman/control.py +++ b/tools/patman/control.py @@ -20,7 +20,7 @@ def setup(): """Do required setup before doing anything""" gitutil.Setup() -def prepare_patches(col, branch, count, start, end, ignore_binary): +def prepare_patches(col, branch, count, start, end, ignore_binary, signoff): """Figure out what patches to generate, then generate them The patch files are written to the current directory, e.g. 0001_xxx.patch @@ -56,7 +56,7 @@ def prepare_patches(col, branch, count, start, end, ignore_binary): to_do = count - end series = patchstream.get_metadata(branch, start, to_do) cover_fname, patch_files = gitutil.CreatePatches( - branch, start, to_do, ignore_binary, series) + branch, start, to_do, ignore_binary, series, signoff) # Fix up the patch files to our liking, and insert the cover letter patchstream.fix_patches(series, patch_files) @@ -163,7 +163,7 @@ def send(args): col = terminal.Color() series, cover_fname, patch_files = prepare_patches( col, args.branch, args.count, args.start, args.end, - args.ignore_binary) + args.ignore_binary, args.add_signoff) ok = check_patches(series, patch_files, args.check_patch, args.verbose) diff --git a/tools/patman/func_test.py b/tools/patman/func_test.py index 74a144dc2d..89072b1ae7 100644 --- a/tools/patman/func_test.py +++ b/tools/patman/func_test.py @@ -237,27 +237,26 @@ class TestFunctional(unittest.TestCase): if 'Cc:' not in prev: break self.assertEqual('To: u-boot@lists.denx.de', prev) - self.assertEqual('Cc: %s' % tools.FromUnicode(stefan), next(lines)) + self.assertEqual('Cc: %s' % stefan, next(lines)) self.assertEqual('Version: 3', next(lines)) self.assertEqual('Prefix:\t RFC', next(lines)) self.assertEqual('Cover: 4 lines', next(lines)) self.assertEqual(' Cc: %s' % self.fred, next(lines)) - self.assertEqual(' Cc: %s' % tools.FromUnicode(self.leb), + self.assertEqual(' Cc: %s' % self.leb, next(lines)) - self.assertEqual(' Cc: %s' % tools.FromUnicode(mel), next(lines)) + self.assertEqual(' Cc: %s' % mel, next(lines)) self.assertEqual(' Cc: %s' % rick, next(lines)) expected = ('Git command: git send-email --annotate ' '--in-reply-to="%s" --to "u-boot@lists.denx.de" ' '--cc "%s" --cc-cmd "%s send --cc-cmd %s" %s %s' % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname, ' '.join(args))) - self.assertEqual(expected, tools.ToUnicode(next(lines))) + self.assertEqual(expected, next(lines)) - self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), - tools.ToUnicode(cc_lines[0])) + self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), cc_lines[0]) self.assertEqual( '%s %s\0%s\0%s\0%s' % (args[1], self.fred, self.leb, rick, stefan), - tools.ToUnicode(cc_lines[1])) + cc_lines[1]) expected = ''' This is a test of how the cover @@ -476,7 +475,7 @@ complicated as possible''') with capture_sys_output() as _: _, cover_fname, patch_files = control.prepare_patches( col, branch=None, count=-1, start=0, end=0, - ignore_binary=False) + ignore_binary=False, signoff=True) self.assertIsNone(cover_fname) self.assertEqual(2, len(patch_files)) @@ -485,7 +484,7 @@ complicated as possible''') with capture_sys_output() as _: _, cover_fname, patch_files = control.prepare_patches( col, branch='second', count=-1, start=0, end=0, - ignore_binary=False) + ignore_binary=False, signoff=True) self.assertIsNotNone(cover_fname) self.assertEqual(3, len(patch_files)) @@ -493,7 +492,7 @@ complicated as possible''') with capture_sys_output() as _: _, cover_fname, patch_files = control.prepare_patches( col, branch='second', count=-1, start=0, end=1, - ignore_binary=False) + ignore_binary=False, signoff=True) self.assertIsNotNone(cover_fname) self.assertEqual(2, len(patch_files)) finally: diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py index 31fb3b2829..bf1271ded7 100644 --- a/tools/patman/gitutil.py +++ b/tools/patman/gitutil.py @@ -305,7 +305,7 @@ def PruneWorktrees(git_dir): if result.return_code != 0: raise OSError('git worktree prune: %s' % result.stderr) -def CreatePatches(branch, start, count, ignore_binary, series): +def CreatePatches(branch, start, count, ignore_binary, series, signoff = True): """Create a series of patches from the top of the current branch. The patch files are written to the current directory using @@ -323,7 +323,9 @@ def CreatePatches(branch, start, count, ignore_binary, series): """ if series.get('version'): version = '%s ' % series['version'] - cmd = ['git', 'format-patch', '-M', '--signoff'] + cmd = ['git', 'format-patch', '-M' ] + if signoff: + cmd.append('--signoff') if ignore_binary: cmd.append('--no-binary') if series.get('cover'): @@ -383,7 +385,6 @@ def BuildEmailList(in_list, tag=None, alias=None, raise_on_error=True): raw += LookupEmail(item, alias, raise_on_error=raise_on_error) result = [] for item in raw: - item = tools.FromUnicode(item) if not item in result: result.append(item) if tag: @@ -494,7 +495,7 @@ send --cc-cmd cc-fname" cover p1 p2' if smtp_server: cmd.append('--smtp-server=%s' % smtp_server) if in_reply_to: - cmd.append('--in-reply-to="%s"' % tools.FromUnicode(in_reply_to)) + cmd.append('--in-reply-to="%s"' % in_reply_to) if thread: cmd.append('--thread') diff --git a/tools/patman/main.py b/tools/patman/main.py index 342fd446a1..c4e4d80d42 100755 --- a/tools/patman/main.py +++ b/tools/patman/main.py @@ -81,6 +81,8 @@ send.add_argument('--no-check', action='store_false', dest='check_patch', help="Don't check for patch compliance") send.add_argument('--no-tags', action='store_false', dest='process_tags', default=True, help="Don't process subject tags as aliases") +send.add_argument('--no-signoff', action='store_false', dest='add_signoff', + default=True, help="Don't add Signed-off-by to patches") send.add_argument('--smtp-server', type=str, help="Specify the SMTP server to 'git send-email'") diff --git a/tools/patman/series.py b/tools/patman/series.py index 1d92bdb910..a6746e87c4 100644 --- a/tools/patman/series.py +++ b/tools/patman/series.py @@ -272,7 +272,6 @@ class Series(dict): for x in set(cc) & set(settings.bounces): print(col.Color(col.YELLOW, 'Skipping "%s"' % x)) cc = set(cc) - set(settings.bounces) - cc = [tools.FromUnicode(m) for m in cc] if limit is not None: cc = cc[:limit] all_ccs += cc @@ -281,11 +280,10 @@ class Series(dict): if cover_fname: cover_cc = gitutil.BuildEmailList(self.get('cover_cc', '')) - cover_cc = [tools.FromUnicode(m) for m in cover_cc] cover_cc = list(set(cover_cc + all_ccs)) if limit is not None: cover_cc = cover_cc[:limit] - cc_list = '\0'.join([tools.ToUnicode(x) for x in sorted(cover_cc)]) + cc_list = '\0'.join([x for x in sorted(cover_cc)]) print(cover_fname, cc_list, file=fd) fd.close() diff --git a/tools/patman/settings.py b/tools/patman/settings.py index 8c10eab264..13c1ee4f56 100644 --- a/tools/patman/settings.py +++ b/tools/patman/settings.py @@ -23,7 +23,12 @@ _default_settings = { "u-boot": {}, "linux": { "process_tags": "False", - } + }, + "gcc": { + "process_tags": "False", + "add_signoff": "False", + "check_patch": "False", + }, } class _ProjectConfigParser(ConfigParser.SafeConfigParser): @@ -112,7 +117,7 @@ class _ProjectConfigParser(ConfigParser.SafeConfigParser): val = ConfigParser.SafeConfigParser.get( self, section, option, *args, **kwargs ) - return tools.ToUnicode(val) + return val def items(self, section, *args, **kwargs): """Extend SafeConfigParser to add project_section to section. @@ -147,8 +152,7 @@ class _ProjectConfigParser(ConfigParser.SafeConfigParser): item_dict = dict(top_items) item_dict.update(project_items) - return {(tools.ToUnicode(item), tools.ToUnicode(val)) - for item, val in item_dict.items()} + return {(item, val) for item, val in item_dict.items()} def ReadGitAliases(fname): """Read a git alias file. This is in the form used by git: diff --git a/tools/patman/test_checkpatch.py b/tools/patman/test_checkpatch.py index 1f7c38c4e9..a4fec1d4c1 100644 --- a/tools/patman/test_checkpatch.py +++ b/tools/patman/test_checkpatch.py @@ -411,6 +411,34 @@ index 0000000..2234c87 pm.add_line('common/main.c', 'if (CONFIG_IS_ENABLED(CONFIG_CLK))') self.checkSingleMessage(pm, 'CONFIG_IS_ENABLED_CONFIG', 'error') + def check_struct(self, auto, suffix, warning): + """Check one of the warnings for struct naming + + Args: + auto: Auto variable name, e.g. 'per_child_auto' + suffix: Suffix to expect on member, e.g. '_priv' + warning: Warning name, e.g. 'PRIV_AUTO' + """ + pm = PatchMaker() + pm.add_line('common/main.c', '.%s = sizeof(struct(fred)),' % auto) + pm.add_line('common/main.c', '.%s = sizeof(struct(mary%s)),' % + (auto, suffix)) + self.checkSingleMessage( + pm, warning, "struct 'fred' should have a %s suffix" % suffix) + + def testDmDriverAuto(self): + """Check for the correct suffix on 'struct driver' auto members""" + self.check_struct('priv_auto', '_priv', 'PRIV_AUTO') + self.check_struct('plat_auto', '_plat', 'PLAT_AUTO') + self.check_struct('per_child_auto', '_priv', 'CHILD_PRIV_AUTO') + self.check_struct('per_child_plat_auto', '_plat', 'CHILD_PLAT_AUTO') + + def testDmUclassAuto(self): + """Check for the correct suffix on 'struct uclass' auto members""" + # Some of these are omitted since they match those from struct driver + self.check_struct('per_device_auto', '_priv', 'DEVICE_PRIV_AUTO') + self.check_struct('per_device_plat_auto', '_plat', 'DEVICE_PLAT_AUTO') + if __name__ == "__main__": unittest.main() diff --git a/tools/patman/tools.py b/tools/patman/tools.py index 05b1a1d4b0..d8e01a3e60 100644 --- a/tools/patman/tools.py +++ b/tools/patman/tools.py @@ -94,6 +94,14 @@ def GetOutputFilename(fname): """ return os.path.join(outdir, fname) +def GetOutputDir(): + """Return the current output directory + + Returns: + str: The output directory + """ + return outdir + def _FinaliseForTest(): """Remove the output directory (for use by tests)""" global outdir @@ -415,8 +423,6 @@ def WriteFile(fname, data, binary=True): def GetBytes(byte, size): """Get a string of bytes of a given size - This handles the unfortunate different between Python 2 and Python 2. - Args: byte: Numeric byte value to use size: Size of bytes/string to return @@ -424,81 +430,7 @@ def GetBytes(byte, size): Returns: A bytes type with 'byte' repeated 'size' times """ - if sys.version_info[0] >= 3: - data = bytes([byte]) * size - else: - data = chr(byte) * size - return data - -def ToUnicode(val): - """Make sure a value is a unicode string - - This allows some amount of compatibility between Python 2 and Python3. For - the former, it returns a unicode object. - - Args: - val: string or unicode object - - Returns: - unicode version of val - """ - if sys.version_info[0] >= 3: - return val - return val if isinstance(val, unicode) else val.decode('utf-8') - -def FromUnicode(val): - """Make sure a value is a non-unicode string - - This allows some amount of compatibility between Python 2 and Python3. For - the former, it converts a unicode object to a string. - - Args: - val: string or unicode object - - Returns: - non-unicode version of val - """ - if sys.version_info[0] >= 3: - return val - return val if isinstance(val, str) else val.encode('utf-8') - -def ToByte(ch): - """Convert a character to an ASCII value - - This is useful because in Python 2 bytes is an alias for str, but in - Python 3 they are separate types. This function converts the argument to - an ASCII value in either case. - - Args: - ch: A string (Python 2) or byte (Python 3) value - - Returns: - integer ASCII value for ch - """ - return ord(ch) if type(ch) == str else ch - -def ToChar(byte): - """Convert a byte to a character - - This is useful because in Python 2 bytes is an alias for str, but in - Python 3 they are separate types. This function converts an ASCII value to - a value with the appropriate type in either case. - - Args: - byte: A byte or str value - """ - return chr(byte) if type(byte) != str else byte - -def ToChars(byte_list): - """Convert a list of bytes to a str/bytes type - - Args: - byte_list: List of ASCII values representing the string - - Returns: - string made by concatenating all the ASCII values - """ - return ''.join([chr(byte) for byte in byte_list]) + return bytes([byte]) * size def ToBytes(string): """Convert a str type into a bytes type @@ -507,12 +439,9 @@ def ToBytes(string): string: string to convert Returns: - Python 3: A bytes type - Python 2: A string type + A bytes type """ - if sys.version_info[0] >= 3: - return string.encode('utf-8') - return string + return string.encode('utf-8') def ToString(bval): """Convert a bytes type into a str type diff --git a/tools/zynqmp_pm_cfg_obj_convert.py b/tools/zynqmp_pm_cfg_obj_convert.py index dd27f47921..0a44710e1e 100755 --- a/tools/zynqmp_pm_cfg_obj_convert.py +++ b/tools/zynqmp_pm_cfg_obj_convert.py @@ -289,7 +289,7 @@ code = in_file.read() code = re.sub('//.*?\n|/\*.*?\*/', '', code, flags=re.DOTALL) # remove everything outside the XPm_ConfigObject array definition -code = re.search('const u32 XPm_ConfigObject.*= {\n(.*)};', +code = re.search('const u32 XPm_ConfigObject.*=.*{\n(.*)};', code, flags=re.DOTALL).group(1) # Process each comma-separated array item |