blob: d8bc855021f341802bdacd5e77fee22f61f1230b [file] [log] [blame]
# -*- 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 " SCONFIG ", join(filename.split('/')[-5:], '/')
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 " SCONFIG ", join(filename.split('/')[-5:], '/')
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")
partstack.pop()
img_dir = argv[3]
#debug.info(debug.dumptree, "DEVICE TREE:")
#dumptree(curimage.getroot(), 0)
writecode(image)
writegraph(image)
sys.exit(0)