1030 lines
30 KiB
Python
1030 lines
30 KiB
Python
# -*- python -*-
|
|
import sys
|
|
import os
|
|
import re
|
|
import string
|
|
import types
|
|
|
|
import traceback
|
|
|
|
warnings = 0
|
|
errors = 0
|
|
|
|
treetop = ''
|
|
full_mainboard_path = ''
|
|
mainboard_path = ''
|
|
romimages = {}
|
|
curimage = 0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Utility Classes
|
|
# -----------------------------------------------------------------------------
|
|
|
|
class stack:
|
|
"""Used to keep track of the current part or dir"""
|
|
class __stack_iter:
|
|
def __init__ (self, stack):
|
|
self.index = 0
|
|
self.len = len(stack)
|
|
self.stack = stack
|
|
|
|
def __iter__ (self):
|
|
return self
|
|
|
|
def next (self):
|
|
if (self.index < self.len):
|
|
s = self.stack[self.index]
|
|
self.index = self.index + 1
|
|
return s
|
|
raise StopIteration
|
|
|
|
def __init__ (self):
|
|
self.stack = []
|
|
|
|
def __len__ (self):
|
|
return len(self.stack)
|
|
|
|
def __getitem__ (self, i):
|
|
return self.stack[i]
|
|
|
|
def __iter__ (self):
|
|
return self.__stack_iter(self.stack)
|
|
|
|
def push(self, part):
|
|
self.stack.append(part)
|
|
|
|
def pop(self):
|
|
try:
|
|
return self.stack.pop()
|
|
except IndexError:
|
|
return 0
|
|
|
|
def tos(self):
|
|
try:
|
|
return self.stack[-1]
|
|
except IndexError:
|
|
return 0
|
|
|
|
def empty(self):
|
|
return (len(self.stack) == 0)
|
|
partstack = stack()
|
|
|
|
class debug_info:
|
|
none = 0
|
|
gencode = 1
|
|
dumptree = 2
|
|
object = 3
|
|
dict = 4
|
|
statement = 5
|
|
dump = 6
|
|
gengraph = 7
|
|
|
|
def __init__(self, *level):
|
|
self.__level = level
|
|
|
|
def setdebug(self, *level):
|
|
self.__level = level
|
|
|
|
def level(self, level):
|
|
return level in self.__level
|
|
|
|
def info(self, level, str):
|
|
if level in self.__level:
|
|
print str
|
|
|
|
global debug
|
|
debug = debug_info(debug_info.none)
|
|
#debug = debug_info(debug_info.dumptree)
|
|
#debug = debug_info(debug_info.object)
|
|
#debug = debug_info(debug_info.gencode)
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Error Handling
|
|
# -----------------------------------------------------------------------------
|
|
|
|
def error(string):
|
|
"""Print error message"""
|
|
global errors, loc
|
|
errors = errors + 1
|
|
print "===> ERROR: %s" % string
|
|
|
|
def fatal(string):
|
|
"""Print error message and exit"""
|
|
error(string)
|
|
exitiferrors()
|
|
|
|
def warning(string):
|
|
"""Print warning message"""
|
|
global warnings, loc
|
|
warnings = warnings + 1
|
|
print "===> WARNING: %s" % string
|
|
|
|
def exitiferrors():
|
|
"""Exit parser if an error has been encountered"""
|
|
if (errors != 0):
|
|
sys.exit(1)
|
|
|
|
def safe_open(file, mode):
|
|
try:
|
|
return open(file, mode)
|
|
except IOError:
|
|
fatal("Could not open file \"%s\"" % file)
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Main classes
|
|
# -----------------------------------------------------------------------------
|
|
|
|
class romimage:
|
|
"""A rom image is the ultimate goal of coreboot"""
|
|
def __init__ (self, name):
|
|
# name of this rom image
|
|
self.name = name
|
|
|
|
# instance counter for parts
|
|
self.partinstance = 0
|
|
|
|
# chip config files included by the 'config' directive
|
|
self.configincludes = {}
|
|
|
|
# root of part tree
|
|
self.root = 0
|
|
|
|
# Last device built
|
|
self.last_device = 0
|
|
|
|
def getname(self):
|
|
return self.name
|
|
|
|
def addconfiginclude(self, part, path):
|
|
setdict(self.configincludes, part, path)
|
|
|
|
def getconfigincludes(self):
|
|
return self.configincludes
|
|
|
|
def getincludefilename(self):
|
|
if (self.useinitincludes):
|
|
return "crt0.S"
|
|
else:
|
|
return "crt0_includes.h"
|
|
|
|
def newformat(self):
|
|
return self.useinitincludes
|
|
|
|
def numparts(self):
|
|
return self.partinstance
|
|
|
|
def newpartinstance(self):
|
|
i = self.partinstance
|
|
self.partinstance = self.partinstance + 1
|
|
return i
|
|
|
|
def setroot(self, part):
|
|
self.root = part
|
|
|
|
def getroot(self):
|
|
return self.root
|
|
|
|
class partobj:
|
|
"""A configuration part"""
|
|
def __init__ (self, image, dir, parent, part, type_name, instance_name, chip_or_device):
|
|
if (parent):
|
|
debug.info(debug.object, "partobj dir %s parent %s part %s" \
|
|
% (dir, parent.instance_name, part))
|
|
else:
|
|
debug.info(debug.object, "partobj dir %s part %s" \
|
|
% (dir, part))
|
|
|
|
# romimage that is configuring this part
|
|
self.image = image
|
|
|
|
# links for static device tree
|
|
self.children = 0
|
|
self.prev_sibling = 0
|
|
self.next_sibling = 0
|
|
self.prev_device = 0
|
|
self.next_device = 0
|
|
self.chip_or_device = chip_or_device
|
|
|
|
# initializers for static device tree
|
|
self.registercode = {}
|
|
|
|
# part name
|
|
self.part = part
|
|
|
|
# type name of this part
|
|
self.type_name = type_name
|
|
|
|
# directory containing part files
|
|
self.dir = dir
|
|
|
|
# instance number, used to distinguish anonymous
|
|
# instances of this part
|
|
self.instance = image.newpartinstance()
|
|
debug.info(debug.object, "INSTANCE %d" % self.instance)
|
|
|
|
# Name of chip config file (0 if not needed)
|
|
self.chipconfig = 0
|
|
|
|
# Flag to indicate that we have generated type
|
|
# definitions for this part (only want to do it once)
|
|
self.done_types = 0
|
|
|
|
# Path to the device
|
|
self.path = ""
|
|
|
|
# Resources of the device
|
|
self.resoruce = ""
|
|
self.resources = 0
|
|
|
|
# Enabled state of the device
|
|
self.enabled = 1
|
|
|
|
# Flag if I am a duplicate device
|
|
self.dup = 0
|
|
|
|
# If there is a chip.h file, we will create an
|
|
# include for it.
|
|
if (dir):
|
|
chiph = os.path.join(dir, "chip.h")
|
|
if (os.path.exists(chiph)):
|
|
debug.info(debug.object, "%s has chip at %s" % (self, dir))
|
|
self.addconfig(chiph)
|
|
|
|
# If no instance name is supplied then generate
|
|
# a unique name
|
|
if (instance_name == 0):
|
|
self.instance_name = self.type_name + \
|
|
"_dev%d" % self.instance
|
|
self.chipinfo_name = "%s_info_%d" \
|
|
% (self.type_name, self.instance)
|
|
else:
|
|
self.instance_name = instance_name
|
|
self.chipinfo_name = "%s_info_%d" % (self.instance_name, self.instance)
|
|
|
|
# Link this part into the device list
|
|
if (self.chip_or_device == 'device'):
|
|
if (image.last_device):
|
|
image.last_device.next_device = self
|
|
self.prev_device = image.last_device
|
|
image.last_device = self
|
|
|
|
# Link this part into the tree
|
|
if (parent and (part != 'arch')):
|
|
debug.info(debug.gencode, "add to parent")
|
|
self.parent = parent
|
|
# add current child as my sibling,
|
|
# me as the child.
|
|
if (parent.children):
|
|
debug.info(debug.gencode, "add %s (%d) as sibling" % (parent.children.dir, parent.children.instance))
|
|
youngest = parent.children
|
|
while(youngest.next_sibling):
|
|
youngest = youngest.next_sibling
|
|
youngest.next_sibling = self
|
|
self.prev_sibling = youngest
|
|
else:
|
|
parent.children = self
|
|
else:
|
|
self.parent = self
|
|
|
|
def info(self):
|
|
return "%s: %s" % (self.part, self.type)
|
|
def type(self):
|
|
return self.chip_or_device
|
|
|
|
def readable_name(self):
|
|
name = ""
|
|
name = "%s_%d" % (self.type_name, self.instance)
|
|
if (self.chip_or_device == 'chip'):
|
|
name = "%s %s %s" % (name, self.part, self.dir)
|
|
else:
|
|
name = "%s %s" % (name, self.path)
|
|
return name
|
|
|
|
def graph_name(self):
|
|
name = "{ {_dev%d|" % self.instance
|
|
if (self.part):
|
|
name = "%s%s" % (name, self.part)
|
|
else:
|
|
name = "%s%s" % (name, self.chip_or_device)
|
|
if (self.type_name):
|
|
name = "%s}|%s}" % (name, self.type_name)
|
|
else:
|
|
name = "%s}|%s}" % (name, self.parent.type_name)
|
|
return name
|
|
|
|
def dumpme(self, lvl):
|
|
"""Dump information about this part for debugging"""
|
|
print "%d: %s" % (lvl, self.readable_name())
|
|
print "%d: part %s" % (lvl, self.part)
|
|
print "%d: instance %d" % (lvl, self.instance)
|
|
print "%d: chip_or_device %s" % (lvl, self.chip_or_device)
|
|
print "%d: dir %s" % (lvl,self.dir)
|
|
print "%d: type_name %s" % (lvl,self.type_name)
|
|
print "%d: parent: %s" % (lvl, self.parent.readable_name())
|
|
if (self.children):
|
|
print "%d: child %s" % (lvl, self.children.readable_name())
|
|
if (self.next_sibling):
|
|
print "%d: siblings %s" % (lvl, self.next_sibling.readable_name())
|
|
print "%d: registercode " % lvl
|
|
for f, v in self.registercode.items():
|
|
print "\t%s = %s" % (f, v)
|
|
print "%d: chipconfig %s" % (lvl, self.chipconfig)
|
|
print "\n"
|
|
|
|
def firstchilddevice(self):
|
|
"""Find the first device in the children link."""
|
|
kid = self.children
|
|
while (kid):
|
|
if (kid.chip_or_device == 'device'):
|
|
return kid
|
|
else:
|
|
kid = kid.children
|
|
return 0
|
|
|
|
def firstparentdevice(self):
|
|
"""Find the first device in the parent link."""
|
|
parent = self.parent
|
|
while (parent and (parent.parent != parent) and (parent.chip_or_device != 'device')):
|
|
parent = parent.parent
|
|
if ((parent.parent != parent) and (parent.chip_or_device != 'device')):
|
|
parent = 0
|
|
while(parent and (parent.dup == 1)):
|
|
parent = parent.prev_sibling
|
|
if (not parent):
|
|
fatal("Device %s has no device parent; this is a config file error" % self.readable_name())
|
|
return parent
|
|
|
|
def firstparentdevicelink(self):
|
|
"""Find the first device in the parent link and record which link it is."""
|
|
link = 0
|
|
parent = self.parent
|
|
while (parent and (parent.parent != parent) and (parent.chip_or_device != 'device')):
|
|
parent = parent.parent
|
|
if ((parent.parent != parent) and (parent.chip_or_device != 'device')):
|
|
parent = 0
|
|
while(parent and (parent.dup == 1)):
|
|
parent = parent.prev_sibling
|
|
link = link + 1
|
|
if (not parent):
|
|
fatal("Device %s has no device parent; this is a config file error" % self.readable_name())
|
|
return link
|
|
|
|
|
|
def firstparentchip(self):
|
|
"""Find the first chip in the parent link."""
|
|
parent = self.parent
|
|
while (parent):
|
|
if ((parent.parent == parent) or (parent.chip_or_device == 'chip')):
|
|
return parent
|
|
else:
|
|
parent = parent.parent
|
|
fatal("Device %s has no chip parent; this is a config file error" % self.readable_name())
|
|
|
|
def firstsiblingdevice(self):
|
|
"""Find the first device in the sibling link."""
|
|
sibling = self.next_sibling
|
|
while(sibling and (sibling.path == self.path)):
|
|
sibling = sibling.next_sibling
|
|
if ((not sibling) and (self.parent.chip_or_device == 'chip')):
|
|
sibling = self.parent.next_sibling
|
|
while(sibling):
|
|
if (sibling.chip_or_device == 'device'):
|
|
return sibling
|
|
else:
|
|
sibling = sibling.children
|
|
return 0
|
|
|
|
def gencode(self, file, pass_num):
|
|
"""Generate static initalizer code for this part. Two passes
|
|
are used - the first generates type information, and the second
|
|
generates instance information"""
|
|
if (pass_num == 0):
|
|
if (self.chip_or_device == 'chip'):
|
|
return;
|
|
else:
|
|
if (self.instance):
|
|
file.write("struct device %s;\n" \
|
|
% self.instance_name)
|
|
else:
|
|
file.write("struct device dev_root;\n")
|
|
return
|
|
# This is pass the second, which is pass number 1
|
|
# this is really just a case statement ...
|
|
|
|
if (self.chip_or_device == 'chip'):
|
|
if (self.chipconfig):
|
|
debug.info(debug.gencode, "gencode: chipconfig(%d)" % \
|
|
self.instance)
|
|
file.write("struct %s_config %s" % (self.type_name ,\
|
|
self.chipinfo_name))
|
|
if (self.registercode):
|
|
file.write("\t= {\n")
|
|
for f, v in self.registercode.items():
|
|
file.write( "\t.%s = %s,\n" % (f, v))
|
|
file.write("};\n")
|
|
else:
|
|
file.write(";")
|
|
file.write("\n")
|
|
|
|
if (self.instance == 0):
|
|
self.instance_name = "dev_root"
|
|
file.write("struct device **last_dev_p = &%s.next;\n" % (self.image.last_device.instance_name))
|
|
file.write("struct device dev_root = {\n")
|
|
file.write("\t.ops = &default_dev_ops_root,\n")
|
|
file.write("\t.bus = &dev_root.link[0],\n")
|
|
file.write("\t.path = { .type = DEVICE_PATH_ROOT },\n")
|
|
file.write("\t.enabled = 1,\n\t.links = 1,\n")
|
|
file.write("\t.on_mainboard = 1,\n")
|
|
file.write("\t.link = {\n\t\t[0] = {\n")
|
|
file.write("\t\t\t.dev=&dev_root,\n\t\t\t.link = 0,\n")
|
|
file.write("\t\t\t.children = &%s,\n" % self.firstchilddevice().instance_name)
|
|
file.write("\t\t},\n")
|
|
file.write("\t},\n")
|
|
if (self.chipconfig):
|
|
file.write("\t.chip_ops = &%s_ops,\n" % self.type_name)
|
|
file.write("\t.chip_info = &%s_info_%s,\n" % (self.type_name, self.instance))
|
|
file.write("\t.next = &%s,\n" % self.firstchilddevice().instance_name)
|
|
file.write("};\n")
|
|
return
|
|
|
|
# Don't print duplicate devices, just print their children
|
|
if (self.dup):
|
|
return
|
|
|
|
file.write("struct device %s = {\n" % self.instance_name)
|
|
file.write("\t.ops = 0,\n")
|
|
file.write("\t.bus = &%s.link[%d],\n" % \
|
|
(self.firstparentdevice().instance_name, \
|
|
self.firstparentdevicelink()))
|
|
file.write("\t.path = {%s},\n" % self.path)
|
|
file.write("\t.enabled = %d,\n" % self.enabled)
|
|
file.write("\t.on_mainboard = 1,\n")
|
|
if (self.resources):
|
|
file.write("\t.resources = %d,\n" % self.resources)
|
|
file.write("\t.resource = {%s\n\t },\n" % self.resource)
|
|
file.write("\t.link = {\n");
|
|
links = 0
|
|
bus = self
|
|
while(bus and (bus.path == self.path)):
|
|
child = bus.firstchilddevice()
|
|
if (child or (bus != self) or (bus.next_sibling and (bus.next_sibling.path == self.path))):
|
|
file.write("\t\t[%d] = {\n" % links)
|
|
file.write("\t\t\t.link = %d,\n" % links)
|
|
file.write("\t\t\t.dev = &%s,\n" % self.instance_name)
|
|
if (child):
|
|
file.write("\t\t\t.children = &%s,\n" %child.instance_name)
|
|
file.write("\t\t},\n")
|
|
links = links + 1
|
|
if (1):
|
|
bus = bus.next_sibling
|
|
else:
|
|
bus = 0
|
|
file.write("\t},\n")
|
|
file.write("\t.links = %d,\n" % (links))
|
|
sibling = self.firstsiblingdevice();
|
|
if (sibling):
|
|
file.write("\t.sibling = &%s,\n" % sibling.instance_name)
|
|
chip = self.firstparentchip()
|
|
if (chip and chip.chipconfig):
|
|
file.write("\t.chip_ops = &%s_ops,\n" % chip.type_name)
|
|
file.write("\t.chip_info = &%s_info_%s,\n" % (chip.type_name, chip.instance))
|
|
if (self.next_device):
|
|
file.write("\t.next=&%s\n" % self.next_device.instance_name)
|
|
file.write("};\n")
|
|
return
|
|
|
|
def addconfig(self, path):
|
|
"""Add chip config file to this part"""
|
|
self.chipconfig = os.path.join(self.dir, path)
|
|
self.image.addconfiginclude(self.type_name, self.chipconfig)
|
|
|
|
def addregister(self, field, value):
|
|
"""Register static initialization information"""
|
|
if (self.chip_or_device != 'chip'):
|
|
fatal("Only chips can have register values")
|
|
field = dequote(field)
|
|
value = dequote(value)
|
|
setdict(self.registercode, field, value)
|
|
|
|
def set_enabled(self, enabled):
|
|
self.enabled = enabled
|
|
|
|
def start_resources(self):
|
|
self.resource = ""
|
|
self.resources = 0
|
|
|
|
def end_resources(self):
|
|
self.resource = "%s" % (self.resource)
|
|
|
|
def add_resource(self, type, index, value):
|
|
""" Add a resource to a device """
|
|
self.resource = "%s\n\t\t{ .flags=%s, .index=0x%x, .base=0x%x}," % (self.resource, type, index, value)
|
|
self.resources = self.resources + 1
|
|
|
|
def set_path(self, path):
|
|
self.path = path
|
|
if (self.prev_sibling and (self.prev_sibling.path == self.path)):
|
|
self.dup = 1
|
|
if (self.prev_device):
|
|
self.prev_device.next_device = self.next_device
|
|
if (self.next_device):
|
|
self.next_device.prev_device = self.prev_device
|
|
if (self.image.last_device == self):
|
|
self.image.last_device = self.prev_device
|
|
self.prev_device = 0
|
|
self.next_device = 0
|
|
|
|
def addpcipath(self, slot, function):
|
|
""" Add a relative pci style path from our parent to this device """
|
|
if ((slot < 0) or (slot > 0x1f)):
|
|
fatal("Invalid device id")
|
|
if ((function < 0) or (function > 7)):
|
|
fatal("Invalid pci function %s" % function )
|
|
self.set_path(".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}" % (slot, function))
|
|
|
|
def addpnppath(self, port, device):
|
|
""" Add a relative path to a pnp device hanging off our parent """
|
|
if ((port < 0) or (port > 65536)):
|
|
fatal("Invalid port")
|
|
if ((device < 0) or (device > 0xffff)):
|
|
fatal("Invalid device")
|
|
self.set_path(".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}" % (port, device))
|
|
|
|
def addi2cpath(self, device):
|
|
""" Add a relative path to a i2c device hanging off our parent """
|
|
if ((device < 0) or (device > 0x7f)):
|
|
fatal("Invalid device")
|
|
self.set_path(".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x }}" % (device))
|
|
|
|
def addapicpath(self, apic_id):
|
|
""" Add a relative path to a cpu device hanging off our parent """
|
|
if ((apic_id < 0) or (apic_id > 255)):
|
|
fatal("Invalid device")
|
|
self.set_path(".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}" % (apic_id))
|
|
|
|
def addpci_domainpath(self, pci_domain):
|
|
""" Add a pci_domain number to a chip """
|
|
if ((pci_domain < 0) or (pci_domain > 0xffff)):
|
|
fatal("Invalid pci_domain: 0x%x is out of the range 0 to 0xffff" % pci_domain)
|
|
self.set_path(".type=DEVICE_PATH_PCI_DOMAIN,{.pci_domain={ .domain = 0x%x }}" % (pci_domain))
|
|
|
|
def addapic_clusterpath(self, cluster):
|
|
""" Add an apic cluster to a chip """
|
|
if ((cluster < 0) or (cluster > 15)):
|
|
fatal("Invalid apic cluster: %d is out of the range 0 to ff" % cluster)
|
|
self.set_path(".type=DEVICE_PATH_APIC_CLUSTER,{.apic_cluster={ .cluster = 0x%x }}" % (cluster))
|
|
|
|
def addcpupath(self, cpu_id):
|
|
""" Add a relative path to a cpu device hanging off our parent """
|
|
if ((cpu_id < 0) or (cpu_id > 255)):
|
|
fatal("Invalid device")
|
|
self.set_path(".type=DEVICE_PATH_CPU,{.cpu={ .id = 0x%x }}" % (cpu_id))
|
|
|
|
|
|
def addcpu_buspath(self, id):
|
|
""" Add a cpu_bus to a chip """
|
|
if ((id < 0) or (id > 255)):
|
|
fatal("Invalid device")
|
|
self.set_path(".type=DEVICE_PATH_CPU_BUS,{.cpu_bus={ .id = 0x%x }}" % (id))
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# statements
|
|
# -----------------------------------------------------------------------------
|
|
|
|
def getdict(dict, name):
|
|
if name not in dict.keys():
|
|
debug.info(debug.dict, "Undefined: %s" % name)
|
|
return 0
|
|
v = dict.get(name, 0)
|
|
debug.info(debug.dict, "getdict %s returning %s" % (name, v))
|
|
return v
|
|
|
|
def setdict(dict, name, value):
|
|
debug.info(debug.dict, "setdict sets %s to %s" % (name, value))
|
|
if name in dict.keys():
|
|
print "Duplicate in dict: %s" % name
|
|
dict[name] = value
|
|
|
|
|
|
def addconfig(path):
|
|
global partstack
|
|
curpart = partstack.tos()
|
|
curpart.addconfig(path)
|
|
|
|
def addregister(field, value):
|
|
global partstack
|
|
curpart = partstack.tos()
|
|
curpart.addregister(field, value)
|
|
|
|
def devicepart(type):
|
|
global curimage, partstack
|
|
newpart = partobj(curimage, 0, partstack.tos(), type, \
|
|
'', 0, 'device')
|
|
#print "Configuring PART %s" % (type)
|
|
partstack.push(newpart)
|
|
#print " new PART tos is now %s\n" %partstack.tos().info()
|
|
# just push TOS, so that we can pop later.
|
|
|
|
def part(type, path, file, name):
|
|
global curimage, partstack
|
|
partdir = os.path.join(type, path)
|
|
srcdir = os.path.join(treetop, 'src')
|
|
fulldir = os.path.join(srcdir, partdir)
|
|
type_name = flatten_name(partdir)
|
|
#print "PART(%s, %s, %s, %s)\n" % (type, path, file, name)
|
|
newpart = partobj(curimage, fulldir, partstack.tos(), type, \
|
|
type_name, name, 'chip')
|
|
#print "Configuring PART %s, path %s" % (type, path)
|
|
partstack.push(newpart)
|
|
|
|
def partpop():
|
|
global partstack
|
|
curpart = partstack.tos()
|
|
if (curpart == 0):
|
|
fatal("Trying to pop non-existent part")
|
|
#print "End PART %s" % curpart.part
|
|
oldpart = partstack.pop()
|
|
#print "partstack.pop, TOS is now %s\n" % oldpart.info()
|
|
|
|
#=============================================================================
|
|
# MISC FUNCTIONS
|
|
#=============================================================================
|
|
def dequote(str):
|
|
a = re.sub("^\"", "", str)
|
|
a = re.sub("\"$", "", a)
|
|
# highly un-intuitive, need four \!
|
|
a = re.sub("\\\\\"", "\"", a)
|
|
return a
|
|
|
|
def flatten_name(str):
|
|
a = re.sub("[/-]", "_", str)
|
|
return a
|
|
%%
|
|
parser Config:
|
|
ignore: r'\s+'
|
|
ignore: "#.*?\r?\n"
|
|
|
|
# less general tokens should come first, otherwise they get matched
|
|
# by the re's
|
|
token COMMENT: 'comment'
|
|
token CPU: 'cpu'
|
|
token CPU_BUS: 'cpu_bus'
|
|
token CHIP: 'chip'
|
|
token DEVICE: 'device'
|
|
token DEVICE_ID: 'device_id'
|
|
token DRQ: 'drq'
|
|
token END: 'end'
|
|
token EOF: '$'
|
|
token EQ: '='
|
|
token FORMAT: 'format'
|
|
token IO: 'io'
|
|
token IRQ: 'irq'
|
|
token MEM: 'mem'
|
|
token NEVER: 'never'
|
|
token NONE: 'none'
|
|
token PMC: 'pmc'
|
|
token PRINT: 'print'
|
|
token REGISTER: 'register'
|
|
token VENDOR_ID: 'vendor_id'
|
|
token WRITE: 'write'
|
|
token NUM: '[0-9]+'
|
|
token HEX_NUM: '[0-9a-fA-F]+'
|
|
token HEX_PREFIX: '0x'
|
|
# Why is path separate? Because paths to resources have to at least
|
|
# have a slash, we thinks
|
|
token PATH: r'[-a-zA-Z0-9_.][-a-zA-Z0-9/_.]+[-a-zA-Z0-9_.]+'
|
|
# Dir's on the other hand are abitrary
|
|
# this may all be stupid.
|
|
token RULE: r'[-a-zA-Z0-9_$()./]+[-a-zA-Z0-9_ $()./]+[-a-zA-Z0-9_$()./]+'
|
|
token ID: r'[a-zA-Z_.]+[a-zA-Z0-9_.]*'
|
|
token STR: r'"([^\\"]+|\\.)*"'
|
|
token RAWTEXT: r'.*'
|
|
token ON: 'on'
|
|
token OFF: 'off'
|
|
token PCI: 'pci'
|
|
token PNP: 'pnp'
|
|
token I2C: 'i2c'
|
|
token APIC: 'apic'
|
|
token APIC_CLUSTER: 'apic_cluster'
|
|
token CPU: 'cpu'
|
|
token CPU_BUS: 'cpu_bus'
|
|
token PCI_DOMAIN: 'pci_domain'
|
|
|
|
|
|
rule expr: logical {{ l = logical }}
|
|
( "&&" logical {{ l = l and logical }}
|
|
| "[|][|]" logical {{ l = l or logical }}
|
|
)* {{ return l }}
|
|
|
|
rule logical: factor {{ n = factor }}
|
|
( "[+]" factor {{ n = n+factor }}
|
|
| "-" factor {{ n = n-factor }}
|
|
)* {{ return n }}
|
|
|
|
rule factor: term {{ v = term }}
|
|
( "[*]" term {{ v = v*term }}
|
|
| "/" term {{ v = v/term }}
|
|
| "<<" term {{ v = v << term }}
|
|
| ">=" term {{ v = (v < term)}}
|
|
)* {{ return v }}
|
|
|
|
# A term is a number, variable, or an expression surrounded by parentheses
|
|
rule term: NUM {{ return long(NUM, 10) }}
|
|
| HEX_PREFIX HEX_NUM {{ return long(HEX_NUM, 16) }}
|
|
| ID {{ return lookup(ID) }}
|
|
| unop {{ return unop }}
|
|
| "\\(" expr "\\)" {{ return expr }}
|
|
|
|
rule unop: "!" expr {{ return not(expr) }}
|
|
|
|
rule partend<<C>>: (stmt<<C>>)* END {{ if (C): partpop()}}
|
|
|
|
# This is needed because the legacy cpu command could not distinguish
|
|
# between cpu vendors. It should just be PATH, but getting this change
|
|
# into the source tree will be tricky...
|
|
# DO NOT USE ID AS IT MAY GO AWAY IN THE FUTURE
|
|
rule partid: ID {{ return ID }}
|
|
| PATH {{ return PATH }}
|
|
|
|
rule parttype: CHIP {{ return '' }}
|
|
|
|
rule partdef<<C>>: {{ name = 0 }}
|
|
parttype partid
|
|
[ STR {{ name = dequote(STR) }}
|
|
] {{ if (C): part(parttype, partid, 'Config.lb', name) }}
|
|
partend<<C>>
|
|
|
|
rule field: STR {{ return STR }}
|
|
|
|
rule register<<C>>: REGISTER field '=' STR {{ if (C): addregister(field, STR) }}
|
|
|
|
rule enable<<C>>: {{ val = 1 }}
|
|
( ON {{ val = 1 }}
|
|
| OFF {{ val = 0 }}
|
|
) {{ if(C): partstack.tos().set_enabled(val) }}
|
|
|
|
rule resource<<C>>: {{ type = "" }}
|
|
( IO {{ type = "IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_IO" }}
|
|
| MEM {{ type = "IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_MEM" }}
|
|
| IRQ {{ type = "IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_IRQ" }}
|
|
| DRQ {{ type = "IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_DRQ" }}
|
|
)
|
|
term '=' {{ index = term }}
|
|
term {{ value = term }}
|
|
{{ if (C): partstack.tos().add_resource(type, index, value) }}
|
|
|
|
|
|
rule resources<<C>>: {{ if (C): partstack.tos().start_resources() }}
|
|
( resource<<C>> )*
|
|
{{ if (C): partstack.tos().end_resources() }}
|
|
|
|
|
|
rule pci<<C>>: PCI {{ if (C): devicepart('pci') }}
|
|
|
|
HEX_NUM {{ slot = int(HEX_NUM,16) }}
|
|
'.' HEX_NUM {{ function = int(HEX_NUM, 16) }}
|
|
{{ if (C): partstack.tos().addpcipath(slot, function) }}
|
|
rule pci_domain<<C>>:
|
|
PCI_DOMAIN {{ if (C): devicepart('pci_domain') }}
|
|
HEX_NUM {{ pci_domain = int(HEX_NUM, 16) }}
|
|
{{ if (C): partstack.tos().addpci_domainpath(pci_domain) }}
|
|
|
|
rule pnp<<C>>: PNP {{ if (C): devicepart('pnp') }}
|
|
HEX_NUM {{ port = int(HEX_NUM,16) }}
|
|
'.' HEX_NUM {{ device = int(HEX_NUM, 16) }}
|
|
{{ if (C): partstack.tos().addpnppath(port, device) }}
|
|
|
|
rule i2c<<C>>: I2C {{ if (C): devicepart('i2c') }}
|
|
HEX_NUM {{ device = int(HEX_NUM, 16) }}
|
|
{{ if (C): partstack.tos().addi2cpath(device) }}
|
|
|
|
rule apic<<C>>: APIC {{ if (C): devicepart('apic') }}
|
|
HEX_NUM {{ apic_id = int(HEX_NUM, 16) }}
|
|
{{ if (C): partstack.tos().addapicpath(apic_id) }}
|
|
|
|
rule apic_cluster<<C>>: APIC_CLUSTER {{ if (C): devicepart('apic_cluster') }}
|
|
HEX_NUM {{ cluster = int(HEX_NUM, 16) }}
|
|
{{ if (C): partstack.tos().addapic_clusterpath(cluster) }}
|
|
|
|
rule cpu<<C>>: CPU {{ if (C): devicepart('cpu') }}
|
|
HEX_NUM {{ id = int(HEX_NUM, 16) }}
|
|
{{ if (C): partstack.tos().addcpupath(id) }}
|
|
|
|
rule cpu_bus<<C>>: CPU_BUS {{ if (C): devicepart('cpu_bus') }}
|
|
HEX_NUM {{ id = int(HEX_NUM, 16) }}
|
|
{{ if (C): partstack.tos().addcpu_buspath(id) }}
|
|
|
|
rule dev_path<<C>>:
|
|
pci<<C>> {{ return pci }}
|
|
| pci_domain<<C>> {{ return pci_domain }}
|
|
| pnp<<C>> {{ return pnp }}
|
|
| i2c<<C>> {{ return i2c }}
|
|
| apic<<C>> {{ return apic }}
|
|
| apic_cluster<<C>> {{ return apic_cluster }}
|
|
| cpu<<C>> {{ return cpu }}
|
|
| cpu_bus<<C>> {{ return cpu_bus }}
|
|
|
|
rule prtval: expr {{ return str(expr) }}
|
|
| STR {{ return STR }}
|
|
|
|
rule prtlist: prtval {{ el = "%(" + prtval }}
|
|
( "," prtval {{ el = el + "," + prtval }}
|
|
)* {{ return el + ")" }}
|
|
|
|
rule prtstmt<<C>>: PRINT STR {{ val = STR }}
|
|
[ "," prtlist {{ val = val + prtlist }}
|
|
] {{ if (C): print eval(val) }}
|
|
|
|
rule device<<C>>: DEVICE dev_path<<C>>
|
|
enable<<C>>
|
|
resources<<C>>
|
|
partend<<C>>
|
|
|
|
rule stmt<<C>>:
|
|
partdef<<C>> {{ return partdef }}
|
|
| prtstmt<<C>> {{ return prtstmt }}
|
|
| register<<C>> {{ return register }}
|
|
| device<<C>> {{ return device }}
|
|
|
|
rule value: STR {{ return dequote(STR) }}
|
|
| expr {{ return expr }}
|
|
|
|
rule devicetree: partdef<<1>>
|
|
EOF {{ return 1 }}
|
|
|
|
rule wrstr<<ID>>: STR {{ setwrite(ID, dequote(STR)) }}
|
|
|
|
%%
|
|
|
|
#=============================================================================
|
|
# FILE OUTPUT
|
|
#=============================================================================
|
|
|
|
def dumptree(part, lvl):
|
|
debug.info(debug.dumptree, "DUMPTREE ME is")
|
|
print "%s " % part
|
|
part.dumpme(lvl)
|
|
# dump the siblings -- actually are there any? not sure
|
|
# siblings are:
|
|
debug.info(debug.dumptree, "DUMPTREE SIBLINGS are")
|
|
kid = part.next_sibling
|
|
while (kid):
|
|
kid.dumpme(lvl)
|
|
kid = kid.next_sibling
|
|
# dump the kids
|
|
debug.info(debug.dumptree, "DUMPTREE KIDS are")
|
|
#for kid in part.children:
|
|
if (part.children):
|
|
dumptree(part.children, lvl+1)
|
|
kid = part.next_sibling
|
|
while (kid):
|
|
if (kid.children):
|
|
dumptree(kid.children, lvl + 1)
|
|
kid = kid.next_sibling
|
|
debug.info(debug.dumptree, "DONE DUMPTREE")
|
|
|
|
def writecode(image):
|
|
filename = os.path.join(img_dir, "static.c")
|
|
print "Creating", filename
|
|
file = safe_open(filename, 'w+')
|
|
file.write("#include <device/device.h>\n")
|
|
file.write("#include <device/pci.h>\n")
|
|
for path in image.getconfigincludes().values():
|
|
file.write("#include \"%s\"\n" % path)
|
|
file.write("\n/* pass 0 */\n")
|
|
gencode(image.getroot(), file, 0)
|
|
file.write("\n/* pass 1 */\n")
|
|
gencode(image.getroot(), file, 1)
|
|
file.close()
|
|
|
|
def gencode(part, file, pass_num):
|
|
debug.info(debug.gencode, "GENCODE ME is")
|
|
part.gencode(file, pass_num)
|
|
# dump the siblings -- actually are there any? not sure
|
|
debug.info(debug.gencode, "GENCODE SIBLINGS are")
|
|
kid = part.next_sibling
|
|
while (kid):
|
|
kid.gencode(file, pass_num)
|
|
kid = kid.next_sibling
|
|
# now dump the children
|
|
debug.info(debug.gencode, "GENCODE KIDS are")
|
|
if (part.children):
|
|
gencode(part.children, file, pass_num)
|
|
kid = part.next_sibling
|
|
while (kid):
|
|
if (kid.children):
|
|
gencode(kid.children, file, pass_num)
|
|
kid = kid.next_sibling
|
|
debug.info(debug.gencode, "DONE GENCODE")
|
|
|
|
def writegraph(image):
|
|
filename = os.path.join(img_dir, "static.dot")
|
|
print "Creating", filename
|
|
file = safe_open(filename, 'w+')
|
|
file.write("digraph devicetree {\n")
|
|
file.write(" rankdir=LR\n")
|
|
genranks(image.getroot(), file, 0)
|
|
gennodes(image.getroot(), file)
|
|
gengraph(image.getroot(), file)
|
|
file.write("}\n")
|
|
file.close()
|
|
|
|
def genranks(part, file, level):
|
|
#file.write(" # Level %d\n" % level )
|
|
file.write(" { rank = same; \"dev_%s_%d\"" % (part.type_name,part.instance ))
|
|
sib = part.next_sibling
|
|
while (sib):
|
|
file.write("; \"dev_%s_%d\"" % (sib.type_name, sib.instance))
|
|
sib = sib.next_sibling
|
|
file.write("}\n" )
|
|
# now dump the children
|
|
if (part.children):
|
|
genranks(part.children, file, level + 1)
|
|
|
|
kid = part.next_sibling
|
|
while (kid):
|
|
if (kid.children):
|
|
genranks(kid.children, file, level + 1)
|
|
kid = kid.next_sibling
|
|
|
|
|
|
def gennodes(part, file):
|
|
file.write(" dev_%s_%d[shape=record, label=\"%s\"];\n" % (part.type_name,part.instance,part.graph_name() ))
|
|
sib = part.next_sibling
|
|
while (sib):
|
|
file.write(" dev_%s_%d[shape=record, label=\"%s\"];\n" % (sib.type_name,sib.instance,sib.graph_name() ))
|
|
sib = sib.next_sibling
|
|
# now dump the children
|
|
if (part.children):
|
|
gennodes(part.children, file)
|
|
|
|
kid = part.next_sibling
|
|
while (kid):
|
|
if (kid.children):
|
|
gennodes(kid.children, file)
|
|
kid = kid.next_sibling
|
|
|
|
|
|
def gengraph(part, file):
|
|
if (part.parent != part):
|
|
file.write(" dev_%s_%d -> dev_%s_%d;\n" % \
|
|
(part.parent.type_name, part.parent.instance, \
|
|
part.type_name, part.instance ))
|
|
sib = part.next_sibling
|
|
while (sib):
|
|
file.write(" dev_%s_%d -> dev_%s_%d;\n" % \
|
|
(sib.parent.type_name, sib.parent.instance, \
|
|
sib.type_name, sib.instance ))
|
|
sib = sib.next_sibling
|
|
|
|
kid = part.next_sibling
|
|
while (kid):
|
|
if (kid.children):
|
|
gengraph(kid.children, file)
|
|
kid = kid.next_sibling
|
|
|
|
if (part.children):
|
|
gengraph(part.children, file)
|
|
|
|
#=============================================================================
|
|
# MAIN PROGRAM
|
|
#=============================================================================
|
|
if __name__=='__main__':
|
|
from sys import argv
|
|
if (len(argv) < 4):
|
|
fatal("Args: <file> <path to coreboot> <output-dir>")
|
|
|
|
file = "devicetree.cb"
|
|
partdir = os.path.join("mainboard", sys.argv[1])
|
|
treetop = argv[2]
|
|
srcdir = os.path.join(treetop, 'src')
|
|
fulldir = os.path.join(srcdir, partdir)
|
|
type_name = flatten_name(partdir)
|
|
config_file = os.path.join(fulldir, file)
|
|
|
|
curimage = romimage("new")
|
|
image = curimage
|
|
|
|
newpart = partobj(curimage, fulldir, partstack.tos(), 'mainboard', \
|
|
'mainboard', 0, 'chip')
|
|
#print "Configuring PART %s, path %s" % (type, path)
|
|
image.setroot(newpart);
|
|
partstack.push(newpart)
|
|
|
|
fp = safe_open(config_file, 'r')
|
|
if (not parse('devicetree', fp.read())):
|
|
fatal("Could not parse file")
|
|
print "PARSED THE TREE"
|
|
partstack.pop()
|
|
|
|
img_dir = argv[3]
|
|
|
|
#debug.info(debug.dumptree, "DEVICE TREE:")
|
|
#dumptree(curimage.getroot(), 0)
|
|
|
|
writecode(image)
|
|
writegraph(image)
|
|
|
|
sys.exit(0)
|