fdthelper.py (12469:ea3fefba5a72) fdthelper.py (13719:74853963ddcf)
1# Copyright (c) 2016 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Redistribution and use in source and binary forms, with or without
14# modification, are permitted provided that the following conditions are
15# met: redistributions of source code must retain the above copyright
16# notice, this list of conditions and the following disclaimer;
17# redistributions in binary form must reproduce the above copyright
18# notice, this list of conditions and the following disclaimer in the
19# documentation and/or other materials provided with the distribution;
20# neither the name of the copyright holders nor the names of its
21# contributors may be used to endorse or promote products derived from
22# this software without specific prior written permission.
23#
24# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35#
36# Author: Glenn Bergmans
37
1# Copyright (c) 2016 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Redistribution and use in source and binary forms, with or without
14# modification, are permitted provided that the following conditions are
15# met: redistributions of source code must retain the above copyright
16# notice, this list of conditions and the following disclaimer;
17# redistributions in binary form must reproduce the above copyright
18# notice, this list of conditions and the following disclaimer in the
19# documentation and/or other materials provided with the distribution;
20# neither the name of the copyright holders nor the names of its
21# contributors may be used to endorse or promote products derived from
22# this software without specific prior written permission.
23#
24# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35#
36# Author: Glenn Bergmans
37
38import six
39if six.PY3:
40 long = int
41
38from m5.ext.pyfdt import pyfdt
39import re
40import os
41from m5.SimObject import SimObject
42
43class FdtProperty(pyfdt.FdtProperty):
44 """Create a property without values."""
45 pass
46
47class FdtPropertyWords(pyfdt.FdtPropertyWords):
48 """Create a property with word (32-bit unsigned) values."""
49 def __init__(self, name, words):
50 if type(words) != list:
51 words = [words]
52 # Make sure all values are ints (use automatic base detection if the
53 # type is str)
54 words = [long(w, base=0) if type(w) == str else long(w) for w in words]
55 super(FdtPropertyWords, self).__init__(name, words)
56
57class FdtPropertyStrings(pyfdt.FdtPropertyStrings):
58 """Create a property with string values."""
59
60 def __init__(self, name, strings):
61 if type(strings) == str:
62 strings = [strings]
63 strings = [str(string) for string in strings] # Make all values strings
64 super(FdtPropertyStrings, self).__init__(name, strings)
65
66class FdtPropertyBytes(pyfdt.FdtPropertyBytes):
67 """Create a property with integer (8-bit signed) values."""
68
69 def __init__(self, name, values):
70 if type(values) != list:
71 values = [values]
72 # Make sure all values are ints (use automatic base detection if the
73 # type is str)
74 values = [int(v, base=0)
75 if isinstance(v, str) else int(v) for v in values]
76 super(FdtPropertyBytes, self).__init__(name, values)
77
78class FdtState(object):
79 """Class for maintaining state while recursively generating a flattened
80 device tree. The state tracks address, size and CPU address cell sizes, and
81 maintains a dictionary of allocated phandles."""
82
83 phandle_counter = 0
84 phandles = dict()
85
86 def __init__(self, addr_cells, size_cells, cpu_cells):
87 """Instantiate values of this state. The state can only be initialized
88 once."""
89
90 self.addr_cells = addr_cells
91 self.size_cells = size_cells
92 self.cpu_cells = cpu_cells
93
94 def phandle(self, obj):
95 """Return a unique phandle number for a key. The key can be a SimObject
96 or any value that is castable to a string. If the phandle doesn't exist
97 a new one is created, otherwise the existing one is returned."""
98
99 if isinstance(obj, SimObject):
100 key = str(id(obj))
101 else:
102 try:
103 key = str(obj)
104 except ValueError:
105 raise ValueError('Phandle keys must be castable to str')
106
107 if not key in FdtState.phandles:
108 FdtState.phandle_counter += 1
109
110 return FdtState.phandles.setdefault(key, FdtState.phandle_counter)
111
112 def resetPhandles(self):
113 FdtState.phandle_counter = 0
114 FdtState.phandles = dict()
115
116 def int_to_cells(self, value, cells):
117 """Helper function for: generates a list of 32 bit cells from an int,
118 used to split up addresses in appropriate 32 bit chunks."""
119 value = long(value)
120
121 if (value >> (32 * cells)) != 0:
122 fatal("Value %d doesn't fit in %d cells" % (value, cells))
123
124 return [(value >> 32*(x-1)) & 0xFFFFFFFF for x in range(cells, 0, -1)]
125
126 def addrCells(self, addr):
127 """Format an integer type according to the address_cells value of this
128 state."""
129 return self.int_to_cells(addr, self.addr_cells)
130
131 def CPUAddrCells(self, addr):
132 """Format an integer type according to the cpu_cells value of this
133 state."""
134 return self.int_to_cells(addr, self.cpu_cells)
135
136 def sizeCells(self, size):
137 """Format an integer type according to the size_cells value of this
138 state."""
139 return self.int_to_cells(size, self.size_cells)
140
141 def addrCellsProperty(self):
142 """Return an #address-cells property with the value of this state."""
143 return FdtPropertyWords("#address-cells", self.addr_cells)
144
145 def sizeCellsProperty(self):
146 """Return an #size-cells property with the value of this state."""
147 return FdtPropertyWords("#size-cells", self.size_cells)
148
149 def CPUCellsProperty(self):
150 """Return an #address-cells property for cpu nodes with the value
151 of this state."""
152 return FdtPropertyWords("#address-cells", self.cpu_cells)
153
154class FdtNop(pyfdt.FdtNop):
155 """Create an empty node."""
156 pass
157
158class FdtNode(pyfdt.FdtNode):
159 def __init__(self, name, obj=None):
160 """Create a new node and immediately set the phandle property, if obj
161 is supplied"""
162 super(FdtNode, self).__init__(name)
163 if obj != None:
164 self.appendPhandle(obj)
165
166 def append(self, subnodes):
167 """Change the behavior of the normal append to override if a node with
168 the same name already exists or merge if the name exists and is a node
169 type. Can also take a list of subnodes, that each get appended."""
170 if not hasattr(subnodes, '__iter__'):
171 subnodes = [subnodes]
172
173 for subnode in subnodes:
174 try:
175 if not issubclass(type(subnode), pyfdt.FdtNop):
176 index = self.index(subnode.name)
177 item = self.pop(index)
178 else:
179 item = None
180 except ValueError:
181 item = None
182
183 if isinstance(item, pyfdt.FdtNode) and \
184 isinstance(subnode, pyfdt.FdtNode):
185 item.merge(subnode)
186 subnode = item
187
188 super(FdtNode, self).append(subnode)
189
190 def appendList(self, subnode_list):
191 """Append all properties/nodes in the iterable."""
192 for subnode in subnode_list:
193 self.append(subnode)
194
195 def appendCompatible(self, compatible):
196 """Append a compatible property with the supplied compatibility
197 strings."""
198 if isinstance(compatible, str):
199 compatible = [compatible]
200 self.append(FdtPropertyStrings('compatible', compatible))
201
202 def appendPhandle(self, obj):
203 """Append a phandle property to this node with the phandle of the
204 supplied object."""
205 # Create a bogus state because we only need the Phandle dictionary
206 state = FdtState(addr_cells=1, size_cells=1, cpu_cells=1)
207
208 phandle = state.phandle(obj)
209 self.append(FdtPropertyWords("phandle", [phandle]))
210
211class Fdt(pyfdt.Fdt):
212 def sortNodes(self, node):
213 """Move all properties to the beginning and subnodes to the end
214 while maintaining the order of the subnodes. DTB files require the
215 properties to go before the nodes, but the PyFdt doesn't account for
216 defining nodes and properties in a random order."""
217 properties = FdtNode(node.name)
218 subnodes = FdtNode(node.name)
219
220 while len(node):
221 subnode = node.pop(0)
222 if issubclass(type(subnode), pyfdt.FdtNode):
223 subnode = self.sortNodes(subnode)
224 subnodes.append(subnode)
225 else:
226 properties.append(subnode)
227
228 properties.merge(subnodes)
229
230 return properties
231
232 def add_rootnode(self, rootnode, prenops=None, postnops=None):
233 """First sort the device tree, so that properties are before nodes."""
234 rootnode = self.sortNodes(rootnode)
235 super(Fdt, self).add_rootnode(rootnode, prenops, postnops)
236
237 def writeDtbFile(self, filename):
238 """Convert the device tree to DTB and write to a file."""
239 filename = os.path.realpath(filename)
240 try:
241 with open(filename, 'wb') as f:
242 f.write(self.to_dtb())
243 return filename
244 except IOError:
245 raise RuntimeError("Failed to open DTB output file")
246
247 def writeDtsFile(self, filename):
248 """Convert the device tree to DTS and write to a file."""
249 filename = os.path.realpath(filename)
250 try:
251 with open(filename, 'w') as f:
252 f.write(self.to_dts())
253 return filename
254 except IOError:
255 raise RuntimeError("Failed to open DTS output file")
42from m5.ext.pyfdt import pyfdt
43import re
44import os
45from m5.SimObject import SimObject
46
47class FdtProperty(pyfdt.FdtProperty):
48 """Create a property without values."""
49 pass
50
51class FdtPropertyWords(pyfdt.FdtPropertyWords):
52 """Create a property with word (32-bit unsigned) values."""
53 def __init__(self, name, words):
54 if type(words) != list:
55 words = [words]
56 # Make sure all values are ints (use automatic base detection if the
57 # type is str)
58 words = [long(w, base=0) if type(w) == str else long(w) for w in words]
59 super(FdtPropertyWords, self).__init__(name, words)
60
61class FdtPropertyStrings(pyfdt.FdtPropertyStrings):
62 """Create a property with string values."""
63
64 def __init__(self, name, strings):
65 if type(strings) == str:
66 strings = [strings]
67 strings = [str(string) for string in strings] # Make all values strings
68 super(FdtPropertyStrings, self).__init__(name, strings)
69
70class FdtPropertyBytes(pyfdt.FdtPropertyBytes):
71 """Create a property with integer (8-bit signed) values."""
72
73 def __init__(self, name, values):
74 if type(values) != list:
75 values = [values]
76 # Make sure all values are ints (use automatic base detection if the
77 # type is str)
78 values = [int(v, base=0)
79 if isinstance(v, str) else int(v) for v in values]
80 super(FdtPropertyBytes, self).__init__(name, values)
81
82class FdtState(object):
83 """Class for maintaining state while recursively generating a flattened
84 device tree. The state tracks address, size and CPU address cell sizes, and
85 maintains a dictionary of allocated phandles."""
86
87 phandle_counter = 0
88 phandles = dict()
89
90 def __init__(self, addr_cells, size_cells, cpu_cells):
91 """Instantiate values of this state. The state can only be initialized
92 once."""
93
94 self.addr_cells = addr_cells
95 self.size_cells = size_cells
96 self.cpu_cells = cpu_cells
97
98 def phandle(self, obj):
99 """Return a unique phandle number for a key. The key can be a SimObject
100 or any value that is castable to a string. If the phandle doesn't exist
101 a new one is created, otherwise the existing one is returned."""
102
103 if isinstance(obj, SimObject):
104 key = str(id(obj))
105 else:
106 try:
107 key = str(obj)
108 except ValueError:
109 raise ValueError('Phandle keys must be castable to str')
110
111 if not key in FdtState.phandles:
112 FdtState.phandle_counter += 1
113
114 return FdtState.phandles.setdefault(key, FdtState.phandle_counter)
115
116 def resetPhandles(self):
117 FdtState.phandle_counter = 0
118 FdtState.phandles = dict()
119
120 def int_to_cells(self, value, cells):
121 """Helper function for: generates a list of 32 bit cells from an int,
122 used to split up addresses in appropriate 32 bit chunks."""
123 value = long(value)
124
125 if (value >> (32 * cells)) != 0:
126 fatal("Value %d doesn't fit in %d cells" % (value, cells))
127
128 return [(value >> 32*(x-1)) & 0xFFFFFFFF for x in range(cells, 0, -1)]
129
130 def addrCells(self, addr):
131 """Format an integer type according to the address_cells value of this
132 state."""
133 return self.int_to_cells(addr, self.addr_cells)
134
135 def CPUAddrCells(self, addr):
136 """Format an integer type according to the cpu_cells value of this
137 state."""
138 return self.int_to_cells(addr, self.cpu_cells)
139
140 def sizeCells(self, size):
141 """Format an integer type according to the size_cells value of this
142 state."""
143 return self.int_to_cells(size, self.size_cells)
144
145 def addrCellsProperty(self):
146 """Return an #address-cells property with the value of this state."""
147 return FdtPropertyWords("#address-cells", self.addr_cells)
148
149 def sizeCellsProperty(self):
150 """Return an #size-cells property with the value of this state."""
151 return FdtPropertyWords("#size-cells", self.size_cells)
152
153 def CPUCellsProperty(self):
154 """Return an #address-cells property for cpu nodes with the value
155 of this state."""
156 return FdtPropertyWords("#address-cells", self.cpu_cells)
157
158class FdtNop(pyfdt.FdtNop):
159 """Create an empty node."""
160 pass
161
162class FdtNode(pyfdt.FdtNode):
163 def __init__(self, name, obj=None):
164 """Create a new node and immediately set the phandle property, if obj
165 is supplied"""
166 super(FdtNode, self).__init__(name)
167 if obj != None:
168 self.appendPhandle(obj)
169
170 def append(self, subnodes):
171 """Change the behavior of the normal append to override if a node with
172 the same name already exists or merge if the name exists and is a node
173 type. Can also take a list of subnodes, that each get appended."""
174 if not hasattr(subnodes, '__iter__'):
175 subnodes = [subnodes]
176
177 for subnode in subnodes:
178 try:
179 if not issubclass(type(subnode), pyfdt.FdtNop):
180 index = self.index(subnode.name)
181 item = self.pop(index)
182 else:
183 item = None
184 except ValueError:
185 item = None
186
187 if isinstance(item, pyfdt.FdtNode) and \
188 isinstance(subnode, pyfdt.FdtNode):
189 item.merge(subnode)
190 subnode = item
191
192 super(FdtNode, self).append(subnode)
193
194 def appendList(self, subnode_list):
195 """Append all properties/nodes in the iterable."""
196 for subnode in subnode_list:
197 self.append(subnode)
198
199 def appendCompatible(self, compatible):
200 """Append a compatible property with the supplied compatibility
201 strings."""
202 if isinstance(compatible, str):
203 compatible = [compatible]
204 self.append(FdtPropertyStrings('compatible', compatible))
205
206 def appendPhandle(self, obj):
207 """Append a phandle property to this node with the phandle of the
208 supplied object."""
209 # Create a bogus state because we only need the Phandle dictionary
210 state = FdtState(addr_cells=1, size_cells=1, cpu_cells=1)
211
212 phandle = state.phandle(obj)
213 self.append(FdtPropertyWords("phandle", [phandle]))
214
215class Fdt(pyfdt.Fdt):
216 def sortNodes(self, node):
217 """Move all properties to the beginning and subnodes to the end
218 while maintaining the order of the subnodes. DTB files require the
219 properties to go before the nodes, but the PyFdt doesn't account for
220 defining nodes and properties in a random order."""
221 properties = FdtNode(node.name)
222 subnodes = FdtNode(node.name)
223
224 while len(node):
225 subnode = node.pop(0)
226 if issubclass(type(subnode), pyfdt.FdtNode):
227 subnode = self.sortNodes(subnode)
228 subnodes.append(subnode)
229 else:
230 properties.append(subnode)
231
232 properties.merge(subnodes)
233
234 return properties
235
236 def add_rootnode(self, rootnode, prenops=None, postnops=None):
237 """First sort the device tree, so that properties are before nodes."""
238 rootnode = self.sortNodes(rootnode)
239 super(Fdt, self).add_rootnode(rootnode, prenops, postnops)
240
241 def writeDtbFile(self, filename):
242 """Convert the device tree to DTB and write to a file."""
243 filename = os.path.realpath(filename)
244 try:
245 with open(filename, 'wb') as f:
246 f.write(self.to_dtb())
247 return filename
248 except IOError:
249 raise RuntimeError("Failed to open DTB output file")
250
251 def writeDtsFile(self, filename):
252 """Convert the device tree to DTS and write to a file."""
253 filename = os.path.realpath(filename)
254 try:
255 with open(filename, 'w') as f:
256 f.write(self.to_dts())
257 return filename
258 except IOError:
259 raise RuntimeError("Failed to open DTS output file")