ia64/xen-unstable

view tools/python/xen/xend/FlatDeviceTree.py @ 12725:36fe7ca48e54

Tidy up the creation of directories that Xend needs. This avoids potential
races in this creation.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Fri Dec 01 11:32:32 2006 +0000 (2006-12-01)
parents 24258e322e88
children a510c94ceaa3
line source
1 #!/usr/bin/env python
2 #
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of version 2.1 of the GNU Lesser General Public
5 # License as published by the Free Software Foundation.
6 #
7 # This library is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 # Lesser General Public License for more details.
11 #
12 # You should have received a copy of the GNU Lesser General Public
13 # License along with this library; if not, write to the Free Software
14 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 #
16 # Copyright (C) IBM Corp. 2006
17 #
18 # Authors: Hollis Blanchard <hollisb@us.ibm.com>
20 import os
21 import sys
22 import struct
23 import stat
24 import re
26 _OF_DT_HEADER = int("d00dfeed", 16) # avoid signed/unsigned FutureWarning
27 _OF_DT_BEGIN_NODE = 0x1
28 _OF_DT_END_NODE = 0x2
29 _OF_DT_PROP = 0x3
30 _OF_DT_END = 0x9
32 def _bincat(seq, separator=''):
33 '''Concatenate the contents of seq into a bytestream.'''
34 strs = []
35 for item in seq:
36 if type(item) == type(0):
37 strs.append(struct.pack(">I", item))
38 else:
39 try:
40 strs.append(item.to_bin())
41 except AttributeError, e:
42 strs.append(item)
43 return separator.join(strs)
45 def _alignup(val, alignment):
46 return (val + alignment - 1) & ~(alignment - 1)
48 def _pad(buf, alignment):
49 '''Pad bytestream with NULLs to specified alignment.'''
50 padlen = _alignup(len(buf), alignment)
51 return buf + '\0' * (padlen - len(buf))
52 # not present in Python 2.3:
53 #return buf.ljust(_padlen, '\0')
55 def _indent(item):
56 indented = []
57 for line in str(item).splitlines(True):
58 indented.append(' ' + line)
59 return ''.join(indented)
61 class _Property:
62 _nonprint = re.compile('[\000-\037\200-\377]')
63 def __init__(self, node, name, value):
64 self.node = node
65 self.value = value
66 self.name = name
67 self.node.tree.stradd(name)
69 def __str__(self):
70 result = self.name
71 if self.value:
72 searchtext = self.value
73 # it's ok for a string to end in NULL
74 if searchtext.find('\000') == len(searchtext)-1:
75 searchtext = searchtext[:-1]
76 m = self._nonprint.search(searchtext)
77 if m:
78 bytes = struct.unpack("B" * len(self.value), self.value)
79 hexbytes = [ '%02x' % b for b in bytes ]
80 words = []
81 for i in range(0, len(self.value), 4):
82 words.append(''.join(hexbytes[i:i+4]))
83 v = '<' + ' '.join(words) + '>'
84 else:
85 v = '"%s"' % self.value
86 result += ': ' + v
87 return result
89 def to_bin(self):
90 offset = self.node.tree.stroffset(self.name)
91 return struct.pack('>III', _OF_DT_PROP, len(self.value), offset) \
92 + _pad(self.value, 4)
94 class _Node:
95 def __init__(self, tree, name):
96 self.tree = tree
97 self.name = name
98 self.props = {}
99 self.children = {}
100 self.phandle = 0
102 def __str__(self):
103 propstrs = [ _indent(prop) for prop in self.props.values() ]
104 childstrs = [ _indent(child) for child in self.children.values() ]
105 return '%s:\n%s\n%s' % (self.name, '\n'.join(propstrs),
106 '\n'.join(childstrs))
108 def to_bin(self):
109 name = _pad(self.name + '\0', 4)
110 return struct.pack('>I', _OF_DT_BEGIN_NODE) + \
111 name + \
112 _bincat(self.props.values()) + \
113 _bincat(self.children.values()) + \
114 struct.pack('>I', _OF_DT_END_NODE)
116 def addprop(self, propname, *cells):
117 '''setprop with duplicate error-checking.'''
118 if propname in self.props:
119 raise AttributeError('%s/%s already exists' % (self.name, propname))
120 self.setprop(propname, *cells)
122 def setprop(self, propname, *cells):
123 self.props[propname] = _Property(self, propname, _bincat(cells))
125 def addnode(self, nodename):
126 '''newnode with duplicate error-checking.'''
127 if nodename in self.children:
128 raise AttributeError('%s/%s already exists' % (self.name, nodename))
129 return self.newnode(nodename)
131 def newnode(self, nodename):
132 node = _Node(self.tree, nodename)
133 self.children[nodename] = node
134 return node
136 def getprop(self, propname):
137 return self.props[propname]
139 def getchild(self, nodename):
140 return self.children[nodename]
142 def get_phandle(self):
143 if self.phandle:
144 return self.phandle
145 self.phandle = self.tree.alloc_phandle()
146 self.addprop('linux,phandle', self.phandle)
147 return self.phandle
149 class _Header:
150 def __init__(self):
151 self.magic = 0
152 self.totalsize = 0
153 self.off_dt_struct = 0
154 self.off_dt_strings = 0
155 self.off_mem_rsvmap = 0
156 self.version = 0
157 self.last_comp_version = 0
158 self.boot_cpuid_phys = 0
159 self.size_dt_strings = 0
160 def to_bin(self):
161 return struct.pack('>9I',
162 self.magic,
163 self.totalsize,
164 self.off_dt_struct,
165 self.off_dt_strings,
166 self.off_mem_rsvmap,
167 self.version,
168 self.last_comp_version,
169 self.boot_cpuid_phys,
170 self.size_dt_strings)
172 class _StringBlock:
173 def __init__(self):
174 self.table = []
175 def to_bin(self):
176 return _bincat(self.table, '\0') + '\0'
177 def add(self, str):
178 self.table.append(str)
179 def getoffset(self, str):
180 return self.to_bin().index(str + '\0')
182 class Tree(_Node):
183 def __init__(self):
184 self.last_phandle = 0
185 self.strings = _StringBlock()
186 self.reserved = [(0, 0)]
187 _Node.__init__(self, self, '\0')
189 def alloc_phandle(self):
190 self.last_phandle += 1
191 return self.last_phandle
193 def stradd(self, str):
194 return self.strings.add(str)
196 def stroffset(self, str):
197 return self.strings.getoffset(str)
199 def reserve(self, start, len):
200 self.reserved.insert(0, (start, len))
202 def to_bin(self):
203 # layout:
204 # header
205 # reservation map
206 # string block
207 # data block
209 datablock = _Node.to_bin(self)
211 r = [ struct.pack('>QQ', rsrv[0], rsrv[1]) for rsrv in self.reserved ]
212 reserved = _bincat(r)
214 strblock = _pad(self.strings.to_bin(), 4)
215 strblocklen = len(strblock)
217 header = _Header()
218 header.magic = _OF_DT_HEADER
219 header.off_mem_rsvmap = _alignup(len(header.to_bin()), 8)
220 header.off_dt_strings = header.off_mem_rsvmap + len(reserved)
221 header.off_dt_struct = header.off_dt_strings + strblocklen
222 header.version = 0x10
223 header.last_comp_version = 0x10
224 header.boot_cpuid_phys = 0
225 header.size_dt_strings = strblocklen
227 payload = reserved + \
228 strblock + \
229 datablock + \
230 struct.pack('>I', _OF_DT_END)
231 header.totalsize = len(payload) + _alignup(len(header.to_bin()), 8)
232 return _pad(header.to_bin(), 8) + payload
234 _host_devtree_root = '/proc/device-tree'
235 def _getprop(propname):
236 '''Extract a property from the system's device tree.'''
237 f = file(os.path.join(_host_devtree_root, propname), 'r')
238 data = f.read()
239 f.close()
240 return data
242 def _copynode(node, dirpath, propfilter):
243 '''Extract all properties from a node in the system's device tree.'''
244 dirents = os.listdir(dirpath)
245 for dirent in dirents:
246 fullpath = os.path.join(dirpath, dirent)
247 st = os.lstat(fullpath)
248 if stat.S_ISDIR(st.st_mode):
249 child = node.addnode(dirent)
250 _copytree(child, fullpath, propfilter)
251 elif stat.S_ISREG(st.st_mode) and propfilter(fullpath):
252 node.addprop(dirent, _getprop(fullpath))
254 def _copytree(node, dirpath, propfilter):
255 path = os.path.join(_host_devtree_root, dirpath)
256 _copynode(node, path, propfilter)
258 def build(imghandler):
259 '''Construct a device tree by combining the domain's configuration and
260 the host's device tree.'''
261 root = Tree()
263 # 4 pages: start_info, console, store, shared_info
264 root.reserve(0x3ffc000, 0x4000)
266 root.addprop('device_type', 'chrp-but-not-really\0')
267 root.addprop('#size-cells', 2)
268 root.addprop('#address-cells', 2)
269 root.addprop('model', 'Momentum,Maple-D\0')
270 root.addprop('compatible', 'Momentum,Maple\0')
272 xen = root.addnode('xen')
273 xen.addprop('start-info', 0, 0x3ffc000, 0, 0x1000)
274 xen.addprop('version', 'Xen-3.0-unstable\0')
275 xen.addprop('reg', 0, imghandler.vm.domid, 0, 0)
276 xen.addprop('domain-name', imghandler.vm.getName() + '\0')
277 xencons = xen.addnode('console')
278 xencons.addprop('interrupts', 1, 0)
280 # XXX split out RMA node
281 mem = root.addnode('memory@0')
282 totalmem = imghandler.vm.getMemoryTarget() * 1024
283 mem.addprop('reg', 0, 0, 0, totalmem)
284 mem.addprop('device_type', 'memory\0')
286 cpus = root.addnode('cpus')
287 cpus.addprop('smp-enabled')
288 cpus.addprop('#size-cells', 0)
289 cpus.addprop('#address-cells', 1)
291 # Copy all properties the system firmware gave us, except for 'linux,'
292 # properties, from 'cpus/@0', once for every vcpu. Hopefully all cpus are
293 # identical...
294 cpu0 = None
295 def _nolinuxprops(fullpath):
296 return not os.path.basename(fullpath).startswith('linux,')
297 for i in range(imghandler.vm.getVCpuCount()):
298 cpu = cpus.addnode('PowerPC,970@0')
299 _copytree(cpu, 'cpus/PowerPC,970@0', _nolinuxprops)
300 # and then overwrite what we need to
301 pft_size = imghandler.vm.info.get('pft-size', 0x14)
302 cpu.setprop('ibm,pft-size', 0, pft_size)
304 # set default CPU
305 if cpu0 == None:
306 cpu0 = cpu
308 chosen = root.addnode('chosen')
309 chosen.addprop('cpu', cpu0.get_phandle())
310 chosen.addprop('memory', mem.get_phandle())
311 chosen.addprop('linux,stdout-path', '/xen/console\0')
312 chosen.addprop('interrupt-controller', xen.get_phandle())
313 chosen.addprop('bootargs', imghandler.cmdline + '\0')
314 # xc_linux_load.c will overwrite these 64-bit properties later
315 chosen.addprop('linux,initrd-start', 0, 0)
316 chosen.addprop('linux,initrd-end', 0, 0)
318 if 1:
319 f = file('/tmp/domU.dtb', 'w')
320 f.write(root.to_bin())
321 f.close()
323 return root