mirror of https://github.com/acidanthera/audk.git
2638 lines
103 KiB
Python
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())
|