diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile | 54 | ||||
-rwxr-xr-x | tools/binman/binman.py | 3 | ||||
-rw-r--r-- | tools/binman/control.py | 12 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_dtb_with_ucode.py | 24 | ||||
-rw-r--r-- | tools/binman/fdt_test.py | 64 | ||||
-rw-r--r-- | tools/binman/func_test.py | 48 | ||||
-rw-r--r-- | tools/binman/test/45_prop_test.dts | 23 | ||||
-rwxr-xr-x | tools/dtoc/dtoc.py | 3 | ||||
-rw-r--r-- | tools/dtoc/fdt.py | 183 | ||||
-rw-r--r-- | tools/dtoc/fdt_fallback.py | 181 | ||||
-rw-r--r-- | tools/dtoc/fdt_normal.py | 225 | ||||
-rw-r--r-- | tools/dtoc/fdt_select.py | 36 |
12 files changed, 304 insertions, 552 deletions
diff --git a/tools/Makefile b/tools/Makefile index 2fc4a583d4..cb1683e153 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -60,9 +60,21 @@ hostprogs-$(CONFIG_FIT_SIGNATURE) += fit_info fit_check_sign FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := common/image-sig.o # Flattened device tree objects -LIBFDT_OBJS := $(addprefix lib/libfdt/, \ - fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o \ - fdt_region.o fdt_sw.o) +LIBFDT_CSRCS := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c \ + fdt_empty_tree.c fdt_addresses.c fdt_overlay.c \ + fdt_region.c + +# Unfortunately setup.py below cannot handle srctree being ".." which it often +# is. It fails with an error like: +# Fatal error: can't create build/temp.linux-x86_64-2.7/../lib/libfdt/fdt.o: +# No such file or directory +# To fix this, use an absolute path. +libfdt_tree := $(shell readlink -f $(srctree)/lib/libfdt) + +LIBFDT_SRCS := $(addprefix $(libfdt_tree)/, $(LIBFDT_CSRCS)) +LIBFDT_SWIG := $(addprefix $(libfdt_tree)/, pylibfdt/libfdt.i) +LIBFDT_OBJS := $(addprefix lib/libfdt/, $(patsubst %.c, %.o, $(LIBFDT_CSRCS))) + RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \ rsa-sign.o rsa-verify.o rsa-checksum.o \ rsa-mod-exp.o) @@ -112,22 +124,22 @@ mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o -# Build a libfdt Python module if swig is available -# Use 'sudo apt-get install swig libpython-dev' to enable this -hostprogs-y += \ - $(if $(shell which swig 2> /dev/null),_libfdt.so) -_libfdt.so-sharedobjs += $(LIBFDT_OBJS) -libfdt: - -tools/_libfdt.so: $(patsubst %.o,%.c,$(LIBFDT_OBJS)) tools/libfdt_wrap.c - LDFLAGS="$(HOSTLDFLAGS)" CFLAGS= ${PYTHON} $(srctree)/lib/libfdt/setup.py \ - "$(_hostc_flags)" $^ - mv _libfdt.so $@ - -tools/libfdt_wrap.c: $(srctree)/lib/libfdt/libfdt.swig - swig -python -o $@ $< - -# TODO(sjg@chromium.org): Is this correct on Mac OS? +# Unfortunately setup.py (or actually the Python distutil implementation) +# puts files into the same directory as the .i file. We cannot touch the source +# directory, so we copy the .i file into the tools/ build subdirectory before +# calling setup. This directory is safe to write to. This ensures that we get +# all three files in $(obj)/tools: _libfdt.so, libfdt.py and libfdt_wrap.c +# The latter is a temporary file which we could actually remove. +tools/_libfdt.so: $(LIBFDT_SRCS) $(LIBFDT_SWIG) + cp $(LIBFDT_SWIG) tools/. + unset CC; \ + unset CROSS_COMPILE; \ + LDFLAGS="$(HOSTLDFLAGS)" CFLAGS= VERSION="u-boot-$(UBOOTVERSION)" \ + CPPFLAGS="$(_hostc_flags)" OBJDIR=tools \ + SOURCES="$(LIBFDT_SRCS) tools/libfdt.i" \ + SWIG_OPTS="-I$(srctree)/lib/libfdt -I$(srctree)/lib" \ + $(libfdt_tree)/pylibfdt/setup.py --quiet build_ext \ + --build-lib tools ifneq ($(CONFIG_MX23)$(CONFIG_MX28),) # Add CONFIG_MXS into host CFLAGS, so we can check whether or not register @@ -216,6 +228,10 @@ clean-dirs := lib common always := $(hostprogs-y) +# Build a libfdt Python module if swig is available +# Use 'sudo apt-get install swig libpython-dev' to enable this +always += $(if $(shell which swig 2> /dev/null),_libfdt.so) + # Generated LCD/video logo LOGO_H = $(objtree)/include/bmp_logo.h LOGO_DATA_H = $(objtree)/include/bmp_logo_data.h diff --git a/tools/binman/binman.py b/tools/binman/binman.py index 857d698b4c..95d3a048d8 100755 --- a/tools/binman/binman.py +++ b/tools/binman/binman.py @@ -21,6 +21,9 @@ sys.path.append(os.path.join(our_path, '../patman')) sys.path.append(os.path.join(our_path, '../dtoc')) sys.path.append(os.path.join(our_path, '../')) +# Bring in the libfdt module +sys.path.append('tools') + # Also allow entry-type modules to be brought in from the etype directory. sys.path.append(os.path.join(our_path, 'etype')) diff --git a/tools/binman/control.py b/tools/binman/control.py index e90967807c..e9d48df030 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -12,7 +12,7 @@ import sys import tools import command -import fdt_select +import fdt import fdt_util from image import Image import tout @@ -40,15 +40,15 @@ def _ReadImageDesc(binman_node): images['image'] = Image('image', binman_node) return images -def _FindBinmanNode(fdt): +def _FindBinmanNode(dtb): """Find the 'binman' node in the device tree Args: - fdt: Fdt object to scan + dtb: Fdt object to scan Returns: Node object of /binman node, or None if not found """ - for node in fdt.GetRoot().subnodes: + for node in dtb.GetRoot().subnodes: if node.name == 'binman': return node return None @@ -92,8 +92,8 @@ def Binman(options, args): try: tools.SetInputDirs(options.indir) tools.PrepareOutputDir(options.outdir, options.preserve) - fdt = fdt_select.FdtScan(dtb_fname) - node = _FindBinmanNode(fdt) + dtb = fdt.FdtScan(dtb_fname) + node = _FindBinmanNode(dtb) if not node: raise ValueError("Device tree '%s' does not have a 'binman' " "node" % dtb_fname) diff --git a/tools/binman/etype/u_boot_dtb_with_ucode.py b/tools/binman/etype/u_boot_dtb_with_ucode.py index fc02c67c14..a384a759c4 100644 --- a/tools/binman/etype/u_boot_dtb_with_ucode.py +++ b/tools/binman/etype/u_boot_dtb_with_ucode.py @@ -6,7 +6,7 @@ # Entry-type module for U-Boot device tree with the microcode removed # -import fdt_select +import fdt from entry import Entry from blob import Entry_blob import tools @@ -44,9 +44,8 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob): fd.write(self.data) # Remove the microcode - fdt = fdt_select.FdtScan(fname) - fdt.Scan() - ucode = fdt.GetNode('/microcode') + dtb = fdt.FdtScan(fname) + ucode = dtb.GetNode('/microcode') if not ucode: raise self.Raise("No /microcode node found in '%s'" % fname) @@ -57,20 +56,15 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob): data_prop = node.props.get('data') if data_prop: self.ucode_data += ''.join(data_prop.bytes) - if not self.collate: - poffset = data_prop.GetOffset() - if poffset is None: - # We cannot obtain a property offset. Collate instead. - self.collate = True - else: - # Find the offset in the device tree of the ucode data - self.ucode_offset = poffset + 12 - self.ucode_size = len(data_prop.bytes) if self.collate: prop = node.DeleteProp('data') + else: + # Find the offset in the device tree of the ucode data + self.ucode_offset = data_prop.GetOffset() + 12 + self.ucode_size = len(data_prop.bytes) if self.collate: - fdt.Pack() - fdt.Flush() + dtb.Pack() + dtb.Flush() # Make this file the contents of this entry self._pathname = fname diff --git a/tools/binman/fdt_test.py b/tools/binman/fdt_test.py index 1d9494e52f..249a9ea388 100644 --- a/tools/binman/fdt_test.py +++ b/tools/binman/fdt_test.py @@ -11,7 +11,8 @@ import sys import tempfile import unittest -from fdt_select import FdtScan +import fdt +from fdt import FdtScan import fdt_util import tools @@ -28,21 +29,56 @@ class TestFdt(unittest.TestCase): def GetCompiled(self, fname): return fdt_util.EnsureCompiled(self.TestFile(fname)) - def _DeleteProp(self, fdt): - node = fdt.GetNode('/microcode/update@0') + def _DeleteProp(self, dt): + node = dt.GetNode('/microcode/update@0') node.DeleteProp('data') def testFdtNormal(self): fname = self.GetCompiled('34_x86_ucode.dts') - fdt = FdtScan(fname) - self._DeleteProp(fdt) + dt = FdtScan(fname) + self._DeleteProp(dt) - def testFdtFallback(self): - fname = self.GetCompiled('34_x86_ucode.dts') - fdt = FdtScan(fname, True) - fdt.GetProp('/microcode/update@0', 'data') - self.assertEqual('fred', - fdt.GetProp('/microcode/update@0', 'none', default='fred')) - self.assertEqual('12345678 12345679', - fdt.GetProp('/microcode/update@0', 'data', typespec='x')) - self._DeleteProp(fdt) + def testFdtNormalProp(self): + fname = self.GetCompiled('45_prop_test.dts') + dt = FdtScan(fname) + node = dt.GetNode('/binman/intel-me') + self.assertEquals('intel-me', node.name) + val = fdt_util.GetString(node, 'filename') + self.assertEquals(str, type(val)) + self.assertEquals('me.bin', val) + + prop = node.props['intval'] + 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(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(chr(8), prop.value) + + prop = node.props['bytearray'] + 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(0x090a0b0c, fdt_util.GetInt(node, 'longbytearray')) + + prop = node.props['stringval'] + 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(list, type(prop.value)) + self.assertEquals(3, len(prop.value)) + self.assertEquals(['another', 'multi-word', 'message'], prop.value) diff --git a/tools/binman/func_test.py b/tools/binman/func_test.py index 740fa9e4e2..8b4db41659 100644 --- a/tools/binman/func_test.py +++ b/tools/binman/func_test.py @@ -21,7 +21,7 @@ import cmdline import command import control import entry -import fdt_select +import fdt import fdt_util import tools import tout @@ -658,8 +658,8 @@ class TestFunctional(unittest.TestCase): fname = tools.GetOutputFilename('test.dtb') with open(fname, 'wb') as fd: fd.write(second) - fdt = fdt_select.FdtScan(fname) - ucode = fdt.GetNode('/microcode') + dtb = fdt.FdtScan(fname) + ucode = dtb.GetNode('/microcode') self.assertTrue(ucode) for node in ucode.subnodes: self.assertFalse(node.props.get('data')) @@ -683,7 +683,7 @@ class TestFunctional(unittest.TestCase): self.assertEqual('nodtb with microcode' + pos_and_size + ' somewhere in here', first) - def _RunPackUbootSingleMicrocode(self, collate): + def _RunPackUbootSingleMicrocode(self): """Test that x86 microcode can be handled correctly We expect to see the following in the image, in order: @@ -695,8 +695,6 @@ class TestFunctional(unittest.TestCase): # We need the libfdt library to run this test since only that allows # finding the offset of a property. This is required by # Entry_u_boot_dtb_with_ucode.ObtainContents(). - if not fdt_select.have_libfdt: - return data = self._DoReadFile('35_x86_single_ucode.dts', True) second = data[len(U_BOOT_NODTB_DATA):] @@ -705,34 +703,22 @@ class TestFunctional(unittest.TestCase): third = second[fdt_len:] second = second[:fdt_len] - if not collate: - ucode_data = struct.pack('>2L', 0x12345678, 0x12345679) - self.assertIn(ucode_data, second) - ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA) + ucode_data = struct.pack('>2L', 0x12345678, 0x12345679) + self.assertIn(ucode_data, second) + ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA) - # Check that the microcode pointer was inserted. It should match the - # expected position and size - pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, - len(ucode_data)) - first = data[:len(U_BOOT_NODTB_DATA)] - self.assertEqual('nodtb with microcode' + pos_and_size + - ' somewhere in here', first) + # Check that the microcode pointer was inserted. It should match the + # expected position and size + pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, + len(ucode_data)) + first = data[:len(U_BOOT_NODTB_DATA)] + self.assertEqual('nodtb with microcode' + pos_and_size + + ' somewhere in here', first) def testPackUbootSingleMicrocode(self): """Test that x86 microcode can be handled correctly with fdt_normal. """ - self._RunPackUbootSingleMicrocode(False) - - def testPackUbootSingleMicrocodeFallback(self): - """Test that x86 microcode can be handled correctly with fdt_fallback. - - This only supports collating the microcode. - """ - try: - old_val = fdt_select.UseFallback(True) - self._RunPackUbootSingleMicrocode(True) - finally: - fdt_select.UseFallback(old_val) + self._RunPackUbootSingleMicrocode() def testUBootImg(self): """Test that u-boot.img can be put in a file""" @@ -763,14 +749,12 @@ class TestFunctional(unittest.TestCase): def testMicrocodeWithoutPtrInElf(self): """Test that a U-Boot binary without the microcode symbol is detected""" # ELF file without a '_dt_ucode_base_size' symbol - if not fdt_select.have_libfdt: - return try: with open(self.TestFile('u_boot_no_ucode_ptr')) as fd: TestFunctional._MakeInputFile('u-boot', fd.read()) with self.assertRaises(ValueError) as e: - self._RunPackUbootSingleMicrocode(False) + self._RunPackUbootSingleMicrocode() self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate " "_dt_ucode_base_size symbol in u-boot", str(e.exception)) diff --git a/tools/binman/test/45_prop_test.dts b/tools/binman/test/45_prop_test.dts new file mode 100644 index 0000000000..d22e460d29 --- /dev/null +++ b/tools/binman/test/45_prop_test.dts @@ -0,0 +1,23 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <16>; + intel-me { + filename = "me.bin"; + pos-unset; + intval = <3>; + intarray = <5 6>; + byteval = [08]; + bytearray = [01 23 34]; + longbytearray = [09 0a 0b 0c]; + stringval = "message2"; + stringarray = "another", "multi-word", "message"; + }; + }; +}; diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 2e0b9c04e2..08e35f148c 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -17,7 +17,6 @@ our_path = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(our_path, '../patman')) import fdt -import fdt_select import fdt_util # When we see these properties we ignore them - i.e. do not create a structure member @@ -170,7 +169,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_select.FdtScan(self._dtb_fname) + self.fdt = fdt.FdtScan(self._dtb_fname) def ScanNode(self, root): for node in root.subnodes: diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index 816fdbe525..63a32ea2d7 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -10,12 +10,15 @@ import struct import sys import fdt_util +import libfdt # 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. +# contains the base classes and defines the high-level API. You can use +# FdtScan() as a convenience function to create and scan an Fdt. + +# This implementation uses a libfdt Python library to access the device tree, +# so it is fairly efficient. # A list of types we support (TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4) @@ -25,7 +28,7 @@ def CheckErr(errnum, msg): raise ValueError('Error %d: %s: %s' % (errnum, libfdt.fdt_strerror(errnum), msg)) -class PropBase: +class Prop: """A device tree property Properties: @@ -34,11 +37,17 @@ class PropBase: bytes type: Value type """ - def __init__(self, node, offset, name): + def __init__(self, node, offset, name, bytes): self._node = node self._offset = offset self.name = name self.value = None + self.bytes = str(bytes) + if not bytes: + self.type = TYPE_BOOL + self.value = True + return + self.type, self.value = self.BytesToValue(bytes) def GetPhandle(self): """Get a (single) phandle value from a property @@ -96,6 +105,7 @@ class PropBase: TYPE_INT: a byte-swapped integer stored as a 4-byte string TYPE_BYTE: a byte stored as a single-byte string """ + bytes = str(bytes) size = len(bytes) strings = bytes.split('\0') is_string = True @@ -147,15 +157,12 @@ class PropBase: 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. + The offset of the property (struct fdt_property) within the file """ - return None + return self._node._fdt.GetStructOffset(self._offset) -class NodeBase: +class Node: """A device tree node Properties: @@ -188,25 +195,65 @@ class NodeBase: return subnode return None + 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 the subnodes of a node + """Scan a node's properties and subnodes - This should be implemented by subclasses + This fills in the props and subnodes properties, recursively + searching into subnodes so that the entire tree is built. """ - raise NotImplementedError() + self.props = self._fdt.GetProps(self) + + offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset()) + while offset >= 0: + sep = '' if self.path[-1] == '/' else '/' + name = self._fdt._fdt_obj.get_name(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 - This should be implemented by subclasses + 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 """ - raise NotImplementedError() + 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 Fdt: - """Provides simple access to a flat device tree blob. + """Provides simple access to a flat device tree blob using libfdts. Properties: fname: Filename of fdt @@ -214,6 +261,13 @@ class Fdt: """ def __init__(self, fname): self._fname = 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()) + self._fdt_obj = libfdt.Fdt(self._fdt) def Scan(self, root='/'): """Scan a device tree, building up a tree of Node objects @@ -255,15 +309,100 @@ class Fdt: """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 + with open(self._fname, 'wb') as fd: + fd.write(self._fdt) def Pack(self): """Pack the device tree down to its minimum size 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. + build up in the device tree binary. """ - pass + CheckErr(libfdt.fdt_pack(self._fdt), 'pack') + fdt_len = libfdt.fdt_totalsize(self._fdt) + del self._fdt[fdt_len:] + + def GetFdt(self): + """Get the contents of the FDT + + Returns: + The FDT contents as a string of bytes + """ + return self._fdt + + def CheckErr(errnum, msg): + if errnum: + raise ValueError('Error %d: %s: %s' % + (errnum, libfdt.fdt_strerror(errnum), msg)) + + + def GetProps(self, node): + """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. + """ + props_dict = {} + poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset) + while poffset >= 0: + p = self._fdt_obj.get_property_by_offset(poffset) + prop = Prop(node, poffset, p.name, p.value) + 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 + +def FdtScan(fname): + """Returns a new Fdt object from the implementation we are using""" + dtb = Fdt(fname) + dtb.Scan() + return dtb diff --git a/tools/dtoc/fdt_fallback.py b/tools/dtoc/fdt_fallback.py deleted file mode 100644 index 23e26796c8..0000000000 --- a/tools/dtoc/fdt_fallback.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/python -# -# Copyright (C) 2016 Google, Inc -# Written by Simon Glass <sjg@chromium.org> -# -# SPDX-License-Identifier: GPL-2.0+ -# - -import command -import fdt -from fdt import Fdt, NodeBase, PropBase -import fdt_util -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 the fdtget tool to access the device tree, so it -# is not very efficient for larger trees. The tool is called once for each -# node and property in the tree. - -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, name, byte_list_str): - PropBase.__init__(self, node, 0, name) - if not byte_list_str.strip(): - self.type = fdt.TYPE_BOOL - return - self.bytes = [chr(int(byte, 16)) - for byte in byte_list_str.strip().split(' ')] - self.type, self.value = self.BytesToValue(''.join(self.bytes)) - - -class Node(NodeBase): - """A device tree node - - Properties: - 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 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. - """ - for name, byte_list_str in self._fdt.GetProps(self.path).items(): - 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, 0, name, path) - self.subnodes.append(node) - - node.Scan() - - def DeleteProp(self, prop_name): - """Delete a property of a node - - 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: - See superclass - """ - - def __init__(self, fname): - 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 - - Args: - node: Node name to return children from - - Returns: - List of children in the node (each a string node name) - - Raises: - CmdError: if the node does not exist. - """ - out = command.Output('fdtget', self._fname, '-l', node) - return out.strip().splitlines() - - def GetProps(self, node): - """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 simply strings - no decoding of lists or numbers - is done. - - Raises: - CmdError: if the node does not exist. - """ - out = command.Output('fdtget', self._fname, node, '-p') - props = out.strip().splitlines() - props_dict = {} - for prop in props: - name = prop - props_dict[prop] = self.GetProp(node, name) - return props_dict - - def GetProp(self, node, prop, default=None, typespec=None): - """Get a property from a device tree. - - This looks up the given node and property, and returns the value as a - string, - - If the node or property does not exist, this will return the default - value. - - Args: - node: Full path to node to look up. - prop: Property name to look up. - default: Default value to return if nothing is present in the fdt, - or None to raise in this case. This will be converted to a - string. - typespec: Type character to use (None for default, 's' for string) - - Returns: - string containing the property value. - - Raises: - CmdError: if the property does not exist and no default is provided. - """ - args = [self._fname, node, prop, '-t', 'bx'] - if default is not None: - args += ['-d', str(default)] - if typespec is not None: - args += ['-t', 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 deleted file mode 100644 index cce5c06d8c..0000000000 --- a/tools/dtoc/fdt_normal.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/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) - - 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): - """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. - """ - props_dict = {} - poffset = libfdt.fdt_first_property_offset(self._fdt, node._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 deleted file mode 100644 index ea78c527fc..0000000000 --- a/tools/dtoc/fdt_select.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python -# -# Copyright (C) 2016 Google, Inc -# Written by Simon Glass <sjg@chromium.org> -# -# SPDX-License-Identifier: GPL-2.0+ -# - -import fdt_fallback - -# 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 - -force_fallback = False - -def FdtScan(fname, _force_fallback=False): - """Returns a new Fdt object from the implementation we are using""" - if have_libfdt and not force_fallback and not _force_fallback: - dtb = fdt_normal.FdtNormal(fname) - else: - dtb = fdt_fallback.FdtFallback(fname) - dtb.Scan() - return dtb - -def UseFallback(fallback): - global force_fallback - - old_val = force_fallback - force_fallback = fallback - return old_val |