summaryrefslogtreecommitdiffstats
path: root/IntelFsp2Pkg/Tools/FspGenCfgData.py
diff options
context:
space:
mode:
Diffstat (limited to 'IntelFsp2Pkg/Tools/FspGenCfgData.py')
-rw-r--r--IntelFsp2Pkg/Tools/FspGenCfgData.py2637
1 files changed, 2637 insertions, 0 deletions
diff --git a/IntelFsp2Pkg/Tools/FspGenCfgData.py b/IntelFsp2Pkg/Tools/FspGenCfgData.py
new file mode 100644
index 0000000000..8d4e49c8d2
--- /dev/null
+++ b/IntelFsp2Pkg/Tools/FspGenCfgData.py
@@ -0,0 +1,2637 @@
+# @ 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())