audk/IntelFsp2Pkg/Tools/FspGenCfgData.py
Loo, Tung Lun 580b11201e IntelFsp2Pkg: Add Config Editor tool support
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3396

This is a GUI interface that can be used by users who
would like to change configuration settings directly
from the interface without having to modify the source.

This tool depends on Python GUI tool kit Tkinter.
It runs on both Windows and Linux.

The user needs to load the YAML file along with DLT file
for a specific board into the ConfigEditor, change the desired
configuration values. Finally, generate a new configuration delta
file or a config binary blob for the newly changed values to take
effect. These will be the inputs to the merge tool or the stitch
tool so that new config changes can be merged and stitched into
the final configuration blob.

This tool also supports binary update directly and display FSP
information. It is also backward compatible for BSF file format.

Running Configuration Editor:
python ConfigEditor.py

Co-authored-by: Maurice Ma <maurice.ma@intel.com>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Loo Tung Lun <tung.lun.loo@intel.com>
Reviewed-by: Chasel Chiu <chasel.chiu@intel.com>
2021-06-30 03:56:59 +00:00

2638 lines
103 KiB
Python

# @ 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())