3 # Copyright (C) 2016 Google, Inc
4 # Written by Simon Glass <sjg@chromium.org>
6 # SPDX-License-Identifier: GPL-2.0+
14 # This deals with a device tree, presenting it as an assortment of Node and
15 # Prop objects, representing nodes and properties, respectively. This file
16 # contains the base classes and defines the high-level API. Most of the
17 # implementation is in the FdtFallback and FdtNormal subclasses. See
18 # fdt_select.py for how to create an Fdt object.
20 # A list of types we support
21 (TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
23 def CheckErr(errnum, msg):
25 raise ValueError('Error %d: %s: %s' %
26 (errnum, libfdt.fdt_strerror(errnum), msg))
29 """A device tree property
32 name: Property name (as per the device tree)
33 value: Property value as a string of bytes, or a list of strings of
37 def __init__(self, node, offset, name):
44 """Get a (single) phandle value from a property
46 Gets the phandle valuie from a property and returns it as an integer
48 return fdt_util.fdt32_to_cpu(self.value[:4])
50 def Widen(self, newprop):
51 """Figure out which property type is more general
53 Given a current property and a new property, this function returns the
54 one that is less specific as to type. The less specific property will
55 be ble to represent the data in the more specific property. This is
67 He we want to use an int array for 'value'. The first property
68 suggests that a single int is enough, but the second one shows that
69 it is not. Calling this function with these two propertes would
70 update the current property to be like the second, since it is less
73 if newprop.type < self.type:
74 self.type = newprop.type
76 if type(newprop.value) == list and type(self.value) != list:
77 self.value = [self.value]
79 if type(self.value) == list and len(newprop.value) > len(self.value):
80 val = self.GetEmpty(self.type)
81 while len(self.value) < len(newprop.value):
82 self.value.append(val)
84 def BytesToValue(self, bytes):
85 """Converts a string of bytes into a type and value
88 A string containing bytes
93 Data, either a single element or a list of elements. Each element
95 TYPE_STRING: string value from the property
96 TYPE_INT: a byte-swapped integer stored as a 4-byte string
97 TYPE_BYTE: a byte stored as a single-byte string
101 strings = bytes.split('\0')
103 count = len(strings) - 1
104 if count > 0 and not strings[-1]:
105 for string in strings[:-1]:
110 if ch < ' ' or ch > '~':
117 return TYPE_STRING, strings[0]
119 return TYPE_STRING, strings[:-1]
122 return TYPE_BYTE, bytes[0]
124 return TYPE_BYTE, list(bytes)
126 for i in range(0, size, 4):
127 val.append(bytes[i:i + 4])
129 return TYPE_INT, val[0]
133 def GetEmpty(self, type):
134 """Get an empty / zero value of the given type
137 A single value of the given type
139 if type == TYPE_BYTE:
141 elif type == TYPE_INT:
142 return struct.pack('<I', 0);
143 elif type == TYPE_STRING:
149 """Get the offset of a property
151 This can be implemented by subclasses.
154 The offset of the property (struct fdt_property) within the
155 file, or None if not known.
160 """A device tree node
163 offset: Integer offset in the device tree
164 name: Device tree node tname
165 path: Full path to node, along with the node name itself
166 _fdt: Device tree object
167 subnodes: A list of subnodes for this node, each a Node object
168 props: A dict of properties for this node, each a Prop object.
169 Keyed by property name
171 def __init__(self, fdt, offset, name, path):
173 self._offset = offset
179 def _FindNode(self, name):
180 """Find a node given its name
183 name: Node name to look for
185 Node object if found, else None
187 for subnode in self.subnodes:
188 if subnode.name == name:
193 """Scan the subnodes of a node
195 This should be implemented by subclasses
197 raise NotImplementedError()
199 def DeleteProp(self, prop_name):
200 """Delete a property of a node
202 This should be implemented by subclasses
205 prop_name: Name of the property to delete
207 raise NotImplementedError()
210 """Provides simple access to a flat device tree blob.
213 fname: Filename of fdt
214 _root: Root of device tree (a Node object)
216 def __init__(self, fname):
219 def Scan(self, root='/'):
220 """Scan a device tree, building up a tree of Node objects
222 This fills in the self._root property
227 TODO(sjg@chromium.org): Implement the 'root' parameter
229 self._root = self.Node(self, 0, '/', '/')
233 """Get the root Node of the device tree
240 def GetNode(self, path):
241 """Look up a node from its path
244 path: Path to look up, e.g. '/microcode/update@0'
246 Node object, or None if not found
249 for part in path.split('/')[1:]:
250 node = node._FindNode(part)
256 """Flush device tree changes back to the file
258 If the device tree has changed in memory, write it back to the file.
259 Subclasses can implement this if needed.
264 """Pack the device tree down to its minimum size
266 When nodes and properties shrink or are deleted, wasted space can
267 build up in the device tree binary. Subclasses can implement this
268 to remove that spare space.