3 # Copyright (C) 2016 Google, Inc
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
100 strings = bytes.split('\0')
102 count = len(strings) - 1
103 if count > 0 and not strings[-1]:
104 for string in strings[:-1]:
109 if ch < ' ' or ch > '~':
116 return TYPE_STRING, strings[0]
118 return TYPE_STRING, strings[:-1]
121 return TYPE_BYTE, bytes[0]
123 return TYPE_BYTE, list(bytes)
125 for i in range(0, size, 4):
126 val.append(bytes[i:i + 4])
128 return TYPE_INT, val[0]
132 def GetEmpty(self, type):
133 """Get an empty / zero value of the given type
136 A single value of the given type
138 if type == TYPE_BYTE:
140 elif type == TYPE_INT:
141 return struct.pack('<I', 0);
142 elif type == TYPE_STRING:
148 """Get the offset of a property
150 This can be implemented by subclasses.
153 The offset of the property (struct fdt_property) within the
154 file, or None if not known.
159 """A device tree node
162 offset: Integer offset in the device tree
163 name: Device tree node tname
164 path: Full path to node, along with the node name itself
165 _fdt: Device tree object
166 subnodes: A list of subnodes for this node, each a Node object
167 props: A dict of properties for this node, each a Prop object.
168 Keyed by property name
170 def __init__(self, fdt, offset, name, path):
172 self._offset = offset
178 def _FindNode(self, name):
179 """Find a node given its name
182 name: Node name to look for
184 Node object if found, else None
186 for subnode in self.subnodes:
187 if subnode.name == name:
192 """Scan the subnodes of a node
194 This should be implemented by subclasses
196 raise NotImplementedError()
198 def DeleteProp(self, prop_name):
199 """Delete a property of a node
201 This should be implemented by subclasses
204 prop_name: Name of the property to delete
206 raise NotImplementedError()
209 """Provides simple access to a flat device tree blob.
212 fname: Filename of fdt
213 _root: Root of device tree (a Node object)
215 def __init__(self, fname):
218 def Scan(self, root='/'):
219 """Scan a device tree, building up a tree of Node objects
221 This fills in the self._root property
228 self._root = self.Node(self, 0, '/', '/')
232 """Get the root Node of the device tree
239 def GetNode(self, path):
240 """Look up a node from its path
243 path: Path to look up, e.g. '/microcode/update@0'
245 Node object, or None if not found
248 for part in path.split('/')[1:]:
249 node = node._FindNode(part)
255 """Flush device tree changes back to the file
257 If the device tree has changed in memory, write it back to the file.
258 Subclasses can implement this if needed.
263 """Pack the device tree down to its minimum size
265 When nodes and properties shrink or are deleted, wasted space can
266 build up in the device tree binary. Subclasses can implement this
267 to remove that spare space.