#!/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 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 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 import sys import struct OF_DT_HEADER = 0xd00dfeed OF_DT_BEGIN_NODE = 0x1 OF_DT_END_NODE = 0x2 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)) else: try: strs.append(item.to_bin()) except AttributeError, e: strs.append(item) 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 self.node.tree.stradd(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) self.children.append(node) 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', self.magic, self.totalsize, self.off_dt_struct, self.off_dt_strings, self.off_mem_rsvmap, self.version, self.last_comp_version, self.boot_cpuid_phys, self.size_dt_strings) 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): self.table.append(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') f.write(buf) f.close() 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('smp-enabled') cpus.addprop('#size-cells', 0) cpus.addprop('#address-cells', 1) cpu0 = cpus.addnode('PowerPC,970@0') 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) cpu0.addprop('timebases-in-sync') 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) l2.addprop('cache-unified') 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__': main(sys.argv[1])