blob: 8d4e49c8d25ace4f9d9f482285d6a99231a1f2c5 [file] [log] [blame]
# @ GenCfgData.py
#
# Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
import os
import re
import sys
import marshal
from functools import reduce
from datetime import date
# Generated file copyright header
__copyright_tmp__ = """/** @file
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 !!!
**/
"""
__copyright_dsc__ = """## @file
#
# Copyright (c) %04d, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[PcdsDynamicVpd.Upd]
#
# Global definitions in BSF
# !BSF BLOCK:{NAME:"FSP UPD Configuration", VER:"0.1"}
#
"""
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 = ''
def errExit(self, err=''):
print("ERROR: Express parsing for:")
print(" %s" % self.string)
print(" %s^" % (' ' * self.index))
if err:
print("INFO : %s" % err)
raise SystemExit
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 normNumber(self, val):
return True if val else False
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:
value = None
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
val = self.getNumber(var)
if val is None:
value = var
else:
value = "%d" % val
return value
def parseSingleOp(self):
self.skipSpace()
if re.match('^NOT\\W', self.getCurr(-1)):
self.moveNext(3)
op = self.parseBrace()
val = self.getNumber(op)
if val is None:
self.errExit("'%s' is not a number" % op)
return "%d" % (not self.normNumber(int(op)))
else:
return self.parseValue()
def parseBrace(self):
self.skipSpace()
char = self.getCurr()
if char == '(':
self.moveNext()
value = self.parseExpr()
self.skipSpace()
if self.getCurr() != ')':
self.errExit("Expecting closing brace or operator")
self.moveNext()
return value
else:
value = self.parseSingleOp()
return value
def parseCompare(self):
value = self.parseBrace()
while True:
self.skipSpace()
char = self.getCurr()
if char in ['<', '>']:
self.moveNext()
next = self.getCurr()
if next == '=':
op = char + next
self.moveNext()
else:
op = char
result = self.parseBrace()
test = self.getNonNumber(result, value)
if test is None:
value = "%d" % self.normNumber(eval(value + op + result))
else:
self.errExit("'%s' is not a valid number for comparision"
% test)
elif char in ['=', '!']:
op = self.getCurr(2)
if op in ['==', '!=']:
self.moveNext(2)
result = self.parseBrace()
test = self.getNonNumber(result, value)
if test is None:
value = "%d" % self.normNumber((eval(value + op
+ result)))
else:
value = "%d" % self.normNumber(eval("'" + value +
"'" + op + "'" +
result + "'"))
else:
break
else:
break
return value
def parseAnd(self):
value = self.parseCompare()
while True:
self.skipSpace()
if re.match('^AND\\W', self.getCurr(-1)):
self.moveNext(3)
result = self.parseCompare()
test = self.getNonNumber(result, value)
if test is None:
value = "%d" % self.normNumber(int(value) & int(result))
else:
self.errExit("'%s' is not a valid op number for AND" %
test)
else:
break
return value
def parseOrXor(self):
value = self.parseAnd()
op = None
while True:
self.skipSpace()
op = None
if re.match('^XOR\\W', self.getCurr(-1)):
self.moveNext(3)
op = '^'
elif re.match('^OR\\W', self.getCurr(-1)):
self.moveNext(2)
op = '|'
else:
break
if op:
result = self.parseAnd()
test = self.getNonNumber(result, value)
if test is None:
value = "%d" % self.normNumber(eval(value + op + result))
else:
self.errExit("'%s' is not a valid op number for XOR/OR" %
test)
return value
def parseExpr(self):
return self.parseOrXor()
def getResult(self):
value = self.parseExpr()
self.skipSpace()
if not self.isLast():
self.errExit("Unexpected character found '%s'" % self.getCurr())
test = self.getNumber(value)
if test is None:
self.errExit("Result '%s' is not a number" % value)
return int(value)
def evaluateExpress(self, Expr):
self.index = 0
self.string = Expr
if self.getResult():
Result = True
else:
Result = False
return Result
class CFspBsf2Dsc:
def __init__(self, bsf_file):
self.cfg_list = CFspBsf2Dsc.parse_bsf(bsf_file)
def get_dsc_lines(self):
return CFspBsf2Dsc.generate_dsc(self.cfg_list)
def save_dsc(self, dsc_file):
return CFspBsf2Dsc.generate_dsc(self.cfg_list, dsc_file)
@staticmethod
def parse_bsf(bsf_file):
fd = open(bsf_file, 'r')
bsf_txt = fd.read()
fd.close()
find_list = []
regex = re.compile(r'\s+Find\s+"(.*?)"(.*?)^\s+(\$(.*?)|Skip)\s+',
re.S | re.MULTILINE)
for match in regex.finditer(bsf_txt):
find = match.group(1)
name = match.group(3)
line = bsf_txt[:match.end()].count("\n")
find_list.append((name, find, line))
idx = 0
count = 0
prefix = ''
chk_dict = {}
cfg_list = []
cfg_temp = {'find': '', 'cname': '', 'length': 0, 'value': '0',
'type': 'Reserved', 'isbit': False,
'embed': '', 'page': '', 'option': '', 'instance': 0}
regex = re.compile(
r'^\s+(\$(.*?)|Skip)\s+(\d+)\s+(bits|bytes)(\s+\$_DEFAULT_\s'
r'+=\s+(.+?))?$', re.S |
re.MULTILINE)
for match in regex.finditer(bsf_txt):
dlen = int(match.group(3))
if match.group(1) == 'Skip':
key = 'gPlatformFspPkgTokenSpaceGuid_BsfSkip%d' % idx
val = ', '.join(['%02X' % ord(i) for i in '\x00' * dlen])
idx += 1
option = '$SKIP'
else:
key = match.group(2)
val = match.group(6)
option = ''
is_bit = True if match.group(4) == 'bits' else False
cfg_item = dict(cfg_temp)
line = bsf_txt[:match.end()].count("\n")
finds = [i for i in find_list if line >= i[2]]
if len(finds) > 0:
prefix = finds[0][1]
cfg_item['embed'] = '%s:TAG_%03X:START' % \
(prefix, ord(prefix[-1]))
cfg_item['find'] = prefix
cfg_item['cname'] = 'Signature'
cfg_item['length'] = len(finds[0][1])
str2byte = Str2Bytes("'" + finds[0][1] + "'",
len(finds[0][1]))
cfg_item['value'] = '0x%X' % Bytes2Val(str2byte)
cfg_list.append(dict(cfg_item))
cfg_item = dict(cfg_temp)
find_list.pop(0)
count = 0
cfg_item['cname'] = key
cfg_item['length'] = dlen
cfg_item['value'] = val
cfg_item['option'] = option
cfg_item['isbit'] = is_bit
if key not in chk_dict.keys():
chk_dict[key] = 0
else:
chk_dict[key] += 1
cfg_item['instance'] = chk_dict[key]
cfg_list.append(cfg_item)
count += 1
if prefix:
cfg_item = dict(cfg_temp)
cfg_item['cname'] = 'Dummy'
cfg_item['embed'] = '%s:%03X:END' % (prefix, ord(prefix[-1]))
cfg_list.append(cfg_item)
option_dict = {}
selreg = re.compile(
r'\s+Selection\s*(.+?)\s*,\s*"(.*?)"$', re.S |
re.MULTILINE)
regex = re.compile(
r'^List\s&(.+?)$(.+?)^EndList$', re.S | re.MULTILINE)
for match in regex.finditer(bsf_txt):
key = match.group(1)
option_dict[key] = []
for select in selreg.finditer(match.group(2)):
option_dict[key].append(
(int(select.group(1), 0), select.group(2)))
chk_dict = {}
pagereg = re.compile(
r'^Page\s"(.*?)"$(.+?)^EndPage$', re.S | re.MULTILINE)
for match in pagereg.finditer(bsf_txt):
page = match.group(1)
for line in match.group(2).splitlines():
match = re.match(
r'\s+(Combo|EditNum)\s\$(.+?),\s"(.*?)",\s(.+?),$', line)
if match:
cname = match.group(2)
if cname not in chk_dict.keys():
chk_dict[cname] = 0
else:
chk_dict[cname] += 1
instance = chk_dict[cname]
cfg_idxs = [i for i, j in enumerate(cfg_list)
if j['cname'] == cname and
j['instance'] == instance]
if len(cfg_idxs) != 1:
raise Exception(
"Multiple CFG item '%s' found !" % cname)
cfg_item = cfg_list[cfg_idxs[0]]
cfg_item['page'] = page
cfg_item['type'] = match.group(1)
cfg_item['prompt'] = match.group(3)
cfg_item['range'] = None
if cfg_item['type'] == 'Combo':
cfg_item['option'] = option_dict[match.group(4)[1:]]
elif cfg_item['type'] == 'EditNum':
cfg_item['option'] = match.group(4)
match = re.match(r'\s+ Help\s"(.*?)"$', line)
if match:
cfg_item['help'] = match.group(1)
match = re.match(r'\s+"Valid\srange:\s(.*)"$', line)
if match:
parts = match.group(1).split()
cfg_item['option'] = (
(int(parts[0], 0), int(parts[2], 0),
cfg_item['option']))
return cfg_list
@staticmethod
def generate_dsc(option_list, dsc_file=None):
dsc_lines = []
header = '%s' % (__copyright_dsc__ % date.today().year)
dsc_lines.extend(header.splitlines())
pages = []
for cfg_item in option_list:
if cfg_item['page'] and (cfg_item['page'] not in pages):
pages.append(cfg_item['page'])
page_id = 0
for page in pages:
dsc_lines.append(' # !BSF PAGES:{PG%02X::"%s"}' % (page_id, page))
page_id += 1
dsc_lines.append('')
last_page = ''
is_bit = False
dlen = 0
dval = 0
bit_fields = []
for idx, option in enumerate(option_list):
if not is_bit and option['isbit']:
is_bit = True
dlen = 0
dval = 0
idxs = idx
if is_bit and not option['isbit']:
is_bit = False
if dlen % 8 != 0:
raise Exception("Bit fields are not aligned at "
"byte boundary !")
bit_fields.append((idxs, idx, dlen, dval))
if is_bit:
blen = option['length']
bval = int(option['value'], 0)
dval = dval + ((bval & ((1 << blen) - 1)) << dlen)
print(dlen, blen, bval, hex(dval))
dlen += blen
struct_idx = 0
for idx, option in enumerate(option_list):
dsc_lines.append('')
default = option['value']
pos = option['cname'].find('_')
name = option['cname'][pos + 1:]
for start_idx, end_idx, bits_len, bits_val in bit_fields:
if idx == start_idx:
val_str = Bytes2Str(Val2Bytes(bits_val, bits_len // 8))
dsc_lines.append(' # !HDR STRUCT:{BIT_FIELD_DATA_%d}'
% struct_idx)
dsc_lines.append(' # !BSF NAME:{BIT_FIELD_STRUCT}')
dsc_lines.append(' gCfgData.BitFiledStruct%d '
' | * | 0x%04X | %s' %
(struct_idx, bits_len // 8, val_str))
dsc_lines.append('')
struct_idx += 1
if option['find']:
dsc_lines.append(' # !BSF FIND:{%s}' % option['find'])
dsc_lines.append('')
if option['instance'] > 0:
name = name + '_%s' % option['instance']
if option['embed']:
dsc_lines.append(' # !HDR EMBED:{%s}' % option['embed'])
if option['type'] == 'Reserved':
dsc_lines.append(' # !BSF NAME:{Reserved} TYPE:{Reserved}')
if option['option'] == '$SKIP':
dsc_lines.append(' # !BSF OPTION:{$SKIP}')
else:
prompt = option['prompt']
if last_page != option['page']:
last_page = option['page']
dsc_lines.append(' # !BSF PAGE:{PG%02X}' %
(pages.index(option['page'])))
if option['type'] == 'Combo':
dsc_lines.append(' # !BSF NAME:{%s} TYPE:{%s}' %
(prompt, option['type']))
ops = []
for val, text in option['option']:
ops.append('0x%x:%s' % (val, text))
dsc_lines.append(' # !BSF OPTION:{%s}' % (', '.join(ops)))
elif option['type'] == 'EditNum':
cfg_len = option['length']
if ',' in default and cfg_len > 8:
dsc_lines.append(' # !BSF NAME:{%s} TYPE:{Table}' %
(prompt))
if cfg_len > 16:
cfg_len = 16
ops = []
for i in range(cfg_len):
ops.append('%X:1:HEX' % i)
dsc_lines.append(' # !BSF OPTION:{%s}' %
(', '.join(ops)))
else:
dsc_lines.append(
' # !BSF NAME:{%s} TYPE:{%s, %s, (0x%X, 0x%X)}' %
(prompt, option['type'], option['option'][2],
option['option'][0], option['option'][1]))
dsc_lines.append(' # !BSF HELP:{%s}' % option['help'])
if ',' in default:
default = '{%s}' % default
if option['isbit']:
dsc_lines.append(' # !BSF FIELD:{%s:%db}'
% (name, option['length']))
else:
dsc_lines.append(' gCfgData.%-30s | * | 0x%04X | %s' %
(name, option['length'], default))
if dsc_file:
fd = open(dsc_file, 'w')
fd.write('\n'.join(dsc_lines))
fd.close()
return dsc_lines
class CGenCfgData:
def __init__(self, Mode=''):
self.Debug = False
self.Error = ''
self.ReleaseMode = True
self.Mode = Mode
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)
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:
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())
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' !" %
CfgDict['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': []}
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 = {}
if type(DscFile) is list:
# it is DSC lines already
DscLines = DscFile
self._DscFile = '.'
else:
DscFd = open(DscFile, "r")
DscLines = DscFd.readlines()
DscFd.close()
self._DscFile = DscFile
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.split("#")[0])
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(self._DscFile), Remaining)
if not os.path.exists(IncludeFilePath):
# Relative to repository to find \
# dsc in common platform
IncludeFilePath = os.path.join(
os.path.dirname(self._DscFile), "..",
Remaining)
try:
IncludeDsc = open(IncludeFilePath, "r")
except Exception:
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:
del self._DscLines[-1]
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(r"^\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.Mode != 'FSP') and (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)
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 Exception:
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) and (self.Mode != 'FSP'):
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 is 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
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 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
EmbedFound = False
StructName = ''
ArrayVarName = ''
VariableName = ''
Count = 0
Level = 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]*)", 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 Exception:
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
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
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=''):
LastStruct = ''
SpaceIdx = 0
Offset = 0
FieldIdx = 0
LastFieldIdx = 0
ResvOffset = 0
ResvIdx = 0
TxtBody = []
LineBuffer = []
CfgTags = []
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 = []
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, IgnoreFind=False):
FindOff = 0
StartOff = 0
for Item in self._CfgItemList:
if Item['length'] == 0:
continue
if not IgnoreFind and Item['find']:
FindBin = Item['find'].encode()
Offset = BinDat.find(FindBin)
if Offset >= 0:
TestOff = BinDat[Offset+len(FindBin):].find(FindBin)
if TestOff >= 0:
raise Exception('Multiple match found for "%s" !' %
Item['find'])
FindOff = Offset + len(FindBin)
StartOff = Item['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 !')
Offset = FindOff + (Item['offset'] - StartOff)
ValStr = Bytes2Str(BinDat[Offset: Offset + Item['length']])
self.UpdateConfigItemValue(Item, ValStr)
self.UpdateDefaultValue()
def PatchBinaryArray(self, BinDat):
FileOff = 0
Offset = 0
FindOff = 0
PatchList = []
CfgBin = bytearray()
for Item in self._CfgItemList:
if Item['length'] == 0:
continue
if Item['find']:
if len(CfgBin) > 0:
PatchList.append((FileOff, CfgBin))
FindBin = Item['find'].encode()
FileOff = BinDat.find(FindBin)
if FileOff < 0:
raise Exception('Could not find "%s" !' % Item['find'])
else:
TestOff = BinDat[FileOff+len(FindBin):].find(FindBin)
if TestOff >= 0:
raise Exception('Multiple match found for "%s" !' %
Item['find'])
FileOff += len(FindBin)
Offset = Item['offset']
FindOff = Offset
CfgBin = bytearray()
if Item['offset'] > Offset:
Gap = Item['offset'] - Offset
CfgBin.extend(b'\x00' * Gap)
if Item['type'] == 'Reserved' and Item['option'] == '$SKIP':
# keep old data
NewOff = FileOff + (Offset - FindOff)
FileData = bytearray(BinDat[NewOff: NewOff + Item['length']])
CfgBin.extend(FileData)
else:
CfgBin.extend(self.ValueToByteArray(Item['value'],
Item['length']))
Offset = Item['offset'] + Item['length']
if len(CfgBin) > 0:
PatchList.append((FileOff, CfgBin))
for FileOff, CfgBin in PatchList:
Length = len(CfgBin)
if FileOff + Length < len(BinDat):
BinDat[FileOff:FileOff+Length] = CfgBin[:]
return BinDat
def GenerateBinaryArray(self):
Offset = 0
BinDat = bytearray()
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 Exception:
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 Exception:
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))
if PlatformId is not None:
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)
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())