slimbootloader/BootloaderCorePkg/Tools/GenCfgDataDsc.py

2094 lines
85 KiB
Python

## @ GenCfgData.py
#
# Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
import os
import re
import sys
import struct
import marshal
from functools import reduce
from datetime import date
# Generated file copyright header
__copyright_tmp__ = """/** @file
Platform Configuration %s File.
Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
This file is automatically generated. Please do NOT modify !!!
**/
"""
def Bytes2Val (Bytes):
return reduce(lambda x,y: (x<<8)|y, Bytes[::-1] )
def Bytes2Str (Bytes):
return '{ %s }' % (', '.join('0x%02X' % i for i in Bytes))
def Str2Bytes (Value, Blen):
Result = bytearray(Value[1:-1], 'utf-8') # Excluding quotes
if len(Result) < Blen:
Result.extend(b'\x00' * (Blen - len(Result)))
return Result
def Val2Bytes (Value, Blen):
return [(Value>>(i*8) & 0xff) for i in range(Blen)]
def Array2Val (ValStr):
ValStr = ValStr.strip()
if ValStr.startswith('{'):
ValStr = ValStr[1:]
if ValStr.endswith('}'):
ValStr = ValStr[:-1]
if ValStr.startswith("'"):
ValStr = ValStr[1:]
if ValStr.endswith("'"):
ValStr = ValStr[:-1]
Value = 0
for Each in ValStr.split(',')[::-1]:
Each = Each.strip()
if Each.startswith('0x'):
Base = 16
else:
Base = 10
Value = (Value << 8) | int(Each, Base)
return Value
def GetCopyrightHeader (FileType, AllowModify = False):
FileDescription = {
'bsf' : 'Boot Setting',
'dsc' : 'Definition',
'dlt' : 'Delta',
'inc' : 'C Binary Blob',
'h' : 'C Struct Header'
}
if FileType in ['bsf', 'dsc', 'dlt']:
CommentChar = '#'
else:
CommentChar = ''
Lines = __copyright_tmp__.split('\n')
if AllowModify:
Lines = [Line for Line in Lines if 'Please do NOT modify' not in Line]
CopyrightHdr = '\n'.join('%s%s' % (CommentChar, Line) for Line in Lines)[:-1] + '\n'
return CopyrightHdr % (FileDescription[FileType], date.today().year)
class CLogicalExpression:
def __init__(self):
self.index = 0
self.string = ''
self.dictVariable = {}
self.parenthesisOpenSet = '('
self.parenthesisCloseSet = ')'
def errExit(self, err = ''):
print ("ERROR: Express parsing for:")
print (" %s" % self.string)
print (" %s^" % (' ' * self.index))
if err:
print ("INFO : %s" % err)
raise Exception ("Logical expression parsing error!")
def getNonNumber (self, n1, n2):
if not n1.isdigit():
return n1
if not n2.isdigit():
return n2
return None
def getCurr(self, lens = 1):
try:
if lens == -1:
return self.string[self.index :]
else:
if self.index + lens > len(self.string):
lens = len(self.string) - self.index
return self.string[self.index : self.index + lens]
except Exception:
return ''
def isLast(self):
return self.index == len(self.string)
def moveNext(self, len = 1):
self.index += len
def skipSpace(self):
while not self.isLast():
if self.getCurr() in ' \t':
self.moveNext()
else:
return
def getNumber(self, var):
var = var.strip()
if re.match('^0x[a-fA-F0-9]+$', var):
value = int(var, 16)
elif re.match('^0b[01]+$', var):
value = int(var, 2)
elif re.match('^[+-]?\d+$', var):
value = int(var, 10)
else:
self.errExit("Invalid value '%s'" % var)
return value
def getVariable(self, var):
value = self.dictVariable.get(var, None)
if value == None:
self.errExit("Unrecognized variable '%s'" % var)
return value
def parseValue(self):
self.skipSpace()
var = ''
while not self.isLast():
char = self.getCurr()
if re.match('^[\w.]', char):
var += char
self.moveNext()
else:
break
if len(var):
if var[0].isdigit():
value = self.getNumber(var)
else:
value = self.getVariable(var)
else:
self.errExit('Invalid number or variable found !')
return int(value)
def parseSingleOp(self):
self.skipSpace()
char = self.getCurr()
if char == '~':
self.moveNext()
return ~self.parseBrace()
else:
return self.parseValue()
def parseBrace(self):
self.skipSpace()
char = self.getCurr()
parenthesisType = self.parenthesisOpenSet.find(char)
if parenthesisType >= 0:
self.moveNext()
value = self.parseExpr()
self.skipSpace()
if self.getCurr() != self.parenthesisCloseSet[parenthesisType]:
self.errExit ("No closing brace !")
self.moveNext()
if parenthesisType == 1: # [ : Get content
value = self.getContent(value)
elif parenthesisType == 2: # { : To address
value = self.toAddress(value)
elif parenthesisType == 3: # < : To offset
value = self.toOffset(value)
return value
else:
return self.parseSingleOp()
def parseMul(self):
values = [self.parseBrace()]
ops = ['*']
while True:
self.skipSpace()
char = self.getCurr()
if char == '*':
self.moveNext()
values.append(self.parseBrace())
ops.append(char)
elif char == '/':
self.moveNext()
values.append(self.parseBrace())
ops.append(char)
else:
break
value = 1
for idx, each in enumerate(values):
if ops[idx] == '*':
value *= each
else:
value //= each
return value
def parseAndOr(self):
value = self.parseMul()
op = None
while True:
self.skipSpace()
char = self.getCurr()
if char == '&':
self.moveNext()
value &= self.parseMul()
elif char == '|':
div_index = self.index
self.moveNext()
value |= self.parseMul()
else:
break
return value
def parseAddMinus(self):
values = [self.parseAndOr()]
while True:
self.skipSpace()
char = self.getCurr()
if char == '+':
self.moveNext()
values.append(self.parseAndOr())
elif char == '-':
self.moveNext()
values.append(-1 * self.parseAndOr())
else:
break
return sum(values)
def parseExpr(self):
return self.parseAddMinus()
def evaluateExpress (self, Expr, VarDict = {}):
self.index = 0
self.string = Expr
self.dictVariable = VarDict
Result = self.parseExpr()
return Result
class CGenCfgData:
def __init__(self):
self.Debug = False
self.Error = ''
self.ReleaseMode = True
self._GlobalDataDef = """
GlobalDataDef
SKUID = 0, "DEFAULT"
EndGlobalData
"""
self._BuidinOptionTxt = """
List &EN_DIS
Selection 0x1 , "Enabled"
Selection 0x0 , "Disabled"
EndList
"""
self._StructType = ['UINT8','UINT16','UINT32','UINT64']
self._BsfKeyList = ['FIND','NAME','HELP','TYPE','PAGE', 'PAGES', 'BLOCK', 'OPTION','CONDITION','ORDER', 'MARKER', 'SUBT']
self._HdrKeyList = ['HEADER','STRUCT', 'EMBED', 'COMMENT']
self._BuidinOption = {'$EN_DIS' : 'EN_DIS'}
self._MacroDict = {}
self._VarDict = {}
self._PcdsDict = {}
self._CfgBlkDict = {}
self._CfgPageDict = {}
self._CfgOptsDict = {}
self._BsfTempDict = {}
self._CfgItemList = []
self._DscLines = []
self._DscFile = ''
self._CfgPageTree = {}
self._MapVer = 0
self._MinCfgTagId = 0x100
def ParseMacros (self, MacroDefStr):
# ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']
self._MacroDict = {}
IsExpression = False
for Macro in MacroDefStr:
if Macro.startswith('-D'):
IsExpression = True
if len(Macro) > 2:
Macro = Macro[2:]
else :
continue
if IsExpression:
IsExpression = False
Match = re.match("(\w+)=(.+)", Macro)
if Match:
self._MacroDict[Match.group(1)] = Match.group(2)
else:
Match = re.match("(\w+)", Macro)
if Match:
self._MacroDict[Match.group(1)] = ''
if len(self._MacroDict) == 0:
Error = 1
else:
Error = 0
if self.Debug:
print ("INFO : Macro dictionary:")
for Each in self._MacroDict:
print (" $(%s) = [ %s ]" % (Each , self._MacroDict[Each]))
return Error
def EvaulateIfdef (self, Macro):
Result = Macro in self._MacroDict
if self.Debug:
print ("INFO : Eval Ifdef [%s] : %s" % (Macro, Result))
return Result
def ExpandMacros (self, Input, Preserve = False):
Line = Input
Match = re.findall("\$\(\w+\)", Input)
if Match:
for Each in Match:
Variable = Each[2:-1]
if Variable in self._MacroDict:
Line = Line.replace(Each, self._MacroDict[Variable])
else:
if self.Debug:
print ("WARN : %s is not defined" % Each)
if not Preserve:
Line = Line.replace(Each, Each[2:-1])
return Line
def ExpandPcds (self, Input):
Line = Input
Match = re.findall("(\w+\.\w+)", Input)
if Match:
for PcdName in Match:
if PcdName in self._PcdsDict:
Line = Line.replace(PcdName, self._PcdsDict[PcdName])
else:
if self.Debug:
print ("WARN : %s is not defined" % PcdName)
return Line
def EvaluateExpress (self, Expr):
ExpExpr = self.ExpandPcds(Expr)
ExpExpr = self.ExpandMacros(ExpExpr)
LogExpr = CLogicalExpression()
Result = LogExpr.evaluateExpress (ExpExpr, self._VarDict)
if self.Debug:
print ("INFO : Eval Express [%s] : %s" % (Expr, Result))
return Result
def ValueToByteArray (self, ValueStr, Length):
Match = re.match("\{\s*FILE:(.+)\}", ValueStr)
if Match:
FileList = Match.group(1).split(',')
Result = bytearray()
for File in FileList:
File = File.strip()
BinPath = os.path.join(os.path.dirname(self._DscFile), File)
Result.extend(bytearray(open(BinPath, 'rb').read()))
else:
try:
Result = bytearray(self.ValueToList(ValueStr, Length))
except ValueError as e:
raise Exception ("Bytes in '%s' must be in range 0~255 !" % ValueStr)
if len(Result) < Length:
Result.extend(b'\x00' * (Length - len(Result)))
elif len(Result) > Length:
raise Exception ("Value '%s' is too big to fit into %d bytes !" % (ValueStr, Length))
return Result[:Length]
def ValueToList (self, ValueStr, Length):
if ValueStr[0] == '{':
Result = []
BinList = ValueStr[1:-1].split(',')
InBitField = False
LastInBitField = False
Value = 0
BitLen = 0
for Element in BinList:
InBitField = False
Each = Element.strip()
if len(Each) == 0:
pass
else:
if Each[0] in ['"', "'"]:
Result.extend(list(bytearray(Each[1:-1], 'utf-8')))
elif ':' in Each:
Match = re.match("(.+):(\d+)b", Each)
if Match is None:
raise Exception("Invald value list format '%s' !" % Each)
InBitField = True
CurrentBitLen = int(Match.group(2))
CurrentValue = ((self.EvaluateExpress(Match.group(1)) & (1<<CurrentBitLen) - 1)) << BitLen
else:
Result.append(self.EvaluateExpress(Each.strip()))
if InBitField:
Value += CurrentValue
BitLen += CurrentBitLen
if LastInBitField and ((not InBitField) or (Element == BinList[-1])):
if BitLen % 8 != 0:
raise Exception("Invald bit field length!")
Result.extend(Val2Bytes(Value, BitLen // 8))
Value = 0
BitLen = 0
LastInBitField = InBitField
elif ValueStr.startswith("'") and ValueStr.endswith("'"):
Result = Str2Bytes (ValueStr, Length)
elif ValueStr.startswith('"') and ValueStr.endswith('"'):
Result = Str2Bytes (ValueStr, Length)
else:
Result = Val2Bytes (self.EvaluateExpress(ValueStr), Length)
return Result
def FormatDeltaValue(self, ConfigDict):
ValStr = ConfigDict['value']
if ValStr[0] == "'":
# Remove padding \x00 in the value string
ValStr = "'%s'" % ValStr[1:-1].rstrip('\x00')
Struct = ConfigDict['struct']
if Struct in self._StructType:
# Format the array using its struct type
Unit = int(Struct[4:]) // 8
Value = Array2Val(ConfigDict['value'])
Loop = ConfigDict['length'] // Unit
Values = []
for Each in range(Loop):
Values.append (Value & ((1 << (Unit * 8)) - 1))
Value = Value >> (Unit * 8)
ValStr = '{ ' + ', '.join ([('0x%%0%dX' % (Unit * 2)) % x for x in Values]) + ' }'
return ValStr
def FormatListValue(self, ConfigDict):
Struct = ConfigDict['struct']
if Struct not in self._StructType:
return
DataList = self.ValueToList(ConfigDict['value'], ConfigDict['length'])
Unit = int(Struct[4:]) // 8
if int(ConfigDict['length']) != Unit * len(DataList):
# Fallback to byte array
Unit = 1
if int(ConfigDict['length']) != len(DataList):
raise Exception("Array size is not proper for '%s' !" % ConfigDict['cname'])
ByteArray = []
for Value in DataList:
for Loop in range(Unit):
ByteArray.append("0x%02X" % (Value & 0xFF))
Value = Value >> 8
NewValue = '{' + ','.join(ByteArray) + '}'
ConfigDict['value'] = NewValue
return ""
def GetOrderNumber (self, Offset, Order, BitOff = 0):
if isinstance(Order, int):
if Order == -1:
Order = Offset << 16
else:
(Major, Minor) = Order.split('.')
Order = (int (Major, 16) << 16) + ((int (Minor, 16) & 0xFF) << 8)
return Order + (BitOff & 0xFF)
def SubtituteLine (self, Line, Args):
Args = Args.strip()
Vars = Args.split(':')
Line = self.ExpandMacros(Line, True)
for Idx in range(len(Vars)-1, 0, -1):
Line = Line.replace('$(%d)' % Idx, Vars[Idx].strip())
Remaining = re.findall ('\$\(\d+\)', Line)
if len(Remaining) > 0:
raise Exception ("ERROR: Unknown argument '%s' for template '%s' !" % (Remaining[0], Vars[0]))
return Line
def CfgDuplicationCheck (self, CfgDict, Name):
if not self.Debug:
return
if Name == 'Dummy':
return
if Name not in CfgDict:
CfgDict[Name] = 1
else:
print ("WARNING: Duplicated item found '%s' !" % ConfigDict['cname'])
def AddBsfChildPage (self, Child, Parent = 'root'):
def AddBsfChildPageRecursive (PageTree, Parent, Child):
Key = next(iter(PageTree))
if Parent == Key:
PageTree[Key].append({Child : []})
return True
else:
Result = False
for Each in PageTree[Key]:
if AddBsfChildPageRecursive (Each, Parent, Child):
Result = True
break
return Result
return AddBsfChildPageRecursive (self._CfgPageTree, Parent, Child)
def ParseDscFile (self, DscFile):
self._DscLines = []
self._CfgItemList = []
self._CfgPageDict = {}
self._CfgBlkDict = {}
self._BsfTempDict = {}
self._CfgPageTree = {'root' : []}
self._DscFile = DscFile
CfgDict = {}
SectionNameList = ["Defines".lower(), "PcdsFeatureFlag".lower(),
"PcdsDynamicVpd.Tmp".lower(), "PcdsDynamicVpd.Upd".lower()]
IsDefSect = False
IsPcdSect = False
IsUpdSect = False
IsTmpSect = False
TemplateName = ''
IfStack = []
ElifStack = []
Error = 0
ConfigDict = {}
DscFd = open(DscFile, "r")
DscLines = DscFd.readlines()
DscFd.close()
BsfRegExp = re.compile("(%s):{(.+?)}(?:$|\s+)" % '|'.join(self._BsfKeyList))
HdrRegExp = re.compile("(%s):{(.+?)}" % '|'.join(self._HdrKeyList))
CfgRegExp = re.compile("^([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+|\*)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)")
TksRegExp = re.compile("^(g[_a-zA-Z0-9]+\.)(.+)")
SkipLines = 0
while len(DscLines):
DscLine = DscLines.pop(0).strip()
if SkipLines == 0:
self._DscLines.append (DscLine)
else:
SkipLines = SkipLines - 1
if len(DscLine) == 0:
continue
Handle = False
Match = re.match("^\[(.+)\]", DscLine)
if Match is not None:
IsDefSect = False
IsPcdSect = False
IsUpdSect = False
IsTmpSect = False
SectionName = Match.group(1).lower()
if SectionName == SectionNameList[0]:
IsDefSect = True
if SectionName == SectionNameList[1]:
IsPcdSect = True
elif SectionName == SectionNameList[2]:
IsTmpSect = True
elif SectionName == SectionNameList[3]:
ConfigDict = {
'header' : 'ON',
'page' : '',
'name' : '',
'find' : '',
'struct' : '',
'embed' : '',
'marker' : '',
'option' : '',
'comment' : '',
'condition' : '',
'order' : -1,
'subreg' : []
}
IsUpdSect = True
Offset = 0
else:
if IsDefSect or IsPcdSect or IsUpdSect or IsTmpSect:
Match = False if DscLine[0] != '!' else True
if Match:
Match = re.match("^!(else|endif|ifdef|ifndef|if|elseif|include)\s*(.+)?$", DscLine)
Keyword = Match.group(1) if Match else ''
Remaining = Match.group(2) if Match else ''
Remaining = '' if Remaining is None else Remaining.strip()
if Keyword in ['if', 'elseif', 'ifdef', 'ifndef', 'include'] and not Remaining:
raise Exception ("ERROR: Expression is expected after '!if' or !elseif' for line '%s'" % DscLine)
if Keyword == 'else':
if IfStack:
IfStack[-1] = not IfStack[-1]
else:
raise Exception ("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine)
elif Keyword == 'endif':
if IfStack:
IfStack.pop()
Level = ElifStack.pop()
if Level > 0:
del IfStack[-Level:]
else:
raise Exception ("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine)
elif Keyword == 'ifdef' or Keyword == 'ifndef':
Result = self.EvaulateIfdef (Remaining)
if Keyword == 'ifndef':
Result = not Result
IfStack.append(Result)
ElifStack.append(0)
elif Keyword == 'if' or Keyword == 'elseif':
Result = self.EvaluateExpress(Remaining)
if Keyword == "if":
ElifStack.append(0)
IfStack.append(Result)
else: #elseif
if IfStack:
IfStack[-1] = not IfStack[-1]
IfStack.append(Result)
ElifStack[-1] = ElifStack[-1] + 1
else:
raise Exception ("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine)
else:
if IfStack:
Handle = reduce(lambda x,y: x and y, IfStack)
else:
Handle = True
if Handle:
if Keyword == 'include':
Remaining = self.ExpandMacros(Remaining)
# Relative to DSC filepath
IncludeFilePath = os.path.join(os.path.dirname(DscFile), Remaining)
if not os.path.exists(IncludeFilePath):
# Relative to repository to find dsc in common platform
IncludeFilePath = os.path.abspath(os.path.join(os.path.dirname(DscFile), "../../..", Remaining))
try:
IncludeDsc = open(IncludeFilePath, "r")
except:
raise Exception ("ERROR: Cannot open file '%s'." % IncludeFilePath)
NewDscLines = IncludeDsc.readlines()
IncludeDsc.close()
StartTag = ['# !< include %s\n' % Remaining]
EndTag = ['# !> include %s\n' % Remaining]
DscLines = StartTag + NewDscLines + EndTag + DscLines
del self._DscLines[-1]
else:
if DscLine.startswith('!'):
raise Exception ("ERROR: Unrecoginized directive for line '%s'" % DscLine)
if not Handle:
continue
if IsDefSect:
Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*(.+)", DscLine)
if Match:
self._MacroDict[Match.group(1)] = Match.group(2)
if self.Debug:
print ("INFO : DEFINE %s = [ %s ]" % (Match.group(1), Match.group(2)))
elif IsPcdSect:
Match = re.match("^\s*([\w\.]+)\s*\|\s*(\w+)", DscLine)
if Match:
self._PcdsDict[Match.group(1)] = Match.group(2)
if self.Debug:
print ("INFO : PCD %s = [ %s ]" % (Match.group(1), Match.group(2)))
elif IsTmpSect:
# !BSF DEFT:{GPIO_TMPL:START}
Match = re.match("^\s*#\s+(!BSF)\s+DEFT:{(.+?):(START|END)}", DscLine)
if Match:
if Match.group(3) == 'START' and not TemplateName:
TemplateName = Match.group(2).strip()
self._BsfTempDict[TemplateName] = []
if Match.group(3) == 'END' and (TemplateName == Match.group(2).strip()) and TemplateName:
TemplateName = ''
else:
if TemplateName:
Match = re.match("^!include\s*(.+)?$", DscLine)
if Match:
continue
self._BsfTempDict[TemplateName].append(DscLine)
else:
Match = re.match("^\s*#\s+(!BSF|!HDR)\s+(.+)", DscLine)
if Match:
Remaining = Match.group(2)
if Match.group(1) == '!BSF':
Result = BsfRegExp.findall (Remaining)
if Result:
for Each in Result:
Key = Each[0]
Remaining = Each[1]
if Key == 'BLOCK':
Match = re.match("NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*", Remaining)
if Match:
self._CfgBlkDict['name'] = Match.group(1)
self._CfgBlkDict['ver'] = Match.group(2)
elif Key == 'SUBT':
#GPIO_TMPL:1:2:3
Remaining = Remaining.strip()
Match = re.match("(\w+)\s*:", Remaining)
if Match:
TemplateName = Match.group(1)
for Line in self._BsfTempDict[TemplateName][::-1]:
NewLine = self.SubtituteLine (Line, Remaining)
DscLines.insert(0, NewLine)
SkipLines += 1
elif Key == 'PAGES':
# !BSF PAGES:{HSW:"Haswell System Agent", LPT:"Lynx Point PCH"}
PageList = Remaining.split(',')
for Page in PageList:
Page = Page.strip()
Match = re.match('(\w+):(\w*:)?\"(.+)\"', Page)
if Match:
PageName = Match.group(1)
ParentName = Match.group(2)
if not ParentName or ParentName == ':' :
ParentName = 'root'
else:
ParentName = ParentName[:-1]
if not self.AddBsfChildPage (PageName, ParentName):
raise Exception("Cannot find parent page '%s'!" % ParentName)
self._CfgPageDict[PageName] = Match.group(3)
else:
raise Exception("Invalid page definitions '%s'!" % Page)
elif Key in ['NAME', 'HELP', 'OPTION'] and Remaining.startswith('+'):
# Allow certain options to be extended to multiple lines
ConfigDict[Key.lower()] += Remaining[1:]
else:
if Key == 'NAME':
Remaining = Remaining.strip()
elif Key == 'CONDITION':
Remaining = self.ExpandMacros(Remaining.strip())
ConfigDict[Key.lower()] = Remaining
else:
Match = HdrRegExp.match(Remaining)
if Match:
Key = Match.group(1)
Remaining = Match.group(2)
if Key == 'EMBED':
Parts = Remaining.split(':')
Names = Parts[0].split(',')
DummyDict = ConfigDict.copy()
if len(Names) > 1:
Remaining = Names[0] + ':' + ':'.join(Parts[1:])
DummyDict['struct'] = Names[1]
else:
DummyDict['struct'] = Names[0]
DummyDict['cname'] = 'Dummy'
DummyDict['name'] = ''
DummyDict['embed'] = Remaining
DummyDict['offset'] = Offset
DummyDict['length'] = 0
DummyDict['value'] = '0'
DummyDict['type'] = 'Reserved'
DummyDict['help'] = ''
DummyDict['subreg'] = []
self._CfgItemList.append(DummyDict)
else:
ConfigDict[Key.lower()] = Remaining
# Check CFG line
# gCfgData.VariableName | * | 0x01 | 0x1
Clear = False
Match = TksRegExp.match (DscLine)
if Match:
DscLine = 'gCfgData.%s' % Match.group(2)
if DscLine.startswith('gCfgData.'):
Match = CfgRegExp.match(DscLine[9:])
else:
Match = None
if Match:
ConfigDict['space'] = 'gCfgData'
ConfigDict['cname'] = Match.group(1)
if Match.group(2) != '*':
Offset = int (Match.group(2), 16)
ConfigDict['offset'] = Offset
ConfigDict['order'] = self.GetOrderNumber (ConfigDict['offset'], ConfigDict['order'])
Value = Match.group(4).strip()
if Match.group(3).startswith("0x"):
Length = int (Match.group(3), 16)
else :
Length = int (Match.group(3))
Offset += Length
ConfigDict['length'] = Length
Match = re.match("\$\((\w+)\)", Value)
if Match:
if Match.group(1) in self._MacroDict:
Value = self._MacroDict[Match.group(1)]
ConfigDict['value'] = Value
if re.match("\{\s*FILE:(.+)\}", Value):
# Expand embedded binary file
ValArray = self.ValueToByteArray (ConfigDict['value'], ConfigDict['length'])
NewValue = Bytes2Str(ValArray)
self._DscLines[-1] = re.sub(r'(.*)(\{\s*FILE:.+\})' , r'\1 %s' % NewValue, self._DscLines[-1])
ConfigDict['value'] = NewValue
if ConfigDict['name'] == '':
# Clear BSF specific items
ConfigDict['bsfname'] = ''
ConfigDict['help'] = ''
ConfigDict['type'] = ''
ConfigDict['option'] = ''
self.CfgDuplicationCheck (CfgDict, ConfigDict['cname'])
self._CfgItemList.append(ConfigDict.copy())
Clear = True
else:
# It could be a virtual item as below
# !BSF FIELD:{SerialDebugPortAddress0:1}
# or
# @Bsf FIELD:{SerialDebugPortAddress0:1b}
Match = re.match("^\s*#\s+(!BSF)\s+FIELD:{(.+)}", DscLine)
if Match:
BitFieldTxt = Match.group(2)
Match = re.match("(.+):(\d+)b([BWDQ])?", BitFieldTxt)
if not Match:
raise Exception ("Incorrect bit field format '%s' !" % BitFieldTxt)
UnitBitLen = 1
SubCfgDict = ConfigDict.copy()
SubCfgDict['cname'] = Match.group(1)
SubCfgDict['bitlength'] = int (Match.group(2)) * UnitBitLen
if SubCfgDict['bitlength'] > 0:
LastItem = self._CfgItemList[-1]
if len(LastItem['subreg']) == 0:
SubOffset = 0
else:
SubOffset = LastItem['subreg'][-1]['bitoffset'] + LastItem['subreg'][-1]['bitlength']
if Match.group(3) == 'B':
SubCfgDict['bitunit'] = 1
elif Match.group(3) == 'W':
SubCfgDict['bitunit'] = 2
elif Match.group(3) == 'Q':
SubCfgDict['bitunit'] = 8
else:
SubCfgDict['bitunit'] = 4
SubCfgDict['bitoffset'] = SubOffset
SubCfgDict['order'] = self.GetOrderNumber (SubCfgDict['offset'], SubCfgDict['order'], SubOffset)
SubCfgDict['value'] = ''
SubCfgDict['cname'] = '%s_%s' % (LastItem['cname'], Match.group(1))
self.CfgDuplicationCheck (CfgDict, SubCfgDict['cname'])
LastItem['subreg'].append (SubCfgDict.copy())
Clear = True
if Clear:
ConfigDict['name'] = ''
ConfigDict['find'] = ''
ConfigDict['struct'] = ''
ConfigDict['embed'] = ''
ConfigDict['marker'] = ''
ConfigDict['comment'] = ''
ConfigDict['order'] = -1
ConfigDict['subreg'] = []
ConfigDict['option'] = ''
ConfigDict['condition'] = ''
return Error
def GetBsfBitFields (self, subitem, bytes):
start = subitem['bitoffset']
end = start + subitem['bitlength']
bitsvalue = ''.join('{0:08b}'.format(i) for i in bytes[::-1])
bitsvalue = bitsvalue[::-1]
bitslen = len(bitsvalue)
if start > bitslen or end > bitslen:
raise Exception ("Invalid bits offset [%d,%d] %d for %s" % (start, end, bitslen, subitem['name']))
return '0x%X' % (int(bitsvalue[start:end][::-1], 2))
def UpdateBsfBitFields (self, SubItem, NewValue, ValueArray):
Start = SubItem['bitoffset']
End = Start + SubItem['bitlength']
Blen = len (ValueArray)
BitsValue = ''.join('{0:08b}'.format(i) for i in ValueArray[::-1])
BitsValue = BitsValue[::-1]
BitsLen = len(BitsValue)
if Start > BitsLen or End > BitsLen:
raise Exception ("Invalid bits offset [%d,%d] %d for %s" % (Start, End, BitsLen, SubItem['name']))
BitsValue = BitsValue[:Start] + '{0:0{1}b}'.format(NewValue, SubItem['bitlength'])[::-1] + BitsValue[End:]
ValueArray[:] = bytearray.fromhex('{0:0{1}x}'.format(int(BitsValue[::-1], 2), Blen * 2))[::-1]
def CreateVarDict (self):
Error = 0
self._VarDict = {}
if len(self._CfgItemList) > 0:
Item = self._CfgItemList[-1]
self._VarDict['_LENGTH_'] = '%d' % (Item['offset'] + Item['length'])
for Item in self._CfgItemList:
Embed = Item['embed']
Match = re.match("^(\w+):(\w+):(START|END)", Embed)
if Match:
StructName = Match.group(1)
VarName = '_%s_%s_' % (Match.group(3), StructName)
if Match.group(3) == 'END':
self._VarDict[VarName] = Item['offset'] + Item['length']
self._VarDict['_LENGTH_%s_' % StructName] = \
self._VarDict['_END_%s_' % StructName] - self._VarDict['_START_%s_' % StructName]
if Match.group(2).startswith('TAG_'):
if self._VarDict['_LENGTH_%s_' % StructName] % 4:
raise Exception("Size of structure '%s' is %d, not DWORD aligned !" % (StructName, self._VarDict['_LENGTH_%s_' % StructName]))
self._VarDict['_TAG_%s_' % StructName] = int (Match.group(2)[4:], 16) & 0xFFF
else:
self._VarDict[VarName] = Item['offset']
if Item['marker']:
self._VarDict['_OFFSET_%s_' % Item['marker'].strip()] = Item['offset']
return Error
def UpdateBsfBitUnit (self, Item):
BitTotal = 0
BitOffset = 0
StartIdx = 0
Unit = None
UnitDec = {1:'BYTE', 2:'WORD', 4:'DWORD', 8:'QWORD'}
for Idx, SubItem in enumerate(Item['subreg']):
if Unit is None:
Unit = SubItem['bitunit']
BitLength = SubItem['bitlength']
BitTotal += BitLength
BitOffset += BitLength
if BitOffset > 64 or BitOffset > Unit * 8:
break
if BitOffset == Unit * 8:
for SubIdx in range (StartIdx, Idx + 1):
Item['subreg'][SubIdx]['bitunit'] = Unit
BitOffset = 0
StartIdx = Idx + 1
Unit = None
if BitOffset > 0:
raise Exception ("Bit fields cannot fit into %s for '%s.%s' !" % (UnitDec[Unit], Item['cname'], SubItem['cname']))
ExpectedTotal = Item['length'] * 8
if Item['length'] * 8 != BitTotal:
raise Exception ("Bit fields total length (%d) does not match length (%d) of '%s' !" % (BitTotal, ExpectedTotal, Item['cname']))
def UpdateDefaultValue (self):
Error = 0
for Idx, Item in enumerate(self._CfgItemList):
if len(Item['subreg']) == 0:
Value = Item['value']
if (len(Value) > 0) and (Value[0] == '{' or Value[0] == "'" or Value[0] == '"'):
# {XXX} or 'XXX' strings
self.FormatListValue(self._CfgItemList[Idx])
else:
Match = re.match("(0x[0-9a-fA-F]+|[0-9]+)", Value)
if not Match:
NumValue = self.EvaluateExpress (Value)
Item['value'] = '0x%X' % NumValue
else:
ValArray = self.ValueToByteArray (Item['value'], Item['length'])
for SubItem in Item['subreg']:
SubItem['value'] = self.GetBsfBitFields(SubItem, ValArray)
self.UpdateBsfBitUnit (Item)
return Error
@staticmethod
def ExpandIncludeFiles (FilePath, CurDir = ''):
if CurDir == '':
CurDir = os.path.dirname(FilePath)
FilePath = os.path.basename(FilePath)
InputFilePath = os.path.join(CurDir, FilePath)
File = open(InputFilePath, "r")
Lines = File.readlines()
File.close()
NewLines = []
for LineNum, Line in enumerate(Lines):
Match = re.match("^!include\s*(.+)?$", Line.strip())
if Match:
IncPath = Match.group(1)
TmpPath = os.path.join(CurDir, IncPath)
OrgPath = TmpPath
if not os.path.exists(TmpPath):
CurDir = os.path.join(os.path.dirname (os.path.realpath(__file__)), "..", "..")
TmpPath = os.path.join(CurDir, IncPath)
if not os.path.exists(TmpPath):
raise Exception ("ERROR: Cannot open include file '%s'." % OrgPath)
else:
NewLines.append (('# Included from file: %s\n' % IncPath, TmpPath, 0))
NewLines.append (('# %s\n' % ('=' * 80), TmpPath, 0))
NewLines.extend (CGenCfgData.ExpandIncludeFiles (IncPath, CurDir))
else:
NewLines.append ((Line, InputFilePath, LineNum))
return NewLines
def OverrideDefaultValue (self, DltFile):
Error = 0
DltLines = CGenCfgData.ExpandIncludeFiles (DltFile);
PlatformId = None
for Line, FilePath, LineNum in DltLines:
Line = Line.strip()
if not Line or Line.startswith('#'):
continue
Match = re.match("\s*(\w+)\.(\w+)(\.\w+)?\s*\|\s*(.+)", Line)
if not Match:
raise Exception("Unrecognized line '%s' (File:'%s' Line:%d) !" % (Line, FilePath, LineNum + 1))
Found = False
InScope = False
for Idx, Item in enumerate(self._CfgItemList):
if not InScope:
if not (Item['embed'].endswith(':START') and Item['embed'].startswith(Match.group(1))):
continue
InScope = True
if Item['cname'] == Match.group(2):
Found = True
break
if Item['embed'].endswith(':END') and Item['embed'].startswith(Match.group(1)):
break
Name = '%s.%s' % (Match.group(1),Match.group(2))
if not Found:
ErrItem = Match.group(2) if InScope else Match.group(1)
raise Exception("Invalid configuration '%s' in '%s' (File:'%s' Line:%d) !" %
(ErrItem, Name, FilePath, LineNum + 1))
ValueStr = Match.group(4).strip()
if Match.group(3) is not None:
# This is a subregion item
BitField = Match.group(3)[1:]
Found = False
if len(Item['subreg']) > 0:
for SubItem in Item['subreg']:
if SubItem['cname'] == '%s_%s' % (Item['cname'], BitField):
Found = True
break
if not Found:
raise Exception("Invalid configuration bit field '%s' in '%s.%s' (File:'%s' Line:%d) !" %
(BitField, Name, BitField, FilePath, LineNum + 1))
try:
Value = int(ValueStr, 16) if ValueStr.startswith('0x') else int(ValueStr, 10)
except:
raise Exception("Invalid value '%s' for bit field '%s.%s' (File:'%s' Line:%d) !" %
(ValueStr, Name, BitField, FilePath, LineNum + 1))
if Value >= 2 ** SubItem['bitlength']:
raise Exception("Invalid configuration bit field value '%s' for '%s.%s' (File:'%s' Line:%d) !" %
(Value, Name, BitField, FilePath, LineNum + 1))
ValArray = self.ValueToByteArray (Item['value'], Item['length'])
self.UpdateBsfBitFields (SubItem, Value, ValArray)
if Item['value'].startswith('{'):
Item['value'] = '{' + ', '.join('0x%02X' % i for i in ValArray) + '}'
else:
BitsValue = ''.join('{0:08b}'.format(i) for i in ValArray[::-1])
Item['value'] = '0x%X' % (int(BitsValue, 2))
else:
if Item['value'].startswith('{') and not ValueStr.startswith('{'):
raise Exception("Data array required for '%s' (File:'%s' Line:%d) !" % (Name, FilePath, LineNum + 1))
Item['value'] = ValueStr
if Name == 'PLATFORMID_CFG_DATA.PlatformId':
PlatformId = ValueStr
if PlatformId is None:
raise Exception("PLATFORMID_CFG_DATA.PlatformId is missing in file '%s' !" % (DltFile))
return Error
def ProcessMultilines (self, String, MaxCharLength):
Multilines = ''
StringLength = len(String)
CurrentStringStart = 0
StringOffset = 0
BreakLineDict = []
if len(String) <= MaxCharLength:
while (StringOffset < StringLength):
if StringOffset >= 1:
if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
BreakLineDict.append (StringOffset + 1)
StringOffset += 1
if BreakLineDict != []:
for Each in BreakLineDict:
Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip()
CurrentStringStart = Each
if StringLength - CurrentStringStart > 0:
Multilines += " %s\n" % String[CurrentStringStart:].lstrip()
else:
Multilines = " %s\n" % String
else:
NewLineStart = 0
NewLineCount = 0
FoundSpaceChar = False
while (StringOffset < StringLength):
if StringOffset >= 1:
if NewLineCount >= MaxCharLength - 1:
if String[StringOffset] == ' ' and StringLength - StringOffset > 10:
BreakLineDict.append (NewLineStart + NewLineCount)
NewLineStart = NewLineStart + NewLineCount
NewLineCount = 0
FoundSpaceChar = True
elif StringOffset == StringLength - 1 and FoundSpaceChar == False:
BreakLineDict.append (0)
if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
BreakLineDict.append (StringOffset + 1)
NewLineStart = StringOffset + 1
NewLineCount = 0
StringOffset += 1
NewLineCount += 1
if BreakLineDict != []:
BreakLineDict.sort ()
for Each in BreakLineDict:
if Each > 0:
Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip()
CurrentStringStart = Each
if StringLength - CurrentStringStart > 0:
Multilines += " %s\n" % String[CurrentStringStart:].lstrip()
return Multilines
def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help, Option, BitsLength = None):
PosName = 28
PosComment = 30
NameLine=''
HelpLine=''
OptionLine=''
if Length == 0 and Name == 'Dummy':
return '\n'
IsArray = False
if Length in [1,2,4,8]:
Type = "UINT%d" % (Length * 8)
else:
IsArray = True
Type = "UINT8"
if Item and Item['value'].startswith('{'):
Type = "UINT8"
IsArray = True
if Struct != '':
Type = Struct
if Struct in ['UINT8','UINT16','UINT32','UINT64']:
IsArray = True
Unit = int(Type[4:]) // 8
Length = Length / Unit
else:
IsArray = False
if IsArray:
Name = Name + '[%d]' % Length
if len(Type) < PosName:
Space1 = PosName - len(Type)
else:
Space1 = 1
if BsfName != '':
NameLine=" %s\n" % BsfName
else:
NameLine="\n"
if Help != '':
HelpLine = self.ProcessMultilines (Help, 80)
if Option != '':
OptionLine = self.ProcessMultilines (Option, 80)
if Offset is None:
OffsetStr = '????'
else:
OffsetStr = '0x%04X' % Offset
if BitsLength is None:
BitsLength = ''
else:
BitsLength = ' : %d' % BitsLength
return "\n/** %s%s%s**/\n %s%s%s%s;\n" % (NameLine, HelpLine, OptionLine, Type, ' ' * Space1, Name, BitsLength)
def SplitTextBody (self, TextBody):
Marker1 = '{ /* _COMMON_STRUCT_START_ */'
Marker2 = '; /* _COMMON_STRUCT_END_ */'
ComBody = []
TxtBody = []
IsCommon = False
for Line in TextBody:
if Line.strip().endswith(Marker1):
Line = Line.replace(Marker1[1:], '')
IsCommon = True
if Line.strip().endswith(Marker2):
Line = Line.replace(Marker2[1:], '')
if IsCommon:
ComBody.append(Line)
IsCommon = False
continue
if IsCommon:
ComBody.append(Line)
else:
TxtBody.append(Line)
return ComBody, TxtBody
def GetStructArrayInfo (self, Input):
ArrayStr = Input.split('[')
Name = ArrayStr[0]
if len(ArrayStr) > 1:
NumStr = ''.join(c for c in ArrayStr[-1] if c.isdigit())
NumStr = '1000' if len(NumStr) == 0 else NumStr
ArrayNum = int(NumStr)
else:
ArrayNum = 0
return Name, ArrayNum
def PostProcessBody (self, TextBody, IncludeEmbedOnly = True):
NewTextBody = []
OldTextBody = []
IncTextBody = []
StructBody = []
IncludeLine = False
LineIsDef = False
EmbedFound = False
StructName = ''
ArrayVarName = ''
VariableName = ''
Count = 0
Level = 0
BaseOffset = 0
IsCommonStruct = False
EmbedStructRe = re.compile("^/\*\sEMBED_STRUCT:([\w\[\]\*]+):([\w\[\]\*]+):(\w+):(START|END)([\s\d]+)\*/([\s\S]*)")
for Line in TextBody:
if Line.startswith('#define '):
IncTextBody.append(Line)
continue
if not Line.startswith ('/* EMBED_STRUCT:'):
Match = False
else:
Match = EmbedStructRe.match(Line)
if Match:
ArrayMarker = Match.group(5)
if Match.group(4) == 'END':
Level -= 1
if Level == 0:
Line = Match.group(6)
else: # 'START'
Level += 1
if Level == 1:
Line = Match.group(6)
else:
EmbedFound = True
TagStr = Match.group(3)
if TagStr.startswith('TAG_'):
try:
TagVal = int(TagStr[4:], 16)
except:
TagVal = -1
if (TagVal >= 0) and (TagVal < self._MinCfgTagId):
IsCommonStruct = True
if Level == 1:
if IsCommonStruct:
Suffix = ' /* _COMMON_STRUCT_START_ */'
else:
Suffix = ''
StructBody = ['typedef struct {%s' % Suffix]
StructName = Match.group(1)
StructType = Match.group(2)
VariableName = Match.group(3)
MatchOffset = re.search('/\*\*\sOffset\s0x([a-fA-F0-9]+)', Line)
if MatchOffset:
Offset = int(MatchOffset.group(1), 16)
else:
Offset = None
IncludeLine = True
BaseOffset = Offset
ModifiedStructType = StructType.rstrip()
if ModifiedStructType.endswith(']'):
Idx = ModifiedStructType.index('[')
if ArrayMarker != ' ':
# Auto array size
OldTextBody.append('')
ArrayVarName = VariableName
if int(ArrayMarker) == 1000:
Count = 1
else:
Count = int(ArrayMarker) + 1000
else:
if Count < 1000:
Count += 1
VariableTemp = ArrayVarName + '[%d]' % (Count if Count < 1000 else Count - 1000)
OldTextBody[-1] = self.CreateField (None, VariableTemp, 0, Offset, ModifiedStructType[:Idx], '', 'Structure Array', '')
else:
ArrayVarName = ''
OldTextBody.append (self.CreateField (None, VariableName, 0, Offset, ModifiedStructType, '', '', ''))
if IncludeLine:
StructBody.append (Line)
else:
OldTextBody.append (Line)
if Match and Match.group(4) == 'END':
if Level == 0:
if (StructType != Match.group(2)) or (VariableName != Match.group(3)):
print ("Unmatched struct name '%s' and '%s' !" % (StructName, Match.group(2)))
else:
if IsCommonStruct:
Suffix = ' /* _COMMON_STRUCT_END_ */'
else:
Suffix = ''
Line = '} %s;%s\n\n\n' % (StructName, Suffix)
StructBody.append (Line)
if (Line not in NewTextBody) and (Line not in OldTextBody):
NewTextBody.extend (StructBody)
IncludeLine = False
BaseOffset = 0
IsCommonStruct = False
if not IncludeEmbedOnly:
NewTextBody.extend(OldTextBody)
if EmbedFound:
NewTextBody = self.PostProcessBody (NewTextBody, False)
NewTextBody = IncTextBody + NewTextBody
return NewTextBody
def WriteHeaderFile (self, TxtBody, FileName, Type = 'h'):
FileNameDef = os.path.basename(FileName).replace ('.', '_')
FileNameDef = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', FileNameDef)
FileNameDef = re.sub('([a-z0-9])([A-Z])', r'\1_\2', FileNameDef).upper()
Lines = []
Lines.append ("%s\n" % GetCopyrightHeader(Type))
Lines.append ("#ifndef __%s__\n" % FileNameDef)
Lines.append ("#define __%s__\n\n" % FileNameDef)
if Type == 'h':
Lines.append ("#pragma pack(1)\n\n")
Lines.extend (TxtBody)
if Type == 'h':
Lines.append ("#pragma pack()\n\n")
Lines.append ("#endif\n")
# Don't rewrite if the contents are the same
Create = True
if os.path.exists(FileName):
HdrFile = open(FileName, "r")
OrgTxt = HdrFile.read()
HdrFile.close()
NewTxt = ''.join(Lines)
if OrgTxt == NewTxt:
Create = False
if Create:
HdrFile = open(FileName, "w")
HdrFile.write (''.join(Lines))
HdrFile.close()
def CreateHeaderFile (self, HdrFileName, ComHdrFileName = ''):
CommentLine = ''
LastStruct = ''
NextOffset = 0
SpaceIdx = 0
Offset = 0
FieldIdx = 0
LastFieldIdx = 0
ResvOffset = 0
ResvIdx = 0
TxtBody = []
LineBuffer = []
CfgTags = []
InRange = True
LastVisible = True
TxtBody.append("typedef struct {\n")
for Item in self._CfgItemList:
# Search for CFGDATA tags
Embed = Item["embed"].upper()
if Embed.endswith(':START'):
Match = re.match (r'(\w+)_CFG_DATA:TAG_([0-9A-F]+):START', Embed)
if Match:
TagName = Match.group(1)
TagId = int(Match.group(2), 16)
CfgTags.append ((TagId, TagName))
# Only process visible items
NextVisible = LastVisible
if LastVisible and (Item['header'] == 'OFF'):
NextVisible = False
ResvOffset = Item['offset']
elif (not LastVisible) and Item['header'] == 'ON':
NextVisible = True
Name = "ReservedUpdSpace%d" % ResvIdx
ResvIdx = ResvIdx + 1
TxtBody.append(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, '', '', '', ''))
FieldIdx += 1
if Offset < Item["offset"]:
if LastVisible:
Name = "UnusedUpdSpace%d" % SpaceIdx
LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, '', '', '', ''))
FieldIdx += 1
SpaceIdx = SpaceIdx + 1
Offset = Item["offset"]
LastVisible = NextVisible
Offset = Offset + Item["length"]
if LastVisible:
for Each in LineBuffer:
TxtBody.append (Each)
LineBuffer = []
Comment = Item["comment"]
Embed = Item["embed"].upper()
if Embed.endswith(':START') or Embed.endswith(':END'):
# EMBED_STRUCT: StructName : ItemName : VariableName : START|END
Name, ArrayNum = self.GetStructArrayInfo (Item["struct"])
Remaining = Item["embed"]
if (LastFieldIdx + 1 == FieldIdx) and (LastStruct == Name):
ArrayMarker = ' '
else:
ArrayMarker = '%d' % ArrayNum
LastFieldIdx = FieldIdx
LastStruct = Name
Marker = '/* EMBED_STRUCT:%s:%s%s*/ ' % (Name, Remaining, ArrayMarker)
if Embed.endswith(':START') and Comment != '':
Marker = '/* COMMENT:%s */ \n' % Item["comment"] + Marker
else:
if Embed == '':
Marker = ''
else:
self.Error = "Invalid embedded structure format '%s'!\n" % Item["embed"]
return 4
# Generate bit fields for structure
if len(Item['subreg']) > 0 and Item["struct"]:
StructType = Item["struct"]
StructName, ArrayNum = self.GetStructArrayInfo (StructType)
if (LastFieldIdx + 1 == FieldIdx) and (LastStruct == Item["struct"]):
ArrayMarker = ' '
else:
ArrayMarker = '%d' % ArrayNum
TxtBody.append('/* EMBED_STRUCT:%s:%s:%s:START%s*/\n' % (StructName, StructType, Item["cname"], ArrayMarker))
for SubItem in Item['subreg']:
Name = SubItem["cname"]
if Name.startswith(Item["cname"]):
Name = Name[len(Item["cname"]) + 1:]
Line = self.CreateField (SubItem, Name, SubItem["bitunit"], SubItem["offset"], SubItem['struct'], SubItem['name'], SubItem['help'], SubItem['option'], SubItem['bitlength'])
TxtBody.append(Line)
TxtBody.append('/* EMBED_STRUCT:%s:%s:%s:END%s*/\n' % (StructName, StructType, Item["cname"], ArrayMarker))
LastFieldIdx = FieldIdx
LastStruct = Item["struct"]
FieldIdx += 1
else:
FieldIdx += 1
Line = Marker + self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct'], Item['name'], Item['help'], Item['option'])
TxtBody.append(Line)
TxtBody.append("}\n\n")
# Handle the embedded data structure
TxtBody = self.PostProcessBody (TxtBody)
ComBody, TxtBody = self.SplitTextBody (TxtBody)
# Prepare TAG defines
PltTagDefTxt = ['\n']
ComTagDefTxt = ['\n']
for TagId, TagName in sorted(CfgTags):
TagLine = '#define %-30s 0x%03X\n' % ('CDATA_%s_TAG' % TagName, TagId)
if TagId < self._MinCfgTagId:
# TAG ID < 0x100, it is a generic TAG
ComTagDefTxt.append (TagLine)
else:
PltTagDefTxt.append (TagLine)
PltTagDefTxt.append ('\n\n')
ComTagDefTxt.append ('\n\n')
# Write file back
self.WriteHeaderFile (PltTagDefTxt + TxtBody, HdrFileName)
if ComHdrFileName:
self.WriteHeaderFile (ComTagDefTxt + ComBody, ComHdrFileName)
return 0
def UpdateConfigItemValue (self, Item, ValueStr):
IsArray = True if Item['value'].startswith('{') else False
IsString = True if Item['value'].startswith("'") else False
Bytes = self.ValueToByteArray(ValueStr, Item['length'])
if IsString:
NewValue = "'%s'" % Bytes.decode("utf-8")
elif IsArray:
NewValue = Bytes2Str(Bytes)
else:
Fmt = '0x%X' if Item['value'].startswith('0x') else '%d'
NewValue = Fmt % Bytes2Val(Bytes)
Item['value'] = NewValue
def LoadDefaultFromBinaryArray (self, BinDat):
BaseOff = 0
for Item in self._CfgItemList:
if Item['length'] == 0:
continue
if Item['find']:
Offset = BinDat.find (Item['find'].encode())
if Offset >= 0:
BaseOff = Offset
else:
raise Exception ('Could not find "%s" !' % Item['find'])
if Item['offset'] + Item['length'] > len(BinDat):
raise Exception ('Mismatching format between DSC and BIN files !')
ValStr = Bytes2Str(BinDat[BaseOff + Item['offset']:BaseOff + Item['offset']+Item['length']])
self.UpdateConfigItemValue (Item, ValStr)
self.UpdateDefaultValue()
def GenerateBinaryArray (self):
BinDat = bytearray()
Offset = 0
for Item in self._CfgItemList:
if Item['offset'] > Offset:
Gap = Item['offset'] - Offset
BinDat.extend(b'\x00' * Gap)
BinDat.extend(self.ValueToByteArray(Item['value'], Item['length']))
Offset = Item['offset'] + Item['length']
return BinDat
def GenerateBinary (self, BinFileName):
BinFile = open(BinFileName, "wb")
BinFile.write (self.GenerateBinaryArray ())
BinFile.close()
return 0
def GenerateDataIncFile (self, DatIncFileName, BinFile = None):
# Put a prefix GUID before CFGDATA so that it can be located later on
Prefix = b'\xa7\xbd\x7f\x73\x20\x1e\x46\xd6\xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
if BinFile:
Fin = open (BinFile, 'rb')
BinDat = Prefix + bytearray(Fin.read())
Fin.close()
else:
BinDat = Prefix + self.GenerateBinaryArray ()
FileName = os.path.basename(DatIncFileName).upper()
FileName = FileName.replace('.', '_')
TxtLines = []
TxtLines.append ("UINT8 mConfigDataBlob[%d] = {\n" % len(BinDat))
Count = 0
Line = [' ']
for Each in BinDat:
Line.append('0x%02X, ' % Each)
Count = Count + 1
if (Count & 0x0F) == 0:
Line.append('\n')
TxtLines.append (''.join(Line))
Line = [' ']
if len(Line) > 1:
TxtLines.append (''.join(Line) + '\n')
TxtLines.append ("};\n\n")
self.WriteHeaderFile (TxtLines, DatIncFileName, 'inc')
return 0
def CheckCfgData (self):
# Check if CfgData contains any duplicated name
def AddItem (Item, ChkList):
Name = Item['cname']
if Name in ChkList:
return Item
if Name not in ['Dummy', 'Reserved', 'CfgHeader', 'CondValue']:
ChkList.append(Name)
return None
Duplicate = None
ChkList = []
for Item in self._CfgItemList:
Duplicate = AddItem (Item, ChkList)
if not Duplicate:
for SubItem in Item['subreg']:
Duplicate = AddItem (SubItem, ChkList)
if Duplicate:
break
if Duplicate:
break
if Duplicate:
self.Error = "Duplicated CFGDATA '%s' found !\n" % Duplicate['cname']
return -1
return 0
def PrintData (self):
for Item in self._CfgItemList:
if not Item['length']:
continue
print ("%-10s @Offset:0x%04X Len:%3d Val:%s" % (Item['cname'], Item['offset'], Item['length'], Item['value']))
for SubItem in Item['subreg']:
print (" %-20s BitOff:0x%04X BitLen:%-3d Val:%s" % (SubItem['cname'], SubItem['bitoffset'], SubItem['bitlength'], SubItem['value']))
def FormatArrayValue (self, Input, Length):
Dat = self.ValueToByteArray(Input, Length)
return ','.join('0x%02X' % Each for Each in Dat)
def GetItemOptionList (self, Item):
TmpList = []
if Item['type'] == "Combo":
if not Item['option'] in self._BuidinOption:
OptList = Item['option'].split(',')
for Option in OptList:
Option = Option.strip()
try:
(OpVal, OpStr) = Option.split(':')
except:
raise Exception("Invalid option format '%s' !" % Option)
TmpList.append((OpVal, OpStr))
return TmpList
def WriteBsfStruct (self, BsfFd, Item):
if Item['type'] == "None":
Space = "gPlatformFspPkgTokenSpaceGuid"
else:
Space = Item['space']
Line = " $%s_%s" % (Space, Item['cname'])
Match = re.match("\s*(\{.+\})\s*", Item['value'])
if Match:
DefaultValue = self.FormatArrayValue (Match.group(1).strip(), Item['length'])
else:
DefaultValue = Item['value'].strip()
if 'bitlength' in Item:
if Item['bitlength']:
BsfFd.write(" %s%s%4d bits $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['bitlength'], DefaultValue))
else:
if Item['length']:
BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue))
return self.GetItemOptionList (Item)
def GetBsfOption (self, OptionName):
if OptionName in self._CfgOptsDict:
return self._CfgOptsDict[OptionName]
else:
return OptionName
def WriteBsfOption (self, BsfFd, Item):
PcdName = Item['space'] + '_' + Item['cname']
WriteHelp = 0
BsfLines = []
if Item['type'] == "Combo":
if Item['option'] in self._BuidinOption:
Options = self._BuidinOption[Item['option']]
else:
Options = self.GetBsfOption (PcdName)
BsfLines.append (' %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options))
WriteHelp = 1
elif Item['type'].startswith("EditNum"):
Match = re.match("EditNum\s*,\s*(HEX|DEC)\s*,\s*\((\d+|0x[0-9A-Fa-f]+)\s*,\s*(\d+|0x[0-9A-Fa-f]+)\)", Item['type'])
if Match:
BsfLines.append (' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1)))
WriteHelp = 2
elif Item['type'].startswith("EditText"):
BsfLines.append (' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name']))
WriteHelp = 1
elif Item['type'] == "Table":
Columns = Item['option'].split(',')
if len(Columns) != 0:
BsfLines.append(' %s $%s "%s",' % (Item['type'], PcdName, Item['name']))
for Col in Columns:
Fmt = Col.split(':')
if len(Fmt) != 3:
raise Exception("Column format '%s' is invalid !" % Fmt)
try:
Dtype = int(Fmt[1].strip())
except:
raise Exception("Column size '%s' is invalid !" % Fmt[1])
BsfLines.append('\n Column "%s", %d bytes, %s' % (Fmt[0].strip(), Dtype, Fmt[2].strip()))
BsfLines.append(',\n')
WriteHelp = 1
if WriteHelp > 0:
HelpLines = Item['help'].split('\\n\\r')
FirstLine = True
for HelpLine in HelpLines:
if FirstLine:
FirstLine = False
BsfLines.append(' Help "%s"\n' % (HelpLine))
else:
BsfLines.append(' "%s"\n' % (HelpLine))
if WriteHelp == 2:
BsfLines.append(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3)))
if len(Item['condition']) > 4:
CondList = Item['condition'].split(',')
Idx = 0
for Cond in CondList:
Cond = Cond.strip()
if Cond.startswith('#'):
BsfLines.insert(Idx, Cond + '\n')
Idx += 1
elif Cond.startswith('@#'):
BsfLines.append(Cond[1:] + '\n')
for Line in BsfLines:
BsfFd.write (Line)
def WriteBsfPages (self, PageTree, BsfFd):
BsfFd.write('\n')
Key = next(iter(PageTree))
for Page in PageTree[Key]:
PageName = next(iter(Page))
BsfFd.write('Page "%s"\n' % self._CfgPageDict[PageName])
if len(PageTree[Key]):
self.WriteBsfPages (Page, BsfFd)
BsfItems = []
for Item in self._CfgItemList:
if Item['name'] != '':
if Item['page'] != PageName:
continue
if len(Item['subreg']) > 0:
for SubItem in Item['subreg']:
if SubItem['name'] != '':
BsfItems.append(SubItem)
else:
BsfItems.append(Item)
BsfItems.sort(key=lambda x: x['order'])
for Item in BsfItems:
self.WriteBsfOption (BsfFd, Item)
BsfFd.write("EndPage\n\n")
def GenerateBsfFile (self, BsfFile):
if BsfFile == '':
self.Error = "BSF output file '%s' is invalid" % BsfFile
return 1
Error = 0
OptionDict = {}
BsfFd = open(BsfFile, "w")
BsfFd.write("%s\n" % GetCopyrightHeader('bsf'))
BsfFd.write("%s\n" % self._GlobalDataDef)
BsfFd.write("StructDef\n")
NextOffset = -1
for Item in self._CfgItemList:
if Item['find'] != '':
BsfFd.write('\n Find "%s"\n' % Item['find'])
NextOffset = Item['offset'] + Item['length']
if Item['name'] != '':
if NextOffset != Item['offset']:
BsfFd.write(" Skip %d bytes\n" % (Item['offset'] - NextOffset))
if len(Item['subreg']) > 0:
NextOffset = Item['offset']
BitsOffset = NextOffset * 8
for SubItem in Item['subreg']:
BitsOffset += SubItem['bitlength']
if SubItem['name'] == '':
if 'bitlength' in SubItem:
BsfFd.write(" Skip %d bits\n" % (SubItem['bitlength']))
else:
BsfFd.write(" Skip %d bytes\n" % (SubItem['length']))
else:
Options = self.WriteBsfStruct(BsfFd, SubItem)
if len(Options) > 0:
OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options
NextBitsOffset = (Item['offset'] + Item['length']) * 8
if NextBitsOffset > BitsOffset:
BitsGap = NextBitsOffset - BitsOffset
BitsRemain = BitsGap % 8
if BitsRemain:
BsfFd.write(" Skip %d bits\n" % BitsRemain)
BitsGap -= BitsRemain
BytesRemain = BitsGap // 8
if BytesRemain:
BsfFd.write(" Skip %d bytes\n" % BytesRemain)
NextOffset = Item['offset'] + Item['length']
else:
NextOffset = Item['offset'] + Item['length']
Options = self.WriteBsfStruct(BsfFd, Item)
if len(Options) > 0:
OptionDict[Item['space']+'_'+Item['cname']] = Options
BsfFd.write("\nEndStruct\n\n")
BsfFd.write("%s" % self._BuidinOptionTxt)
NameList = []
OptionList = []
for Each in sorted(OptionDict):
if OptionDict[Each] not in OptionList:
NameList.append(Each)
OptionList.append (OptionDict[Each])
BsfFd.write("List &%s\n" % Each)
for Item in OptionDict[Each]:
BsfFd.write(' Selection %s , "%s"\n' % (self.EvaluateExpress(Item[0]), Item[1]))
BsfFd.write("EndList\n\n")
else:
# Item has idential options as other item
# Try to reuse the previous options instead
Idx = OptionList.index (OptionDict[Each])
self._CfgOptsDict[Each] = NameList[Idx]
BsfFd.write("BeginInfoBlock\n")
BsfFd.write(' PPVer "%s"\n' % (self._CfgBlkDict['ver']))
BsfFd.write(' Description "%s"\n' % (self._CfgBlkDict['name']))
BsfFd.write("EndInfoBlock\n\n")
self.WriteBsfPages (self._CfgPageTree, BsfFd)
BsfFd.close()
return Error
def WriteDeltaLine (self, OutLines, Name, ValStr, IsArray):
if IsArray:
Output = '%s | { %s }' % (Name, ValStr)
else:
Output = '%s | 0x%X' % (Name, Array2Val(ValStr))
OutLines.append (Output)
def WriteDeltaFile (self, OutFile, PlatformId, OutLines):
DltFd = open (OutFile, "w")
DltFd.write ("%s\n" % GetCopyrightHeader('dlt', True))
DltFd.write ('#\n')
DltFd.write ('# Delta configuration values for platform ID 0x%04X\n' % PlatformId)
DltFd.write ('#\n\n')
for Line in OutLines:
DltFd.write ('%s\n' % Line)
DltFd.close()
def GenerateDeltaFile(self, DeltaFile, BinFile, Full=False):
Fd = open (BinFile, 'rb')
NewData = bytearray(Fd.read())
Fd.close()
OldData = self.GenerateBinaryArray()
return self.GenerateDeltaFileFromBin (DeltaFile, OldData, NewData, Full)
def GenerateDeltaFileFromBin (self, DeltaFile, OldData, NewData, Full=False):
self.LoadDefaultFromBinaryArray (NewData)
Lines = []
TagName = ''
Level = 0
PlatformId = None
DefPlatformId = 0
for Item in self._CfgItemList:
if Level == 0 and Item['embed'].endswith(':START'):
TagName = Item['embed'].split(':')[0]
Level += 1
Start = Item['offset']
End = Start + Item['length']
FullName = '%s.%s' % (TagName, Item['cname'])
if 'PLATFORMID_CFG_DATA.PlatformId' == FullName:
DefPlatformId = Bytes2Val(OldData[Start:End])
if NewData[Start:End] != OldData[Start:End] or (
Full and Item['name'] and (Item['cname'] != 'Dummy')):
if TagName == '':
continue
ValStr = self.FormatDeltaValue (Item)
if not Item['subreg']:
Text = '%-40s | %s' % (FullName, ValStr)
if 'PLATFORMID_CFG_DATA.PlatformId' == FullName:
PlatformId = Array2Val(Item['value'])
else:
Lines.append(Text)
else:
if Full:
Text = '## %-40s | %s' % (FullName, ValStr)
Lines.append(Text)
OldArray = OldData[Start:End]
NewArray = NewData[Start:End]
for SubItem in Item['subreg']:
NewBitValue = self.GetBsfBitFields(SubItem, NewArray)
OldBitValue = self.GetBsfBitFields(SubItem, OldArray)
if OldBitValue != NewBitValue or (
Full and Item['name'] and
(Item['cname'] != 'Dummy')):
if SubItem['cname'].startswith(Item['cname']):
Offset = len(Item['cname']) + 1
FieldName = '%s.%s' % (
FullName, SubItem['cname'][Offset:])
ValStr = self.FormatDeltaValue (SubItem)
Text = '%-40s | %s' % (FieldName, ValStr)
Lines.append(Text)
if Item['embed'].endswith(':END'):
EndTagName = Item['embed'].split(':')[0]
if EndTagName == TagName:
Level -= 1
if PlatformId is None or DefPlatformId == PlatformId:
PlatformId = DefPlatformId
print("WARNING: 'PlatformId' configuration is same as default %d!"
% PlatformId)
Lines.insert(0, '%-40s | %s\n\n' %
('PLATFORMID_CFG_DATA.PlatformId', '0x%04X' % PlatformId))
self.WriteDeltaFile (DeltaFile, PlatformId, Lines)
return 0
def GenerateDscFile (self, OutFile):
DscFd = open(OutFile, "w")
for Line in self._DscLines:
DscFd.write (Line + '\n')
DscFd.close ()
return 0
def Usage():
print ('\n'.join([
"GenCfgData Version 0.01",
"Usage:",
" GenCfgData GENINC BinFile IncOutFile [-D Macros]",
" GenCfgData GENPKL DscFile PklOutFile [-D Macros]",
" GenCfgData GENINC DscFile[;DltFile] IncOutFile [-D Macros]",
" GenCfgData GENBIN DscFile[;DltFile] BinOutFile [-D Macros]",
" GenCfgData GENBSF DscFile[;DltFile] BsfOutFile [-D Macros]",
" GenCfgData GENDLT DscFile[;BinFile] DltOutFile [-D Macros]",
" GenCfgData GENDSC DscFile DscOutFile [-D Macros]",
" GenCfgData GENHDR DscFile[;DltFile] HdrOutFile[;ComHdrOutFile] [-D Macros]"
]))
def Main():
#
# Parse the options and args
#
argc = len(sys.argv)
if argc < 4:
Usage()
return 1
GenCfgData = CGenCfgData()
Command = sys.argv[1].upper()
OutFile = sys.argv[3]
if argc > 5 and GenCfgData.ParseMacros(sys.argv[4:]) != 0:
raise Exception ("ERROR: Macro parsing failed !")
FileList = sys.argv[2].split(';')
if len(FileList) == 2:
DscFile = FileList[0]
DltFile = FileList[1]
elif len(FileList) == 1:
DscFile = FileList[0]
DltFile = ''
else:
raise Exception ("ERROR: Invalid parameter '%s' !" % sys.argv[2])
if Command == "GENDLT" and DscFile.endswith('.dlt'):
# It needs to expand an existing DLT file
DltFile = DscFile
Lines = CGenCfgData.ExpandIncludeFiles (DltFile)
OutTxt = ''.join ([x[0] for x in Lines])
OutFile = open(OutFile, "w")
OutFile.write (OutTxt)
OutFile.close ()
return 0;
if not os.path.exists(DscFile):
raise Exception ("ERROR: Cannot open file '%s' !" % DscFile)
CfgBinFile = ''
if DltFile:
if not os.path.exists(DltFile):
raise Exception ("ERROR: Cannot open file '%s' !" % DltFile)
if Command == "GENDLT":
CfgBinFile = DltFile
DltFile = ''
BinFile = ''
if (DscFile.lower().endswith('.bin')) and (Command == "GENINC"):
# It is binary file
BinFile = DscFile
DscFile = ''
if BinFile:
if GenCfgData.GenerateDataIncFile(OutFile, BinFile) != 0:
raise Exception (GenCfgData.Error)
return 0
if DscFile.lower().endswith('.pkl'):
with open(DscFile, "rb") as PklFile:
GenCfgData.__dict__ = marshal.load(PklFile)
else:
if GenCfgData.ParseDscFile(DscFile) != 0:
raise Exception (GenCfgData.Error)
if GenCfgData.CheckCfgData() != 0:
raise Exception (GenCfgData.Error)
if GenCfgData.CreateVarDict() != 0:
raise Exception (GenCfgData.Error)
if Command == 'GENPKL':
with open(OutFile, "wb") as PklFile:
marshal.dump(GenCfgData.__dict__, PklFile)
return 0
if DltFile and Command in ['GENHDR','GENBIN','GENINC','GENBSF']:
if GenCfgData.OverrideDefaultValue(DltFile) != 0:
raise Exception (GenCfgData.Error)
if GenCfgData.UpdateDefaultValue() != 0:
raise Exception (GenCfgData.Error)
#GenCfgData.PrintData ()
if sys.argv[1] == "GENBIN":
if GenCfgData.GenerateBinary(OutFile) != 0:
raise Exception (GenCfgData.Error)
elif sys.argv[1] == "GENHDR":
OutFiles = OutFile.split(';')
BrdOutFile = OutFiles[0].strip()
if len(OutFiles) > 1:
ComOutFile = OutFiles[1].strip()
else:
ComOutFile = ''
if GenCfgData.CreateHeaderFile(BrdOutFile, ComOutFile) != 0:
raise Exception (GenCfgData.Error)
elif sys.argv[1] == "GENBSF":
if GenCfgData.GenerateBsfFile(OutFile) != 0:
raise Exception (GenCfgData.Error)
elif sys.argv[1] == "GENINC":
if GenCfgData.GenerateDataIncFile(OutFile) != 0:
raise Exception (GenCfgData.Error)
elif sys.argv[1] == "GENDLT":
if GenCfgData.GenerateDeltaFile(OutFile, CfgBinFile) != 0:
raise Exception (GenCfgData.Error)
elif sys.argv[1] == "GENDSC":
if GenCfgData.GenerateDscFile(OutFile) != 0:
raise Exception (GenCfgData.Error)
else:
raise Exception ("Unsuported command '%s' !" % Command)
return 0
if __name__ == '__main__':
sys.exit(Main())