| ## @ GenCfgOpt.py | |
| # | |
| # Copyright (c) 2014 - 2022, Intel Corporation. All rights reserved.<BR> | |
| # SPDX-License-Identifier: BSD-2-Clause-Patent | |
| # | |
| ## | |
| import os | |
| import re | |
| import sys | |
| import struct | |
| from datetime import date | |
| from functools import reduce | |
| # Generated file copyright header | |
| __copyright_txt__ = """## @file | |
| # | |
| # THIS IS AUTO-GENERATED FILE BY BUILD TOOLS AND PLEASE DO NOT MAKE MODIFICATION. | |
| # | |
| # This file lists all VPD informations for a platform collected by build.exe. | |
| # | |
| # Copyright (c) %4d, Intel Corporation. All rights reserved.<BR> | |
| # This program and the accompanying materials | |
| # are licensed and made available under the terms and conditions of the BSD License | |
| # which accompanies this distribution. The full text of the license may be found at | |
| # http://opensource.org/licenses/bsd-license.php | |
| # | |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| # | |
| """ | |
| __copyright_bsf__ = """/** @file | |
| Boot Setting File for Platform Configuration. | |
| Copyright (c) %4d, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| This file is automatically generated. Please do NOT modify !!! | |
| **/ | |
| """ | |
| __copyright_h__ = """/** @file | |
| Copyright (c) %4d, Intel Corporation. All rights reserved.<BR> | |
| Redistribution and use in source and binary forms, with or without modification, | |
| are permitted provided that the following conditions are met: | |
| * Redistributions of source code must retain the above copyright notice, this | |
| list of conditions and the following disclaimer. | |
| * Redistributions in binary form must reproduce the above copyright notice, this | |
| list of conditions and the following disclaimer in the documentation and/or | |
| other materials provided with the distribution. | |
| * Neither the name of Intel Corporation nor the names of its contributors may | |
| be used to endorse or promote products derived from this software without | |
| specific prior written permission. | |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
| THE POSSIBILITY OF SUCH DAMAGE. | |
| This file is automatically generated. Please do NOT modify !!! | |
| **/ | |
| """ | |
| BuildOptionPcd = [] | |
| 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 CGenCfgOpt: | |
| def __init__(self, Mode = ''): | |
| self.Debug = False | |
| self.Error = '' | |
| self.Mode = Mode | |
| self._GlobalDataDef = """ | |
| GlobalDataDef | |
| SKUID = 0, "DEFAULT" | |
| EndGlobalData | |
| """ | |
| self._BuidinOptionTxt = """ | |
| List &EN_DIS | |
| Selection 0x1 , "Enabled" | |
| Selection 0x0 , "Disabled" | |
| EndList | |
| """ | |
| 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._BsfTempDict = {} | |
| self._CfgItemList = [] | |
| self._DscLines = [] | |
| self._DscFile = '' | |
| self._MapVer = 0 | |
| self._DscTime = 0 | |
| 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 as e: | |
| raise Exception ("Bytes in '%s' must be in range 0~255 !" % ValueStr) | |
| if len(Result) < Length: | |
| Result.extend(b'\x00' * (Length - len(Result))) | |
| elif len(Result) > Length: | |
| raise Exception ("Value '%s' is too big to fit into %d bytes !" % (ValueStr, Length)) | |
| return Result[:Length] | |
| def ValueToList (self, ValueStr, Length): | |
| if ValueStr[0] == '{': | |
| Result = [] | |
| BinList = ValueStr[1:-1].split(',') | |
| InBitField = False | |
| LastInBitField = False | |
| Value = 0 | |
| BitLen = 0 | |
| for Element in BinList: | |
| InBitField = False | |
| Each = Element.strip() | |
| if len(Each) == 0: | |
| pass | |
| else: | |
| if Each[0] in ['"', "'"]: | |
| Result.extend(list(bytearray(Each[1:-1], 'utf-8'))) | |
| elif ':' in Each: | |
| Match = re.match("(.+):(\d+)b", Each) | |
| if Match is None: | |
| raise Exception("Invald value list format '%s' !" % Each) | |
| InBitField = True | |
| CurrentBitLen = int(Match.group(2)) | |
| CurrentValue = ((self.EvaluateExpress(Match.group(1)) & (1<<CurrentBitLen) - 1)) << BitLen | |
| else: | |
| Result.append(self.EvaluateExpress(Each.strip())) | |
| if InBitField: | |
| Value += CurrentValue | |
| BitLen += CurrentBitLen | |
| if LastInBitField and ((not InBitField) or (Element == BinList[-1])): | |
| if BitLen % 8 != 0: | |
| raise Exception("Invald bit field length!") | |
| Result.extend(Val2Bytes(Value, BitLen // 8)) | |
| Value = 0 | |
| BitLen = 0 | |
| LastInBitField = InBitField | |
| elif ValueStr.startswith("'") and ValueStr.endswith("'"): | |
| Result = Str2Bytes (ValueStr, Length) | |
| elif ValueStr.startswith('"') and ValueStr.endswith('"'): | |
| Result = Str2Bytes (ValueStr, Length) | |
| else: | |
| Result = Val2Bytes (self.EvaluateExpress(ValueStr), Length) | |
| return Result | |
| def FormatListValue(self, ConfigDict): | |
| Struct = ConfigDict['struct'] | |
| if Struct not in ['UINT8','UINT16','UINT32','UINT64']: | |
| return | |
| dataarray = [] | |
| binlist = ConfigDict['value'][1:-1].split(',') | |
| for each in binlist: | |
| each = each.strip() | |
| if each.startswith('0x'): | |
| value = int(each, 16) | |
| else: | |
| value = int(each) | |
| dataarray.append(value) | |
| unit = int(Struct[4:]) / 8 | |
| if int(ConfigDict['length']) != unit * len(dataarray): | |
| raise Exception("Array size is not proper for '%s' !" % ConfigDict['cname']) | |
| bytearray = [] | |
| for each in dataarray: | |
| value = each | |
| for loop in range(int(unit)): | |
| bytearray.append("0x%02X" % (value & 0xFF)) | |
| value = value >> 8 | |
| newvalue = '{' + ','.join(bytearray) + '}' | |
| ConfigDict['value'] = newvalue | |
| return "" | |
| def ParseDscFile (self, DscFile, FvDir): | |
| Hardcode = False | |
| AutoAlign = False | |
| self._CfgItemList = [] | |
| self._CfgPageDict = {} | |
| self._CfgBlkDict = {} | |
| self._DscFile = DscFile | |
| self._FvDir = FvDir | |
| self._DscLines = [] | |
| self._BsfTempDict = {} | |
| # Initial DSC time is parent DSC time. | |
| self._DscTime = os.path.getmtime(DscFile) | |
| CfgDict = {} | |
| IsDefSect = False | |
| IsPcdSect = False | |
| IsUpdSect = False | |
| IsVpdSect = 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 | |
| SkipLines = 0 | |
| MaxAlign = 32 #Default align to 32, but if there are 64 bit unit, align to 64 | |
| SizeAlign = 0 #record the struct max align | |
| Base = 0 #Starting offset of sub-structure. | |
| 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 | |
| IsVpdSect = False | |
| IsUpdSect = False | |
| IsTmpSect = False | |
| SectionName = Match.group(1).lower() | |
| if SectionName == "Defines".lower(): | |
| IsDefSect = True | |
| if (SectionName == "PcdsFeatureFlag".lower() or SectionName == "PcdsFixedAtBuild".lower()): | |
| IsPcdSect = True | |
| elif SectionName == "PcdsDynamicVpd.Tmp".lower(): | |
| IsTmpSect = True | |
| elif SectionName == "PcdsDynamicVpd.Upd".lower(): | |
| ConfigDict = {} | |
| ConfigDict['header'] = 'ON' | |
| ConfigDict['region'] = 'UPD' | |
| ConfigDict['order'] = -1 | |
| ConfigDict['page'] = '' | |
| ConfigDict['name'] = '' | |
| ConfigDict['find'] = '' | |
| ConfigDict['marker'] = '' | |
| ConfigDict['struct'] = '' | |
| ConfigDict['embed'] = '' | |
| ConfigDict['comment'] = '' | |
| ConfigDict['subreg'] = [] | |
| ConfigDict['condition'] = '' | |
| ConfigDict['option'] = '' | |
| IsUpdSect = True | |
| Offset = 0 | |
| else: | |
| if IsDefSect or IsPcdSect or IsUpdSect or IsVpdSect 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: | |
| Match = re.match("!include\s+(.+)", DscLine) | |
| if Match: | |
| IncludeFilePath = Match.group(1) | |
| IncludeFilePath = self.ExpandMacros(IncludeFilePath) | |
| PackagesPath = os.getenv("PACKAGES_PATH") | |
| if PackagesPath: | |
| for PackagePath in PackagesPath.split(os.pathsep): | |
| IncludeFilePathAbs = os.path.join(os.path.normpath(PackagePath), os.path.normpath(IncludeFilePath)) | |
| if os.path.exists(IncludeFilePathAbs): | |
| IncludeDsc = open(IncludeFilePathAbs, "r") | |
| break | |
| else: | |
| IncludeDsc = open(IncludeFilePath, "r") | |
| if IncludeDsc == None: | |
| print("ERROR: Cannot open file '%s'" % IncludeFilePath) | |
| raise SystemExit | |
| # Update DscTime when newer DSC time found. | |
| CurrentDscTime = os.path.getmtime(os.path.realpath(IncludeDsc.name)) | |
| if CurrentDscTime > self._DscTime: | |
| self._DscTime = CurrentDscTime | |
| NewDscLines = IncludeDsc.readlines() | |
| IncludeDsc.close() | |
| DscLines = NewDscLines + DscLines | |
| del self._DscLines[-1] | |
| Offset = 0 | |
| else: | |
| if DscLine.startswith('!'): | |
| print("ERROR: Unrecognized directive for line '%s'" % DscLine) | |
| raise SystemExit | |
| if not Handle: | |
| del self._DscLines[-1] | |
| continue | |
| if IsDefSect: | |
| #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09 | |
| #DEFINE FSP_T_UPD_TOOL_GUID = 34686CA3-34F9-4901-B82A-BA630F0714C6 | |
| #DEFINE FSP_M_UPD_TOOL_GUID = 39A250DB-E465-4DD1-A2AC-E2BD3C0E2385 | |
| #DEFINE FSP_S_UPD_TOOL_GUID = CAE3605B-5B34-4C85-B3D7-27D54273C40F | |
| Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*(.+)", DscLine) | |
| if Match: | |
| self._MacroDict[Match.group(1)] = self.ExpandMacros(Match.group(2)) | |
| if self.Debug: | |
| print ("INFO : DEFINE %s = [ %s ]" % (Match.group(1), self.ExpandMacros(Match.group(2)))) | |
| elif IsPcdSect: | |
| #gSiPkgTokenSpaceGuid.PcdTxtEnable|FALSE | |
| #gSiPkgTokenSpaceGuid.PcdOverclockEnable|TRUE | |
| 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))) | |
| i = 0 | |
| while i < len(BuildOptionPcd): | |
| Match = re.match("\s*([\w\.]+)\s*\=\s*(\w+)", BuildOptionPcd[i]) | |
| if Match: | |
| self._PcdsDict[Match.group(1)] = Match.group(2) | |
| i += 1 | |
| 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|@Bsf|!HDR)\s+(.+)", DscLine) | |
| if Match: | |
| Remaining = Match.group(2) | |
| if Match.group(1) == '!BSF' or Match.group(1) == '@Bsf': | |
| Match = re.match("(?:^|.+\s+)PAGES:{(.+?)}", Remaining) | |
| if Match: | |
| # !BSF PAGES:{HSW:"Haswell System Agent", LPT:"Lynx Point PCH"} | |
| PageList = Match.group(1).split(',') | |
| for Page in PageList: | |
| Page = Page.strip() | |
| Match = re.match("(\w+):\"(.+)\"", Page) | |
| if Match != None: | |
| self._CfgPageDict[Match.group(1)] = Match.group(2) | |
| Match = re.match("(?:^|.+\s+)BLOCK:{NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*}", Remaining) | |
| if Match: | |
| self._CfgBlkDict['name'] = Match.group(1) | |
| self._CfgBlkDict['ver'] = Match.group(2) | |
| for Key in self._BsfKeyList: | |
| Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining) | |
| if Match: | |
| if Key in ['NAME', 'HELP', 'OPTION'] and Match.group(1).startswith('+'): | |
| ConfigDict[Key.lower()] += Match.group(1)[1:] | |
| else: | |
| ConfigDict[Key.lower()] = Match.group(1) | |
| else: | |
| for Key in self._HdrKeyList: | |
| Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining) | |
| if Match: | |
| ConfigDict[Key.lower()] = Match.group(1) | |
| Match = re.match("^\s*#\s+@Prompt\s+(.+)", DscLine) | |
| if Match: | |
| ConfigDict['name'] = Match.group(1) | |
| Match = re.match("^\s*#\s*@ValidList\s*(.+)\s*\|\s*(.+)\s*\|\s*(.+)\s*", DscLine) | |
| if Match: | |
| if Match.group(2).strip() in self._BuidinOption: | |
| ConfigDict['option'] = Match.group(2).strip() | |
| else: | |
| OptionValueList = Match.group(2).split(',') | |
| OptionStringList = Match.group(3).split(',') | |
| Index = 0 | |
| for Option in OptionValueList: | |
| Option = Option.strip() | |
| ConfigDict['option'] = ConfigDict['option'] + str(Option) + ':' + OptionStringList[Index].strip() | |
| Index += 1 | |
| if Index in range(len(OptionValueList)): | |
| ConfigDict['option'] += ', ' | |
| ConfigDict['type'] = "Combo" | |
| Match = re.match("^\s*#\s*@ValidRange\s*(.+)\s*\|\s*(.+)\s*-\s*(.+)\s*", DscLine) | |
| if Match: | |
| if "0x" in Match.group(2) or "0x" in Match.group(3): | |
| ConfigDict['type'] = "EditNum, HEX, (%s,%s)" % (Match.group(2), Match.group(3)) | |
| else: | |
| ConfigDict['type'] = "EditNum, DEC, (%s,%s)" % (Match.group(2), Match.group(3)) | |
| Match = re.match("^\s*##\s+(.+)", DscLine) | |
| if Match: | |
| ConfigDict['help'] = Match.group(1) | |
| # Check VPD/UPD | |
| if IsUpdSect: | |
| Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+|\*)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine) | |
| else: | |
| Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)(?:\s*\|\s*(.+))?", DscLine) | |
| if Match: | |
| ConfigDict['space'] = Match.group(1) | |
| ConfigDict['cname'] = Match.group(2) | |
| if Match.group(3) != '*': | |
| Hardcode = True | |
| Offset = int (Match.group(3), 16) | |
| else: | |
| AutoAlign = True | |
| if Hardcode and AutoAlign: | |
| print("Hardcode and auto-align mixed mode is not supported by GenCfgOpt") | |
| raise SystemExit | |
| ConfigDict['offset'] = Offset | |
| if ConfigDict['order'] == -1: | |
| ConfigDict['order'] = ConfigDict['offset'] << 8 | |
| else: | |
| (Major, Minor) = ConfigDict['order'].split('.') | |
| ConfigDict['order'] = (int (Major, 16) << 8 ) + int (Minor, 16) | |
| if IsUpdSect: | |
| Value = Match.group(5).strip() | |
| if Match.group(4).startswith("0x"): | |
| Length = int (Match.group(4), 16) | |
| else : | |
| Length = int (Match.group(4)) | |
| Offset += Length | |
| else: | |
| Value = Match.group(4) | |
| if Value is None: | |
| Value = '' | |
| Value = Value.strip() | |
| if '|' in Value: | |
| Match = re.match("^.+\s*\|\s*(.+)", Value) | |
| if Match: | |
| Value = Match.group(1) | |
| Length = -1 | |
| 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 (len(Value) > 0) and (Value[0] == '{'): | |
| Value = self.FormatListValue(ConfigDict) | |
| if ConfigDict['name'] == '': | |
| # Clear BSF specific items | |
| ConfigDict['bsfname'] = '' | |
| ConfigDict['help'] = '' | |
| ConfigDict['type'] = '' | |
| ConfigDict['option'] = '' | |
| if IsUpdSect and AutoAlign: | |
| ItemLength = int(ConfigDict['length']) | |
| ItemOffset = int(ConfigDict['offset']) | |
| ItemStruct = ConfigDict['struct'] | |
| Unit = 1 | |
| if ItemLength in [1, 2, 4, 8] and not ConfigDict['value'].startswith('{'): | |
| Unit = ItemLength | |
| # If there are 64 bit unit, align to 64 | |
| if Unit == 8: | |
| MaxAlign = 64 | |
| SizeAlign = 8 | |
| if ItemStruct != '': | |
| UnitDict = {'UINT8':1, 'UINT16':2, 'UINT32':4, 'UINT64':8} | |
| if ItemStruct in ['UINT8', 'UINT16', 'UINT32', 'UINT64']: | |
| Unit = UnitDict[ItemStruct] | |
| # If there are 64 bit unit, align to 64 | |
| if Unit == 8: | |
| MaxAlign = 64 | |
| SizeAlign = max(SizeAlign, Unit) | |
| if (ConfigDict['embed'].find(':START') != -1): | |
| Base = ItemOffset | |
| SubOffset = ItemOffset - Base | |
| SubRemainder = SubOffset % Unit | |
| if SubRemainder: | |
| Diff = Unit - SubRemainder | |
| Offset = Offset + Diff | |
| ItemOffset = ItemOffset + Diff | |
| if (ConfigDict['embed'].find(':END') != -1): | |
| Remainder = Offset % (MaxAlign/8) # MaxAlign is either 32 or 64 | |
| if Remainder: | |
| Diff = int((MaxAlign/8) - Remainder) | |
| Offset = Offset + Diff | |
| ItemOffset = ItemOffset + Diff | |
| MaxAlign = 32 # Reset to default 32 align when struct end | |
| if (ConfigDict['cname'] == 'UpdTerminator'): | |
| # ItemLength is the size of UpdTerminator | |
| # Itemlength might be 16, 32, or 64 | |
| # Struct align to 64 if UpdTerminator | |
| # or struct size is 64 bit, else align to 32 | |
| Remainder = Offset % max(ItemLength/8, 4, SizeAlign) | |
| Offset = Offset + ItemLength | |
| if Remainder: | |
| Diff = int(max(ItemLength/8, 4, SizeAlign) - Remainder) | |
| ItemOffset = ItemOffset + Diff | |
| ConfigDict['offset'] = ItemOffset | |
| self._CfgItemList.append(ConfigDict.copy()) | |
| ConfigDict['name'] = '' | |
| ConfigDict['find'] = '' | |
| ConfigDict['struct'] = '' | |
| ConfigDict['embed'] = '' | |
| ConfigDict['comment'] = '' | |
| ConfigDict['marker'] = '' | |
| ConfigDict['order'] = -1 | |
| ConfigDict['subreg'] = [] | |
| ConfigDict['option'] = '' | |
| else: | |
| # It could be a virtual item as below | |
| # !BSF FIELD:{SerialDebugPortAddress0:1} | |
| # or | |
| # @Bsf FIELD:{SerialDebugPortAddress0:1b} | |
| Match = re.match("^\s*#\s+(!BSF|@Bsf)\s+FIELD:{(.+):(\d+)([Bb])?}", DscLine) | |
| if Match: | |
| SubCfgDict = ConfigDict.copy() | |
| if (Match.group(4) == None) or (Match.group(4) == 'B'): | |
| UnitBitLen = 8 | |
| elif Match.group(4) == 'b': | |
| UnitBitLen = 1 | |
| else: | |
| print("ERROR: Invalide BSF FIELD length for line '%s'" % DscLine) | |
| raise SystemExit | |
| SubCfgDict['cname'] = Match.group(2) | |
| SubCfgDict['bitlength'] = int (Match.group(3)) * 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'] | |
| SubCfgDict['bitoffset'] = SubOffset | |
| LastItem['subreg'].append (SubCfgDict.copy()) | |
| ConfigDict['name'] = '' | |
| 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 UpdateSubRegionDefaultValue (self): | |
| Error = 0 | |
| for Item in self._CfgItemList: | |
| if len(Item['subreg']) == 0: | |
| continue | |
| bytearray = [] | |
| if Item['value'][0] == '{': | |
| binlist = Item['value'][1:-1].split(',') | |
| for each in binlist: | |
| each = each.strip() | |
| if each.startswith('0x'): | |
| value = int(each, 16) | |
| else: | |
| value = int(each) | |
| bytearray.append(value) | |
| else: | |
| if Item['value'].startswith('0x'): | |
| value = int(Item['value'], 16) | |
| else: | |
| value = int(Item['value']) | |
| idx = 0 | |
| while idx < Item['length']: | |
| bytearray.append(value & 0xFF) | |
| value = value >> 8 | |
| idx = idx + 1 | |
| for SubItem in Item['subreg']: | |
| valuestr = self.GetBsfBitFields(SubItem, bytearray) | |
| SubItem['value'] = valuestr | |
| return Error | |
| def NoDscFileChange (self, OutPutFile): | |
| NoFileChange = True | |
| if not os.path.exists(OutPutFile): | |
| NoFileChange = False | |
| else: | |
| OutputTime = os.path.getmtime(OutPutFile) | |
| if self._DscTime > OutputTime: | |
| NoFileChange = False | |
| return NoFileChange | |
| def CreateSplitUpdTxt (self, UpdTxtFile): | |
| GuidList = ['FSP_T_UPD_TOOL_GUID','FSP_M_UPD_TOOL_GUID','FSP_S_UPD_TOOL_GUID','FSP_I_UPD_TOOL_GUID'] | |
| SignatureList = ['0x545F', '0x4D5F','0x535F','0x495F'] # _T, _M, _S and _I signature for FSPT, FSPM, FSPS, FSPI | |
| for Index in range(len(GuidList)): | |
| UpdTxtFile = '' | |
| FvDir = self._FvDir | |
| if GuidList[Index] not in self._MacroDict: | |
| NoFSPI = False | |
| if GuidList[Index] == 'FSP_I_UPD_TOOL_GUID': | |
| NoFSPI = True | |
| continue | |
| else: | |
| self.Error = "%s definition is missing in DSC file" % (GuidList[Index]) | |
| return 1 | |
| if UpdTxtFile == '': | |
| UpdTxtFile = os.path.join(FvDir, self._MacroDict[GuidList[Index]] + '.txt') | |
| if (self.NoDscFileChange (UpdTxtFile)): | |
| # DSC has not been modified yet | |
| # So don't have to re-generate other files | |
| self.Error = 'No DSC file change, skip to create UPD TXT file' | |
| return 256 | |
| TxtFd = open(UpdTxtFile, "w") | |
| TxtFd.write("%s\n" % (__copyright_txt__ % date.today().year)) | |
| NextOffset = 0 | |
| SpaceIdx = 0 | |
| StartAddr = 0 | |
| EndAddr = 0 | |
| Default = 'DEFAULT|' | |
| InRange = False | |
| for Item in self._CfgItemList: | |
| if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == SignatureList[Index]: | |
| StartAddr = Item['offset'] | |
| NextOffset = StartAddr | |
| InRange = True | |
| if Item['cname'] == 'UpdTerminator' and InRange == True: | |
| EndAddr = Item['offset'] | |
| InRange = False | |
| InRange = False | |
| for Item in self._CfgItemList: | |
| if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == SignatureList[Index]: | |
| InRange = True | |
| if InRange != True: | |
| continue | |
| if Item['cname'] == 'UpdTerminator': | |
| InRange = False | |
| if Item['region'] != 'UPD': | |
| continue | |
| Offset = Item['offset'] | |
| if StartAddr > Offset or EndAddr < Offset: | |
| continue | |
| if NextOffset < Offset: | |
| # insert one line | |
| TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset - StartAddr, Offset - NextOffset)) | |
| SpaceIdx = SpaceIdx + 1 | |
| NextOffset = Offset + Item['length'] | |
| TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'] - StartAddr,Item['length'],Item['value'])) | |
| TxtFd.close() | |
| return 0 | |
| 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 | |
| def ProcessMultilines (self, String, MaxCharLength): | |
| Multilines = '' | |
| StringLength = len(String) | |
| CurrentStringStart = 0 | |
| StringOffset = 0 | |
| BreakLineDict = [] | |
| if len(String) <= MaxCharLength: | |
| while (StringOffset < StringLength): | |
| if StringOffset >= 1: | |
| if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n': | |
| BreakLineDict.append (StringOffset + 1) | |
| StringOffset += 1 | |
| if BreakLineDict != []: | |
| for Each in BreakLineDict: | |
| Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip() | |
| CurrentStringStart = Each | |
| if StringLength - CurrentStringStart > 0: | |
| Multilines += " %s\n" % String[CurrentStringStart:].lstrip() | |
| else: | |
| Multilines = " %s\n" % String | |
| else: | |
| NewLineStart = 0 | |
| NewLineCount = 0 | |
| FoundSpaceChar = False | |
| while (StringOffset < StringLength): | |
| if StringOffset >= 1: | |
| if NewLineCount >= MaxCharLength - 1: | |
| if String[StringOffset] == ' ' and StringLength - StringOffset > 10: | |
| BreakLineDict.append (NewLineStart + NewLineCount) | |
| NewLineStart = NewLineStart + NewLineCount | |
| NewLineCount = 0 | |
| FoundSpaceChar = True | |
| elif StringOffset == StringLength - 1 and FoundSpaceChar == False: | |
| BreakLineDict.append (0) | |
| if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n': | |
| BreakLineDict.append (StringOffset + 1) | |
| NewLineStart = StringOffset + 1 | |
| NewLineCount = 0 | |
| StringOffset += 1 | |
| NewLineCount += 1 | |
| if BreakLineDict != []: | |
| BreakLineDict.sort () | |
| for Each in BreakLineDict: | |
| if Each > 0: | |
| Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip() | |
| CurrentStringStart = Each | |
| if StringLength - CurrentStringStart > 0: | |
| Multilines += " %s\n" % String[CurrentStringStart:].lstrip() | |
| return Multilines | |
| def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help, Option, BitsLength = None): | |
| PosName = 28 | |
| PosComment = 30 | |
| NameLine='' | |
| HelpLine='' | |
| OptionLine='' | |
| if Length == 0 and Name == 'Dummy': | |
| return '\n' | |
| IsArray = False | |
| if Length in [1,2,4,8]: | |
| Type = "UINT%d" % (Length * 8) | |
| if Name.startswith("UnusedUpdSpace") and Length != 1: | |
| IsArray = True | |
| Type = "UINT8" | |
| else: | |
| IsArray = True | |
| Type = "UINT8" | |
| if Item and Item['value'].startswith('{'): | |
| Type = "UINT8" | |
| IsArray = True | |
| if Struct != '': | |
| Type = Struct | |
| if Struct in ['UINT8','UINT16','UINT32','UINT64']: | |
| IsArray = True | |
| Unit = int(Type[4:]) / 8 | |
| Length = Length / Unit | |
| else: | |
| IsArray = False | |
| if IsArray: | |
| Name = Name + '[%d]' % Length | |
| if len(Type) < PosName: | |
| Space1 = PosName - len(Type) | |
| else: | |
| Space1 = 1 | |
| if BsfName != '': | |
| NameLine=" - %s\n" % BsfName | |
| else: | |
| NameLine="\n" | |
| if Help != '': | |
| HelpLine = self.ProcessMultilines (Help, 80) | |
| if Option != '': | |
| OptionLine = self.ProcessMultilines (Option, 80) | |
| if Offset is None: | |
| OffsetStr = '????' | |
| else: | |
| OffsetStr = '0x%04X' % Offset | |
| if BitsLength is None: | |
| BitsLength = '' | |
| else: | |
| BitsLength = ' : %d' % BitsLength | |
| return "\n/** Offset %s%s%s%s**/\n %s%s%s%s;\n" % (OffsetStr, NameLine, HelpLine, OptionLine, Type, ' ' * Space1, Name, BitsLength) | |
| def PostProcessBody (self, TextBody): | |
| NewTextBody = [] | |
| OldTextBody = [] | |
| IncludeLine = False | |
| StructName = '' | |
| VariableName = '' | |
| IsUpdHdrDefined = False | |
| IsUpdHeader = False | |
| for Line in TextBody: | |
| SplitToLines = Line.splitlines() | |
| MatchComment = re.match("^/\*\sCOMMENT:(\w+):([\w|\W|\s]+)\s\*/\s([\s\S]*)", SplitToLines[0]) | |
| if MatchComment: | |
| if MatchComment.group(1) == 'FSP_UPD_HEADER': | |
| IsUpdHeader = True | |
| else: | |
| IsUpdHeader = False | |
| if IsUpdHdrDefined != True or IsUpdHeader != True: | |
| CommentLine = " " + MatchComment.group(2) + "\n" | |
| NewTextBody.append("/**" + CommentLine + "**/\n") | |
| Line = Line[(len(SplitToLines[0]) + 1):] | |
| Match = re.match("^/\*\sEMBED_STRUCT:(\w+):(\w+):(START|END)\s\*/\s([\s\S]*)", Line) | |
| if Match: | |
| Line = Match.group(4) | |
| if Match.group(1) == 'FSP_UPD_HEADER': | |
| IsUpdHeader = True | |
| else: | |
| IsUpdHeader = False | |
| if Match and Match.group(3) == 'START': | |
| if IsUpdHdrDefined != True or IsUpdHeader != True: | |
| NewTextBody.append ('typedef struct {\n') | |
| StructName = Match.group(1) | |
| VariableName = Match.group(2) | |
| MatchOffset = re.search('/\*\*\sOffset\s0x([a-fA-F0-9]+)', Line) | |
| if MatchOffset: | |
| Offset = int(MatchOffset.group(1), 16) | |
| else: | |
| Offset = None | |
| Line | |
| IncludeLine = True | |
| OldTextBody.append (self.CreateField (None, VariableName, 0, Offset, StructName, '', '', '')) | |
| if IncludeLine: | |
| if IsUpdHdrDefined != True or IsUpdHeader != True: | |
| NewTextBody.append (Line) | |
| else: | |
| OldTextBody.append (Line) | |
| if Match and Match.group(3) == 'END': | |
| if (StructName != Match.group(1)) or (VariableName != Match.group(2)): | |
| print ("Unmatched struct name '%s' and '%s' !" % (StructName, Match.group(1))) | |
| else: | |
| if IsUpdHdrDefined != True or IsUpdHeader != True: | |
| NewTextBody.append ('} %s;\n\n' % StructName) | |
| IsUpdHdrDefined = True | |
| IncludeLine = False | |
| NewTextBody.extend(OldTextBody) | |
| return NewTextBody | |
| def WriteLinesWithoutTailingSpace (self, HeaderFd, Line): | |
| TxtBody2 = Line.splitlines(True) | |
| for Line2 in TxtBody2: | |
| Line2 = Line2.rstrip() | |
| Line2 += '\n' | |
| HeaderFd.write (Line2) | |
| return 0 | |
| def CreateHeaderFile (self, InputHeaderFile): | |
| FvDir = self._FvDir | |
| HeaderFileName = 'FspUpd.h' | |
| HeaderFile = os.path.join(FvDir, HeaderFileName) | |
| # Check if header needs to be recreated | |
| if (self.NoDscFileChange (HeaderFile)): | |
| # DSC has not been modified yet | |
| # So don't have to re-generate other files | |
| self.Error = 'No DSC file change, skip to create UPD header file' | |
| return 256 | |
| TxtBody = [] | |
| for Item in self._CfgItemList: | |
| if str(Item['cname']) == 'Signature' and Item['length'] == 8: | |
| Value = int(Item['value'], 16) | |
| Chars = [] | |
| while Value != 0x0: | |
| Chars.append(chr(Value & 0xFF)) | |
| Value = Value >> 8 | |
| SignatureStr = ''.join(Chars) | |
| # Signature will be _T / _M / _S / _I for FSPT / FSPM / FSPS /FSPI accordingly | |
| if '_T' in SignatureStr[6:6+2]: | |
| TxtBody.append("#define FSPT_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr)) | |
| elif '_M' in SignatureStr[6:6+2]: | |
| TxtBody.append("#define FSPM_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr)) | |
| elif '_S' in SignatureStr[6:6+2]: | |
| TxtBody.append("#define FSPS_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr)) | |
| elif '_I' in SignatureStr[6:6+2]: | |
| if NoFSPI == False: | |
| TxtBody.append("#define FSPI_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr)) | |
| TxtBody.append("\n") | |
| for Region in ['UPD']: | |
| UpdOffsetTable = [] | |
| UpdSignature = ['0x545F', '0x4D5F', '0x535F', '0x495F'] #['_T', '_M', '_S', '_I'] signature for FSPT, FSPM, FSPS, FSPI | |
| UpdStructure = ['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD', 'FSPI_UPD'] | |
| for Item in self._CfgItemList: | |
| if Item["cname"] == 'Signature' and Item["value"][0:6] in UpdSignature: | |
| Item["offset"] = 0 # re-initialize offset to 0 when new UPD structure starting | |
| UpdOffsetTable.append (Item["offset"]) | |
| for UpdIdx in range(len(UpdOffsetTable)): | |
| CommentLine = "" | |
| for Item in self._CfgItemList: | |
| if Item["comment"] != '' and Item["offset"] >= UpdOffsetTable[UpdIdx]: | |
| MatchComment = re.match("^(U|V)PD_DATA_REGION:([\w|\W|\s]+)", Item["comment"]) | |
| if MatchComment and MatchComment.group(1) == Region[0]: | |
| CommentLine = " " + MatchComment.group(2) + "\n" | |
| TxtBody.append("/**" + CommentLine + "**/\n") | |
| elif Item["offset"] >= UpdOffsetTable[UpdIdx] and Item["comment"] == '': | |
| Match = re.match("^FSP([\w|\W|\s])_UPD", UpdStructure[UpdIdx]) | |
| if Match: | |
| TxtBody.append("/** Fsp " + Match.group(1) + " UPD Configuration\n**/\n") | |
| TxtBody.append("typedef struct {\n") | |
| NextOffset = 0 | |
| SpaceIdx = 0 | |
| Offset = 0 | |
| LastVisible = True | |
| ResvOffset = 0 | |
| ResvIdx = 0 | |
| LineBuffer = [] | |
| InRange = False | |
| for Item in self._CfgItemList: | |
| if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == UpdSignature[UpdIdx] or Region[0] == 'V': | |
| InRange = True | |
| if InRange != True: | |
| continue | |
| if Item['cname'] == 'UpdTerminator': | |
| InRange = False | |
| if Item['region'] != Region: | |
| continue | |
| if Item["offset"] < UpdOffsetTable[UpdIdx]: | |
| continue | |
| NextVisible = LastVisible | |
| if LastVisible and (Item['header'] == 'OFF'): | |
| NextVisible = False | |
| ResvOffset = Item['offset'] | |
| elif (not LastVisible) and Item['header'] == 'ON': | |
| NextVisible = True | |
| Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx | |
| ResvIdx = ResvIdx + 1 | |
| TxtBody.append(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, '', '', '', '')) | |
| if Offset < Item["offset"]: | |
| if LastVisible: | |
| Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx | |
| LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, '', '', '', '')) | |
| SpaceIdx = SpaceIdx + 1 | |
| Offset = Item["offset"] | |
| LastVisible = NextVisible | |
| Offset = Offset + Item["length"] | |
| if LastVisible: | |
| for Each in LineBuffer: | |
| TxtBody.append (Each) | |
| LineBuffer = [] | |
| Comment = Item["comment"] | |
| Embed = Item["embed"].upper() | |
| if Embed.endswith(':START') or Embed.endswith(':END'): | |
| if not Comment == '' and Embed.endswith(':START'): | |
| Marker = '/* COMMENT:%s */ \n' % Item["comment"] | |
| Marker = Marker + '/* EMBED_STRUCT:%s */ ' % Item["embed"] | |
| else: | |
| Marker = '/* EMBED_STRUCT:%s */ ' % Item["embed"] | |
| else: | |
| if Embed == '': | |
| Marker = '' | |
| else: | |
| self.Error = "Invalid embedded structure format '%s'!\n" % Item["embed"] | |
| return 4 | |
| Line = Marker + self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct'], Item['name'], Item['help'], Item['option']) | |
| TxtBody.append(Line) | |
| if Item['cname'] == 'UpdTerminator': | |
| break | |
| TxtBody.append("} " + UpdStructure[UpdIdx] + ";\n\n") | |
| # Handle the embedded data structure | |
| TxtBody = self.PostProcessBody (TxtBody) | |
| HeaderTFileName = 'FsptUpd.h' | |
| HeaderMFileName = 'FspmUpd.h' | |
| HeaderSFileName = 'FspsUpd.h' | |
| HeaderIFileName = 'FspiUpd.h' | |
| UpdRegionCheck = ['FSPT', 'FSPM', 'FSPS', 'FSPI'] # FSPX_UPD_REGION | |
| UpdConfigCheck = ['FSP_T', 'FSP_M', 'FSP_S', 'FSP_I'] # FSP_X_CONFIG, FSP_X_TEST_CONFIG, FSP_X_RESTRICTED_CONFIG | |
| UpdSignatureCheck = ['FSPT_UPD_SIGNATURE', 'FSPM_UPD_SIGNATURE', 'FSPS_UPD_SIGNATURE', 'FSPI_UPD_SIGNATURE'] | |
| ExcludedSpecificUpd = ['FSPT_ARCH_UPD', 'FSPM_ARCH_UPD', 'FSPS_ARCH_UPD', 'FSPI_ARCH_UPD'] | |
| ExcludedSpecificUpd1 = ['FSPT_ARCH2_UPD', 'FSPM_ARCH2_UPD', 'FSPS_ARCH2_UPD'] | |
| IncLines = [] | |
| if InputHeaderFile != '': | |
| if not os.path.exists(InputHeaderFile): | |
| self.Error = "Input header file '%s' does not exist" % InputHeaderFile | |
| return 6 | |
| InFd = open(InputHeaderFile, "r") | |
| IncLines = InFd.readlines() | |
| InFd.close() | |
| for item in range(len(UpdRegionCheck)): | |
| if UpdRegionCheck[item] == 'FSPT': | |
| HeaderFd = open(os.path.join(FvDir, HeaderTFileName), "w") | |
| FileBase = os.path.basename(os.path.join(FvDir, HeaderTFileName)) | |
| elif UpdRegionCheck[item] == 'FSPM': | |
| HeaderFd = open(os.path.join(FvDir, HeaderMFileName), "w") | |
| FileBase = os.path.basename(os.path.join(FvDir, HeaderMFileName)) | |
| elif UpdRegionCheck[item] == 'FSPS': | |
| HeaderFd = open(os.path.join(FvDir, HeaderSFileName), "w") | |
| FileBase = os.path.basename(os.path.join(FvDir, HeaderSFileName)) | |
| elif UpdRegionCheck[item] == 'FSPI': | |
| HeaderFd = open(os.path.join(FvDir, HeaderIFileName), "w") | |
| FileBase = os.path.basename(os.path.join(FvDir, HeaderIFileName)) | |
| FileName = FileBase.replace(".", "_").upper() | |
| HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year)) | |
| HeaderFd.write("#ifndef __%s__\n" % FileName) | |
| HeaderFd.write("#define __%s__\n\n" % FileName) | |
| HeaderFd.write("#include <%s>\n\n" % HeaderFileName) | |
| HeaderFd.write("#pragma pack(1)\n\n") | |
| Export = False | |
| for Line in IncLines: | |
| Match = re.search ("!EXPORT\s+([A-Z]+)\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line) | |
| if Match: | |
| if Match.group(2) == "BEGIN" and Match.group(1) == UpdRegionCheck[item]: | |
| Export = True | |
| continue | |
| else: | |
| Export = False | |
| continue | |
| if Export: | |
| HeaderFd.write(Line) | |
| HeaderFd.write("\n") | |
| Index = 0 | |
| StartIndex = 0 | |
| EndIndex = 0 | |
| StructStart = [] | |
| StructStartWithComment = [] | |
| StructEnd = [] | |
| for Line in TxtBody: | |
| Index += 1 | |
| Match = re.match("(typedef struct {)", Line) | |
| if Match: | |
| StartIndex = Index - 1 | |
| Match = re.match("}\s([_A-Z0-9]+);", Line) | |
| if Match and (UpdRegionCheck[item] in Match.group(1) or UpdConfigCheck[item] in Match.group(1)) and (ExcludedSpecificUpd[item] not in Match.group(1)) and (ExcludedSpecificUpd1[item] not in Match.group(1)): | |
| EndIndex = Index | |
| StructStart.append(StartIndex) | |
| StructEnd.append(EndIndex) | |
| Index = 0 | |
| for Line in TxtBody: | |
| Index += 1 | |
| for Item in range(len(StructStart)): | |
| if Index == StructStart[Item]: | |
| Match = re.match("^(/\*\*\s*)", Line) | |
| if Match: | |
| StructStartWithComment.append(StructStart[Item]) | |
| else: | |
| StructStartWithComment.append(StructStart[Item] + 1) | |
| Index = 0 | |
| for Line in TxtBody: | |
| Index += 1 | |
| for Item in range(len(StructStart)): | |
| if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]: | |
| self.WriteLinesWithoutTailingSpace(HeaderFd, Line) | |
| HeaderFd.write("#pragma pack()\n\n") | |
| HeaderFd.write("#endif\n") | |
| HeaderFd.close() | |
| HeaderFd = open(HeaderFile, "w") | |
| FileBase = os.path.basename(HeaderFile) | |
| FileName = FileBase.replace(".", "_").upper() | |
| HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year)) | |
| HeaderFd.write("#ifndef __%s__\n" % FileName) | |
| HeaderFd.write("#define __%s__\n\n" % FileName) | |
| HeaderFd.write("#include <FspEas.h>\n\n") | |
| HeaderFd.write("#pragma pack(1)\n\n") | |
| for item in range(len(UpdRegionCheck)): | |
| Index = 0 | |
| StartIndex = 0 | |
| EndIndex = 0 | |
| StructStart = [] | |
| StructStartWithComment = [] | |
| StructEnd = [] | |
| for Line in TxtBody: | |
| Index += 1 | |
| Match = re.match("(typedef struct {)", Line) | |
| if Match: | |
| StartIndex = Index - 1 | |
| Match = re.match("#define\s([_A-Z0-9]+)\s*", Line) | |
| if Match and (UpdSignatureCheck[item] in Match.group(1) or UpdSignatureCheck[item] in Match.group(1)): | |
| StructStart.append(Index - 1) | |
| StructEnd.append(Index) | |
| Index = 0 | |
| for Line in TxtBody: | |
| Index += 1 | |
| for Item in range(len(StructStart)): | |
| if Index == StructStart[Item]: | |
| Match = re.match("^(/\*\*\s*)", Line) | |
| if Match: | |
| StructStartWithComment.append(StructStart[Item]) | |
| else: | |
| StructStartWithComment.append(StructStart[Item] + 1) | |
| Index = 0 | |
| for Line in TxtBody: | |
| Index += 1 | |
| for Item in range(len(StructStart)): | |
| if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]: | |
| self.WriteLinesWithoutTailingSpace(HeaderFd, Line) | |
| HeaderFd.write("#pragma pack()\n\n") | |
| HeaderFd.write("#endif\n") | |
| HeaderFd.close() | |
| return 0 | |
| def WriteBsfStruct (self, BsfFd, Item): | |
| LogExpr = CLogicalExpression() | |
| if Item['type'] == "None": | |
| Space = "gPlatformFspPkgTokenSpaceGuid" | |
| else: | |
| Space = Item['space'] | |
| Line = " $%s_%s" % (Space, Item['cname']) | |
| Match = re.match("\s*\{([x0-9a-fA-F,\s]+)\}\s*", Item['value']) | |
| if Match: | |
| DefaultValue = Match.group(1).strip() | |
| else: | |
| DefaultValue = Item['value'].strip() | |
| if 'bitlength' in Item: | |
| BsfFd.write(" %s%s%4d bits $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['bitlength'], DefaultValue)) | |
| else: | |
| BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue)) | |
| TmpList = [] | |
| if Item['type'] == "Combo": | |
| if not Item['option'] in self._BuidinOption: | |
| OptList = Item['option'].split(',') | |
| for Option in OptList: | |
| Option = Option.strip() | |
| (OpVal, OpStr) = Option.split(':') | |
| test = LogExpr.getNumber (OpVal) | |
| if test is None: | |
| raise Exception("Selection Index '%s' is not a number" % OpVal) | |
| TmpList.append((OpVal, OpStr)) | |
| return TmpList | |
| def WriteBsfOption (self, BsfFd, Item): | |
| PcdName = Item['space'] + '_' + Item['cname'] | |
| WriteHelp = 0 | |
| if Item['type'] == "Combo": | |
| if Item['option'] in self._BuidinOption: | |
| Options = self._BuidinOption[Item['option']] | |
| else: | |
| Options = PcdName | |
| BsfFd.write(' %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: | |
| BsfFd.write(' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1))) | |
| WriteHelp = 2 | |
| elif Item['type'].startswith("EditText"): | |
| BsfFd.write(' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name'])) | |
| WriteHelp = 1 | |
| elif Item['type'] == "Table": | |
| Columns = Item['option'].split(',') | |
| if len(Columns) != 0: | |
| BsfFd.write(' %s $%s "%s",' % (Item['type'], PcdName, Item['name'])) | |
| for Col in Columns: | |
| Fmt = Col.split(':') | |
| if len(Fmt) != 3: | |
| raise Exception("Column format '%s' is invalid !" % Fmt) | |
| try: | |
| Dtype = int(Fmt[1].strip()) | |
| except: | |
| raise Exception("Column size '%s' is invalid !" % Fmt[1]) | |
| BsfFd.write('\n Column "%s", %d bytes, %s' % (Fmt[0].strip(), Dtype, Fmt[2].strip())) | |
| BsfFd.write(',\n') | |
| WriteHelp = 1 | |
| if WriteHelp > 0: | |
| HelpLines = Item['help'].split('\\n\\r') | |
| FirstLine = True | |
| for HelpLine in HelpLines: | |
| if FirstLine: | |
| FirstLine = False | |
| BsfFd.write(' Help "%s"\n' % (HelpLine)) | |
| else: | |
| BsfFd.write(' "%s"\n' % (HelpLine)) | |
| if WriteHelp == 2: | |
| BsfFd.write(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3))) | |
| def GenerateBsfFile (self, BsfFile): | |
| if BsfFile == '': | |
| self.Error = "BSF output file '%s' is invalid" % BsfFile | |
| return 1 | |
| if (self.NoDscFileChange (BsfFile)): | |
| # DSC has not been modified yet | |
| # So don't have to re-generate other files | |
| self.Error = 'No DSC file change, skip to create UPD BSF file' | |
| return 256 | |
| Error = 0 | |
| OptionDict = {} | |
| BsfFd = open(BsfFile, "w") | |
| BsfFd.write("%s\n" % (__copyright_bsf__ % date.today().year)) | |
| 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 = int(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) | |
| for Each in OptionDict: | |
| BsfFd.write("List &%s\n" % Each) | |
| for Item in OptionDict[Each]: | |
| BsfFd.write(' Selection %s , "%s"\n' % (Item[0], Item[1])) | |
| BsfFd.write("EndList\n\n") | |
| 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") | |
| for Each in self._CfgPageDict: | |
| BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each]) | |
| BsfItems = [] | |
| for Item in self._CfgItemList: | |
| if Item['name'] != '': | |
| if Item['page'] != Each: | |
| 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") | |
| BsfFd.close() | |
| return Error | |
| def Usage(): | |
| print ("GenCfgOpt Version 0.59") | |
| print ("Usage:") | |
| print (" GenCfgOpt UPDTXT PlatformDscFile BuildFvDir [-D Macros]") | |
| print (" GenCfgOpt HEADER PlatformDscFile BuildFvDir InputHFile [-D Macros]") | |
| print (" GenCfgOpt GENBSF PlatformDscFile BuildFvDir BsfOutFile [-D Macros]") | |
| def Main(): | |
| # | |
| # Parse the options and args | |
| # | |
| i = 1 | |
| GenCfgOpt = CGenCfgOpt() | |
| while i < len(sys.argv): | |
| if sys.argv[i].strip().lower() == "--pcd": | |
| BuildOptionPcd.append(sys.argv[i+1]) | |
| i += 1 | |
| i += 1 | |
| argc = len(sys.argv) | |
| if argc < 4: | |
| Usage() | |
| return 1 | |
| else: | |
| DscFile = sys.argv[2] | |
| if not os.path.exists(DscFile): | |
| print ("ERROR: Cannot open DSC file '%s' !" % DscFile) | |
| return 2 | |
| OutFile = '' | |
| if argc > 4: | |
| if sys.argv[4][0] == '-': | |
| Start = 4 | |
| else: | |
| OutFile = sys.argv[4] | |
| Start = 5 | |
| if argc > Start: | |
| if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0: | |
| print ("ERROR: Macro parsing failed !") | |
| return 3 | |
| FvDir = sys.argv[3] | |
| if not os.path.exists(FvDir): | |
| os.makedirs(FvDir) | |
| if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0: | |
| print ("ERROR: %s !" % GenCfgOpt.Error) | |
| return 5 | |
| if GenCfgOpt.UpdateSubRegionDefaultValue() != 0: | |
| print ("ERROR: %s !" % GenCfgOpt.Error) | |
| return 7 | |
| if sys.argv[1] == "UPDTXT": | |
| Ret = GenCfgOpt.CreateSplitUpdTxt(OutFile) | |
| if Ret != 0: | |
| # No change is detected | |
| if Ret == 256: | |
| print ("INFO: %s !" % (GenCfgOpt.Error)) | |
| else : | |
| print ("ERROR: %s !" % (GenCfgOpt.Error)) | |
| return Ret | |
| elif sys.argv[1] == "HEADER": | |
| Ret = GenCfgOpt.CreateHeaderFile(OutFile) | |
| if Ret != 0: | |
| # No change is detected | |
| if Ret == 256: | |
| print ("INFO: %s !" % (GenCfgOpt.Error)) | |
| else : | |
| print ("ERROR: %s !" % (GenCfgOpt.Error)) | |
| return 8 | |
| return Ret | |
| elif sys.argv[1] == "GENBSF": | |
| Ret = GenCfgOpt.GenerateBsfFile(OutFile) | |
| if Ret != 0: | |
| # No change is detected | |
| if Ret == 256: | |
| print ("INFO: %s !" % (GenCfgOpt.Error)) | |
| else : | |
| print ("ERROR: %s !" % (GenCfgOpt.Error)) | |
| return 9 | |
| return Ret | |
| else: | |
| if argc < 5: | |
| Usage() | |
| return 1 | |
| print ("ERROR: Unknown command '%s' !" % sys.argv[1]) | |
| Usage() | |
| return 1 | |
| return 0 | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(Main()) |