X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=BaseTools%2FSource%2FPython%2FGenFds%2FFdfParser.py;h=ffc54abc847f80d9742d3958e20584f38cbc22ed;hp=5cdbe8888964ef2e42922917c8fbbd9bae0e6e98;hb=a3251d844695f90711bfe094f12755fd01742369;hpb=4234283c3acb8c35014acc1546621fbc2621b095 diff --git a/BaseTools/Source/Python/GenFds/FdfParser.py b/BaseTools/Source/Python/GenFds/FdfParser.py index 5cdbe88889..ffc54abc84 100644 --- a/BaseTools/Source/Python/GenFds/FdfParser.py +++ b/BaseTools/Source/Python/GenFds/FdfParser.py @@ -1,7 +1,7 @@ ## @file # parse FDF file # -# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -15,6 +15,8 @@ ## # Import Modules # +import re + import Fd import Region import Fv @@ -45,9 +47,16 @@ from Common.BuildToolError import * from Common import EdkLogger from Common.Misc import PathClass from Common.String import NormPath +import Common.GlobalData as GlobalData +from Common.Expression import * +from Common import GlobalData +from Common.String import ReplaceMacro + +from Common.Misc import tdict import re -import os +import Common.LongFilePathOs as os +from Common.LongFilePathSupport import OpenLongFilePath as open ##define T_CHAR_SPACE ' ' ##define T_CHAR_NULL '\0' @@ -67,11 +76,12 @@ T_CHAR_BACKSLASH, T_CHAR_DOUBLE_QUOTE, T_CHAR_SINGLE_QUOTE, T_CHAR_STAR, T_CHAR_ SEPERATOR_TUPLE = ('=', '|', ',', '{', '}') +RegionSizePattern = re.compile("\s*(?P(?:0x|0X)?[a-fA-F0-9]+)\s*\|\s*(?P(?:0x|0X)?[a-fA-F0-9]+)\s*") +RegionSizeGuidPattern = re.compile("\s*(?P\w+\.\w+)\s*\|\s*(?P\w+\.\w+)\s*") +RegionOffsetPcdPattern = re.compile("\s*(?P\w+\.\w+)\s*$") +ShortcutPcdPattern = re.compile("\s*\w+\s*=\s*(?P(?:0x|0X)?[a-fA-F0-9]+)\s*\|\s*(?P\w+\.\w+)\s*") + IncludeFileList = [] -# Macro passed from command line, which has greatest priority and can NOT be overridden by those in FDF -InputMacroDict = {} -# All Macro values when parsing file, not replace existing Macro -AllMacroList = [] def GetRealFileLine (File, Line): @@ -173,7 +183,10 @@ class FileProfile : self.PcdDict = {} self.InfList = [] - + # ECC will use this Dict and List information + self.PcdFileLineDict = {} + self.InfFileLineList = [] + self.FdDict = {} self.FdNameNotSet = False self.FvDict = {} @@ -181,6 +194,7 @@ class FileProfile : self.VtfList = [] self.RuleDict = {} self.OptRomDict = {} + self.FmpPayloadDict = {} ## The syntax parser for FDF # @@ -205,6 +219,14 @@ class FdfParser: self.CurrentFvName = None self.__Token = "" self.__SkippedChars = "" + GlobalData.gFdfParser = self + + # Used to section info + self.__CurSection = [] + # Key: [section name, UI name, arch] + # Value: {MACRO_NAME : MACRO_VALUE} + self.__MacroDict = tdict(True, 3) + self.__PcdDict = {} self.__WipeOffArea = [] if GenFdsGlobalVariable.WorkSpaceDir == '': @@ -316,10 +338,10 @@ class FdfParser: # def __GetOneChar(self): if self.CurrentOffsetWithinLine == len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) - 1: - self.CurrentLineNumber += 1 - self.CurrentOffsetWithinLine = 0 + self.CurrentLineNumber += 1 + self.CurrentOffsetWithinLine = 0 else: - self.CurrentOffsetWithinLine += 1 + self.CurrentOffsetWithinLine += 1 ## __CurrentChar() method # @@ -368,30 +390,6 @@ class FdfParser: self.Profile.FileLinesList = [list(s) for s in self.Profile.FileLinesList] self.Profile.FileLinesList[-1].append(' ') - def __ReplaceMacros(self, Str, File, Line): - MacroEnd = 0 - while Str.find('$(', MacroEnd) >= 0: - MacroStart = Str.find('$(', MacroEnd) - if Str.find(')', MacroStart) > 0: - MacroEnd = Str.find(')', MacroStart) - Name = Str[MacroStart + 2 : MacroEnd] - Value = None - if Name in InputMacroDict: - Value = InputMacroDict[Name] - - else: - for Profile in AllMacroList: - if Profile.FileName == File and Profile.MacroName == Name and Profile.DefinedAtLine <= Line: - Value = Profile.MacroValue - - if Value != None: - Str = Str.replace('$(' + Name + ')', Value) - MacroEnd = MacroStart + len(Value) - - else: - raise Warning("Macro not complete", self.FileName, self.CurrentLineNumber) - return Str - def __ReplaceFragment(self, StartPos, EndPos, Value = ' '): if StartPos[0] == EndPos[0]: Offset = StartPos[1] @@ -433,7 +431,67 @@ class FdfParser: self.FileName, self.CurrentLineNumber) MacroName = MacroName[2:-1] return MacroName, NotFlag - + + def __SetMacroValue(self, Macro, Value): + if not self.__CurSection: + return + + MacroDict = {} + if not self.__MacroDict[self.__CurSection[0], self.__CurSection[1], self.__CurSection[2]]: + self.__MacroDict[self.__CurSection[0], self.__CurSection[1], self.__CurSection[2]] = MacroDict + else: + MacroDict = self.__MacroDict[self.__CurSection[0], self.__CurSection[1], self.__CurSection[2]] + MacroDict[Macro] = Value + + def __GetMacroValue(self, Macro): + # Highest priority + if Macro in GlobalData.gCommandLineDefines: + return GlobalData.gCommandLineDefines[Macro] + if Macro in GlobalData.gGlobalDefines: + return GlobalData.gGlobalDefines[Macro] + + if self.__CurSection: + MacroDict = self.__MacroDict[ + self.__CurSection[0], + self.__CurSection[1], + self.__CurSection[2] + ] + if MacroDict and Macro in MacroDict: + return MacroDict[Macro] + + # Lowest priority + if Macro in GlobalData.gPlatformDefines: + return GlobalData.gPlatformDefines[Macro] + return None + + def __SectionHeaderParser(self, Section): + # [Defines] + # [FD.UiName]: use dummy instead if UI name is optional + # [FV.UiName] + # [Capsule.UiName] + # [Rule]: don't take rule section into account, macro is not allowed in this section + # [VTF.arch.UiName, arch] + # [OptionRom.DriverName] + self.__CurSection = [] + Section = Section.strip()[1:-1].upper().replace(' ', '').strip('.') + ItemList = Section.split('.') + Item = ItemList[0] + if Item == '' or Item == 'RULE': + return + + if Item == 'DEFINES': + self.__CurSection = ['COMMON', 'COMMON', 'COMMON'] + elif Item == 'VTF' and len(ItemList) == 3: + UiName = ItemList[2] + Pos = UiName.find(',') + if Pos != -1: + UiName = UiName[:Pos] + self.__CurSection = ['VTF', UiName, ItemList[1]] + elif len(ItemList) > 1: + self.__CurSection = [ItemList[0], ItemList[1], 'COMMON'] + elif len(ItemList) > 0: + self.__CurSection = [ItemList[0], 'DUMMY', 'COMMON'] + ## PreprocessFile() method # # Preprocess file contents, replace comments with spaces. @@ -516,25 +574,45 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("expected include file name", self.FileName, self.CurrentLineNumber) IncFileName = self.__Token - if not os.path.isabs(IncFileName): - if IncFileName.startswith('$(WORKSPACE)'): - Str = IncFileName.replace('$(WORKSPACE)', os.environ.get('WORKSPACE')) - if os.path.exists(Str): - if not os.path.isabs(Str): - Str = os.path.abspath(Str) - IncFileName = Str - else: - # file is in the same dir with FDF file - FullFdf = self.FileName - if not os.path.isabs(self.FileName): - FullFdf = os.path.join(os.environ.get('WORKSPACE'), self.FileName) - - IncFileName = os.path.join(os.path.dirname(FullFdf), IncFileName) - - if not os.path.exists(os.path.normpath(IncFileName)): - raise Warning("Include file not exists", self.FileName, self.CurrentLineNumber) + __IncludeMacros = {} + for Macro in ['WORKSPACE', 'ECP_SOURCE', 'EFI_SOURCE', 'EDK_SOURCE']: + MacroVal = self.__GetMacroValue(Macro) + if MacroVal: + __IncludeMacros[Macro] = MacroVal + + try: + IncludedFile = NormPath(ReplaceMacro(IncFileName, __IncludeMacros, RaiseError=True)) + except: + raise Warning("only these system environment variables are permitted to start the path of the included file: " + "$(WORKSPACE), $(ECP_SOURCE), $(EFI_SOURCE), $(EDK_SOURCE)", + self.FileName, self.CurrentLineNumber) + # + # First search the include file under the same directory as FDF file + # + IncludedFile1 = PathClass(IncludedFile, os.path.dirname(self.FileName)) + ErrorCode = IncludedFile1.Validate()[0] + if ErrorCode != 0: + # + # Then search the include file under the same directory as DSC file + # + PlatformDir = '' + if GenFdsGlobalVariable.ActivePlatform: + PlatformDir = GenFdsGlobalVariable.ActivePlatform.Dir + elif GlobalData.gActivePlatform: + PlatformDir = GlobalData.gActivePlatform.MetaFile.Dir + IncludedFile1 = PathClass(IncludedFile, PlatformDir) + ErrorCode = IncludedFile1.Validate()[0] + if ErrorCode != 0: + # + # Also search file under the WORKSPACE directory + # + IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace) + ErrorCode = IncludedFile1.Validate()[0] + if ErrorCode != 0: + raise Warning("The include file does not exist under below directories: \n%s\n%s\n%s\n"%(os.path.dirname(self.FileName), PlatformDir, GlobalData.gWorkspace), + self.FileName, self.CurrentLineNumber) - IncFileProfile = IncludeFileProfile(os.path.normpath(IncFileName)) + IncFileProfile = IncludeFileProfile(IncludedFile1.Path) CurrentLine = self.CurrentLineNumber CurrentOffset = self.CurrentOffsetWithinLine @@ -563,7 +641,7 @@ class FdfParser: self.Profile.FileLinesList[IncludeLine - 1] = ''.join(TempList) self.Rewind() - + def __GetIfListCurrentItemStat(self, IfList): if len(IfList) == 0: return True @@ -573,8 +651,7 @@ class FdfParser: return False return True - - + ## PreprocessConditionalStatement() method # # Preprocess conditional statement. @@ -585,9 +662,48 @@ class FdfParser: def PreprocessConditionalStatement(self): # IfList is a stack of if branches with elements of list [Pos, CondSatisfied, BranchDetermined] IfList = [] + RegionLayoutLine = 0 + ReplacedLine = -1 while self.__GetNextToken(): + # Determine section name and the location dependent macro + if self.__GetIfListCurrentItemStat(IfList): + if self.__Token.startswith('['): + Header = self.__Token + if not self.__Token.endswith(']'): + self.__SkipToToken(']') + Header += self.__SkippedChars + if Header.find('$(') != -1: + raise Warning("macro cannot be used in section header", self.FileName, self.CurrentLineNumber) + self.__SectionHeaderParser(Header) + continue + # Replace macros except in RULE section or out of section + elif self.__CurSection and ReplacedLine != self.CurrentLineNumber: + ReplacedLine = self.CurrentLineNumber + self.__UndoToken() + CurLine = self.Profile.FileLinesList[ReplacedLine - 1] + PreIndex = 0 + StartPos = CurLine.find('$(', PreIndex) + EndPos = CurLine.find(')', StartPos+2) + while StartPos != -1 and EndPos != -1 and self.__Token not in ['!ifdef', '!ifndef', '!if', '!elseif']: + MacroName = CurLine[StartPos+2 : EndPos] + MacorValue = self.__GetMacroValue(MacroName) + if MacorValue != None: + CurLine = CurLine.replace('$(' + MacroName + ')', MacorValue, 1) + if MacorValue.find('$(') != -1: + PreIndex = StartPos + else: + PreIndex = StartPos + len(MacorValue) + else: + PreIndex = EndPos + 1 + StartPos = CurLine.find('$(', PreIndex) + EndPos = CurLine.find(')', StartPos+2) + self.Profile.FileLinesList[ReplacedLine - 1] = CurLine + continue + if self.__Token == 'DEFINE': if self.__GetIfListCurrentItemStat(IfList): + if not self.__CurSection: + raise Warning("macro cannot be defined in Rule section or out of section", self.FileName, self.CurrentLineNumber) DefineLine = self.CurrentLineNumber - 1 DefineOffset = self.CurrentOffsetWithinLine - len('DEFINE') if not self.__GetNextToken(): @@ -596,72 +712,52 @@ class FdfParser: if not self.__IsToken( "="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - if not self.__GetNextToken(): - raise Warning("expected value", self.FileName, self.CurrentLineNumber) - - if self.__GetStringData(): - pass - Value = self.__Token - if not Macro in InputMacroDict: - FileLineTuple = GetRealFileLine(self.FileName, DefineLine + 1) - MacProfile = MacroProfile(FileLineTuple[0], FileLineTuple[1]) - MacProfile.MacroName = Macro - MacProfile.MacroValue = Value - AllMacroList.append(MacProfile) + Value = self.__GetExpression() + self.__SetMacroValue(Macro, Value) self.__WipeOffArea.append(((DefineLine, DefineOffset), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + elif self.__Token == 'SET': + if not self.__GetIfListCurrentItemStat(IfList): + continue + SetLine = self.CurrentLineNumber - 1 + SetOffset = self.CurrentOffsetWithinLine - len('SET') + PcdPair = self.__GetNextPcdName() + PcdName = "%s.%s" % (PcdPair[1], PcdPair[0]) + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + Value = self.__GetExpression() + Value = self.__EvaluateConditional(Value, self.CurrentLineNumber, 'eval', True) + + self.__PcdDict[PcdName] = Value + + self.Profile.PcdDict[PcdPair] = Value + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[PcdPair] = FileLineTuple + + self.__WipeOffArea.append(((SetLine, SetOffset), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) elif self.__Token in ('!ifdef', '!ifndef', '!if'): IfStartPos = (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len(self.__Token)) IfList.append([IfStartPos, None, None]) + CondLabel = self.__Token + Expression = self.__GetExpression() - MacroName, NotFlag = self.__GetMacroName() - NotDefineFlag = False - if CondLabel == '!ifndef': - NotDefineFlag = True - if CondLabel == '!ifdef' or CondLabel == '!ifndef': - if NotFlag: - raise Warning("'NOT' operation not allowed for Macro name", self.FileName, self.CurrentLineNumber) - if CondLabel == '!if': - - if not self.__GetNextOp(): - raise Warning("expected !endif", self.FileName, self.CurrentLineNumber) - - if self.__Token in ('!=', '==', '>', '<', '>=', '<='): - Op = self.__Token - if not self.__GetNextToken(): - raise Warning("expected value", self.FileName, self.CurrentLineNumber) - if self.__GetStringData(): - pass - MacroValue = self.__Token - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1, Op, MacroValue) - if NotFlag: - ConditionSatisfied = not ConditionSatisfied - BranchDetermined = ConditionSatisfied - else: - self.CurrentOffsetWithinLine -= len(self.__Token) - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1, None, 'Bool') - if NotFlag: - ConditionSatisfied = not ConditionSatisfied - BranchDetermined = ConditionSatisfied - IfList[-1] = [IfList[-1][0], ConditionSatisfied, BranchDetermined] - if ConditionSatisfied: - self.__WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) - + ConditionSatisfied = self.__EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'eval') else: - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1) - if NotDefineFlag: + ConditionSatisfied = self.__EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'in') + if CondLabel == '!ifndef': ConditionSatisfied = not ConditionSatisfied - BranchDetermined = ConditionSatisfied - IfList[-1] = [IfList[-1][0], ConditionSatisfied, BranchDetermined] - if ConditionSatisfied: - self.__WipeOffArea.append((IfStartPos, (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + BranchDetermined = ConditionSatisfied + IfList[-1] = [IfList[-1][0], ConditionSatisfied, BranchDetermined] + if ConditionSatisfied: + self.__WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) elif self.__Token in ('!elseif', '!else'): ElseStartPos = (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len(self.__Token)) if len(IfList) <= 0: raise Warning("Missing !if statement", self.FileName, self.CurrentLineNumber) + if IfList[-1][1]: IfList[-1] = [ElseStartPos, False, True] self.__WipeOffArea.append((ElseStartPos, (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) @@ -669,27 +765,8 @@ class FdfParser: self.__WipeOffArea.append((IfList[-1][0], ElseStartPos)) IfList[-1] = [ElseStartPos, True, IfList[-1][2]] if self.__Token == '!elseif': - MacroName, NotFlag = self.__GetMacroName() - if not self.__GetNextOp(): - raise Warning("expected !endif", self.FileName, self.CurrentLineNumber) - - if self.__Token in ('!=', '==', '>', '<', '>=', '<='): - Op = self.__Token - if not self.__GetNextToken(): - raise Warning("expected value", self.FileName, self.CurrentLineNumber) - if self.__GetStringData(): - pass - MacroValue = self.__Token - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1, Op, MacroValue) - if NotFlag: - ConditionSatisfied = not ConditionSatisfied - - else: - self.CurrentOffsetWithinLine -= len(self.__Token) - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1, None, 'Bool') - if NotFlag: - ConditionSatisfied = not ConditionSatisfied - + Expression = self.__GetExpression() + ConditionSatisfied = self.__EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'eval') IfList[-1] = [IfList[-1][0], ConditionSatisfied, IfList[-1][2]] if IfList[-1][1]: @@ -698,115 +775,107 @@ class FdfParser: else: IfList[-1][2] = True self.__WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) - - elif self.__Token == '!endif': + if len(IfList) <= 0: + raise Warning("Missing !if statement", self.FileName, self.CurrentLineNumber) if IfList[-1][1]: self.__WipeOffArea.append(((self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len('!endif')), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) else: self.__WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) IfList.pop() + elif not IfList: # Don't use PCDs inside conditional directive + if self.CurrentLineNumber <= RegionLayoutLine: + # Don't try the same line twice + continue + SetPcd = ShortcutPcdPattern.match(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) + if SetPcd: + self.__PcdDict[SetPcd.group('name')] = SetPcd.group('value') + RegionLayoutLine = self.CurrentLineNumber + continue + RegionSize = RegionSizePattern.match(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) + if not RegionSize: + RegionLayoutLine = self.CurrentLineNumber + continue + RegionSizeGuid = RegionSizeGuidPattern.match(self.Profile.FileLinesList[self.CurrentLineNumber]) + if not RegionSizeGuid: + RegionLayoutLine = self.CurrentLineNumber + 1 + continue + self.__PcdDict[RegionSizeGuid.group('base')] = RegionSize.group('base') + self.__PcdDict[RegionSizeGuid.group('size')] = RegionSize.group('size') + RegionLayoutLine = self.CurrentLineNumber + 1 - - if len(IfList) > 0: + if IfList: raise Warning("Missing !endif", self.FileName, self.CurrentLineNumber) self.Rewind() - def __EvaluateConditional(self, Name, Line, Op = None, Value = None): + def __CollectMacroPcd(self): + MacroDict = {} + # PCD macro + MacroDict.update(GlobalData.gPlatformPcds) + MacroDict.update(self.__PcdDict) + + # Lowest priority + MacroDict.update(GlobalData.gPlatformDefines) + + if self.__CurSection: + # Defines macro + ScopeMacro = self.__MacroDict['COMMON', 'COMMON', 'COMMON'] + if ScopeMacro: + MacroDict.update(ScopeMacro) + + # Section macro + ScopeMacro = self.__MacroDict[ + self.__CurSection[0], + self.__CurSection[1], + self.__CurSection[2] + ] + if ScopeMacro: + MacroDict.update(ScopeMacro) + + MacroDict.update(GlobalData.gGlobalDefines) + MacroDict.update(GlobalData.gCommandLineDefines) + # Highest priority + + return MacroDict + + def __EvaluateConditional(self, Expression, Line, Op = None, Value = None): FileLineTuple = GetRealFileLine(self.FileName, Line) - if Name in InputMacroDict: - MacroValue = InputMacroDict[Name] - if Op == None: - if Value == 'Bool' and MacroValue == None or MacroValue.upper() == 'FALSE': - return False - return True - elif Op == '!=': - if Value != MacroValue: - return True - else: - return False - elif Op == '==': - if Value == MacroValue: - return True - else: - return False - else: - if (self.__IsHex(Value) or Value.isdigit()) and (self.__IsHex(MacroValue) or (MacroValue != None and MacroValue.isdigit())): - InputVal = long(Value, 0) - MacroVal = long(MacroValue, 0) - if Op == '>': - if MacroVal > InputVal: - return True - else: - return False - elif Op == '>=': - if MacroVal >= InputVal: - return True - else: - return False - elif Op == '<': - if MacroVal < InputVal: - return True - else: - return False - elif Op == '<=': - if MacroVal <= InputVal: - return True - else: - return False - else: - return False + MacroPcdDict = self.__CollectMacroPcd() + if Op == 'eval': + try: + if Value: + return ValueExpression(Expression, MacroPcdDict)(True) else: - raise Warning("Value %s is not a number", self.FileName, Line) - - for Profile in AllMacroList: - if Profile.MacroName == Name and Profile.DefinedAtLine <= FileLineTuple[1]: - if Op == None: - if Value == 'Bool' and Profile.MacroValue == None or Profile.MacroValue.upper() == 'FALSE': - return False - return True - elif Op == '!=': - if Value != Profile.MacroValue: - return True + return ValueExpression(Expression, MacroPcdDict)() + except WrnExpression, Excpt: + # + # Catch expression evaluation warning here. We need to report + # the precise number of line and return the evaluation result + # + EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt), + File=self.FileName, ExtraData=self.__CurrentLine(), + Line=Line) + return Excpt.result + except Exception, Excpt: + if hasattr(Excpt, 'Pcd'): + if Excpt.Pcd in GlobalData.gPlatformOtherPcds: + Info = GlobalData.gPlatformOtherPcds[Excpt.Pcd] + raise Warning("Cannot use this PCD (%s) in an expression as" + " it must be defined in a [PcdsFixedAtBuild] or [PcdsFeatureFlag] section" + " of the DSC file (%s), and it is currently defined in this section:" + " %s, line #: %d." % (Excpt.Pcd, GlobalData.gPlatformOtherPcds['DSCFILE'], Info[0], Info[1]), + *FileLineTuple) else: - return False - elif Op == '==': - if Value == Profile.MacroValue: - return True - else: - return False + raise Warning("PCD (%s) is not defined in DSC file (%s)" % (Excpt.Pcd, GlobalData.gPlatformOtherPcds['DSCFILE']), + *FileLineTuple) else: - if (self.__IsHex(Value) or Value.isdigit()) and (self.__IsHex(Profile.MacroValue) or (Profile.MacroValue != None and Profile.MacroValue.isdigit())): - InputVal = long(Value, 0) - MacroVal = long(Profile.MacroValue, 0) - if Op == '>': - if MacroVal > InputVal: - return True - else: - return False - elif Op == '>=': - if MacroVal >= InputVal: - return True - else: - return False - elif Op == '<': - if MacroVal < InputVal: - return True - else: - return False - elif Op == '<=': - if MacroVal <= InputVal: - return True - else: - return False - else: - return False - else: - raise Warning("Value %s is not a number", self.FileName, Line) - - return False + raise Warning(str(Excpt), *FileLineTuple) + else: + if Expression.startswith('$(') and Expression[-1] == ')': + Expression = Expression[2:-1] + return Expression in MacroPcdDict ## __IsToken() method # @@ -865,6 +934,16 @@ class FdfParser: return True return False + def __GetExpression(self): + Line = self.Profile.FileLinesList[self.CurrentLineNumber - 1] + Index = len(Line) - 1 + while Line[Index] in ['\r', '\n']: + Index -= 1 + ExpressionString = self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:Index+1] + self.CurrentOffsetWithinLine += len(ExpressionString) + ExpressionString = ExpressionString.strip() + return ExpressionString + ## __GetNextWord() method # # Get next C name from file lines @@ -914,7 +993,7 @@ class FdfParser: # Record the token start position, the position of the first non-space char. StartPos = self.CurrentOffsetWithinLine StartLine = self.CurrentLineNumber - while not self.__EndOfLine(): + while StartLine == self.CurrentLineNumber: TempChar = self.__CurrentChar() # Try to find the end char that is not a space and not in seperator tuple. # That is, when we got a space or any char in the tuple, we got the end of token. @@ -1004,7 +1083,7 @@ class FdfParser: # That is, when we got a space or any char in the tuple, we got the end of token. if not str(TempChar).isspace() and not TempChar in SEPERATOR_TUPLE: if not self.__UndoOneChar(): - break + return # if we happen to meet a seperator as the first char, we must proceed to get it. # That is, we get a token that is a seperator char. nomally it is the boundary of other tokens. elif StartPos == self.CurrentOffsetWithinLine and TempChar in SEPERATOR_TUPLE: @@ -1187,6 +1266,28 @@ class FdfParser: def SetFileBufferPos(self, Pos): (self.CurrentLineNumber, self.CurrentOffsetWithinLine) = Pos + ## Preprocess() method + # + # Preprocess comment, conditional directive, include directive, replace macro. + # Exception will be raised if syntax error found + # + # @param self The object pointer + # + def Preprocess(self): + self.__StringToList() + self.PreprocessFile() + self.PreprocessIncludeFile() + self.__StringToList() + self.PreprocessFile() + self.PreprocessConditionalStatement() + self.__StringToList() + for Pos in self.__WipeOffArea: + self.__ReplaceFragment(Pos[0], Pos[1]) + self.Profile.FileLinesList = ["".join(list) for list in self.Profile.FileLinesList] + + while self.__GetDefines(): + pass + ## ParseFile() method # # Parse the file profile buffer to extract fd, fv ... information @@ -1197,32 +1298,16 @@ class FdfParser: def ParseFile(self): try: - self.__StringToList() - self.PreprocessFile() - self.PreprocessIncludeFile() - self.__StringToList() - self.PreprocessFile() - self.PreprocessConditionalStatement() - self.__StringToList() - for Pos in self.__WipeOffArea: - self.__ReplaceFragment(Pos[0], Pos[1]) - self.Profile.FileLinesList = ["".join(list) for list in self.Profile.FileLinesList] - - while self.__GetDefines(): - pass - - Index = 0 - while Index < len(self.Profile.FileLinesList): - FileLineTuple = GetRealFileLine(self.FileName, Index + 1) - self.Profile.FileLinesList[Index] = self.__ReplaceMacros(self.Profile.FileLinesList[Index], FileLineTuple[0], FileLineTuple[1]) - Index += 1 - + self.Preprocess() while self.__GetFd(): pass while self.__GetFv(): pass + while self.__GetFmp(): + pass + while self.__GetCapsule(): pass @@ -1288,11 +1373,6 @@ class FdfParser: if not self.__GetNextToken() or self.__Token.startswith('['): raise Warning("expected MACRO value", self.FileName, self.CurrentLineNumber) Value = self.__Token - FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) - MacProfile = MacroProfile(FileLineTuple[0], FileLineTuple[1]) - MacProfile.MacroName = Macro - MacProfile.MacroValue = Value - AllMacroList.append(MacProfile) return False @@ -1311,7 +1391,7 @@ class FdfParser: S = self.__Token.upper() if S.startswith("[") and not S.startswith("[FD."): - if not S.startswith("[FV.") and not S.startswith("[CAPSULE.") \ + if not S.startswith("[FV.") and not S.startswith('[FMPPAYLOAD.') and not S.startswith("[CAPSULE.") \ and not S.startswith("[VTF.") and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."): raise Warning("Unknown section", self.FileName, self.CurrentLineNumber) self.__UndoToken() @@ -1328,6 +1408,8 @@ class FdfParser: if FdName == "": if len (self.Profile.FdDict) == 0: FdName = GenFdsGlobalVariable.PlatformName + if FdName == "" and GlobalData.gActivePlatform: + FdName = GlobalData.gActivePlatform.PlatformName self.Profile.FdNameNotSet = True else: raise Warning("expected FdName in [FD.] section", self.FileName, self.CurrentLineNumber) @@ -1350,7 +1432,15 @@ class FdfParser: if not Status: raise Warning("FD name error", self.FileName, self.CurrentLineNumber) - self.__GetTokenStatements(FdObj) + while self.__GetTokenStatements(FdObj): + pass + for Attr in ("BaseAddress", "Size", "ErasePolarity"): + if getattr(FdObj, Attr) == None: + self.__GetNextToken() + raise Warning("Keyword %s missing" % Attr, self.FileName, self.CurrentLineNumber) + + if not FdObj.BlockSizeList: + FdObj.BlockSizeList.append((1, FdObj.Size, None)) self.__GetDefineStatements(FdObj) @@ -1407,54 +1497,54 @@ class FdfParser: # @param Obj for whom token statement is got # def __GetTokenStatements(self, Obj): - if not self.__IsKeyword( "BaseAddress"): - raise Warning("BaseAddress missing", self.FileName, self.CurrentLineNumber) - - if not self.__IsToken( "="): - raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - - if not self.__GetNextHexNumber(): - raise Warning("expected Hex base address", self.FileName, self.CurrentLineNumber) - - Obj.BaseAddress = self.__Token - - if self.__IsToken( "|"): - pcdPair = self.__GetNextPcdName() - Obj.BaseAddressPcd = pcdPair - self.Profile.PcdDict[pcdPair] = Obj.BaseAddress - - if not self.__IsKeyword( "Size"): - raise Warning("Size missing", self.FileName, self.CurrentLineNumber) - - if not self.__IsToken( "="): - raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - - if not self.__GetNextHexNumber(): - raise Warning("expected Hex size", self.FileName, self.CurrentLineNumber) - - - Size = self.__Token - if self.__IsToken( "|"): - pcdPair = self.__GetNextPcdName() - Obj.SizePcd = pcdPair - self.Profile.PcdDict[pcdPair] = Size - Obj.Size = long(Size, 0) - - if not self.__IsKeyword( "ErasePolarity"): - raise Warning("ErasePolarity missing", self.FileName, self.CurrentLineNumber) - - if not self.__IsToken( "="): - raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if self.__IsKeyword( "BaseAddress"): + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextHexNumber(): + raise Warning("expected Hex base address", self.FileName, self.CurrentLineNumber) + + Obj.BaseAddress = self.__Token + + if self.__IsToken( "|"): + pcdPair = self.__GetNextPcdName() + Obj.BaseAddressPcd = pcdPair + self.Profile.PcdDict[pcdPair] = Obj.BaseAddress + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[pcdPair] = FileLineTuple + return True - if not self.__GetNextToken(): - raise Warning("expected Erase Polarity", self.FileName, self.CurrentLineNumber) + if self.__IsKeyword( "Size"): + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextHexNumber(): + raise Warning("expected Hex size", self.FileName, self.CurrentLineNumber) - if self.__Token != "1" and self.__Token != "0": - raise Warning("expected 1 or 0 Erase Polarity", self.FileName, self.CurrentLineNumber) + Size = self.__Token + if self.__IsToken( "|"): + pcdPair = self.__GetNextPcdName() + Obj.SizePcd = pcdPair + self.Profile.PcdDict[pcdPair] = Size + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[pcdPair] = FileLineTuple + Obj.Size = long(Size, 0) + return True - Obj.ErasePolarity = self.__Token + if self.__IsKeyword( "ErasePolarity"): + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected Erase Polarity", self.FileName, self.CurrentLineNumber) + + if self.__Token != "1" and self.__Token != "0": + raise Warning("expected 1 or 0 Erase Polarity", self.FileName, self.CurrentLineNumber) + + Obj.ErasePolarity = self.__Token + return True - self.__GetBlockStatements(Obj) + return self.__GetBlockStatements(Obj) ## __GetAddressStatements() method # @@ -1495,18 +1585,14 @@ class FdfParser: # @param Obj for whom block statement is got # def __GetBlockStatements(self, Obj): - - if not self.__GetBlockStatement(Obj): - #set default block size is 1 - Obj.BlockSizeList.append((1, Obj.Size, None)) - return - + IsBlock = False while self.__GetBlockStatement(Obj): - pass + IsBlock = True - for Item in Obj.BlockSizeList: + Item = Obj.BlockSizeList[-1] if Item[0] == None or Item[1] == None: raise Warning("expected block statement", self.FileName, self.CurrentLineNumber) + return IsBlock ## __GetBlockStatement() method # @@ -1533,6 +1619,8 @@ class FdfParser: PcdPair = self.__GetNextPcdName() BlockSizePcd = PcdPair self.Profile.PcdDict[PcdPair] = BlockSize + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[PcdPair] = FileLineTuple BlockSize = long(BlockSize, 0) BlockNumber = None @@ -1616,23 +1704,49 @@ class FdfParser: if not self.__IsToken( "="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - if not self.__GetNextToken(): - raise Warning("expected value", self.FileName, self.CurrentLineNumber) - - Value = self.__Token - if Value.startswith("{"): - # deal with value with {} - if not self.__SkipToToken( "}"): - raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) - Value += self.__SkippedChars + Value = self.__GetExpression() + Value = self.__EvaluateConditional(Value, self.CurrentLineNumber, 'eval', True) if Obj: Obj.SetVarDict[PcdPair] = Value self.Profile.PcdDict[PcdPair] = Value + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[PcdPair] = FileLineTuple return True return False + ## __CalcRegionExpr(self) + # + # Calculate expression for offset or size of a region + # + # @return: None if invalid expression + # Calculated number if successfully + # + def __CalcRegionExpr(self): + StartPos = self.GetFileBufferPos() + Expr = '' + PairCount = 0 + while not self.__EndOfFile(): + CurCh = self.__CurrentChar() + if CurCh == '(': + PairCount += 1 + elif CurCh == ')': + PairCount -= 1 + + if CurCh in '|\r\n' and PairCount == 0: + break + Expr += CurCh + self.__GetOneChar() + try: + return long( + ValueExpression(Expr, + self.__CollectMacroPcd() + )(True),0) + except Exception: + self.SetFileBufferPos(StartPos) + return None + ## __GetRegionLayout() method # # Get region layout for FD @@ -1643,30 +1757,46 @@ class FdfParser: # @retval False Not able to find # def __GetRegionLayout(self, Fd): - if not self.__GetNextHexNumber(): + Offset = self.__CalcRegionExpr() + if Offset == None: return False RegionObj = Region.Region() - RegionObj.Offset = long(self.__Token, 0) + RegionObj.Offset = Offset Fd.RegionList.append(RegionObj) if not self.__IsToken( "|"): raise Warning("expected '|'", self.FileName, self.CurrentLineNumber) - if not self.__GetNextHexNumber(): + Size = self.__CalcRegionExpr() + if Size == None: raise Warning("expected Region Size", self.FileName, self.CurrentLineNumber) - RegionObj.Size = long(self.__Token, 0) + RegionObj.Size = Size if not self.__GetNextWord(): return True if not self.__Token in ("SET", "FV", "FILE", "DATA", "CAPSULE"): + # + # If next token is a word which is not a valid FV type, it might be part of [PcdOffset[|PcdSize]] + # Or it might be next region's offset described by an expression which starts with a PCD. + # PcdOffset[|PcdSize] or OffsetPcdExpression|Size + # self.__UndoToken() - RegionObj.PcdOffset = self.__GetNextPcdName() - self.Profile.PcdDict[RegionObj.PcdOffset] = "0x%08X" % (RegionObj.Offset + long(Fd.BaseAddress, 0)) - if self.__IsToken( "|"): - RegionObj.PcdSize = self.__GetNextPcdName() - self.Profile.PcdDict[RegionObj.PcdSize] = "0x%08X" % RegionObj.Size + IsRegionPcd = (RegionSizeGuidPattern.match(self.__CurrentLine()[self.CurrentOffsetWithinLine:]) or + RegionOffsetPcdPattern.match(self.__CurrentLine()[self.CurrentOffsetWithinLine:])) + if IsRegionPcd: + RegionObj.PcdOffset = self.__GetNextPcdName() + self.Profile.PcdDict[RegionObj.PcdOffset] = "0x%08X" % (RegionObj.Offset + long(Fd.BaseAddress, 0)) + self.__PcdDict['%s.%s' % (RegionObj.PcdOffset[1], RegionObj.PcdOffset[0])] = "0x%x" % RegionObj.Offset + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[RegionObj.PcdOffset] = FileLineTuple + if self.__IsToken( "|"): + RegionObj.PcdSize = self.__GetNextPcdName() + self.Profile.PcdDict[RegionObj.PcdSize] = "0x%08X" % RegionObj.Size + self.__PcdDict['%s.%s' % (RegionObj.PcdSize[1], RegionObj.PcdSize[0])] = "0x%x" % RegionObj.Size + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[RegionObj.PcdSize] = FileLineTuple if not self.__GetNextWord(): return True @@ -1689,9 +1819,16 @@ class FdfParser: self.__UndoToken() self.__GetRegionFileType( RegionObj) - else: + elif self.__Token == "DATA": self.__UndoToken() self.__GetRegionDataType( RegionObj) + else: + self.__UndoToken() + if self.__GetRegionLayout(Fd): + return True + raise Warning("A valid region type was not found. " + "Valid types are [SET, FV, CAPSULE, FILE, DATA]. This error occurred", + self.FileName, self.CurrentLineNumber) return True @@ -1891,7 +2028,7 @@ class FdfParser: S = self.__Token.upper() if S.startswith("[") and not S.startswith("[FV."): - if not S.startswith("[CAPSULE.") \ + if not S.startswith('[FMPPAYLOAD.') and not S.startswith("[CAPSULE.") \ and not S.startswith("[VTF.") and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."): raise Warning("Unknown section or section appear sequence error (The correct sequence should be [FD.], [FV.], [Capsule.], [VTF.], [Rule.], [OptionRom.])", self.FileName, self.CurrentLineNumber) self.__UndoToken() @@ -1922,25 +2059,16 @@ class FdfParser: self.__GetAddressStatements(FvObj) - while self.__GetBlockStatement(FvObj): - pass - - self.__GetSetStatements(FvObj) - - self.__GetFvBaseAddress(FvObj) - - self.__GetFvAlignment(FvObj) - - self.__GetFvAttributes(FvObj) - - self.__GetFvNameGuid(FvObj) - FvObj.FvExtEntryTypeValue = [] FvObj.FvExtEntryType = [] FvObj.FvExtEntryData = [] while True: - isFvExtEntry = self.__GetFvExtEntryStatement(FvObj) - if not isFvExtEntry: + self.__GetSetStatements(FvObj) + + if not (self.__GetBlockStatement(FvObj) or self.__GetFvBaseAddress(FvObj) or + self.__GetFvForceRebase(FvObj) or self.__GetFvAlignment(FvObj) or + self.__GetFvAttributes(FvObj) or self.__GetFvNameGuid(FvObj) or + self.__GetFvExtEntryStatement(FvObj)): break self.__GetAprioriSection(FvObj, FvObj.DefineVarDict.copy()) @@ -2005,10 +2133,42 @@ class FdfParser: IsValidBaseAddrValue = re.compile('^0[x|X][0-9a-fA-F]+') if not IsValidBaseAddrValue.match(self.__Token.upper()): - raise Warning("Unknown alignment value '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) + raise Warning("Unknown FV base address value '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) Obj.FvBaseAddress = self.__Token - return True - + return True + + ## __GetFvForceRebase() method + # + # Get FvForceRebase for FV + # + # @param self The object pointer + # @param Obj for whom FvForceRebase is got + # @retval True Successfully find a FvForceRebase statement + # @retval False Not able to find a FvForceRebase statement + # + def __GetFvForceRebase(self, Obj): + + if not self.__IsKeyword("FvForceRebase"): + return False + + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected FvForceRebase value", self.FileName, self.CurrentLineNumber) + + if self.__Token.upper() not in ["TRUE", "FALSE", "0", "0X0", "0X00", "1", "0X1", "0X01"]: + raise Warning("Unknown FvForceRebase value '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) + + if self.__Token.upper() in ["TRUE", "1", "0X1", "0X01"]: + Obj.FvForceRebase = True + elif self.__Token.upper() in ["FALSE", "0", "0X0", "0X00"]: + Obj.FvForceRebase = False + else: + Obj.FvForceRebase = None + + return True + ## __GetFvAttributes() method # @@ -2019,17 +2179,18 @@ class FdfParser: # @retval None # def __GetFvAttributes(self, FvObj): - + IsWordToken = False while self.__GetNextWord(): + IsWordToken = True name = self.__Token if name not in ("ERASE_POLARITY", "MEMORY_MAPPED", \ "STICKY_WRITE", "LOCK_CAP", "LOCK_STATUS", "WRITE_ENABLED_CAP", \ "WRITE_DISABLED_CAP", "WRITE_STATUS", "READ_ENABLED_CAP", \ "READ_DISABLED_CAP", "READ_STATUS", "READ_LOCK_CAP", \ "READ_LOCK_STATUS", "WRITE_LOCK_CAP", "WRITE_LOCK_STATUS", \ - "WRITE_POLICY_RELIABLE"): + "WRITE_POLICY_RELIABLE", "WEAK_ALIGNMENT"): self.__UndoToken() - return + return False if not self.__IsToken( "="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) @@ -2039,7 +2200,7 @@ class FdfParser: FvObj.FvAttributeDict[name] = self.__Token - return + return IsWordToken ## __GetFvNameGuid() method # @@ -2052,7 +2213,7 @@ class FdfParser: def __GetFvNameGuid(self, FvObj): if not self.__IsKeyword( "FvNameGuid"): - return + return False if not self.__IsToken( "="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) @@ -2062,7 +2223,7 @@ class FdfParser: FvObj.FvNameGuid = self.__Token - return + return True def __GetFvExtEntryStatement(self, FvObj): @@ -2198,6 +2359,13 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("expected INF file path", self.FileName, self.CurrentLineNumber) ffsInf.InfFileName = self.__Token + + ffsInf.CurrentLineNum = self.CurrentLineNumber + ffsInf.CurrentLineContent = self.__CurrentLine() + + #Replace $(SAPCE) with real space + ffsInf.InfFileName = ffsInf.InfFileName.replace('$(SPACE)', ' ') + if ffsInf.InfFileName.replace('$(WORKSPACE)', '').find('$') == -1: #do case sensitive check for file path ErrorCode, ErrorInfo = PathClass(NormPath(ffsInf.InfFileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() @@ -2206,6 +2374,8 @@ class FdfParser: if not ffsInf.InfFileName in self.Profile.InfList: self.Profile.InfList.append(ffsInf.InfFileName) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.InfFileLineList.append(FileLineTuple) if self.__IsToken('|'): if self.__IsKeyword('RELOCS_STRIPPED'): @@ -2214,7 +2384,7 @@ class FdfParser: ffsInf.KeepReloc = True else: raise Warning("Unknown reloc strip flag '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) - + if ForCapsule: capsuleFfs = CapsuleData.CapsuleFfs() capsuleFfs.Ffs = ffsInf @@ -2231,6 +2401,12 @@ class FdfParser: # @param FfsInfObj for whom option is got # def __GetInfOptions(self, FfsInfObj): + if self.__IsKeyword("FILE_GUID"): + if not self.__IsToken("="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if not self.__GetNextGuid(): + raise Warning("expected GUID value", self.FileName, self.CurrentLineNumber) + FfsInfObj.OverrideGuid = self.__Token if self.__IsKeyword( "RuleOverride"): if not self.__IsToken( "="): @@ -2266,8 +2442,8 @@ class FdfParser: if self.__GetNextToken(): - p = re.compile(r'([a-zA-Z0-9\-]+|\$\(TARGET\)|\*)_([a-zA-Z0-9\-]+|\$\(TOOL_CHAIN_TAG\)|\*)_([a-zA-Z0-9\-]+|\$\(ARCH\)|\*)') - if p.match(self.__Token): + p = re.compile(r'([a-zA-Z0-9\-]+|\$\(TARGET\)|\*)_([a-zA-Z0-9\-]+|\$\(TOOL_CHAIN_TAG\)|\*)_([a-zA-Z0-9\-]+|\$\(ARCH\))') + if p.match(self.__Token) and p.match(self.__Token).span()[1] == len(self.__Token): FfsInfObj.KeyStringList.append(self.__Token) if not self.__IsToken(","): return @@ -2298,10 +2474,15 @@ class FdfParser: if not self.__IsKeyword( "FILE"): return False - FfsFileObj = FfsFileStatement.FileStatement() - if not self.__GetNextWord(): raise Warning("expected FFS type", self.FileName, self.CurrentLineNumber) + + if ForCapsule and self.__Token == 'DATA': + self.__UndoToken() + self.__UndoToken() + return False + + FfsFileObj = FfsFileStatement.FileStatement() FfsFileObj.FvFileType = self.__Token if not self.__IsToken( "="): @@ -2319,7 +2500,7 @@ class FdfParser: self.__Token = 'PCD('+PcdPair[1]+'.'+PcdPair[0]+')' FfsFileObj.NameGuid = self.__Token - + self.__GetFilePart( FfsFileObj, MacroDict.copy()) if ForCapsule: @@ -2376,16 +2557,16 @@ class FdfParser: self.__GetFileOpts( FfsFileObj) if not self.__IsToken("{"): -# if self.__IsKeyword('RELOCS_STRIPPED') or self.__IsKeyword('RELOCS_RETAINED'): -# if self.__FileCouldHaveRelocFlag(FfsFileObj.FvFileType): -# if self.__Token == 'RELOCS_STRIPPED': -# FfsFileObj.KeepReloc = False -# else: -# FfsFileObj.KeepReloc = True -# else: -# raise Warning("File type %s could not have reloc strip flag%d" % (FfsFileObj.FvFileType, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) -# -# if not self.__IsToken("{"): + if self.__IsKeyword('RELOCS_STRIPPED') or self.__IsKeyword('RELOCS_RETAINED'): + if self.__FileCouldHaveRelocFlag(FfsFileObj.FvFileType): + if self.__Token == 'RELOCS_STRIPPED': + FfsFileObj.KeepReloc = False + else: + FfsFileObj.KeepReloc = True + else: + raise Warning("File type %s could not have reloc strip flag%d" % (FfsFileObj.FvFileType, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) + + if not self.__IsToken("{"): raise Warning("expected '{'", self.FileName, self.CurrentLineNumber) if not self.__GetNextToken(): @@ -2409,12 +2590,10 @@ class FdfParser: self.__UndoToken() self.__GetSectionData( FfsFileObj, MacroDict) else: - FfsFileObj.FileName = self.__Token - if FfsFileObj.FileName.replace('$(WORKSPACE)', '').find('$') == -1: - #do case sensitive check for file path - ErrorCode, ErrorInfo = PathClass(NormPath(FfsFileObj.FileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() - if ErrorCode != 0: - EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + FfsFileObj.CurrentLineNum = self.CurrentLineNumber + FfsFileObj.CurrentLineContent = self.__CurrentLine() + FfsFileObj.FileName = self.__Token.replace('$(SPACE)', ' ') + self.__VerifyFile(FfsFileObj.FileName) if not self.__IsToken( "}"): raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) @@ -2660,11 +2839,7 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("expected section file path", self.FileName, self.CurrentLineNumber) DataSectionObj.SectFileName = self.__Token - if DataSectionObj.SectFileName.replace('$(WORKSPACE)', '').find('$') == -1: - #do case sensitive check for file path - ErrorCode, ErrorInfo = PathClass(NormPath(DataSectionObj.SectFileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() - if ErrorCode != 0: - EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + self.__VerifyFile(DataSectionObj.SectFileName) else: if not self.__GetCglSection(DataSectionObj): return False @@ -2673,6 +2848,21 @@ class FdfParser: return True + ## __VerifyFile + # + # Check if file exists or not: + # If current phase if GenFds, the file must exist; + # If current phase is AutoGen and the file is not in $(OUTPUT_DIRECTORY), the file must exist + # @param FileName: File path to be verified. + # + def __VerifyFile(self, FileName): + if FileName.replace('$(WORKSPACE)', '').find('$') != -1: + return + if not GlobalData.gAutoGenPhase or not self.__GetMacroValue("OUTPUT_DIRECTORY") in FileName: + ErrorCode, ErrorInfo = PathClass(NormPath(FileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + ## __GetCglSection() method # # Get compressed or GUIDed section for Obj @@ -2727,6 +2917,7 @@ class FdfParser: GuidSectionObj.SectionType = "GUIDED" GuidSectionObj.ProcessRequired = AttribDict["PROCESSING_REQUIRED"] GuidSectionObj.AuthStatusValid = AttribDict["AUTH_STATUS_VALID"] + GuidSectionObj.ExtraHeaderSize = AttribDict["EXTRA_HEADER_SIZE"] # Recursive sections... while True: IsLeafSection = self.__GetLeafSection(GuidSectionObj) @@ -2754,23 +2945,26 @@ class FdfParser: AttribDict = {} AttribDict["PROCESSING_REQUIRED"] = "NONE" AttribDict["AUTH_STATUS_VALID"] = "NONE" - if self.__IsKeyword("PROCESSING_REQUIRED") or self.__IsKeyword("AUTH_STATUS_VALID"): + AttribDict["EXTRA_HEADER_SIZE"] = -1 + while self.__IsKeyword("PROCESSING_REQUIRED") or self.__IsKeyword("AUTH_STATUS_VALID") \ + or self.__IsKeyword("EXTRA_HEADER_SIZE"): AttribKey = self.__Token if not self.__IsToken("="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - if not self.__GetNextToken() or self.__Token.upper() not in ("TRUE", "FALSE", "1", "0"): - raise Warning("expected TRUE/FALSE (1/0)", self.FileName, self.CurrentLineNumber) - AttribDict[AttribKey] = self.__Token - - if self.__IsKeyword("PROCESSING_REQUIRED") or self.__IsKeyword("AUTH_STATUS_VALID"): - AttribKey = self.__Token - - if not self.__IsToken("="): - raise Warning("expected '='") - - if not self.__GetNextToken() or self.__Token.upper() not in ("TRUE", "FALSE", "1", "0"): + if not self.__GetNextToken(): + raise Warning("expected TRUE(1)/FALSE(0)/Number", self.FileName, self.CurrentLineNumber) + elif AttribKey == "EXTRA_HEADER_SIZE": + Base = 10 + if self.__Token[0:2].upper() == "0X": + Base = 16 + try: + AttribDict[AttribKey] = int(self.__Token, Base) + continue + except ValueError: + raise Warning("expected Number", self.FileName, self.CurrentLineNumber) + elif self.__Token.upper() not in ("TRUE", "FALSE", "1", "0"): raise Warning("expected TRUE/FALSE (1/0)", self.FileName, self.CurrentLineNumber) AttribDict[AttribKey] = self.__Token @@ -2806,6 +3000,67 @@ class FdfParser: else: return True + def __GetFmp(self): + if not self.__GetNextToken(): + return False + S = self.__Token.upper() + if not S.startswith("[FMPPAYLOAD."): + if not S.startswith("[CAPSULE.") and not S.startswith("[VTF.") and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."): + raise Warning("Unknown section or section appear sequence error (The correct sequence should be [FD.], [FV.], [FmpPayload.], [Capsule.], [VTF.], [Rule.], [OptionRom.])", self.FileName, self.CurrentLineNumber) + self.__UndoToken() + return False + + self.__UndoToken() + self.__SkipToToken("[FMPPAYLOAD.", True) + FmpUiName = self.__GetUiName().upper() + if FmpUiName in self.Profile.FmpPayloadDict: + raise Warning("Duplicated FMP UI name found: %s" % FmpUiName, self.FileName, self.CurrentLineNumber) + + FmpData = CapsuleData.CapsulePayload() + FmpData.UiName = FmpUiName + + if not self.__IsToken( "]"): + raise Warning("expected ']'", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("The FMP payload section is empty!", self.FileName, self.CurrentLineNumber) + FmpKeyList = ['IMAGE_HEADER_INIT_VERSION', 'IMAGE_TYPE_ID', 'IMAGE_INDEX', 'HARDWARE_INSTANCE'] + while self.__Token in FmpKeyList: + Name = self.__Token + FmpKeyList.remove(Name) + if not self.__IsToken("="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if Name == 'IMAGE_TYPE_ID': + if not self.__GetNextGuid(): + raise Warning("expected GUID value for IMAGE_TYPE_ID", self.FileName, self.CurrentLineNumber) + FmpData.ImageTypeId = self.__Token + else: + if not self.__GetNextToken(): + raise Warning("expected value of %s" % Name, self.FileName, self.CurrentLineNumber) + Value = self.__Token + if Name == 'IMAGE_HEADER_INIT_VERSION': + FmpData.Version = Value + elif Name == 'IMAGE_INDEX': + FmpData.ImageIndex = Value + elif Name == 'HARDWARE_INSTANCE': + FmpData.HardwareInstance = Value + if not self.__GetNextToken(): + break + else: + self.__UndoToken() + + if FmpKeyList: + raise Warning("Missing keywords %s in FMP payload section" % ', '.join(FmpKeyList), self.FileName, self.CurrentLineNumber) + ImageFile = self.__ParseRawFileStatement() + if not ImageFile: + raise Warning("Missing image file in FMP payload section", self.FileName, self.CurrentLineNumber) + FmpData.ImageFile = ImageFile + VendorCodeFile = self.__ParseRawFileStatement() + if VendorCodeFile: + FmpData.VendorCodeFile = VendorCodeFile + self.Profile.FmpPayloadDict[FmpUiName] = FmpData + return True + ## __GetCapsule() method # # Get capsule section contents and store its data into capsule list of self.Profile @@ -2880,7 +3135,7 @@ class FdfParser: def __GetCapsuleTokens(self, Obj): if not self.__GetNextToken(): return False - while self.__Token in ("CAPSULE_GUID", "CAPSULE_HEADER_SIZE", "CAPSULE_FLAGS"): + while self.__Token in ("CAPSULE_GUID", "CAPSULE_HEADER_SIZE", "CAPSULE_FLAGS", "OEM_CAPSULE_FLAGS", "CAPSULE_HEADER_INIT_VERSION"): Name = self.__Token.strip() if not self.__IsToken("="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) @@ -2897,6 +3152,17 @@ class FdfParser: if not self.__Token in ("PersistAcrossReset", "PopulateSystemTable", "InitiateReset"): raise Warning("expected PersistAcrossReset, PopulateSystemTable, or InitiateReset", self.FileName, self.CurrentLineNumber) Value += self.__Token.strip() + elif Name == 'OEM_CAPSULE_FLAGS': + Value = self.__Token.strip() + if not Value.upper().startswith('0X'): + raise Warning("expected hex value between 0x0000 and 0xFFFF", self.FileName, self.CurrentLineNumber) + try: + Value = int(Value, 0) + except ValueError: + raise Warning("expected hex value between 0x0000 and 0xFFFF", self.FileName, self.CurrentLineNumber) + if not 0x0000 <= Value <= 0xFFFF: + raise Warning("expected hex value between 0x0000 and 0xFFFF", self.FileName, self.CurrentLineNumber) + Value = self.__Token.strip() else: Value = self.__Token.strip() Obj.TokensDict[Name] = Value @@ -2917,7 +3183,11 @@ class FdfParser: IsInf = self.__GetInfStatement(Obj, True) IsFile = self.__GetFileStatement(Obj, True) IsFv = self.__GetFvStatement(Obj) - if not IsInf and not IsFile and not IsFv: + IsFd = self.__GetFdStatement(Obj) + IsAnyFile = self.__GetAnyFileStatement(Obj) + IsAfile = self.__GetAfileStatement(Obj) + IsFmp = self.__GetFmpStatement(Obj) + if not (IsInf or IsFile or IsFv or IsFd or IsAnyFile or IsAfile or IsFmp): break ## __GetFvStatement() method @@ -2940,11 +3210,141 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("expected FV name", self.FileName, self.CurrentLineNumber) + if self.__Token.upper() not in self.Profile.FvDict.keys(): + raise Warning("FV name does not exist", self.FileName, self.CurrentLineNumber) + CapsuleFv = CapsuleData.CapsuleFv() CapsuleFv.FvName = self.__Token CapsuleObj.CapsuleDataList.append(CapsuleFv) return True + ## __GetFdStatement() method + # + # Get FD for capsule + # + # @param self The object pointer + # @param CapsuleObj for whom FD is got + # @retval True Successfully find a FD statement + # @retval False Not able to find a FD statement + # + def __GetFdStatement(self, CapsuleObj): + + if not self.__IsKeyword("FD"): + return False + + if not self.__IsToken("="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected FD name", self.FileName, self.CurrentLineNumber) + + if self.__Token.upper() not in self.Profile.FdDict.keys(): + raise Warning("FD name does not exist", self.FileName, self.CurrentLineNumber) + + CapsuleFd = CapsuleData.CapsuleFd() + CapsuleFd.FdName = self.__Token + CapsuleObj.CapsuleDataList.append(CapsuleFd) + return True + + def __GetFmpStatement(self, CapsuleObj): + if not self.__IsKeyword("FMP"): + return False + + if not self.__IsKeyword("PAYLOAD"): + self.__UndoToken() + return False + + if not self.__IsToken("="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected payload name after FMP PAYLOAD =", self.FileName, self.CurrentLineNumber) + Payload = self.__Token.upper() + if Payload not in self.Profile.FmpPayloadDict: + raise Warning("This FMP Payload does not exist: %s" % self.__Token, self.FileName, self.CurrentLineNumber) + CapsuleObj.FmpPayloadList.append(self.Profile.FmpPayloadDict[Payload]) + return True + + def __ParseRawFileStatement(self): + if not self.__IsKeyword("FILE"): + return None + + if not self.__IsKeyword("DATA"): + self.__UndoToken() + return None + + if not self.__IsToken("="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected File name", self.FileName, self.CurrentLineNumber) + + AnyFileName = self.__Token + AnyFileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(AnyFileName) + if not os.path.exists(AnyFileName): + raise Warning("File %s not exists"%AnyFileName, self.FileName, self.CurrentLineNumber) + return AnyFileName + + ## __GetAnyFileStatement() method + # + # Get AnyFile for capsule + # + # @param self The object pointer + # @param CapsuleObj for whom AnyFile is got + # @retval True Successfully find a Anyfile statement + # @retval False Not able to find a AnyFile statement + # + def __GetAnyFileStatement(self, CapsuleObj): + AnyFileName = self.__ParseRawFileStatement() + if not AnyFileName: + return False + + CapsuleAnyFile = CapsuleData.CapsuleAnyFile() + CapsuleAnyFile.FileName = AnyFileName + CapsuleObj.CapsuleDataList.append(CapsuleAnyFile) + return True + + ## __GetAfileStatement() method + # + # Get Afile for capsule + # + # @param self The object pointer + # @param CapsuleObj for whom Afile is got + # @retval True Successfully find a Afile statement + # @retval False Not able to find a Afile statement + # + def __GetAfileStatement(self, CapsuleObj): + + if not self.__IsKeyword("APPEND"): + return False + + if not self.__IsToken("="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected Afile name", self.FileName, self.CurrentLineNumber) + + AfileName = self.__Token + AfileBaseName = os.path.basename(AfileName) + + if os.path.splitext(AfileBaseName)[1] not in [".bin",".BIN",".Bin",".dat",".DAT",".Dat",".data",".DATA",".Data"]: + raise Warning('invalid binary file type, should be one of "bin","BIN","Bin","dat","DAT","Dat","data","DATA","Data"', \ + self.FileName, self.CurrentLineNumber) + + if not os.path.isabs(AfileName): + AfileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(AfileName) + self.__VerifyFile(AfileName) + else: + if not os.path.exists(AfileName): + raise Warning('%s does not exist' % AfileName, self.FileName, self.CurrentLineNumber) + else: + pass + + CapsuleAfile = CapsuleData.CapsuleAfile() + CapsuleAfile.FileName = AfileName + CapsuleObj.CapsuleDataList.append(CapsuleAfile) + return True + ## __GetRule() method # # Get Rule section contents and store its data into rule list of self.Profile @@ -2975,7 +3375,7 @@ class FdfParser: raise Warning("expected '.'", self.FileName, self.CurrentLineNumber) Arch = self.__SkippedChars.rstrip(".") - if Arch.upper() not in ("IA32", "X64", "IPF", "EBC", "ARM", "COMMON"): + if Arch.upper() not in ("IA32", "X64", "IPF", "EBC", "ARM", "AARCH64", "COMMON"): raise Warning("Unknown Arch '%s'" % Arch, self.FileName, self.CurrentLineNumber) ModuleType = self.__GetModuleType() @@ -3505,6 +3905,7 @@ class FdfParser: GuidSectionObj.SectionType = "GUIDED" GuidSectionObj.ProcessRequired = AttribDict["PROCESSING_REQUIRED"] GuidSectionObj.AuthStatusValid = AttribDict["AUTH_STATUS_VALID"] + GuidSectionObj.ExtraHeaderSize = AttribDict["EXTRA_HEADER_SIZE"] # Efi sections... while True: @@ -3552,7 +3953,7 @@ class FdfParser: raise Warning("expected '.'", self.FileName, self.CurrentLineNumber) Arch = self.__SkippedChars.rstrip(".").upper() - if Arch not in ("IA32", "X64", "IPF", "ARM"): + if Arch not in ("IA32", "X64", "IPF", "ARM", "AARCH64"): raise Warning("Unknown Arch '%s'" % Arch, self.FileName, self.CurrentLineNumber) if not self.__GetNextWord(): @@ -3566,7 +3967,7 @@ class FdfParser: if self.__IsToken(","): if not self.__GetNextWord(): raise Warning("expected Arch list", self.FileName, self.CurrentLineNumber) - if self.__Token.upper() not in ("IA32", "X64", "IPF", "ARM"): + if self.__Token.upper() not in ("IA32", "X64", "IPF", "ARM", "AARCH64"): raise Warning("Unknown Arch '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) VtfObj.ArchList = self.__Token.upper() @@ -3794,6 +4195,8 @@ class FdfParser: if not ffsInf.InfFileName in self.Profile.InfList: self.Profile.InfList.append(ffsInf.InfFileName) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.InfFileLineList.append(FileLineTuple) self.__GetOptRomOverrides (ffsInf) @@ -3845,7 +4248,7 @@ class FdfParser: Overrides.PciRevision = self.__Token continue - if self.__IsKeyword( "COMPRESS"): + if self.__IsKeyword( "PCI_COMPRESS"): if not self.__IsToken( "="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) if not self.__GetNextToken(): @@ -3930,16 +4333,18 @@ class FdfParser: def __GetReferencedFdCapTuple(self, CapObj, RefFdList = [], RefFvList = []): for CapsuleDataObj in CapObj.CapsuleDataList : - if CapsuleDataObj.FvName != None and CapsuleDataObj.FvName.upper() not in RefFvList: + if hasattr(CapsuleDataObj, 'FvName') and CapsuleDataObj.FvName != None and CapsuleDataObj.FvName.upper() not in RefFvList: RefFvList.append (CapsuleDataObj.FvName.upper()) + elif hasattr(CapsuleDataObj, 'FdName') and CapsuleDataObj.FdName != None and CapsuleDataObj.FdName.upper() not in RefFdList: + RefFdList.append (CapsuleDataObj.FdName.upper()) elif CapsuleDataObj.Ffs != None: - if isinstance(CapsuleDataObj.Ffs, FfsFileStatement.FileStatement): - if CapsuleDataObj.Ffs.FvName != None and CapsuleDataObj.Ffs.FvName.upper() not in RefFvList: - RefFvList.append(CapsuleDataObj.Ffs.FvName.upper()) - elif CapsuleDataObj.Ffs.FdName != None and CapsuleDataObj.Ffs.FdName.upper() not in RefFdList: - RefFdList.append(CapsuleDataObj.Ffs.FdName.upper()) - else: - self.__GetReferencedFdFvTupleFromSection(CapsuleDataObj.Ffs, RefFdList, RefFvList) + if isinstance(CapsuleDataObj.Ffs, FfsFileStatement.FileStatement): + if CapsuleDataObj.Ffs.FvName != None and CapsuleDataObj.Ffs.FvName.upper() not in RefFvList: + RefFvList.append(CapsuleDataObj.Ffs.FvName.upper()) + elif CapsuleDataObj.Ffs.FdName != None and CapsuleDataObj.Ffs.FdName.upper() not in RefFdList: + RefFdList.append(CapsuleDataObj.Ffs.FdName.upper()) + else: + self.__GetReferencedFdFvTupleFromSection(CapsuleDataObj.Ffs, RefFdList, RefFvList) ## __GetFvInFd() method # @@ -4139,12 +4544,19 @@ class FdfParser: return False if __name__ == "__main__": - parser = FdfParser("..\LakeportX64Pkg.fdf") + import sys + try: + test_file = sys.argv[1] + except IndexError, v: + print "Usage: %s filename" % sys.argv[0] + sys.exit(1) + + parser = FdfParser(test_file) try: parser.ParseFile() parser.CycleReferenceCheck() except Warning, X: - print str(X) + print str(X) else: print "Success!"