You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
a4a1b76c3b
Current ConfigEditor does not run well with PY3. The generated DLT file has invalid strings. It was caused by the incompability between PY2 and PY3. This patch rewrote some code with compatibility for both PY2 and PY3. Signed-off-by: Maurice Ma <maurice.ma@intel.com>
2067 lines
81 KiB
Python
2067 lines
81 KiB
Python
## @ GenCfgData.py
|
|
#
|
|
# Copyright (c) 2014 - 2018, 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('^[+-]?\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)
|
|
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())
|
|
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*(.+)")
|
|
|
|
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' : '',
|
|
'comment' : '',
|
|
'condition' : '',
|
|
'order' : -1,
|
|
'subreg' : []
|
|
}
|
|
IsUpdSect = True
|
|
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.join(os.path.dirname (os.path.realpath(__file__)), "../..", Remaining)
|
|
|
|
try:
|
|
IncludeDsc = open(IncludeFilePath, "r")
|
|
except:
|
|
raise Exception ("ERROR: Cannot open file '%s'." % IncludeFilePath)
|
|
NewDscLines = IncludeDsc.readlines()
|
|
IncludeDsc.close()
|
|
DscLines = NewDscLines + 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:
|
|
ParentName = 'root'
|
|
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
|
|
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 = {}
|
|
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] == "'"):
|
|
# {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)
|
|
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('{'):
|
|
print (Item['value'])
|
|
print (ValueStr)
|
|
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
|
|
|
|
for Line in TextBody:
|
|
if Line.startswith('#define '):
|
|
IncTextBody.append(Line)
|
|
continue
|
|
|
|
if not Line.startswith ('/* EMBED_STRUCT:'):
|
|
Match = False
|
|
else:
|
|
Match = re.match("^/\*\sEMBED_STRUCT:([\w\[\]\*]+):([\w\[\]\*]+):(\w+):(START|END)([\s\d]+)\*/\s([\s\S]*)", 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):
|
|
for Item in self._CfgItemList:
|
|
if Item['length'] == 0:
|
|
continue
|
|
if Item['offset'] + Item['length'] > len(BinDat):
|
|
raise Exception ('Mismatching format between DSC and BIN files !')
|
|
ValStr = Bytes2Str(BinDat[Item['offset']: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("Invalide 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, OutFile, AbsfFile):
|
|
# Parse ABSF Build in dict
|
|
if not os.path.exists(AbsfFile):
|
|
Lines = []
|
|
else:
|
|
with open(AbsfFile) as Fin:
|
|
Lines = Fin.readlines()
|
|
|
|
AbsfBuiltValDict = {}
|
|
Process = False
|
|
for Line in Lines:
|
|
Line = Line.strip()
|
|
if Line.startswith('StructDef'):
|
|
Process = True
|
|
if Line.startswith('EndStruct'):
|
|
break
|
|
if not Process:
|
|
continue
|
|
Match = re.match('\s*\$gCfgData_(\w+)\s+(\d+)\s+(bits|bytes)\s+\$_AS_BUILT_\s+=\s+(.+)\$', Line)
|
|
if Match:
|
|
if Match.group(1) not in AbsfBuiltValDict:
|
|
AbsfBuiltValDict[Match.group(1)] = Match.group(4).strip()
|
|
else:
|
|
raise Exception ("Duplicated configuration name '%s' found !", Match.group(1))
|
|
|
|
# Match config item in DSC
|
|
PlatformId = None
|
|
OutLines = []
|
|
TagName = ''
|
|
Level = 0
|
|
for Item in self._CfgItemList:
|
|
Name = None
|
|
if Level == 0 and Item['embed'].endswith(':START'):
|
|
TagName = Item['embed'].split(':')[0]
|
|
Level += 1
|
|
if Item['cname'] in AbsfBuiltValDict:
|
|
ValStr = AbsfBuiltValDict[Item['cname']]
|
|
Name = '%s.%s' % (TagName, Item['cname'])
|
|
if not Item['subreg'] and Item['value'].startswith('{'):
|
|
Value = Array2Val(Item['value'])
|
|
IsArray = True
|
|
else:
|
|
Value = int(Item['value'], 16)
|
|
IsArray = False
|
|
AbsfVal = Array2Val(ValStr)
|
|
if AbsfVal != Value:
|
|
if 'PLATFORMID_CFG_DATA.PlatformId' == Name:
|
|
PlatformId = AbsfVal
|
|
self.WriteDeltaLine (OutLines, Name, ValStr, IsArray)
|
|
else:
|
|
if 'PLATFORMID_CFG_DATA.PlatformId' == Name:
|
|
raise Exception ("'PlatformId' has the same value as DSC default !")
|
|
|
|
if Item['subreg']:
|
|
for SubItem in Item['subreg']:
|
|
if SubItem['cname'] in AbsfBuiltValDict:
|
|
ValStr = AbsfBuiltValDict[SubItem['cname']]
|
|
if Array2Val(ValStr) == int(SubItem['value'], 16):
|
|
continue
|
|
Name = '%s.%s.%s' % (TagName, Item['cname'], SubItem['cname'])
|
|
self.WriteDeltaLine (OutLines, Name, ValStr, False)
|
|
|
|
if Item['embed'].endswith(':END'):
|
|
Level -= 1
|
|
|
|
if PlatformId is None and Lines:
|
|
raise Exception ("'PlatformId' configuration is missing in ABSF file!")
|
|
else:
|
|
PlatformId = 0
|
|
|
|
self.WriteDeltaFile (OutFile, 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[;AbsfFile] 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)
|
|
|
|
AbsfFile = ''
|
|
if DltFile:
|
|
if not os.path.exists(DltFile):
|
|
raise Exception ("ERROR: Cannot open file '%s' !" % DltFile)
|
|
if Command == "GENDLT":
|
|
AbsfFile = 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, AbsfFile) != 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())
|