X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=BaseTools%2FSource%2FPython%2FGenFds%2FFdfParser.py;h=ffc54abc847f80d9742d3958e20584f38cbc22ed;hp=0bf8f5514bf7e779dd663605a62a5e6cafa335ab;hb=a3251d844695f90711bfe094f12755fd01742369;hpb=30fdf1140b8d1ce93f3821d986fa165552023440 diff --git a/BaseTools/Source/Python/GenFds/FdfParser.py b/BaseTools/Source/Python/GenFds/FdfParser.py index 0bf8f5514b..ffc54abc84 100644 --- a/BaseTools/Source/Python/GenFds/FdfParser.py +++ b/BaseTools/Source/Python/GenFds/FdfParser.py @@ -1,9 +1,9 @@ ## @file # parse FDF file # -# Copyright (c) 2007, Intel Corporation +# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
# -# All rights reserved. This program and the accompanying materials +# 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 @@ -15,6 +15,8 @@ ## # Import Modules # +import re + import Fd import Region import Fv @@ -40,11 +42,21 @@ import OptionRom import OptRomInfStatement import OptRomFileStatement +from GenFdsGlobalVariable import GenFdsGlobalVariable 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' @@ -64,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): @@ -170,13 +183,18 @@ 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 = {} - self.CapsuleList = [] + self.CapsuleDict = {} self.VtfList = [] self.RuleDict = {} self.OptRomDict = {} + self.FmpPayloadDict = {} ## The syntax parser for FDF # @@ -201,8 +219,18 @@ 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 == '': + GenFdsGlobalVariable.WorkSpaceDir = os.getenv("WORKSPACE") ## __IsWhiteSpace() method # @@ -310,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 # @@ -362,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] @@ -413,6 +417,81 @@ class FdfParser: Offset += 1 + def __GetMacroName(self): + if not self.__GetNextToken(): + raise Warning("expected Macro name", self.FileName, self.CurrentLineNumber) + MacroName = self.__Token + NotFlag = False + if MacroName.startswith('!'): + NotFlag = True + MacroName = MacroName[1:].strip() + + if not MacroName.startswith('$(') or not MacroName.endswith(')'): + raise Warning("Macro name expected(Please use '$(%(Token)s)' if '%(Token)s' is a macro.)" % {"Token" : MacroName}, + 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. @@ -495,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) - - IncFileProfile = IncludeFileProfile(os.path.normpath(IncFileName)) + __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(IncludedFile1.Path) CurrentLine = self.CurrentLineNumber CurrentOffset = self.CurrentOffsetWithinLine @@ -542,10 +641,20 @@ class FdfParser: self.Profile.FileLinesList[IncludeLine - 1] = ''.join(TempList) self.Rewind() - - ## PreprocessIncludeFile() method + + def __GetIfListCurrentItemStat(self, IfList): + if len(IfList) == 0: + return True + + for Item in IfList: + if Item[1] == False: + return False + + return True + + ## PreprocessConditionalStatement() method # - # Preprocess file contents, replace !include statements with file contents. + # Preprocess conditional statement. # In the end, rewind the file buffer pointer to the beginning # # @param self The object pointer @@ -553,89 +662,102 @@ 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': - DefineLine = self.CurrentLineNumber - 1 - DefineOffset = self.CurrentOffsetWithinLine - len('DEFINE') - if not self.__GetNextToken(): - raise Warning("expected Macro name", self.FileName, self.CurrentLineNumber) - Macro = self.__Token + 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(): + raise Warning("expected Macro name", self.FileName, self.CurrentLineNumber) + Macro = self.__Token + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + 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) - if not self.__GetNextToken(): - raise Warning("expected value", self.FileName, self.CurrentLineNumber) + Value = self.__GetExpression() + Value = self.__EvaluateConditional(Value, self.CurrentLineNumber, 'eval', True) - 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) - self.__WipeOffArea.append(((DefineLine, DefineOffset), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + 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 - - if not self.__GetNextToken(): - raise Warning("expected Macro name", self.FileName, self.CurrentLineNumber) - MacroName = self.__Token - NotFlag = False - if MacroName.startswith('!'): - NotFlag = True - MacroName = MacroName[1:] - - 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) + CondLabel = self.__Token + Expression = self.__GetExpression() + 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))) @@ -643,34 +765,8 @@ class FdfParser: self.__WipeOffArea.append((IfList[-1][0], ElseStartPos)) IfList[-1] = [ElseStartPos, True, IfList[-1][2]] if self.__Token == '!elseif': - if not self.__GetNextToken(): - raise Warning("expected Macro name", self.FileName, self.CurrentLineNumber) - MacroName = self.__Token - NotFlag = False - if MacroName.startswith('!'): - NotFlag = True - MacroName = MacroName[1:] - - 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]: @@ -679,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() - - - if len(IfList) > 0: + 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 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.FileName == FileLineTuple[0] and 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 - else: - return False - 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 + 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 # @@ -846,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 @@ -895,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. @@ -985,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: @@ -1168,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 @@ -1178,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 @@ -1256,6 +1360,12 @@ class FdfParser: raise Warning("expected ']'", self.FileName, self.CurrentLineNumber) while self.__GetNextWord(): + # handle the SET statement + if self.__Token == 'SET': + self.__UndoToken() + self.__GetSetStatement(None) + continue + Macro = self.__Token if not self.__IsToken("="): @@ -1263,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 @@ -1286,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() @@ -1300,7 +1405,18 @@ class FdfParser: raise Warning("expected [FD.]", self.FileName, self.CurrentLineNumber) FdName = self.__GetUiName() + 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) self.CurrentFdName = FdName.upper() + + if self.CurrentFdName in self.Profile.FdDict: + raise Warning("Unexpected the same FD name", self.FileName, self.CurrentLineNumber) if not self.__IsToken( "]"): raise Warning("expected ']'", self.FileName, self.CurrentLineNumber) @@ -1308,12 +1424,23 @@ class FdfParser: FdObj = Fd.FD() FdObj.FdUiName = self.CurrentFdName self.Profile.FdDict[self.CurrentFdName] = FdObj + + if len (self.Profile.FdDict) > 1 and self.Profile.FdNameNotSet: + raise Warning("expected all FDs have their name", self.FileName, self.CurrentLineNumber) + Status = self.__GetCreateFile(FdObj) if not Status: raise Warning("FD name error", self.FileName, self.CurrentLineNumber) - if not self.__GetTokenStatements(FdObj): - return False + 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) @@ -1368,59 +1495,56 @@ class FdfParser: # # @param self The object pointer # @param Obj for whom token statement is got - # @retval True Successfully find a token statement - # @retval False Not able to find a token statement # 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 - Status = self.__GetBlockStatements(Obj) - return Status + return self.__GetBlockStatements(Obj) ## __GetAddressStatements() method # @@ -1459,17 +1583,16 @@ class FdfParser: # # @param self The object pointer # @param Obj for whom block statement is got - # @retval True Successfully find - # @retval False Not able to find # def __GetBlockStatements(self, Obj): - - if not self.__GetBlockStatement(Obj): - raise Warning("expected block statement", self.FileName, self.CurrentLineNumber) - + IsBlock = False while self.__GetBlockStatement(Obj): - pass - return True + IsBlock = True + + 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 # @@ -1488,7 +1611,7 @@ class FdfParser: raise Warning("expected '='", self.FileName, self.CurrentLineNumber) if not self.__GetNextHexNumber() and not self.__GetNextDecimalNumber(): - raise Warning("expected Hex block size", self.FileName, self.CurrentLineNumber) + raise Warning("expected Hex or Integer block size", self.FileName, self.CurrentLineNumber) BlockSize = self.__Token BlockSizePcd = None @@ -1496,7 +1619,9 @@ class FdfParser: PcdPair = self.__GetNextPcdName() BlockSizePcd = PcdPair self.Profile.PcdDict[PcdPair] = BlockSize - BlockSize = long(self.__Token, 0) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[PcdPair] = FileLineTuple + BlockSize = long(BlockSize, 0) BlockNumber = None if self.__IsKeyword( "NumBlocks"): @@ -1579,22 +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) - Obj.SetVarDict[PcdPair] = Value + 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 @@ -1605,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"): + 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 @@ -1639,17 +1807,28 @@ class FdfParser: if not self.__GetNextWord(): return True - if self.__Token == "FV": + elif self.__Token == "FV": self.__UndoToken() self.__GetRegionFvType( RegionObj) + elif self.__Token == "CAPSULE": + self.__UndoToken() + self.__GetRegionCapType( RegionObj) + elif self.__Token == "FILE": 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 @@ -1684,6 +1863,37 @@ class FdfParser: RegionObj.RegionDataList.append(self.__Token) + ## __GetRegionCapType() method + # + # Get region capsule data for region + # + # @param self The object pointer + # @param RegionObj for whom region data is got + # + def __GetRegionCapType(self, RegionObj): + + if not self.__IsKeyword("CAPSULE"): + raise Warning("expected Keyword 'CAPSULE'", self.FileName, self.CurrentLineNumber) + + if not self.__IsToken("="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected CAPSULE name", self.FileName, self.CurrentLineNumber) + + RegionObj.RegionType = "CAPSULE" + RegionObj.RegionDataList.append(self.__Token) + + while self.__IsKeyword("CAPSULE"): + + if not self.__IsToken("="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected CAPSULE name", self.FileName, self.CurrentLineNumber) + + RegionObj.RegionDataList.append(self.__Token) + ## __GetRegionFileType() method # # Get region file data for region @@ -1736,19 +1946,27 @@ class FdfParser: if not self.__GetNextHexNumber(): raise Warning("expected Hex byte", self.FileName, self.CurrentLineNumber) - if len(self.__Token) > 4: - raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + if len(self.__Token) > 18: + raise Warning("Hex string can't be converted to a valid UINT64 value", self.FileName, self.CurrentLineNumber) - DataString = self.__Token - DataString += "," + # convert hex string value to byte hex string array + AllString = self.__Token + AllStrLen = len (AllString) + DataString = "" + while AllStrLen > 4: + DataString = DataString + "0x" + AllString[AllStrLen - 2: AllStrLen] + "," + AllStrLen = AllStrLen - 2 + DataString = DataString + AllString[:AllStrLen] + "," - while self.__IsToken(","): - if not self.__GetNextHexNumber(): - raise Warning("Invalid Hex number", self.FileName, self.CurrentLineNumber) - if len(self.__Token) > 4: - raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) - DataString += self.__Token - DataString += "," + # byte value array + if len (self.__Token) <= 4: + while self.__IsToken(","): + if not self.__GetNextHexNumber(): + raise Warning("Invalid Hex number", self.FileName, self.CurrentLineNumber) + if len(self.__Token) > 4: + raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + DataString += self.__Token + DataString += "," if not self.__IsToken( "}"): raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) @@ -1768,18 +1986,27 @@ class FdfParser: if not self.__GetNextHexNumber(): raise Warning("expected Hex byte", self.FileName, self.CurrentLineNumber) - if len(self.__Token) > 4: - raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) - - DataString = self.__Token - DataString += "," - - while self.__IsToken(","): - self.__GetNextHexNumber() - if len(self.__Token) > 4: - raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) - DataString += self.__Token - DataString += "," + if len(self.__Token) > 18: + raise Warning("Hex string can't be converted to a valid UINT64 value", self.FileName, self.CurrentLineNumber) + + # convert hex string value to byte hex string array + AllString = self.__Token + AllStrLen = len (AllString) + DataString = "" + while AllStrLen > 4: + DataString = DataString + "0x" + AllString[AllStrLen - 2: AllStrLen] + "," + AllStrLen = AllStrLen - 2 + DataString = DataString + AllString[:AllStrLen] + "," + + # byte value array + if len (self.__Token) <= 4: + while self.__IsToken(","): + if not self.__GetNextHexNumber(): + raise Warning("Invalid Hex number", self.FileName, self.CurrentLineNumber) + if len(self.__Token) > 4: + raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + DataString += self.__Token + DataString += "," if not self.__IsToken( "}"): raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) @@ -1801,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() @@ -1832,15 +2059,17 @@ class FdfParser: self.__GetAddressStatements(FvObj) - self.__GetBlockStatement(FvObj) - - self.__GetSetStatements(FvObj) - - self.__GetFvAlignment(FvObj) + FvObj.FvExtEntryTypeValue = [] + FvObj.FvExtEntryType = [] + FvObj.FvExtEntryData = [] + while True: + self.__GetSetStatements(FvObj) - self.__GetFvAttributes(FvObj) - - self.__GetFvNameGuid(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()) self.__GetAprioriSection(FvObj, FvObj.DefineVarDict.copy()) @@ -1880,6 +2109,66 @@ class FdfParser: raise Warning("Unknown alignment value '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) Obj.FvAlignment = self.__Token return True + + ## __GetFvBaseAddress() method + # + # Get BaseAddress for FV + # + # @param self The object pointer + # @param Obj for whom FvBaseAddress is got + # @retval True Successfully find a FvBaseAddress statement + # @retval False Not able to find a FvBaseAddress statement + # + def __GetFvBaseAddress(self, Obj): + + if not self.__IsKeyword("FvBaseAddress"): + return False + + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected FV base address value", self.FileName, self.CurrentLineNumber) + + IsValidBaseAddrValue = re.compile('^0[x|X][0-9a-fA-F]+') + + if not IsValidBaseAddrValue.match(self.__Token.upper()): + raise Warning("Unknown FV base address value '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) + Obj.FvBaseAddress = self.__Token + 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 # @@ -1890,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) @@ -1910,7 +2200,7 @@ class FdfParser: FvObj.FvAttributeDict[name] = self.__Token - return + return IsWordToken ## __GetFvNameGuid() method # @@ -1923,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) @@ -1933,7 +2223,80 @@ class FdfParser: FvObj.FvNameGuid = self.__Token - return + return True + + def __GetFvExtEntryStatement(self, FvObj): + + if not self.__IsKeyword( "FV_EXT_ENTRY"): + return False + + if not self.__IsKeyword ("TYPE"): + raise Warning("expected 'TYPE'", self.FileName, self.CurrentLineNumber) + + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextHexNumber() and not self.__GetNextDecimalNumber(): + raise Warning("expected Hex FV extension entry type value At Line ", self.FileName, self.CurrentLineNumber) + + FvObj.FvExtEntryTypeValue += [self.__Token] + + if not self.__IsToken( "{"): + raise Warning("expected '{'", self.FileName, self.CurrentLineNumber) + + if not self.__IsKeyword ("FILE") and not self.__IsKeyword ("DATA"): + raise Warning("expected 'FILE' or 'DATA'", self.FileName, self.CurrentLineNumber) + + FvObj.FvExtEntryType += [self.__Token] + + if self.__Token == 'DATA': + + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__IsToken( "{"): + raise Warning("expected '{'", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextHexNumber(): + raise Warning("expected Hex byte", self.FileName, self.CurrentLineNumber) + + if len(self.__Token) > 4: + raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + + DataString = self.__Token + DataString += "," + + while self.__IsToken(","): + if not self.__GetNextHexNumber(): + raise Warning("Invalid Hex number", self.FileName, self.CurrentLineNumber) + if len(self.__Token) > 4: + raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + DataString += self.__Token + DataString += "," + + if not self.__IsToken( "}"): + raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) + + if not self.__IsToken( "}"): + raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) + + DataString = DataString.rstrip(",") + FvObj.FvExtEntryData += [DataString] + + if self.__Token == 'FILE': + + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + + if not self.__GetNextToken(): + raise Warning("expected FV Extension Entry file path At Line ", self.FileName, self.CurrentLineNumber) + + FvObj.FvExtEntryData += [self.__Token] + + if not self.__IsToken( "}"): + raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) + + return True ## __GetAprioriSection() method # @@ -1997,11 +2360,22 @@ class FdfParser: raise Warning("expected INF file path", self.FileName, self.CurrentLineNumber) ffsInf.InfFileName = self.__Token -# if ffsInf.InfFileName.find('$') >= 0: -# ffsInf.InfFileName = GenFdsGlobalVariable.GenFdsGlobalVariable.MacroExtend(ffsInf.InfFileName, MacroDict) + 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() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) 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'): @@ -2010,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 @@ -2027,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( "="): @@ -2062,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 @@ -2094,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( "="): @@ -2115,7 +2500,7 @@ class FdfParser: self.__Token = 'PCD('+PcdPair[1]+'.'+PcdPair[0]+')' FfsFileObj.NameGuid = self.__Token - + self.__GetFilePart( FfsFileObj, MacroDict.copy()) if ForCapsule: @@ -2172,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(): @@ -2205,7 +2590,10 @@ class FdfParser: self.__UndoToken() self.__GetSectionData( FfsFileObj, MacroDict) else: - FfsFileObj.FileName = self.__Token + 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) @@ -2242,9 +2630,11 @@ class FdfParser: FfsFileObj.CheckSum = True if self.__GetAlignment(): - FfsFileObj.Alignment = self.__Token - - + if self.__Token not in ("Auto", "8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): + raise Warning("Incorrect alignment '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) + #For FFS, Auto is default option same to "" + if not self.__Token == "Auto": + FfsFileObj.Alignment = self.__Token ## __GetAlignment() method # @@ -2311,6 +2701,8 @@ class FdfParser: AlignValue = None if self.__GetAlignment(): + if self.__Token not in ("Auto", "8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): + raise Warning("Incorrect alignment '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) AlignValue = self.__Token BuildNum = None @@ -2324,6 +2716,8 @@ class FdfParser: BuildNum = self.__Token if self.__IsKeyword( "VERSION"): + if AlignValue == 'Auto': + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) if not self.__IsToken( "="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) if not self.__GetNextToken(): @@ -2336,8 +2730,10 @@ class FdfParser: else: VerSectionObj.FileName = self.__Token Obj.SectionList.append(VerSectionObj) - + elif self.__IsKeyword( "UI"): + if AlignValue == 'Auto': + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) if not self.__IsToken( "="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) if not self.__GetNextToken(): @@ -2351,6 +2747,8 @@ class FdfParser: Obj.SectionList.append(UiSectionObj) elif self.__IsKeyword( "FV_IMAGE"): + if AlignValue == 'Auto': + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) if not self.__IsToken( "="): raise Warning("expected '='", self.FileName, self.CurrentLineNumber) if not self.__GetNextToken(): @@ -2392,6 +2790,8 @@ class FdfParser: Obj.SectionList.append(FvImageSectionObj) elif self.__IsKeyword("PEI_DEPEX_EXP") or self.__IsKeyword("DXE_DEPEX_EXP") or self.__IsKeyword("SMM_DEPEX_EXP"): + if AlignValue == 'Auto': + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) DepexSectionObj = DepexSection.DepexSection() DepexSectionObj.Alignment = AlignValue DepexSectionObj.DepexType = self.__Token @@ -2407,7 +2807,6 @@ class FdfParser: Obj.SectionList.append(DepexSectionObj) else: - if not self.__GetNextWord(): raise Warning("expected section type", self.FileName, self.CurrentLineNumber) @@ -2419,6 +2818,9 @@ class FdfParser: if self.__Token not in ("COMPAT16", "PE32", "PIC", "TE", "FV_IMAGE", "RAW", "DXE_DEPEX",\ "UI", "VERSION", "PEI_DEPEX", "SUBTYPE_GUID", "SMM_DEPEX"): raise Warning("Unknown section type '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) + if AlignValue == 'Auto'and (not self.__Token == 'PE32') and (not self.__Token == 'TE'): + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + # DataSection DataSectionObj = DataSection.DataSection() DataSectionObj.Alignment = AlignValue @@ -2437,6 +2839,7 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("expected section file path", self.FileName, self.CurrentLineNumber) DataSectionObj.SectFileName = self.__Token + self.__VerifyFile(DataSectionObj.SectFileName) else: if not self.__GetCglSection(DataSectionObj): return False @@ -2445,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 @@ -2499,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) @@ -2524,25 +2943,28 @@ class FdfParser: def __GetGuidAttrib(self): AttribDict = {} - AttribDict["PROCESSING_REQUIRED"] = False - AttribDict["AUTH_STATUS_VALID"] = False - if self.__IsKeyword("PROCESSING_REQUIRED") or self.__IsKeyword("AUTH_STATUS_VALID"): + AttribDict["PROCESSING_REQUIRED"] = "NONE" + AttribDict["AUTH_STATUS_VALID"] = "NONE" + 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 @@ -2568,6 +2990,8 @@ class FdfParser: AlignValue = None if self.__GetAlignment(): + if self.__Token not in ("8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): + raise Warning("Incorrect alignment '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) AlignValue = self.__Token if not self.__GetCglSection(FfsFileObj, AlignValue): @@ -2576,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 @@ -2624,7 +3109,7 @@ class FdfParser: CapsuleObj.CreateFile = self.__Token self.__GetCapsuleStatements(CapsuleObj) - self.Profile.CapsuleList.append(CapsuleObj) + self.Profile.CapsuleDict[CapsuleObj.UiCapsuleName] = CapsuleObj return True ## __GetCapsuleStatements() method @@ -2638,10 +3123,9 @@ class FdfParser: self.__GetCapsuleTokens(Obj) self.__GetDefineStatements(Obj) self.__GetSetStatements(Obj) - self.__GetCapsuleData(Obj) - ## __GetCapsuleStatements() method + ## __GetCapsuleTokens() method # # Get token statements for capsule # @@ -2649,15 +3133,42 @@ class FdfParser: # @param Obj for whom token statements are got # def __GetCapsuleTokens(self, Obj): - - if not self.__IsKeyword("CAPSULE_GUID"): - raise Warning("expected 'CAPSULE_GUID'", self.FileName, self.CurrentLineNumber) - - while self.__CurrentLine().find("=") != -1: - NameValue = self.__CurrentLine().split("=") - Obj.TokensDict[NameValue[0].strip()] = NameValue[1].strip() - self.CurrentLineNumber += 1 - self.CurrentOffsetWithinLine = 0 + if not self.__GetNextToken(): + return False + 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) + if not self.__GetNextToken(): + raise Warning("expected value", self.FileName, self.CurrentLineNumber) + if Name == 'CAPSULE_FLAGS': + if not self.__Token in ("PersistAcrossReset", "PopulateSystemTable", "InitiateReset"): + raise Warning("expected PersistAcrossReset, PopulateSystemTable, or InitiateReset", self.FileName, self.CurrentLineNumber) + Value = self.__Token.strip() + while self.__IsToken(","): + Value += ',' + if not self.__GetNextToken(): + raise Warning("expected value", self.FileName, self.CurrentLineNumber) + 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 + if not self.__GetNextToken(): + return False + self.__UndoToken() ## __GetCapsuleData() method # @@ -2672,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 @@ -2695,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 @@ -2730,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() @@ -2781,7 +3426,7 @@ class FdfParser: "DXE_SMM_DRIVER", "DXE_RUNTIME_DRIVER", \ "UEFI_DRIVER", "UEFI_APPLICATION", "USER_DEFINED", "DEFAULT", "BASE", \ "SECURITY_CORE", "COMBINED_PEIM_DRIVER", "PIC_PEIM", "RELOCATABLE_PEIM", \ - "PE32_PEIM", "BS_DRIVER", "RT_DRIVER", "SAL_RT_DRIVER", "APPLICATION", "ACPITABLE", "SMM_DRIVER", "SMM_CORE"): + "PE32_PEIM", "BS_DRIVER", "RT_DRIVER", "SAL_RT_DRIVER", "APPLICATION", "ACPITABLE", "SMM_CORE"): raise Warning("Unknown Module type '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) return self.__Token @@ -2825,7 +3470,7 @@ class FdfParser: Type = self.__Token.strip().upper() if Type not in ("RAW", "FREEFORM", "SEC", "PEI_CORE", "PEIM",\ - "PEI_DXE_COMBO", "DRIVER", "DXE_CORE", "APPLICATION", "FV_IMAGE", "SMM_DXE_COMBO", "SMM", "SMM_CORE"): + "PEI_DXE_COMBO", "DRIVER", "DXE_CORE", "APPLICATION", "FV_IMAGE", "SMM", "SMM_CORE"): raise Warning("Unknown FV type '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) if not self.__IsToken("="): @@ -2882,9 +3527,11 @@ class FdfParser: AlignValue = "" if self.__GetAlignment(): - if self.__Token not in ("8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): + if self.__Token not in ("Auto", "8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): raise Warning("Incorrect alignment '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) - AlignValue = self.__Token + #For FFS, Auto is default option same to "" + if not self.__Token == "Auto": + AlignValue = self.__Token if self.__IsToken("{"): # Complex file rule expected @@ -2909,24 +3556,6 @@ class FdfParser: return Rule - elif self.__IsToken("|"): - # Ext rule expected - Ext = self.__GetFileExtension() - - Rule = RuleSimpleFile.RuleSimpleFile() - - Rule.FvFileType = Type - Rule.NameGuid = NameGuid - Rule.Alignment = AlignValue - Rule.CheckSum = CheckSum - Rule.Fixed = Fixed - Rule.FileExtension = Ext - Rule.KeyStringList = KeyStringList - if KeepReloc != None: - Rule.KeepReloc = KeepReloc - - return Rule - else: # Simple file rule expected if not self.__GetNextWord(): @@ -2945,12 +3574,18 @@ class FdfParser: if self.__IsKeyword("CheckSum", True): CheckSum = True + SectAlignment = "" if self.__GetAlignment(): - if self.__Token not in ("8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): + if self.__Token not in ("Auto", "8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): raise Warning("Incorrect alignment '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) - AlignValue = self.__Token + if self.__Token == 'Auto' and (not SectionName == 'PE32') and (not SectionName == 'TE'): + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + SectAlignment = self.__Token - if not self.__GetNextToken(): + Ext = None + if self.__IsToken('|'): + Ext = self.__GetFileExtension() + elif not self.__GetNextToken(): raise Warning("expected File name", self.FileName, self.CurrentLineNumber) Rule = RuleSimpleFile.RuleSimpleFile() @@ -2958,12 +3593,14 @@ class FdfParser: Rule.FvFileType = Type Rule.NameGuid = NameGuid Rule.Alignment = AlignValue + Rule.SectAlignment = SectAlignment Rule.CheckSum = CheckSum Rule.Fixed = Fixed - Rule.FileName = self.__Token Rule.KeyStringList = KeyStringList if KeepReloc != None: Rule.KeepReloc = KeepReloc + Rule.FileExtension = Ext + Rule.FileName = self.__Token return Rule ## __GetEfiSection() method @@ -3017,14 +3654,6 @@ class FdfParser: raise Warning("expected 'FV'", self.FileName, self.CurrentLineNumber) FvImageSectionObj.FvFileType = self.__Token - if self.__GetAlignment(): - if self.__Token not in ("8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): - raise Warning("Incorrect alignment '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) - FvImageSectionObj.Alignment = self.__Token - - if self.__IsKeyword("FV"): - FvImageSectionObj.FvFileType = self.__Token - if self.__GetAlignment(): if self.__Token not in ("8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): raise Warning("Incorrect alignment '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) @@ -3093,6 +3722,10 @@ class FdfParser: EfiSectionObj.BuildNum = self.__Token if self.__GetAlignment(): + if self.__Token not in ("Auto", "8", "16", "32", "64", "128", "512", "1K", "4K", "32K" ,"64K"): + raise Warning("Incorrect alignment '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) + if self.__Token == 'Auto' and (not SectionName == 'PE32') and (not SectionName == 'TE'): + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) EfiSectionObj.Alignment = self.__Token if self.__IsKeyword('RELOCS_STRIPPED') or self.__IsKeyword('RELOCS_RETAINED'): @@ -3204,8 +3837,8 @@ class FdfParser: elif SectionType == "RAW": if FileType not in ("BIN", "SEC_BIN", "RAW", "ASL", "ACPI"): raise Warning("Incorrect section file type '%s'" % FileType, self.FileName, self.CurrentLineNumber) - elif SectionType == "DXE_DEPEX": - if FileType not in ("DXE_DEPEX", "SEC_DXE_DEPEX"): + elif SectionType == "DXE_DEPEX" or SectionType == "SMM_DEPEX": + if FileType not in ("DXE_DEPEX", "SEC_DXE_DEPEX", "SMM_DEPEX"): raise Warning("Incorrect section file type '%s'" % FileType, self.FileName, self.CurrentLineNumber) elif SectionType == "UI": if FileType not in ("UI", "SEC_UI"): @@ -3272,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: @@ -3319,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(): @@ -3333,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() @@ -3348,6 +3982,11 @@ class FdfParser: raise Warning("expected Reset file", self.FileName, self.CurrentLineNumber) VtfObj.ResetBin = self.__Token + if VtfObj.ResetBin.replace('$(WORKSPACE)', '').find('$') == -1: + #check for file path + ErrorCode, ErrorInfo = PathClass(NormPath(VtfObj.ResetBin), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) while self.__GetComponentStatement(VtfObj): pass @@ -3422,7 +4061,7 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("expected Component version", self.FileName, self.CurrentLineNumber) - Pattern = re.compile('-$|[0-9]{0,1}[0-9]{1}\.[0-9]{0,1}[0-9]{1}') + Pattern = re.compile('-$|[0-9a-fA-F]{1,2}\.[0-9a-fA-F]{1,2}$', re.DOTALL) if Pattern.match(self.__Token) == None: raise Warning("Unknown version format '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) CompStatementObj.CompVer = self.__Token @@ -3450,6 +4089,11 @@ class FdfParser: raise Warning("expected Component file", self.FileName, self.CurrentLineNumber) CompStatementObj.CompBin = self.__Token + if CompStatementObj.CompBin != '-' and CompStatementObj.CompBin.replace('$(WORKSPACE)', '').find('$') == -1: + #check for file path + ErrorCode, ErrorInfo = PathClass(NormPath(CompStatementObj.CompBin), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) if not self.__IsKeyword("COMP_SYM"): raise Warning("expected COMP_SYM", self.FileName, self.CurrentLineNumber) @@ -3461,6 +4105,11 @@ class FdfParser: raise Warning("expected Component symbol file", self.FileName, self.CurrentLineNumber) CompStatementObj.CompSym = self.__Token + if CompStatementObj.CompSym != '-' and CompStatementObj.CompSym.replace('$(WORKSPACE)', '').find('$') == -1: + #check for file path + ErrorCode, ErrorInfo = PathClass(NormPath(CompStatementObj.CompSym), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) if not self.__IsKeyword("COMP_SIZE"): raise Warning("expected COMP_SIZE", self.FileName, self.CurrentLineNumber) @@ -3538,9 +4187,16 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("expected INF file path", self.FileName, self.CurrentLineNumber) ffsInf.InfFileName = self.__Token + if ffsInf.InfFileName.replace('$(WORKSPACE)', '').find('$') == -1: + #check for file path + ErrorCode, ErrorInfo = PathClass(NormPath(ffsInf.InfFileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) 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) @@ -3558,51 +4214,53 @@ class FdfParser: def __GetOptRomOverrides(self, Obj): if self.__IsToken('{'): Overrides = OptionRom.OverrideAttribs() - if self.__IsKeyword( "PCI_VENDOR_ID"): - if not self.__IsToken( "="): - raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - if not self.__GetNextHexNumber(): - raise Warning("expected Hex vendor id", self.FileName, self.CurrentLineNumber) - Overrides.PciVendorId = self.__Token - - if self.__IsKeyword( "PCI_CLASS_CODE"): - if not self.__IsToken( "="): - raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - if not self.__GetNextHexNumber(): - raise Warning("expected Hex class code", self.FileName, self.CurrentLineNumber) - Overrides.PciClassCode = self.__Token - - if self.__IsKeyword( "PCI_DEVICE_ID"): - if not self.__IsToken( "="): - raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - if not self.__GetNextHexNumber(): - raise Warning("expected Hex device id", self.FileName, self.CurrentLineNumber) - - Overrides.PciDeviceId = self.__Token - - if self.__IsKeyword( "PCI_REVISION"): - if not self.__IsToken( "="): - raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - if not self.__GetNextHexNumber(): - raise Warning("expected Hex revision", self.FileName, self.CurrentLineNumber) - Overrides.PciRevision = self.__Token - - if self.__IsKeyword( "COMPRESS"): - if not self.__IsToken( "="): - raise Warning("expected '='", self.FileName, self.CurrentLineNumber) - if not self.__GetNextToken(): - raise Warning("expected TRUE/FALSE for compress", self.FileName, self.CurrentLineNumber) - - if self.__Token.upper() == 'TRUE': - Overrides.NeedCompress = True - - if not self.__IsToken( "}"): - - if self.__Token not in ("PCI_CLASS_CODE", "PCI_VENDOR_ID", "PCI_DEVICE_ID", "PCI_REVISION", "COMPRESS"): - raise Warning("unknown attribute %s" % self.__Token, self.FileName, self.CurrentLineNumber) - - raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) - + while True: + if self.__IsKeyword( "PCI_VENDOR_ID"): + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if not self.__GetNextHexNumber(): + raise Warning("expected Hex vendor id", self.FileName, self.CurrentLineNumber) + Overrides.PciVendorId = self.__Token + continue + + if self.__IsKeyword( "PCI_CLASS_CODE"): + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if not self.__GetNextHexNumber(): + raise Warning("expected Hex class code", self.FileName, self.CurrentLineNumber) + Overrides.PciClassCode = self.__Token + continue + + if self.__IsKeyword( "PCI_DEVICE_ID"): + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if not self.__GetNextHexNumber(): + raise Warning("expected Hex device id", self.FileName, self.CurrentLineNumber) + + Overrides.PciDeviceId = self.__Token + continue + + if self.__IsKeyword( "PCI_REVISION"): + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if not self.__GetNextHexNumber(): + raise Warning("expected Hex revision", self.FileName, self.CurrentLineNumber) + Overrides.PciRevision = self.__Token + continue + + if self.__IsKeyword( "PCI_COMPRESS"): + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if not self.__GetNextToken(): + raise Warning("expected TRUE/FALSE for compress", self.FileName, self.CurrentLineNumber) + Overrides.NeedCompress = self.__Token.upper() == 'TRUE' + continue + + if self.__IsToken( "}"): + break + else: + EdkLogger.error("FdfParser", FORMAT_INVALID, File=self.FileName, Line=self.CurrentLineNumber) + Obj.OverrideAttribs = Overrides ## __GetOptRomFileStatement() method @@ -3628,6 +4286,11 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("expected File path", self.FileName, self.CurrentLineNumber) FfsFileObj.FileName = self.__Token + if FfsFileObj.FileName.replace('$(WORKSPACE)', '').find('$') == -1: + #check for file path + ErrorCode, ErrorInfo = PathClass(NormPath(FfsFileObj.FileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) if FfsFileObj.FileType == 'EFI': self.__GetOptRomOverrides(FfsFileObj) @@ -3635,8 +4298,54 @@ class FdfParser: Obj.FfsList.append(FfsFileObj) return True - - + + ## __GetCapInFd() method + # + # Get Cap list contained in FD + # + # @param self The object pointer + # @param FdName FD name + # @retval CapList List of Capsule in FD + # + def __GetCapInFd (self, FdName): + + CapList = [] + if FdName.upper() in self.Profile.FdDict.keys(): + FdObj = self.Profile.FdDict[FdName.upper()] + for elementRegion in FdObj.RegionList: + if elementRegion.RegionType == 'CAPSULE': + for elementRegionData in elementRegion.RegionDataList: + if elementRegionData.endswith(".cap"): + continue + if elementRegionData != None and elementRegionData.upper() not in CapList: + CapList.append(elementRegionData.upper()) + return CapList + + ## __GetReferencedFdCapTuple() method + # + # Get FV and FD list referenced by a capsule image + # + # @param self The object pointer + # @param CapObj Capsule section to be searched + # @param RefFdList referenced FD by section + # @param RefFvList referenced FV by section + # + def __GetReferencedFdCapTuple(self, CapObj, RefFdList = [], RefFvList = []): + + for CapsuleDataObj in CapObj.CapsuleDataList : + 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) + ## __GetFvInFd() method # # Get FV list contained in FD @@ -3653,6 +4362,8 @@ class FdfParser: for elementRegion in FdObj.RegionList: if elementRegion.RegionType == 'FV': for elementRegionData in elementRegion.RegionDataList: + if elementRegionData.endswith(".fv"): + continue if elementRegionData != None and elementRegionData.upper() not in FvList: FvList.append(elementRegionData.upper()) return FvList @@ -3711,68 +4422,141 @@ class FdfParser: # @retval False Not exists cycle reference # def CycleReferenceCheck(self): + # + # Check the cycle between FV and FD image + # + MaxLength = len (self.Profile.FvDict) + for FvName in self.Profile.FvDict.keys(): + LogStr = "\nCycle Reference Checking for FV: %s\n" % FvName + RefFvStack = [] + RefFvStack.append(FvName) + FdAnalyzedList = [] + + Index = 0 + while RefFvStack != [] and Index < MaxLength: + Index = Index + 1 + FvNameFromStack = RefFvStack.pop() + if FvNameFromStack.upper() in self.Profile.FvDict.keys(): + FvObj = self.Profile.FvDict[FvNameFromStack.upper()] + else: + continue - CycleRefExists = False + RefFdList = [] + RefFvList = [] + self.__GetReferencedFdFvTuple(FvObj, RefFdList, RefFvList) - try: - for FvName in self.Profile.FvDict.keys(): - LogStr = "Cycle Reference Checking for FV: %s\n" % FvName - RefFvStack = [] - RefFvStack.append(FvName) - FdAnalyzedList = [] - - while RefFvStack != []: - FvNameFromStack = RefFvStack.pop() - if FvNameFromStack.upper() in self.Profile.FvDict.keys(): - FvObj = self.Profile.FvDict[FvNameFromStack.upper()] - else: + for RefFdName in RefFdList: + if RefFdName in FdAnalyzedList: continue - RefFdList = [] - RefFvList = [] - self.__GetReferencedFdFvTuple(FvObj, RefFdList, RefFvList) + LogStr += "FV %s contains FD %s\n" % (FvNameFromStack, RefFdName) + FvInFdList = self.__GetFvInFd(RefFdName) + if FvInFdList != []: + for FvNameInFd in FvInFdList: + LogStr += "FD %s contains FV %s\n" % (RefFdName,FvNameInFd) + if FvNameInFd not in RefFvStack: + RefFvStack.append(FvNameInFd) + + if FvName in RefFvStack or FvNameFromStack in RefFvStack: + EdkLogger.info(LogStr) + return True + FdAnalyzedList.append(RefFdName) + + for RefFvName in RefFvList: + LogStr += "FV %s contains FV %s\n" % (FvNameFromStack, RefFvName) + if RefFvName not in RefFvStack: + RefFvStack.append(RefFvName) + + if FvName in RefFvStack or FvNameFromStack in RefFvStack: + EdkLogger.info(LogStr) + return True + + # + # Check the cycle between Capsule and FD image + # + MaxLength = len (self.Profile.CapsuleDict) + for CapName in self.Profile.CapsuleDict.keys(): + # + # Capsule image to be checked. + # + LogStr = "\n\n\nCycle Reference Checking for Capsule: %s\n" % CapName + RefCapStack = [] + RefCapStack.append(CapName) + FdAnalyzedList = [] + FvAnalyzedList = [] + + Index = 0 + while RefCapStack != [] and Index < MaxLength: + Index = Index + 1 + CapNameFromStack = RefCapStack.pop() + if CapNameFromStack.upper() in self.Profile.CapsuleDict.keys(): + CapObj = self.Profile.CapsuleDict[CapNameFromStack.upper()] + else: + continue + + RefFvList = [] + RefFdList = [] + self.__GetReferencedFdCapTuple(CapObj, RefFdList, RefFvList) + FvListLength = 0 + FdListLength = 0 + while FvListLength < len (RefFvList) or FdListLength < len (RefFdList): for RefFdName in RefFdList: if RefFdName in FdAnalyzedList: continue - LogStr += "FD %s is referenced by FV %s\n" % (RefFdName, FvNameFromStack) + LogStr += "Capsule %s contains FD %s\n" % (CapNameFromStack, RefFdName) + CapInFdList = self.__GetCapInFd(RefFdName) + if CapInFdList != []: + for CapNameInFd in CapInFdList: + LogStr += "FD %s contains Capsule %s\n" % (RefFdName,CapNameInFd) + if CapNameInFd not in RefCapStack: + RefCapStack.append(CapNameInFd) + + if CapName in RefCapStack or CapNameFromStack in RefCapStack: + EdkLogger.info(LogStr) + return True + FvInFdList = self.__GetFvInFd(RefFdName) if FvInFdList != []: - LogStr += "FD %s contains FV: " % RefFdName - for FvObj in FvInFdList: - LogStr += FvObj - LogStr += ' \n' - if FvObj not in RefFvStack: - RefFvStack.append(FvObj) - - if FvName in RefFvStack: - CycleRefExists = True - raise Warning(LogStr) - FdAnalyzedList.append(RefFdName) + for FvNameInFd in FvInFdList: + LogStr += "FD %s contains FV %s\n" % (RefFdName,FvNameInFd) + if FvNameInFd not in RefFvList: + RefFvList.append(FvNameInFd) + FdAnalyzedList.append(RefFdName) + # + # the number of the parsed FV and FD image + # + FvListLength = len (RefFvList) + FdListLength = len (RefFdList) for RefFvName in RefFvList: - LogStr += "FV %s is referenced by FV %s\n" % (RefFvName, FvNameFromStack) - if RefFvName not in RefFvStack: - RefFvStack.append(RefFvName) - - if FvName in RefFvStack: - CycleRefExists = True - raise Warning(LogStr) - - except Warning: - print LogStr + if RefFvName in FvAnalyzedList: + continue + LogStr += "Capsule %s contains FV %s\n" % (CapNameFromStack, RefFvName) + if RefFvName.upper() in self.Profile.FvDict.keys(): + FvObj = self.Profile.FvDict[RefFvName.upper()] + else: + continue + self.__GetReferencedFdFvTuple(FvObj, RefFdList, RefFvList) + FvAnalyzedList.append(RefFvName) - finally: - return CycleRefExists + 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!"