diff options
| author | Tom Rini <trini@konsulko.com> | 2016-09-20 09:34:53 -0400 | 
|---|---|---|
| committer | Tom Rini <trini@konsulko.com> | 2016-09-20 09:34:53 -0400 | 
| commit | a2ed3f452dd1cf4982fe46d5111d200909786686 (patch) | |
| tree | a66b5a2f3b6491df7ba9345178502959fb19c84f /tools | |
| parent | 60c629b836fb6b6ae79e4e0663977056d75de198 (diff) | |
| parent | 8f224b3734d042884a8981a14db64c48e87b87a2 (diff) | |
Merge git://git.denx.de/u-boot-dm
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/buildman/control.py | 2 | ||||
| -rwxr-xr-x | tools/dtoc/dtoc.py | 38 | ||||
| -rw-r--r-- | tools/dtoc/fdt.py | 219 | ||||
| -rw-r--r-- | tools/dtoc/fdt_fallback.py | 138 | ||||
| -rw-r--r-- | tools/dtoc/fdt_normal.py | 228 | ||||
| -rw-r--r-- | tools/dtoc/fdt_select.py | 26 | ||||
| -rw-r--r-- | tools/dtoc/fdt_util.py | 126 | ||||
| -rw-r--r-- | tools/patman/checkpatch.py | 3 | ||||
| -rw-r--r-- | tools/patman/command.py | 5 | ||||
| -rw-r--r-- | tools/patman/gitutil.py | 3 | ||||
| -rw-r--r-- | tools/patman/tools.py | 120 | ||||
| -rw-r--r-- | tools/patman/tout.py | 166 | 
12 files changed, 831 insertions, 243 deletions
| diff --git a/tools/buildman/control.py b/tools/buildman/control.py index b86d7b3c1f9..0b6ab03b4c3 100644 --- a/tools/buildman/control.py +++ b/tools/buildman/control.py @@ -237,7 +237,7 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,          options.step = len(series.commits) - 1      gnu_make = command.Output(os.path.join(options.git, -                                           'scripts/show-gnu-make')).rstrip() +            'scripts/show-gnu-make'), raise_on_error=False).rstrip()      if not gnu_make:          sys.exit('GNU Make not found') diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index ec80abe717d..518aa512169 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -9,27 +9,16 @@  import copy  from optparse import OptionError, OptionParser  import os +import struct  import sys -import fdt_util -  # Bring in the patman libraries  our_path = os.path.dirname(os.path.realpath(__file__))  sys.path.append(os.path.join(our_path, '../patman')) -# Bring in either the normal fdt library (which relies on libfdt) or the -# fallback one (which uses fdtget and is slower). Both provide the same -# interfface for this file to use. -try: -    from fdt import Fdt -    import fdt -    have_libfdt = True -except ImportError: -    have_libfdt = False -    from fdt_fallback import Fdt -    import fdt_fallback as fdt - -import struct +import fdt +import fdt_select +import fdt_util  # When we see these properties we ignore them - i.e. do not create a structure member  PROP_IGNORE_LIST = [ @@ -45,10 +34,10 @@ PROP_IGNORE_LIST = [  # C type declarations for the tyues we support  TYPE_NAMES = { -    fdt_util.TYPE_INT: 'fdt32_t', -    fdt_util.TYPE_BYTE: 'unsigned char', -    fdt_util.TYPE_STRING: 'const char *', -    fdt_util.TYPE_BOOL: 'bool', +    fdt.TYPE_INT: 'fdt32_t', +    fdt.TYPE_BYTE: 'unsigned char', +    fdt.TYPE_STRING: 'const char *', +    fdt.TYPE_BOOL: 'bool',  };  STRUCT_PREFIX = 'dtd_' @@ -150,13 +139,13 @@ class DtbPlatdata:              type: Data type (fdt_util)              value: Data value, as a string of bytes          """ -        if type == fdt_util.TYPE_INT: +        if type == fdt.TYPE_INT:              return '%#x' % fdt_util.fdt32_to_cpu(value) -        elif type == fdt_util.TYPE_BYTE: +        elif type == fdt.TYPE_BYTE:              return '%#x' % ord(value[0]) -        elif type == fdt_util.TYPE_STRING: +        elif type == fdt.TYPE_STRING:              return '"%s"' % value -        elif type == fdt_util.TYPE_BOOL: +        elif type == fdt.TYPE_BOOL:              return 'true'      def GetCompatName(self, node): @@ -178,8 +167,7 @@ class DtbPlatdata:          Once this is done, self.fdt.GetRoot() can be called to obtain the          device tree root node, and progress from there.          """ -        self.fdt = Fdt(self._dtb_fname) -        self.fdt.Scan() +        self.fdt = fdt_select.FdtScan(self._dtb_fname)      def ScanTree(self):          """Scan the device tree for useful information diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index 1d913a925ec..816fdbe5258 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -6,17 +6,26 @@  # SPDX-License-Identifier:      GPL-2.0+  # -import fdt_util -import libfdt +import struct  import sys -# This deals with a device tree, presenting it as a list of Node and Prop -# objects, representing nodes and properties, respectively. -# -# This implementation uses a libfdt Python library to access the device tree, -# so it is fairly efficient. +import fdt_util + +# This deals with a device tree, presenting it as an assortment of Node and +# Prop objects, representing nodes and properties, respectively. This file +# contains the base classes and defines the high-level API. Most of the +# implementation is in the FdtFallback and FdtNormal subclasses. See +# fdt_select.py for how to create an Fdt object. + +# A list of types we support +(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4) -class Prop: +def CheckErr(errnum, msg): +    if errnum: +        raise ValueError('Error %d: %s: %s' % +            (errnum, libfdt.fdt_strerror(errnum), msg)) + +class PropBase:      """A device tree property      Properties: @@ -25,14 +34,11 @@ class Prop:              bytes          type: Value type      """ -    def __init__(self, name, bytes): +    def __init__(self, node, offset, name): +        self._node = node +        self._offset = offset          self.name = name          self.value = None -        if not bytes: -            self.type = fdt_util.TYPE_BOOL -            self.value = True -            return -        self.type, self.value = fdt_util.BytesToValue(bytes)      def GetPhandle(self):          """Get a (single) phandle value from a property @@ -71,12 +77,85 @@ class Prop:              self.value = [self.value]          if type(self.value) == list and len(newprop.value) > len(self.value): -            val = fdt_util.GetEmpty(self.type) +            val = self.GetEmpty(self.type)              while len(self.value) < len(newprop.value):                  self.value.append(val) +    def BytesToValue(self, bytes): +        """Converts a string of bytes into a type and value + +        Args: +            A string containing bytes + +        Return: +            A tuple: +                Type of data +                Data, either a single element or a list of elements. Each element +                is one of: +                    TYPE_STRING: string value from the property +                    TYPE_INT: a byte-swapped integer stored as a 4-byte string +                    TYPE_BYTE: a byte stored as a single-byte string +        """ +        size = len(bytes) +        strings = bytes.split('\0') +        is_string = True +        count = len(strings) - 1 +        if count > 0 and not strings[-1]: +            for string in strings[:-1]: +                if not string: +                    is_string = False +                    break +                for ch in string: +                    if ch < ' ' or ch > '~': +                        is_string = False +                        break +        else: +            is_string = False +        if is_string: +            if count == 1: +                return TYPE_STRING, strings[0] +            else: +                return TYPE_STRING, strings[:-1] +        if size % 4: +            if size == 1: +                return TYPE_BYTE, bytes[0] +            else: +                return TYPE_BYTE, list(bytes) +        val = [] +        for i in range(0, size, 4): +            val.append(bytes[i:i + 4]) +        if size == 4: +            return TYPE_INT, val[0] +        else: +            return TYPE_INT, val + +    def GetEmpty(self, type): +        """Get an empty / zero value of the given type + +        Returns: +            A single value of the given type +        """ +        if type == TYPE_BYTE: +            return chr(0) +        elif type == TYPE_INT: +            return struct.pack('<I', 0); +        elif type == TYPE_STRING: +            return '' +        else: +            return True + +    def GetOffset(self): +        """Get the offset of a property + +        This can be implemented by subclasses. + +        Returns: +            The offset of the property (struct fdt_property) within the +            file, or None if not known. +        """ +        return None -class Node: +class NodeBase:      """A device tree node      Properties: @@ -89,32 +168,42 @@ class Node:              Keyed by property name      """      def __init__(self, fdt, offset, name, path): -        self.offset = offset +        self._fdt = fdt +        self._offset = offset          self.name = name          self.path = path -        self._fdt = fdt          self.subnodes = []          self.props = {} +    def _FindNode(self, name): +        """Find a node given its name + +        Args: +            name: Node name to look for +        Returns: +            Node object if found, else None +        """ +        for subnode in self.subnodes: +            if subnode.name == name: +                return subnode +        return None +      def Scan(self): -        """Scan a node's properties and subnodes +        """Scan the subnodes of a node -        This fills in the props and subnodes properties, recursively -        searching into subnodes so that the entire tree is built. +        This should be implemented by subclasses          """ -        self.props = self._fdt.GetProps(self.path) +        raise NotImplementedError() -        offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset) -        while offset >= 0: -            sep = '' if self.path[-1] == '/' else '/' -            name = libfdt.Name(self._fdt.GetFdt(), offset) -            path = self.path + sep + name -            node = Node(self._fdt, offset, name, path) -            self.subnodes.append(node) +    def DeleteProp(self, prop_name): +        """Delete a property of a node -            node.Scan() -            offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset) +        This should be implemented by subclasses +        Args: +            prop_name: Name of the property to delete +        """ +        raise NotImplementedError()  class Fdt:      """Provides simple access to a flat device tree blob. @@ -123,26 +212,20 @@ class Fdt:        fname: Filename of fdt        _root: Root of device tree (a Node object)      """ -      def __init__(self, fname): -        self.fname = fname -        with open(fname) as fd: -            self._fdt = fd.read() - -    def GetFdt(self): -        """Get the contents of the FDT +        self._fname = fname -        Returns: -            The FDT contents as a string of bytes -        """ -        return self._fdt - -    def Scan(self): +    def Scan(self, root='/'):          """Scan a device tree, building up a tree of Node objects          This fills in the self._root property + +        Args: +            root: Ignored + +        TODO(sjg@chromium.org): Implement the 'root' parameter          """ -        self._root = Node(self, 0, '/', '/') +        self._root = self.Node(self, 0, '/', '/')          self._root.Scan()      def GetRoot(self): @@ -153,28 +236,34 @@ class Fdt:          """          return self._root -    def GetProps(self, node): -        """Get all properties from a node. +    def GetNode(self, path): +        """Look up a node from its path          Args: -            node: Full path to node name to look in. - +            path: Path to look up, e.g. '/microcode/update@0'          Returns: -            A dictionary containing all the properties, indexed by node name. -            The entries are Prop objects. +            Node object, or None if not found +        """ +        node = self._root +        for part in path.split('/')[1:]: +            node = node._FindNode(part) +            if not node: +                return None +        return node + +    def Flush(self): +        """Flush device tree changes back to the file + +        If the device tree has changed in memory, write it back to the file. +        Subclasses can implement this if needed. +        """ +        pass + +    def Pack(self): +        """Pack the device tree down to its minimum size -        Raises: -            ValueError: if the node does not exist. +        When nodes and properties shrink or are deleted, wasted space can +        build up in the device tree binary. Subclasses can implement this +        to remove that spare space.          """ -        offset = libfdt.fdt_path_offset(self._fdt, node) -        if offset < 0: -            libfdt.Raise(offset) -        props_dict = {} -        poffset = libfdt.fdt_first_property_offset(self._fdt, offset) -        while poffset >= 0: -            dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset) -            prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop)) -            props_dict[prop.name] = prop - -            poffset = libfdt.fdt_next_property_offset(self._fdt, poffset) -        return props_dict +        pass diff --git a/tools/dtoc/fdt_fallback.py b/tools/dtoc/fdt_fallback.py index 9ed11e4cbfe..0c0ebbcf47a 100644 --- a/tools/dtoc/fdt_fallback.py +++ b/tools/dtoc/fdt_fallback.py @@ -7,6 +7,8 @@  #  import command +import fdt +from fdt import Fdt, NodeBase, PropBase  import fdt_util  import sys @@ -17,7 +19,7 @@ import sys  # is not very efficient for larger trees. The tool is called once for each  # node and property in the tree. -class Prop: +class Prop(PropBase):      """A device tree property      Properties: @@ -26,58 +28,17 @@ class Prop:              bytes          type: Value type      """ -    def __init__(self, name, byte_list_str): -        self.name = name -        self.value = None +    def __init__(self, node, name, byte_list_str): +        PropBase.__init__(self, node, 0, name)          if not byte_list_str.strip(): -            self.type = fdt_util.TYPE_BOOL +            self.type = fdt.TYPE_BOOL              return -        bytes = [chr(int(byte, 16)) for byte in byte_list_str.strip().split(' ')] -        self.type, self.value = fdt_util.BytesToValue(''.join(bytes)) +        self.bytes = [chr(int(byte, 16)) +                      for byte in byte_list_str.strip().split(' ')] +        self.type, self.value = self.BytesToValue(''.join(self.bytes)) -    def GetPhandle(self): -        """Get a (single) phandle value from a property -        Gets the phandle valuie from a property and returns it as an integer -        """ -        return fdt_util.fdt32_to_cpu(self.value[:4]) - -    def Widen(self, newprop): -        """Figure out which property type is more general - -        Given a current property and a new property, this function returns the -        one that is less specific as to type. The less specific property will -        be ble to represent the data in the more specific property. This is -        used for things like: - -            node1 { -                compatible = "fred"; -                value = <1>; -            }; -            node1 { -                compatible = "fred"; -                value = <1 2>; -            }; - -        He we want to use an int array for 'value'. The first property -        suggests that a single int is enough, but the second one shows that -        it is not. Calling this function with these two propertes would -        update the current property to be like the second, since it is less -        specific. -        """ -        if newprop.type < self.type: -            self.type = newprop.type - -        if type(newprop.value) == list and type(self.value) != list: -            self.value = newprop.value - -        if type(self.value) == list and len(newprop.value) > len(self.value): -            val = fdt_util.GetEmpty(self.type) -            while len(self.value) < len(newprop.value): -                self.value.append(val) - - -class Node: +class Node(NodeBase):      """A device tree node      Properties: @@ -88,12 +49,8 @@ class Node:          props: A dict of properties for this node, each a Prop object.              Keyed by property name      """ -    def __init__(self, fdt, name, path): -        self.name = name -        self.path = path -        self._fdt = fdt -        self.subnodes = [] -        self.props = {} +    def __init__(self, fdt, offset, name, path): +        NodeBase.__init__(self, fdt, offset, name, path)      def Scan(self):          """Scan a node's properties and subnodes @@ -102,44 +59,42 @@ class Node:          searching into subnodes so that the entire tree is built.          """          for name, byte_list_str in self._fdt.GetProps(self.path).iteritems(): -            prop = Prop(name, byte_list_str) +            prop = Prop(self, name, byte_list_str)              self.props[name] = prop          for name in self._fdt.GetSubNodes(self.path):              sep = '' if self.path[-1] == '/' else '/'              path = self.path + sep + name -            node = Node(self._fdt, name, path) +            node = Node(self._fdt, 0, name, path)              self.subnodes.append(node)              node.Scan() +    def DeleteProp(self, prop_name): +        """Delete a property of a node -class Fdt: -    """Provides simple access to a flat device tree blob. +        The property is deleted using fdtput. + +        Args: +            prop_name: Name of the property to delete +        Raises: +            CommandError if the property does not exist +        """ +        args = [self._fdt._fname, '-d', self.path, prop_name] +        command.Output('fdtput', *args) +        del self.props[prop_name] + +class FdtFallback(Fdt): +    """Provides simple access to a flat device tree blob using fdtget/fdtput      Properties: -      fname: Filename of fdt -      _root: Root of device tree (a Node object) +        See superclass      """      def __init__(self, fname): -        self.fname = fname - -    def Scan(self): -        """Scan a device tree, building up a tree of Node objects - -        This fills in the self._root property -        """ -        self._root = Node(self, '/', '/') -        self._root.Scan() - -    def GetRoot(self): -        """Get the root Node of the device tree - -        Returns: -            The root Node object -        """ -        return self._root +        Fdt.__init__(self, fname) +        if self._fname: +            self._fname = fdt_util.EnsureCompiled(self._fname)      def GetSubNodes(self, node):          """Returns a list of sub-nodes of a given node @@ -153,15 +108,14 @@ class Fdt:          Raises:              CmdError: if the node does not exist.          """ -        out = command.Output('fdtget', self.fname, '-l', node) +        out = command.Output('fdtget', self._fname, '-l', node)          return out.strip().splitlines() -    def GetProps(self, node, convert_dashes=False): +    def GetProps(self, node):          """Get all properties from a node          Args:              node: full path to node name to look in -            convert_dashes: True to convert - to _ in node names          Returns:              A dictionary containing all the properties, indexed by node name. @@ -171,13 +125,11 @@ class Fdt:          Raises:              CmdError: if the node does not exist.          """ -        out = command.Output('fdtget', self.fname, node, '-p') +        out = command.Output('fdtget', self._fname, node, '-p')          props = out.strip().splitlines()          props_dict = {}          for prop in props:              name = prop -            if convert_dashes: -                prop = re.sub('-', '_', prop)              props_dict[prop] = self.GetProp(node, name)          return props_dict @@ -204,10 +156,26 @@ class Fdt:          Raises:              CmdError: if the property does not exist and no default is provided.          """ -        args = [self.fname, node, prop, '-t', 'bx'] +        args = [self._fname, node, prop, '-t', 'bx']          if default is not None:            args += ['-d', str(default)]          if typespec is not None:            args += ['-t%s' % typespec]          out = command.Output('fdtget', *args)          return out.strip() + +    @classmethod +    def Node(self, fdt, offset, name, path): +        """Create a new node + +        This is used by Fdt.Scan() to create a new node using the correct +        class. + +        Args: +            fdt: Fdt object +            offset: Offset of node +            name: Node name +            path: Full path to node +        """ +        node = Node(fdt, offset, name, path) +        return node diff --git a/tools/dtoc/fdt_normal.py b/tools/dtoc/fdt_normal.py new file mode 100644 index 00000000000..aae258e4128 --- /dev/null +++ b/tools/dtoc/fdt_normal.py @@ -0,0 +1,228 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier:      GPL-2.0+ +# + +import struct +import sys + +import fdt +from fdt import Fdt, NodeBase, PropBase +import fdt_util +import libfdt + +# This deals with a device tree, presenting it as a list of Node and Prop +# objects, representing nodes and properties, respectively. +# +# This implementation uses a libfdt Python library to access the device tree, +# so it is fairly efficient. + +def CheckErr(errnum, msg): +    if errnum: +        raise ValueError('Error %d: %s: %s' % +            (errnum, libfdt.fdt_strerror(errnum), msg)) + +class Prop(PropBase): +    """A device tree property + +    Properties: +        name: Property name (as per the device tree) +        value: Property value as a string of bytes, or a list of strings of +            bytes +        type: Value type +    """ +    def __init__(self, node, offset, name, bytes): +        PropBase.__init__(self, node, offset, name) +        self.bytes = bytes +        if not bytes: +            self.type = fdt.TYPE_BOOL +            self.value = True +            return +        self.type, self.value = self.BytesToValue(bytes) + +    def GetOffset(self): +        """Get the offset of a property + +        Returns: +            The offset of the property (struct fdt_property) within the file +        """ +        return self._node._fdt.GetStructOffset(self._offset) + +class Node(NodeBase): +    """A device tree node + +    Properties: +        offset: Integer offset in the device tree +        name: Device tree node tname +        path: Full path to node, along with the node name itself +        _fdt: Device tree object +        subnodes: A list of subnodes for this node, each a Node object +        props: A dict of properties for this node, each a Prop object. +            Keyed by property name +    """ +    def __init__(self, fdt, offset, name, path): +        NodeBase.__init__(self, fdt, offset, name, path) + +    def Offset(self): +        """Returns the offset of a node, after checking the cache + +        This should be used instead of self._offset directly, to ensure that +        the cache does not contain invalid offsets. +        """ +        self._fdt.CheckCache() +        return self._offset + +    def Scan(self): +        """Scan a node's properties and subnodes + +        This fills in the props and subnodes properties, recursively +        searching into subnodes so that the entire tree is built. +        """ +        self.props = self._fdt.GetProps(self, self.path) + +        offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset()) +        while offset >= 0: +            sep = '' if self.path[-1] == '/' else '/' +            name = libfdt.Name(self._fdt.GetFdt(), offset) +            path = self.path + sep + name +            node = Node(self._fdt, offset, name, path) +            self.subnodes.append(node) + +            node.Scan() +            offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset) + +    def Refresh(self, my_offset): +        """Fix up the _offset for each node, recursively + +        Note: This does not take account of property offsets - these will not +        be updated. +        """ +        if self._offset != my_offset: +            #print '%s: %d -> %d\n' % (self.path, self._offset, my_offset) +            self._offset = my_offset +        offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset) +        for subnode in self.subnodes: +            subnode.Refresh(offset) +            offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset) + +    def DeleteProp(self, prop_name): +        """Delete a property of a node + +        The property is deleted and the offset cache is invalidated. + +        Args: +            prop_name: Name of the property to delete +        Raises: +            ValueError if the property does not exist +        """ +        CheckErr(libfdt.fdt_delprop(self._fdt.GetFdt(), self.Offset(), prop_name), +                 "Node '%s': delete property: '%s'" % (self.path, prop_name)) +        del self.props[prop_name] +        self._fdt.Invalidate() + +class FdtNormal(Fdt): +    """Provides simple access to a flat device tree blob using libfdt. + +    Properties: +        _fdt: Device tree contents (bytearray) +        _cached_offsets: True if all the nodes have a valid _offset property, +            False if something has changed to invalidate the offsets +    """ +    def __init__(self, fname): +        Fdt.__init__(self, fname) +        self._cached_offsets = False +        if self._fname: +            self._fname = fdt_util.EnsureCompiled(self._fname) + +            with open(self._fname) as fd: +                self._fdt = bytearray(fd.read()) + +    def GetFdt(self): +        """Get the contents of the FDT + +        Returns: +            The FDT contents as a string of bytes +        """ +        return self._fdt + +    def Flush(self): +        """Flush device tree changes back to the file""" +        with open(self._fname, 'wb') as fd: +            fd.write(self._fdt) + +    def Pack(self): +        """Pack the device tree down to its minimum size""" +        CheckErr(libfdt.fdt_pack(self._fdt), 'pack') +        fdt_len = libfdt.fdt_totalsize(self._fdt) +        del self._fdt[fdt_len:] + +    def GetProps(self, node, path): +        """Get all properties from a node. + +        Args: +            node: Full path to node name to look in. + +        Returns: +            A dictionary containing all the properties, indexed by node name. +            The entries are Prop objects. + +        Raises: +            ValueError: if the node does not exist. +        """ +        offset = libfdt.fdt_path_offset(self._fdt, path) +        if offset < 0: +            libfdt.Raise(offset) +        props_dict = {} +        poffset = libfdt.fdt_first_property_offset(self._fdt, offset) +        while poffset >= 0: +            dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset) +            prop = Prop(node, poffset, libfdt.String(self._fdt, dprop.nameoff), +                        libfdt.Data(dprop)) +            props_dict[prop.name] = prop + +            poffset = libfdt.fdt_next_property_offset(self._fdt, poffset) +        return props_dict + +    def Invalidate(self): +        """Mark our offset cache as invalid""" +        self._cached_offsets = False + +    def CheckCache(self): +        """Refresh the offset cache if needed""" +        if self._cached_offsets: +            return +        self.Refresh() +        self._cached_offsets = True + +    def Refresh(self): +        """Refresh the offset cache""" +        self._root.Refresh(0) + +    def GetStructOffset(self, offset): +        """Get the file offset of a given struct offset + +        Args: +            offset: Offset within the 'struct' region of the device tree +        Returns: +            Position of @offset within the device tree binary +        """ +        return libfdt.fdt_off_dt_struct(self._fdt) + offset + +    @classmethod +    def Node(self, fdt, offset, name, path): +        """Create a new node + +        This is used by Fdt.Scan() to create a new node using the correct +        class. + +        Args: +            fdt: Fdt object +            offset: Offset of node +            name: Node name +            path: Full path to node +        """ +        node = Node(fdt, offset, name, path) +        return node diff --git a/tools/dtoc/fdt_select.py b/tools/dtoc/fdt_select.py new file mode 100644 index 00000000000..18a36d88a02 --- /dev/null +++ b/tools/dtoc/fdt_select.py @@ -0,0 +1,26 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier:      GPL-2.0+ +# + +# Bring in either the normal fdt library (which relies on libfdt) or the +# fallback one (which uses fdtget and is slower). Both provide the same +# interface for this file to use. +try: +    import fdt_normal +    have_libfdt = True +except ImportError: +    have_libfdt = False +    import fdt_fallback + +def FdtScan(fname): +    """Returns a new Fdt object from the implementation we are using""" +    if have_libfdt: +        dtb = fdt_normal.FdtNormal(fname) +    else: +        dtb = fdt_fallback.FdtFallback(fname) +    dtb.Scan() +    return dtb diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py index 929b524fcfe..3a108381099 100644 --- a/tools/dtoc/fdt_util.py +++ b/tools/dtoc/fdt_util.py @@ -6,81 +6,81 @@  # SPDX-License-Identifier:      GPL-2.0+  # +import os  import struct +import tempfile -# A list of types we support -(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4) +import command +import tools -def BytesToValue(bytes): -    """Converts a string of bytes into a type and value +def fdt32_to_cpu(val): +    """Convert a device tree cell to an integer      Args: -        A string containing bytes +        Value to convert (4-character string representing the cell value)      Return: -        A tuple: -            Type of data -            Data, either a single element or a list of elements. Each element -            is one of: -                TYPE_STRING: string value from the property -                TYPE_INT: a byte-swapped integer stored as a 4-byte string -                TYPE_BYTE: a byte stored as a single-byte string +        A native-endian integer value      """ -    size = len(bytes) -    strings = bytes.split('\0') -    is_string = True -    count = len(strings) - 1 -    if count > 0 and not strings[-1]: -        for string in strings[:-1]: -            if not string: -                is_string = False -                break -            for ch in string: -                if ch < ' ' or ch > '~': -                    is_string = False -                    break -    else: -        is_string = False -    if is_string: -        if count == 1: -            return TYPE_STRING, strings[0] -        else: -            return TYPE_STRING, strings[:-1] -    if size % 4: -        if size == 1: -            return TYPE_BYTE, bytes[0] -        else: -            return TYPE_BYTE, list(bytes) -    val = [] -    for i in range(0, size, 4): -        val.append(bytes[i:i + 4]) -    if size == 4: -        return TYPE_INT, val[0] -    else: -        return TYPE_INT, val +    return struct.unpack('>I', val)[0] -def GetEmpty(type): -    """Get an empty / zero value of the given type +def EnsureCompiled(fname): +    """Compile an fdt .dts source file into a .dtb binary blob if needed. + +    Args: +        fname: Filename (if .dts it will be compiled). It not it will be +            left alone      Returns: -        A single value of the given type +        Filename of resulting .dtb file      """ -    if type == TYPE_BYTE: -        return chr(0) -    elif type == TYPE_INT: -        return struct.pack('<I', 0); -    elif type == TYPE_STRING: -        return '' -    else: -        return True +    _, ext = os.path.splitext(fname) +    if ext != '.dts': +        return fname -def fdt32_to_cpu(val): -    """Convert a device tree cell to an integer +    dts_input = tools.GetOutputFilename('source.dts') +    dtb_output = tools.GetOutputFilename('source.dtb') -    Args: -        Value to convert (4-character string representing the cell value) +    search_paths = [os.path.join(os.getcwd(), 'include')] +    root, _ = os.path.splitext(fname) +    args = ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__'] +    args += ['-Ulinux'] +    for path in search_paths: +        args.extend(['-I', path]) +    args += ['-o', dts_input, fname] +    command.Run('cc', *args) -    Return: -        A native-endian integer value -    """ -    return struct.unpack(">I", val)[0] +    # If we don't have a directory, put it in the tools tempdir +    search_list = [] +    for path in search_paths: +        search_list.extend(['-i', path]) +    args = ['-I', 'dts', '-o', dtb_output, '-O', 'dtb'] +    args.extend(search_list) +    args.append(dts_input) +    command.Run('dtc', *args) +    return dtb_output + +def GetInt(node, propname, default=None): +    prop = node.props.get(propname) +    if not prop: +        return default +    value = fdt32_to_cpu(prop.value) +    if type(value) == type(list): +        raise ValueError("Node '%s' property '%' has list value: expecting" +                         "a single integer" % (node.name, propname)) +    return value + +def GetString(node, propname, default=None): +    prop = node.props.get(propname) +    if not prop: +        return default +    value = prop.value +    if type(value) == type(list): +        raise ValueError("Node '%s' property '%' has list value: expecting" +                         "a single string" % (node.name, propname)) +    return value + +def GetBool(node, propname, default=False): +    if propname in node.props: +        return True +    return default diff --git a/tools/patman/checkpatch.py b/tools/patman/checkpatch.py index 34a3bd22b08..3eef6de2210 100644 --- a/tools/patman/checkpatch.py +++ b/tools/patman/checkpatch.py @@ -63,7 +63,8 @@ def CheckPatch(fname, verbose=False):      result.problems = []      chk = FindCheckPatch()      item = {} -    result.stdout = command.Output(chk, '--no-tree', fname) +    result.stdout = command.Output(chk, '--no-tree', fname, +                                   raise_on_error=False)      #pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)      #stdout, stderr = pipe.communicate() diff --git a/tools/patman/command.py b/tools/patman/command.py index d586f111586..d1f0ca505c0 100644 --- a/tools/patman/command.py +++ b/tools/patman/command.py @@ -104,8 +104,9 @@ def RunPipe(pipe_list, infile=None, outfile=None,          raise Exception("Error running '%s'" % user_pipestr)      return result -def Output(*cmd): -    return RunPipe([cmd], capture=True, raise_on_error=False).stdout +def Output(*cmd, **kwargs): +    raise_on_error = kwargs.get('raise_on_error', True) +    return RunPipe([cmd], capture=True, raise_on_error=raise_on_error).stdout  def OutputOneLine(*cmd, **kwargs):      raise_on_error = kwargs.pop('raise_on_error', True) diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py index e088baeb819..bb7c9e08bc2 100644 --- a/tools/patman/gitutil.py +++ b/tools/patman/gitutil.py @@ -391,7 +391,8 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,      """      to = BuildEmailList(series.get('to'), '--to', alias, raise_on_error)      if not to: -        git_config_to = command.Output('git', 'config', 'sendemail.to') +        git_config_to = command.Output('git', 'config', 'sendemail.to', +                                       raise_on_error=False)          if not git_config_to:              print ("No recipient.\n"                     "Please add something like this to a commit\n" diff --git a/tools/patman/tools.py b/tools/patman/tools.py new file mode 100644 index 00000000000..ba248530303 --- /dev/null +++ b/tools/patman/tools.py @@ -0,0 +1,120 @@ +# +# Copyright (c) 2016 Google, Inc +# +# SPDX-License-Identifier:      GPL-2.0+ +# + +import os +import shutil +import tempfile + +import tout + +outdir = None +indirs = None +preserve_outdir = False + +def PrepareOutputDir(dirname, preserve=False): +    """Select an output directory, ensuring it exists. + +    This either creates a temporary directory or checks that the one supplied +    by the user is valid. For a temporary directory, it makes a note to +    remove it later if required. + +    Args: +        dirname: a string, name of the output directory to use to store +                intermediate and output files. If is None - create a temporary +                directory. +        preserve: a Boolean. If outdir above is None and preserve is False, the +                created temporary directory will be destroyed on exit. + +    Raises: +        OSError: If it cannot create the output directory. +    """ +    global outdir, preserve_outdir + +    preserve_outdir = dirname or preserve +    if dirname: +        outdir = dirname +        if not os.path.isdir(outdir): +            try: +                os.makedirs(outdir) +            except OSError as err: +                raise CmdError("Cannot make output directory '%s': '%s'" % +                                (outdir, err.strerror)) +        tout.Debug("Using output directory '%s'" % outdir) +    else: +        outdir = tempfile.mkdtemp(prefix='binman.') +        tout.Debug("Using temporary directory '%s'" % outdir) + +def _RemoveOutputDir(): +    global outdir + +    shutil.rmtree(outdir) +    tout.Debug("Deleted temporary directory '%s'" % outdir) +    outdir = None + +def FinaliseOutputDir(): +    global outdir, preserve_outdir + +    """Tidy up: delete output directory if temporary and not preserved.""" +    if outdir and not preserve_outdir: +        _RemoveOutputDir() + +def GetOutputFilename(fname): +    """Return a filename within the output directory. + +    Args: +        fname: Filename to use for new file + +    Returns: +        The full path of the filename, within the output directory +    """ +    return os.path.join(outdir, fname) + +def _FinaliseForTest(): +    """Remove the output directory (for use by tests)""" +    global outdir + +    if outdir: +        _RemoveOutputDir() + +def SetInputDirs(dirname): +    """Add a list of input directories, where input files are kept. + +    Args: +        dirname: a list of paths to input directories to use for obtaining +                files needed by binman to place in the image. +    """ +    global indir + +    indir = dirname +    tout.Debug("Using input directories %s" % indir) + +def GetInputFilename(fname): +    """Return a filename for use as input. + +    Args: +        fname: Filename to use for new file + +    Returns: +        The full path of the filename, within the input directory +    """ +    if not indir: +        return fname +    for dirname in indir: +        pathname = os.path.join(dirname, fname) +        if os.path.exists(pathname): +            return pathname + +    raise ValueError("Filename '%s' not found in input path (%s)" % +                     (fname, ','.join(indir))) + +def Align(pos, align): +    if align: +        mask = align - 1 +        pos = (pos + mask) & ~mask +    return pos + +def NotPowerOfTwo(num): +    return num and (num & (num - 1)) diff --git a/tools/patman/tout.py b/tools/patman/tout.py new file mode 100644 index 00000000000..c5fbd80dbce --- /dev/null +++ b/tools/patman/tout.py @@ -0,0 +1,166 @@ +# Copyright (c) 2016 Google, Inc +# +# SPDX-License-Identifier:            GPL-2.0+ +# +# Terminal output logging. +# + +import sys + +import terminal + +# Output verbosity levels that we support +ERROR = 0 +WARNING = 1 +NOTICE = 2 +INFO = 3 +DEBUG = 4 + +""" +This class handles output of progress and other useful information +to the user. It provides for simple verbosity level control and can +output nothing but errors at verbosity zero. + +The idea is that modules set up an Output object early in their years and pass +it around to other modules that need it. This keeps the output under control +of a single class. + +Public properties: +    verbose: Verbosity level: 0=silent, 1=progress, 3=full, 4=debug +""" +def __enter__(): +    return + +def __exit__(unused1, unused2, unused3): +    """Clean up and remove any progress message.""" +    ClearProgress() +    return False + +def UserIsPresent(): +    """This returns True if it is likely that a user is present. + +    Sometimes we want to prompt the user, but if no one is there then this +    is a waste of time, and may lock a script which should otherwise fail. + +    Returns: +        True if it thinks the user is there, and False otherwise +    """ +    return stdout_is_tty and verbose > 0 + +def ClearProgress(): +    """Clear any active progress message on the terminal.""" +    if verbose > 0 and stdout_is_tty: +        _stdout.write('\r%s\r' % (" " * len (_progress))) +        _stdout.flush() + +def Progress(msg, warning=False, trailer='...'): +    """Display progress information. + +    Args: +        msg: Message to display. +        warning: True if this is a warning.""" +    ClearProgress() +    if verbose > 0: +        _progress = msg + trailer +        if stdout_is_tty: +            col = _color.YELLOW if warning else _color.GREEN +            _stdout.write('\r' + _color.Color(col, _progress)) +            _stdout.flush() +        else: +            _stdout.write(_progress + '\n') + +def _Output(level, msg, color=None): +    """Output a message to the terminal. + +    Args: +        level: Verbosity level for this message. It will only be displayed if +                this as high as the currently selected level. +        msg; Message to display. +        error: True if this is an error message, else False. +    """ +    if verbose >= level: +        ClearProgress() +        if color: +            msg = _color.Color(color, msg) +        _stdout.write(msg + '\n') + +def DoOutput(level, msg): +    """Output a message to the terminal. + +    Args: +        level: Verbosity level for this message. It will only be displayed if +                this as high as the currently selected level. +        msg; Message to display. +    """ +    _Output(level, msg) + +def Error(msg): +    """Display an error message + +    Args: +        msg; Message to display. +    """ +    _Output(0, msg, _color.RED) + +def Warning(msg): +    """Display a warning message + +    Args: +        msg; Message to display. +    """ +    _Output(1, msg, _color.YELLOW) + +def Notice(msg): +    """Display an important infomation message + +    Args: +        msg; Message to display. +    """ +    _Output(2, msg) + +def Info(msg): +    """Display an infomation message + +    Args: +        msg; Message to display. +    """ +    _Output(3, msg) + +def Debug(msg): +    """Display a debug message + +    Args: +        msg; Message to display. +    """ +    _Output(4, msg) + +def UserOutput(msg): +    """Display a message regardless of the current output level. + +    This is used when the output was specifically requested by the user. +    Args: +        msg; Message to display. +    """ +    _Output(0, msg) + +def Init(_verbose=WARNING, stdout=sys.stdout): +    """Initialize a new output object. + +    Args: +        verbose: Verbosity level (0-4). +        stdout: File to use for stdout. +    """ +    global verbose, _progress, _color, _stdout, stdout_is_tty + +    verbose = _verbose +    _progress = ''                    # Our last progress message +    _color = terminal.Color() +    _stdout = stdout + +    # TODO(sjg): Move this into Chromite libraries when we have them +    stdout_is_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() + +def Uninit(): +    ClearProgress() + +Init() | 
