You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
Convert the line endings stored for all text files in the repository to LF. The majority previously used DOS-style CRLF line endings. Add a .gitattributes file to enforce this and treat certain extensions as never being text files. Update PatchCheck.py to insist on LF line endings rather than CRLF. However, its other checks fail on this commit due to lots of pre-existing complaints that it only notices because the line endings have changed. Silicon/QemuSocPkg/FspBin/Patches/0001-Build-QEMU-FSP-2.0-binaries.patch needs to be treated as binary since it contains a mixture of line endings. This change has implications depending on the client platform you are using the repository from: * Windows The usual configuration for Git on Windows means that text files will be checked out to the work tree with DOS-style CRLF line endings. If that's not the case then you can configure Git to do so for the entire machine with: git config --global core.autocrlf true or for just the repository with: git config core.autocrlf true Line endings will be normalised to LF when they are committed to the repository. If you commit a text file with only LF line endings then it will be converted to CRLF line endings in your work tree. * Linux, MacOS and other Unices The usual configuration for Git on such platforms is to check files out of the repository with LF line endings. This is probably the right thing for you. In the unlikely even that you are using Git on Unix but editing or compiling on Windows for some reason then you may need to tweak your configuration to force the use of CRLF line endings as described above. * General For more information see https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings . Fixes: https://github.com/slimbootloader/slimbootloader/issues/1400 Signed-off-by: Mike Crowe <mac@mcrowe.com>
2094 lines
83 KiB
Python
2094 lines
83 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())
|