This patch clean some coding style issues, majorly for space character. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu <yonghong.zhu@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19080 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			449 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			449 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| ## @file
 | |
| # This file is used to generate DEPEX file for module's dependency expression
 | |
| #
 | |
| # Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
| # This program and the accompanying materials
 | |
| # are licensed and made available under the terms and conditions of the BSD License
 | |
| # which accompanies this distribution.    The full text of the license may be found at
 | |
| # http://opensource.org/licenses/bsd-license.php
 | |
| #
 | |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| ## Import Modules
 | |
| #
 | |
| import sys
 | |
| import Common.LongFilePathOs as os
 | |
| import re
 | |
| import traceback
 | |
| from Common.LongFilePathSupport import OpenLongFilePath as open
 | |
| from StringIO import StringIO
 | |
| from struct import pack
 | |
| from Common.BuildToolError import *
 | |
| from Common.Misc import SaveFileOnChange
 | |
| from Common.Misc import GuidStructureStringToGuidString
 | |
| from Common import EdkLogger as EdkLogger
 | |
| from Common.BuildVersion import gBUILD_VERSION
 | |
| 
 | |
| ## Regular expression for matching "DEPENDENCY_START ... DEPENDENCY_END"
 | |
| gStartClosePattern = re.compile(".*DEPENDENCY_START(.+)DEPENDENCY_END.*", re.S)
 | |
| 
 | |
| ## Mapping between module type and EFI phase
 | |
| gType2Phase = {
 | |
|     "BASE"              :   None,
 | |
|     "SEC"               :   "PEI",
 | |
|     "PEI_CORE"          :   "PEI",
 | |
|     "PEIM"              :   "PEI",
 | |
|     "DXE_CORE"          :   "DXE",
 | |
|     "DXE_DRIVER"        :   "DXE",
 | |
|     "DXE_SMM_DRIVER"    :   "DXE",
 | |
|     "DXE_RUNTIME_DRIVER":   "DXE",
 | |
|     "DXE_SAL_DRIVER"    :   "DXE",
 | |
|     "UEFI_DRIVER"       :   "DXE",
 | |
|     "UEFI_APPLICATION"  :   "DXE",
 | |
|     "SMM_CORE"          :   "DXE",
 | |
| }
 | |
| 
 | |
| ## Convert dependency expression string into EFI internal representation
 | |
| #
 | |
| #   DependencyExpression class is used to parse dependency expression string and
 | |
| # convert it into its binary form.
 | |
| #
 | |
| class DependencyExpression:
 | |
| 
 | |
|     ArchProtocols = set([
 | |
|                         '665e3ff6-46cc-11d4-9a38-0090273fc14d',     #   'gEfiBdsArchProtocolGuid'
 | |
|                         '26baccb1-6f42-11d4-bce7-0080c73c8881',     #   'gEfiCpuArchProtocolGuid'
 | |
|                         '26baccb2-6f42-11d4-bce7-0080c73c8881',     #   'gEfiMetronomeArchProtocolGuid'
 | |
|                         '1da97072-bddc-4b30-99f1-72a0b56fff2a',     #   'gEfiMonotonicCounterArchProtocolGuid'
 | |
|                         '27cfac87-46cc-11d4-9a38-0090273fc14d',     #   'gEfiRealTimeClockArchProtocolGuid'
 | |
|                         '27cfac88-46cc-11d4-9a38-0090273fc14d',     #   'gEfiResetArchProtocolGuid'
 | |
|                         'b7dfb4e1-052f-449f-87be-9818fc91b733',     #   'gEfiRuntimeArchProtocolGuid'
 | |
|                         'a46423e3-4617-49f1-b9ff-d1bfa9115839',     #   'gEfiSecurityArchProtocolGuid'
 | |
|                         '26baccb3-6f42-11d4-bce7-0080c73c8881',     #   'gEfiTimerArchProtocolGuid'
 | |
|                         '6441f818-6362-4e44-b570-7dba31dd2453',     #   'gEfiVariableWriteArchProtocolGuid'
 | |
|                         '1e5668e2-8481-11d4-bcf1-0080c73c8881',     #   'gEfiVariableArchProtocolGuid'
 | |
|                         '665e3ff5-46cc-11d4-9a38-0090273fc14d'      #   'gEfiWatchdogTimerArchProtocolGuid'
 | |
|                         ]
 | |
|                     )
 | |
| 
 | |
|     OpcodePriority = {
 | |
|         "AND"   :   1,
 | |
|         "OR"    :   1,
 | |
|         "NOT"   :   2,
 | |
|         # "SOR"   :   9,
 | |
|         # "BEFORE":   9,
 | |
|         # "AFTER" :   9,
 | |
|     }
 | |
| 
 | |
|     Opcode = {
 | |
|         "PEI"   : {
 | |
|             "PUSH"  :   0x02,
 | |
|             "AND"   :   0x03,
 | |
|             "OR"    :   0x04,
 | |
|             "NOT"   :   0x05,
 | |
|             "TRUE"  :   0x06,
 | |
|             "FALSE" :   0x07,
 | |
|             "END"   :   0x08
 | |
|         },
 | |
| 
 | |
|         "DXE"   : {
 | |
|             "BEFORE":   0x00,
 | |
|             "AFTER" :   0x01,
 | |
|             "PUSH"  :   0x02,
 | |
|             "AND"   :   0x03,
 | |
|             "OR"    :   0x04,
 | |
|             "NOT"   :   0x05,
 | |
|             "TRUE"  :   0x06,
 | |
|             "FALSE" :   0x07,
 | |
|             "END"   :   0x08,
 | |
|             "SOR"   :   0x09
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # all supported op codes and operands
 | |
|     SupportedOpcode = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "END", "SOR"]
 | |
|     SupportedOperand = ["TRUE", "FALSE"]
 | |
| 
 | |
|     OpcodeWithSingleOperand = ['NOT', 'BEFORE', 'AFTER']
 | |
|     OpcodeWithTwoOperand = ['AND', 'OR']
 | |
| 
 | |
|     # op code that should not be the last one
 | |
|     NonEndingOpcode = ["AND", "OR", "NOT", 'SOR']
 | |
|     # op code must not present at the same time
 | |
|     ExclusiveOpcode = ["BEFORE", "AFTER"]
 | |
|     # op code that should be the first one if it presents
 | |
|     AboveAllOpcode = ["SOR", "BEFORE", "AFTER"]
 | |
| 
 | |
|     #
 | |
|     # open and close brace must be taken as individual tokens
 | |
|     #
 | |
|     TokenPattern = re.compile("(\(|\)|\{[^{}]+\{?[^{}]+\}?[ ]*\}|\w+)")
 | |
| 
 | |
|     ## Constructor
 | |
|     #
 | |
|     #   @param  Expression  The list or string of dependency expression
 | |
|     #   @param  ModuleType  The type of the module using the dependency expression
 | |
|     #
 | |
|     def __init__(self, Expression, ModuleType, Optimize=False):
 | |
|         self.ModuleType = ModuleType
 | |
|         self.Phase = gType2Phase[ModuleType]
 | |
|         if type(Expression) == type([]):
 | |
|             self.ExpressionString = " ".join(Expression)
 | |
|             self.TokenList = Expression
 | |
|         else:
 | |
|             self.ExpressionString = Expression
 | |
|             self.GetExpressionTokenList()
 | |
| 
 | |
|         self.PostfixNotation = []
 | |
|         self.OpcodeList = []
 | |
| 
 | |
|         self.GetPostfixNotation()
 | |
|         self.ValidateOpcode()
 | |
| 
 | |
|         EdkLogger.debug(EdkLogger.DEBUG_8, repr(self))
 | |
|         if Optimize:
 | |
|             self.Optimize()
 | |
|             EdkLogger.debug(EdkLogger.DEBUG_8, "\n    Optimized: " + repr(self))
 | |
| 
 | |
|     def __str__(self):
 | |
|         return " ".join(self.TokenList)
 | |
| 
 | |
|     def __repr__(self):
 | |
|         WellForm = ''
 | |
|         for Token in self.PostfixNotation:
 | |
|             if Token in self.SupportedOpcode:
 | |
|                 WellForm += "\n    " + Token
 | |
|             else:
 | |
|                 WellForm += ' ' + Token
 | |
|         return WellForm
 | |
| 
 | |
|     ## Split the expression string into token list
 | |
|     def GetExpressionTokenList(self):
 | |
|         self.TokenList = self.TokenPattern.findall(self.ExpressionString)
 | |
| 
 | |
|     ## Convert token list into postfix notation
 | |
|     def GetPostfixNotation(self):
 | |
|         Stack = []
 | |
|         LastToken = ''
 | |
|         for Token in self.TokenList:
 | |
|             if Token == "(":
 | |
|                 if LastToken not in self.SupportedOpcode + ['(', '', None]:
 | |
|                     EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before open parentheses",
 | |
|                                     ExtraData="Near %s" % LastToken)
 | |
|                 Stack.append(Token)
 | |
|             elif Token == ")":
 | |
|                 if '(' not in Stack:
 | |
|                     EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: mismatched parentheses",
 | |
|                                     ExtraData=str(self))
 | |
|                 elif LastToken in self.SupportedOpcode + ['', None]:
 | |
|                     EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operand before close parentheses",
 | |
|                                     ExtraData="Near %s" % LastToken)
 | |
|                 while len(Stack) > 0:
 | |
|                     if Stack[-1] == '(':
 | |
|                         Stack.pop()
 | |
|                         break
 | |
|                     self.PostfixNotation.append(Stack.pop())
 | |
|             elif Token in self.OpcodePriority:
 | |
|                 if Token == "NOT":
 | |
|                     if LastToken not in self.SupportedOpcode + ['(', '', None]:
 | |
|                         EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before NOT",
 | |
|                                         ExtraData="Near %s" % LastToken)
 | |
|                 elif LastToken in self.SupportedOpcode + ['(', '', None]:
 | |
|                         EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operand before " + Token,
 | |
|                                         ExtraData="Near %s" % LastToken)
 | |
| 
 | |
|                 while len(Stack) > 0:
 | |
|                     if Stack[-1] == "(" or self.OpcodePriority[Token] >= self.OpcodePriority[Stack[-1]]:
 | |
|                         break
 | |
|                     self.PostfixNotation.append(Stack.pop())
 | |
|                 Stack.append(Token)
 | |
|                 self.OpcodeList.append(Token)
 | |
|             else:
 | |
|                 if Token not in self.SupportedOpcode:
 | |
|                     # not OP, take it as GUID
 | |
|                     if LastToken not in self.SupportedOpcode + ['(', '', None]:
 | |
|                         EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before %s" % Token,
 | |
|                                         ExtraData="Near %s" % LastToken)
 | |
|                     if len(self.OpcodeList) == 0 or self.OpcodeList[-1] not in self.ExclusiveOpcode:
 | |
|                         if Token not in self.SupportedOperand:
 | |
|                             self.PostfixNotation.append("PUSH")
 | |
|                 # check if OP is valid in this phase
 | |
|                 elif Token in self.Opcode[self.Phase]:
 | |
|                     if Token == "END":
 | |
|                         break
 | |
|                     self.OpcodeList.append(Token)
 | |
|                 else:
 | |
|                     EdkLogger.error("GenDepex", PARSER_ERROR,
 | |
|                                     "Opcode=%s doesn't supported in %s stage " % (Token, self.Phase),
 | |
|                                     ExtraData=str(self))
 | |
|                 self.PostfixNotation.append(Token)
 | |
|             LastToken = Token
 | |
| 
 | |
|         # there should not be parentheses in Stack
 | |
|         if '(' in Stack or ')' in Stack:
 | |
|             EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: mismatched parentheses",
 | |
|                             ExtraData=str(self))
 | |
|         while len(Stack) > 0:
 | |
|             self.PostfixNotation.append(Stack.pop())
 | |
|         if self.PostfixNotation[-1] != 'END':
 | |
|             self.PostfixNotation.append("END")
 | |
| 
 | |
|     ## Validate the dependency expression
 | |
|     def ValidateOpcode(self):
 | |
|         for Op in self.AboveAllOpcode:
 | |
|             if Op in self.PostfixNotation:
 | |
|                 if Op != self.PostfixNotation[0]:
 | |
|                     EdkLogger.error("GenDepex", PARSER_ERROR, "%s should be the first opcode in the expression" % Op,
 | |
|                                     ExtraData=str(self))
 | |
|                 if len(self.PostfixNotation) < 3:
 | |
|                     EdkLogger.error("GenDepex", PARSER_ERROR, "Missing operand for %s" % Op,
 | |
|                                     ExtraData=str(self))
 | |
|         for Op in self.ExclusiveOpcode:
 | |
|             if Op in self.OpcodeList:
 | |
|                 if len(self.OpcodeList) > 1:
 | |
|                     EdkLogger.error("GenDepex", PARSER_ERROR, "%s should be the only opcode in the expression" % Op,
 | |
|                                     ExtraData=str(self))
 | |
|                 if len(self.PostfixNotation) < 3:
 | |
|                     EdkLogger.error("GenDepex", PARSER_ERROR, "Missing operand for %s" % Op,
 | |
|                                     ExtraData=str(self))
 | |
|         if self.TokenList[-1] != 'END' and self.TokenList[-1] in self.NonEndingOpcode:
 | |
|             EdkLogger.error("GenDepex", PARSER_ERROR, "Extra %s at the end of the dependency expression" % self.TokenList[-1],
 | |
|                             ExtraData=str(self))
 | |
|         if self.TokenList[-1] == 'END' and self.TokenList[-2] in self.NonEndingOpcode:
 | |
|             EdkLogger.error("GenDepex", PARSER_ERROR, "Extra %s at the end of the dependency expression" % self.TokenList[-2],
 | |
|                             ExtraData=str(self))
 | |
|         if "END" in self.TokenList and "END" != self.TokenList[-1]:
 | |
|             EdkLogger.error("GenDepex", PARSER_ERROR, "Extra expressions after END",
 | |
|                             ExtraData=str(self))
 | |
| 
 | |
|     ## Simply optimize the dependency expression by removing duplicated operands
 | |
|     def Optimize(self):
 | |
|         ValidOpcode = list(set(self.OpcodeList))
 | |
|         if len(ValidOpcode) != 1 or ValidOpcode[0] not in ['AND', 'OR']:
 | |
|             return
 | |
|         Op = ValidOpcode[0]
 | |
|         NewOperand = []
 | |
|         AllOperand = set()
 | |
|         for Token in self.PostfixNotation:
 | |
|             if Token in self.SupportedOpcode or Token in NewOperand:
 | |
|                 continue
 | |
|             AllOperand.add(Token)
 | |
|             if Token == 'TRUE':
 | |
|                 if Op == 'AND':
 | |
|                     continue
 | |
|                 else:
 | |
|                     NewOperand.append(Token)
 | |
|                     break
 | |
|             elif Token == 'FALSE':
 | |
|                 if Op == 'OR':
 | |
|                     continue
 | |
|                 else:
 | |
|                     NewOperand.append(Token)
 | |
|                     break
 | |
|             NewOperand.append(Token)
 | |
| 
 | |
|         # don't generate depex if only TRUE operand left
 | |
|         if self.ModuleType == 'PEIM' and len(NewOperand) == 1 and NewOperand[0] == 'TRUE':
 | |
|             self.PostfixNotation = []
 | |
|             return
 | |
| 
 | |
|         # don't generate depex if all operands are architecture protocols
 | |
|         if self.ModuleType in ['UEFI_DRIVER', 'DXE_DRIVER', 'DXE_RUNTIME_DRIVER', 'DXE_SAL_DRIVER', 'DXE_SMM_DRIVER'] and \
 | |
|            Op == 'AND' and \
 | |
|            self.ArchProtocols == set([GuidStructureStringToGuidString(Guid) for Guid in AllOperand]):
 | |
|             self.PostfixNotation = []
 | |
|             return
 | |
| 
 | |
|         if len(NewOperand) == 0:
 | |
|             self.TokenList = list(AllOperand)
 | |
|         else:
 | |
|             self.TokenList = []
 | |
|             while True:
 | |
|                 self.TokenList.append(NewOperand.pop(0))
 | |
|                 if NewOperand == []:
 | |
|                     break
 | |
|                 self.TokenList.append(Op)
 | |
|         self.PostfixNotation = []
 | |
|         self.GetPostfixNotation()
 | |
| 
 | |
| 
 | |
|     ## Convert a GUID value in C structure format into its binary form
 | |
|     #
 | |
|     #   @param  Guid    The GUID value in C structure format
 | |
|     #
 | |
|     #   @retval array   The byte array representing the GUID value
 | |
|     #
 | |
|     def GetGuidValue(self, Guid):
 | |
|         GuidValueString = Guid.replace("{", "").replace("}", "").replace(" ", "")
 | |
|         GuidValueList = GuidValueString.split(",")
 | |
|         if len(GuidValueList) != 11:
 | |
|             EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid GUID value string or opcode: %s" % Guid)
 | |
|         return pack("1I2H8B", *(int(value, 16) for value in GuidValueList))
 | |
| 
 | |
|     ## Save the binary form of dependency expression in file
 | |
|     #
 | |
|     #   @param  File    The path of file. If None is given, put the data on console
 | |
|     #
 | |
|     #   @retval True    If the file doesn't exist or file is changed
 | |
|     #   @retval False   If file exists and is not changed.
 | |
|     #
 | |
|     def Generate(self, File=None):
 | |
|         Buffer = StringIO()
 | |
|         if len(self.PostfixNotation) == 0:
 | |
|             return False
 | |
| 
 | |
|         for Item in self.PostfixNotation:
 | |
|             if Item in self.Opcode[self.Phase]:
 | |
|                 Buffer.write(pack("B", self.Opcode[self.Phase][Item]))
 | |
|             elif Item in self.SupportedOpcode:
 | |
|                 EdkLogger.error("GenDepex", FORMAT_INVALID,
 | |
|                                 "Opcode [%s] is not expected in %s phase" % (Item, self.Phase),
 | |
|                                 ExtraData=self.ExpressionString)
 | |
|             else:
 | |
|                 Buffer.write(self.GetGuidValue(Item))
 | |
| 
 | |
|         FilePath = ""
 | |
|         FileChangeFlag = True
 | |
|         if File == None:
 | |
|             sys.stdout.write(Buffer.getvalue())
 | |
|             FilePath = "STDOUT"
 | |
|         else:
 | |
|             FileChangeFlag = SaveFileOnChange(File, Buffer.getvalue(), True)
 | |
| 
 | |
|         Buffer.close()
 | |
|         return FileChangeFlag
 | |
| 
 | |
| versionNumber = ("0.04" + " " + gBUILD_VERSION)
 | |
| __version__ = "%prog Version " + versionNumber
 | |
| __copyright__ = "Copyright (c) 2007-2010, Intel Corporation  All rights reserved."
 | |
| __usage__ = "%prog [options] [dependency_expression_file]"
 | |
| 
 | |
| ## Parse command line options
 | |
| #
 | |
| #   @retval OptionParser
 | |
| #
 | |
| def GetOptions():
 | |
|     from optparse import OptionParser
 | |
| 
 | |
|     Parser = OptionParser(description=__copyright__, version=__version__, usage=__usage__)
 | |
| 
 | |
|     Parser.add_option("-o", "--output", dest="OutputFile", default=None, metavar="FILE",
 | |
|                       help="Specify the name of depex file to be generated")
 | |
|     Parser.add_option("-t", "--module-type", dest="ModuleType", default=None,
 | |
|                       help="The type of module for which the dependency expression serves")
 | |
|     Parser.add_option("-e", "--dependency-expression", dest="Expression", default="",
 | |
|                       help="The string of dependency expression. If this option presents, the input file will be ignored.")
 | |
|     Parser.add_option("-m", "--optimize", dest="Optimize", default=False, action="store_true",
 | |
|                       help="Do some simple optimization on the expression.")
 | |
|     Parser.add_option("-v", "--verbose", dest="verbose", default=False, action="store_true",
 | |
|                       help="build with verbose information")
 | |
|     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
 | |
|     Parser.add_option("-q", "--quiet", dest="quiet", default=False, action="store_true",
 | |
|                       help="build with little information")
 | |
| 
 | |
|     return Parser.parse_args()
 | |
| 
 | |
| 
 | |
| ## Entrance method
 | |
| #
 | |
| # @retval 0     Tool was successful
 | |
| # @retval 1     Tool failed
 | |
| #
 | |
| def Main():
 | |
|     EdkLogger.Initialize()
 | |
|     Option, Input = GetOptions()
 | |
| 
 | |
|     # Set log level
 | |
|     if Option.quiet:
 | |
|         EdkLogger.SetLevel(EdkLogger.QUIET)
 | |
|     elif Option.verbose:
 | |
|         EdkLogger.SetLevel(EdkLogger.VERBOSE)
 | |
|     elif Option.debug != None:
 | |
|         EdkLogger.SetLevel(Option.debug + 1)
 | |
|     else:
 | |
|         EdkLogger.SetLevel(EdkLogger.INFO)
 | |
| 
 | |
|     try:
 | |
|         if Option.ModuleType == None or Option.ModuleType not in gType2Phase:
 | |
|             EdkLogger.error("GenDepex", OPTION_MISSING, "Module type is not specified or supported")
 | |
| 
 | |
|         DxsFile = ''
 | |
|         if len(Input) > 0 and Option.Expression == "":
 | |
|             DxsFile = Input[0]
 | |
|             DxsString = open(DxsFile, 'r').read().replace("\n", " ").replace("\r", " ")
 | |
|             DxsString = gStartClosePattern.sub("\\1", DxsString)
 | |
|         elif Option.Expression != "":
 | |
|             if Option.Expression[0] == '"':
 | |
|                 DxsString = Option.Expression[1:-1]
 | |
|             else:
 | |
|                 DxsString = Option.Expression
 | |
|         else:
 | |
|             EdkLogger.error("GenDepex", OPTION_MISSING, "No expression string or file given")
 | |
| 
 | |
|         Dpx = DependencyExpression(DxsString, Option.ModuleType, Option.Optimize)
 | |
|         if Option.OutputFile != None:
 | |
|             FileChangeFlag = Dpx.Generate(Option.OutputFile)
 | |
|             if not FileChangeFlag and DxsFile:
 | |
|                 #
 | |
|                 # Touch the output file if its time stamp is older than the original
 | |
|                 # DXS file to avoid re-invoke this tool for the dependency check in build rule.
 | |
|                 #
 | |
|                 if os.stat(DxsFile)[8] > os.stat(Option.OutputFile)[8]:
 | |
|                     os.utime(Option.OutputFile, None)
 | |
|         else:
 | |
|             Dpx.Generate()
 | |
|     except BaseException, X:
 | |
|         EdkLogger.quiet("")
 | |
|         if Option != None and Option.debug != None:
 | |
|             EdkLogger.quiet(traceback.format_exc())
 | |
|         else:
 | |
|             EdkLogger.quiet(str(X))
 | |
|         return 1
 | |
| 
 | |
|     return 0
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     sys.exit(Main())
 | |
| 
 |