I'm sending this out for reference since it doesn't look like I'm going
to have time to hook it up before I leave until next week.

This python generates a sample device tree that dtc and early Linux DomU
boot is happy with. (Due to an apparent DomU event channel bug, I can't
see the rest of the kernel's boot log to know if it's completely happy
with it.)

I need to get with Ewan to figure out a clean way to integrate this into
Xend, but the basic idea is to translate the DomU config file (the one
you pass to xm create) into a flattened device tree using this code.
We'll insert null properties into the tree for the initrd, and libxc
code will later overwrite those properties with the address/length after
loading the initrd into place. (I guess this is how Linux bootloaders
are expected to work with the tree as well.) I don't have that C
tree-parsing code yet.

The code isn't in a final form yet, but I'm putting it out for review.
It's a little hairier than I'd like in a few places (in particular I'm
unhappy with Header and Tree.to_bin()), but it seems to be working.
Improvements and comments welcome.

(I'll send it as an FYI to linuxppc-dev once it's more final.)

Hollis Blanchard
IBM Linux Technology Center
#!/usr/bin/env python
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# Copyright (C) IBM Corp. 2006
# Authors: Hollis Blanchard <[EMAIL PROTECTED]>

import sys
import struct

OF_DT_HEADER = 0xd00dfeed
OF_DT_PROP = 0x3
OF_DT_END = 0x9

def bincat(seq, separator=''):
	'''Concatenate the contents of seq into a bytestream.'''
	strs = []
	for item in seq:
		if type(item) == type(0):
			strs.append(struct.pack(">I", item))
			except AttributeError, e:
	return separator.join(strs)

def exists_in(name, seq):
	'''Helper function that works on seqs with ".name" attributes.'''
	# create a list of True/False
	list = [ item.name == name for item in seq ]
	# if they're all False, sum == 0
	return sum(list) > 0

def alignup(val, alignment):
	return (val + alignment - 1) & ~(alignment - 1)

def pad(buf, alignment):
	'''Pad bytestream with NULLs to specified alignment.'''
	padlen = alignup(len(buf), alignment)
	return buf.ljust(padlen, '\0')

class Property:
	def __init__(self, node, name, value):
		self.node = node
		self.value = value
		self.name = name
	def to_bin(self):
		offset = self.node.tree.stroffset(self.name)
		return struct.pack('>III', OF_DT_PROP, len(self.value), offset) \
			+ pad(self.value, 4)

class Node:
	def __init__(self, tree, name):
		self.tree = tree
		self.name = name
		self.props = []
		self.children = []
		self.phandle = 0
	def to_bin(self):
		name = pad(self.name + '\0', 4)
		return struct.pack('>I', OF_DT_BEGIN_NODE) + \
				name + \
				bincat(self.props) + \
				bincat(self.children) + \
				struct.pack('>I', OF_DT_END_NODE)
	def addprop(self, name, *cells):
		if exists_in(name, self.props):
			raise AttributeError('%s/%s already exists' % (self.name, name))
		val = bincat(cells)
		self.props.append(Property(self, name, val))
	def addnode(self, name):
		if exists_in(name, self.children):
			raise AttributeError('%s/%s already exists' % (self.name, name))
		node = Node(self.tree, name)
		return node
	def get_phandle(self):
		if self.phandle:
			return self.phandle
		self.phandle = self.tree.alloc_phandle()
		self.addprop('linux,phandle', self.phandle)
		return self.phandle

class Header:
	def __init__(self):
		self.magic = 0
		self.totalsize = 0
		self.off_dt_struct = 0
		self.off_dt_strings = 0
		self.off_mem_rsvmap = 0
		self.version = 0
		self.last_comp_version = 0
		self.boot_cpuid_phys = 0
		self.size_dt_strings = 0
	def to_bin(self):
		return struct.pack('>9I',

class StringBlock:
	def __init__(self):
		self.table = []
	def to_bin(self):
		return bincat(self.table, '\0') + '\0'
	def lookup(self, str):
		return self.to_bin().index(str)
	def add(self, str):
	def getoffset(self, str):
		return self.lookup(str)

class Tree(Node):
	def __init__(self):
		self.last_phandle = 0
		self.strings = StringBlock()
		self.reserved = [(0, 0)]
		Node.__init__(self, self, '\0')
	def alloc_phandle(self):
		self.last_phandle += 1
		return self.last_phandle
	def stradd(self, str):
		return self.strings.add(str)
	def stroffset(self, str):
		return self.strings.getoffset(str)
	def reserve(self, start, len):
		self.reserved.insert(0, (start, len))
	def to_bin(self):
		# layout:
		# 	header
		#	reservation map
		#	string block
		# 	data block

		datablock = Node.to_bin(self)

		r = [ struct.pack('>QQ', rsrv[0], rsrv[1]) for rsrv in self.reserved ]
		reserved = bincat(r)

		strblock = pad(self.strings.to_bin(), 4)
		strblocklen = len(strblock)

		header = Header()
		header.magic = OF_DT_HEADER
		header.off_mem_rsvmap = alignup(len(header.to_bin()), 8)
		header.off_dt_strings = header.off_mem_rsvmap + len(reserved)
		header.off_dt_struct = header.off_dt_strings + strblocklen
		header.version = 0x10
		header.last_comp_version = 0x10
		header.boot_cpuid_phys = 0
		header.size_dt_strings = strblocklen

		payload = reserved + \
				strblock + \
				datablock + \
				struct.pack('>I', OF_DT_END)
		header.totalsize = len(payload) + alignup(len(header.to_bin()), 8)
		return pad(header.to_bin(), 8) + payload

def writebuf(filename, buf):
	f = file(filename, 'w')

def main(outfile):
	root = Tree()
	root.reserve(0x3ffc000, 0x4000)

	root.addprop('device_type', 'chrp-but-not-really\0')
	root.addprop('#size-cells', 2)
	root.addprop('#address-cells', 2)
	root.addprop('model', 'Momentum,Maple-D\0')
	root.addprop('compatible', 'Momentum,Maple\0')

	xen = root.addnode('xen')
	xen.addprop('start-info', 0, 0x3ffc000, 0, 0x1000)
	xen.addprop('version', 'Xen-3.0-unstable\0')
	xen.addprop('reg', 0, 1, 0, 0)
	xen.addprop('domain-name', 'User Domain\0')
	xencons = xen.addnode('console')
	xencons.addprop('interrupts', 1, 0)

	mem = root.addnode('memory')
	mem.addprop('reg', 0, 0, 0, 0x4000000)
	mem.addprop('device_type', 'memory\0')

	cpus = root.addnode('cpus')
	cpus.addprop('#size-cells', 0)
	cpus.addprop('#address-cells', 1)

	cpu0 = cpus.addnode('PowerPC,[EMAIL PROTECTED]')
	cpu0.addprop('ibm,pft-size', 0, 0x14)
	cpu0.addprop('reg', 0)
	cpu0.addprop('cpu#', 0)
	cpu0.addprop('device_type', 'cpu\0')
	cpu0.addprop('d-cache-size', 0x8000)
	cpu0.addprop('d-cache-line-size', 0x80)
	cpu0.addprop('d-cache-sets', 0x80)
	cpu0.addprop('i-cache-size', 0x10000)
	cpu0.addprop('i-cache-line-size', 0x80)
	cpu0.addprop('i-cache-sets', 0x200)
	cpu0.addprop('clock-frequency', 'SrN\0')
	cpu0.addprop('timebase-frequency', 0xa6e49c0)

	l2 = cpu0.addnode('l2-cache')
	l2.addprop('name', 'l2-cache\0')
	l2.addprop('device_type', 'cache\0')
	l2.addprop('i-cache-size', 0x80000)
	l2.addprop('d-cache-size', 0x80000)
	l2.addprop('i-cache-sets', 0x200)
	l2.addprop('d-cache-sets', 0x200)

	chosen = root.addnode('chosen')
	chosen.addprop('linux,platform', 0x501)
	chosen.addprop('linux,stdout-path', '/xen/console\0')
	chosen.addprop('interrupt-controller', xen.get_phandle())
	chosen.addprop('bootargs', '\0')

	writebuf(outfile, root.to_bin())

if __name__ == '__main__':
Xen-ppc-devel mailing list

Reply via email to