2 # This file is used to generate DEPEX file for module's dependency expression
4 # Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 import Common
.LongFilePathOs
as os
19 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
20 from StringIO
import StringIO
21 from struct
import pack
22 from Common
.BuildToolError
import *
23 from Common
.Misc
import SaveFileOnChange
24 from Common
.Misc
import GuidStructureStringToGuidString
25 from Common
import EdkLogger
as EdkLogger
26 from Common
.BuildVersion
import gBUILD_VERSION
27 from Common
.DataType
import *
29 ## Regular expression for matching "DEPENDENCY_START ... DEPENDENCY_END"
30 gStartClosePattern
= re
.compile(".*DEPENDENCY_START(.+)DEPENDENCY_END.*", re
.S
)
32 ## Mapping between module type and EFI phase
34 SUP_MODULE_BASE
: None,
35 SUP_MODULE_SEC
: "PEI",
36 SUP_MODULE_PEI_CORE
: "PEI",
37 SUP_MODULE_PEIM
: "PEI",
38 SUP_MODULE_DXE_CORE
: "DXE",
39 SUP_MODULE_DXE_DRIVER
: "DXE",
40 SUP_MODULE_DXE_SMM_DRIVER
: "DXE",
41 SUP_MODULE_DXE_RUNTIME_DRIVER
: "DXE",
42 SUP_MODULE_DXE_SAL_DRIVER
: "DXE",
43 SUP_MODULE_UEFI_DRIVER
: "DXE",
44 SUP_MODULE_UEFI_APPLICATION
: "DXE",
45 SUP_MODULE_SMM_CORE
: "DXE",
46 SUP_MODULE_MM_STANDALONE
: "MM",
47 SUP_MODULE_MM_CORE_STANDALONE
: "MM",
50 ## Convert dependency expression string into EFI internal representation
52 # DependencyExpression class is used to parse dependency expression string and
53 # convert it into its binary form.
55 class DependencyExpression
:
58 '665e3ff6-46cc-11d4-9a38-0090273fc14d', # 'gEfiBdsArchProtocolGuid'
59 '26baccb1-6f42-11d4-bce7-0080c73c8881', # 'gEfiCpuArchProtocolGuid'
60 '26baccb2-6f42-11d4-bce7-0080c73c8881', # 'gEfiMetronomeArchProtocolGuid'
61 '1da97072-bddc-4b30-99f1-72a0b56fff2a', # 'gEfiMonotonicCounterArchProtocolGuid'
62 '27cfac87-46cc-11d4-9a38-0090273fc14d', # 'gEfiRealTimeClockArchProtocolGuid'
63 '27cfac88-46cc-11d4-9a38-0090273fc14d', # 'gEfiResetArchProtocolGuid'
64 'b7dfb4e1-052f-449f-87be-9818fc91b733', # 'gEfiRuntimeArchProtocolGuid'
65 'a46423e3-4617-49f1-b9ff-d1bfa9115839', # 'gEfiSecurityArchProtocolGuid'
66 '26baccb3-6f42-11d4-bce7-0080c73c8881', # 'gEfiTimerArchProtocolGuid'
67 '6441f818-6362-4e44-b570-7dba31dd2453', # 'gEfiVariableWriteArchProtocolGuid'
68 '1e5668e2-8481-11d4-bcf1-0080c73c8881', # 'gEfiVariableArchProtocolGuid'
69 '665e3ff5-46cc-11d4-9a38-0090273fc14d' # 'gEfiWatchdogTimerArchProtocolGuid'
120 # all supported op codes and operands
121 SupportedOpcode
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "END", "SOR"]
122 SupportedOperand
= ["TRUE", "FALSE"]
124 OpcodeWithSingleOperand
= ['NOT', 'BEFORE', 'AFTER']
125 OpcodeWithTwoOperand
= ['AND', 'OR']
127 # op code that should not be the last one
128 NonEndingOpcode
= ["AND", "OR", "NOT", 'SOR']
129 # op code must not present at the same time
130 ExclusiveOpcode
= ["BEFORE", "AFTER"]
131 # op code that should be the first one if it presents
132 AboveAllOpcode
= ["SOR", "BEFORE", "AFTER"]
135 # open and close brace must be taken as individual tokens
137 TokenPattern
= re
.compile("(\(|\)|\{[^{}]+\{?[^{}]+\}?[ ]*\}|\w+)")
141 # @param Expression The list or string of dependency expression
142 # @param ModuleType The type of the module using the dependency expression
144 def __init__(self
, Expression
, ModuleType
, Optimize
=False):
145 self
.ModuleType
= ModuleType
146 self
.Phase
= gType2Phase
[ModuleType
]
147 if type(Expression
) == type([]):
148 self
.ExpressionString
= " ".join(Expression
)
149 self
.TokenList
= Expression
151 self
.ExpressionString
= Expression
152 self
.GetExpressionTokenList()
154 self
.PostfixNotation
= []
157 self
.GetPostfixNotation()
158 self
.ValidateOpcode()
160 EdkLogger
.debug(EdkLogger
.DEBUG_8
, repr(self
))
163 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "\n Optimized: " + repr(self
))
166 return " ".join(self
.TokenList
)
170 for Token
in self
.PostfixNotation
:
171 if Token
in self
.SupportedOpcode
:
172 WellForm
+= "\n " + Token
174 WellForm
+= ' ' + Token
177 ## Split the expression string into token list
178 def GetExpressionTokenList(self
):
179 self
.TokenList
= self
.TokenPattern
.findall(self
.ExpressionString
)
181 ## Convert token list into postfix notation
182 def GetPostfixNotation(self
):
185 for Token
in self
.TokenList
:
187 if LastToken
not in self
.SupportedOpcode
+ ['(', '', None]:
188 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operator before open parentheses",
189 ExtraData
="Near %s" % LastToken
)
193 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: mismatched parentheses",
195 elif LastToken
in self
.SupportedOpcode
+ ['', None]:
196 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operand before close parentheses",
197 ExtraData
="Near %s" % LastToken
)
198 while len(Stack
) > 0:
202 self
.PostfixNotation
.append(Stack
.pop())
203 elif Token
in self
.OpcodePriority
:
205 if LastToken
not in self
.SupportedOpcode
+ ['(', '', None]:
206 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operator before NOT",
207 ExtraData
="Near %s" % LastToken
)
208 elif LastToken
in self
.SupportedOpcode
+ ['(', '', None]:
209 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operand before " + Token
,
210 ExtraData
="Near %s" % LastToken
)
212 while len(Stack
) > 0:
213 if Stack
[-1] == "(" or self
.OpcodePriority
[Token
] >= self
.OpcodePriority
[Stack
[-1]]:
215 self
.PostfixNotation
.append(Stack
.pop())
217 self
.OpcodeList
.append(Token
)
219 if Token
not in self
.SupportedOpcode
:
220 # not OP, take it as GUID
221 if LastToken
not in self
.SupportedOpcode
+ ['(', '', None]:
222 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operator before %s" % Token
,
223 ExtraData
="Near %s" % LastToken
)
224 if len(self
.OpcodeList
) == 0 or self
.OpcodeList
[-1] not in self
.ExclusiveOpcode
:
225 if Token
not in self
.SupportedOperand
:
226 self
.PostfixNotation
.append("PUSH")
227 # check if OP is valid in this phase
228 elif Token
in self
.Opcode
[self
.Phase
]:
231 self
.OpcodeList
.append(Token
)
233 EdkLogger
.error("GenDepex", PARSER_ERROR
,
234 "Opcode=%s doesn't supported in %s stage " % (Token
, self
.Phase
),
236 self
.PostfixNotation
.append(Token
)
239 # there should not be parentheses in Stack
240 if '(' in Stack
or ')' in Stack
:
241 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: mismatched parentheses",
243 while len(Stack
) > 0:
244 self
.PostfixNotation
.append(Stack
.pop())
245 if self
.PostfixNotation
[-1] != 'END':
246 self
.PostfixNotation
.append("END")
248 ## Validate the dependency expression
249 def ValidateOpcode(self
):
250 for Op
in self
.AboveAllOpcode
:
251 if Op
in self
.PostfixNotation
:
252 if Op
!= self
.PostfixNotation
[0]:
253 EdkLogger
.error("GenDepex", PARSER_ERROR
, "%s should be the first opcode in the expression" % Op
,
255 if len(self
.PostfixNotation
) < 3:
256 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Missing operand for %s" % Op
,
258 for Op
in self
.ExclusiveOpcode
:
259 if Op
in self
.OpcodeList
:
260 if len(self
.OpcodeList
) > 1:
261 EdkLogger
.error("GenDepex", PARSER_ERROR
, "%s should be the only opcode in the expression" % Op
,
263 if len(self
.PostfixNotation
) < 3:
264 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Missing operand for %s" % Op
,
266 if self
.TokenList
[-1] != 'END' and self
.TokenList
[-1] in self
.NonEndingOpcode
:
267 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Extra %s at the end of the dependency expression" % self
.TokenList
[-1],
269 if self
.TokenList
[-1] == 'END' and self
.TokenList
[-2] in self
.NonEndingOpcode
:
270 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Extra %s at the end of the dependency expression" % self
.TokenList
[-2],
272 if "END" in self
.TokenList
and "END" != self
.TokenList
[-1]:
273 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Extra expressions after END",
276 ## Simply optimize the dependency expression by removing duplicated operands
278 ValidOpcode
= list(set(self
.OpcodeList
))
279 if len(ValidOpcode
) != 1 or ValidOpcode
[0] not in ['AND', 'OR']:
284 for Token
in self
.PostfixNotation
:
285 if Token
in self
.SupportedOpcode
or Token
in NewOperand
:
287 AllOperand
.add(Token
)
292 NewOperand
.append(Token
)
294 elif Token
== 'FALSE':
298 NewOperand
.append(Token
)
300 NewOperand
.append(Token
)
302 # don't generate depex if only TRUE operand left
303 if self
.ModuleType
== SUP_MODULE_PEIM
and len(NewOperand
) == 1 and NewOperand
[0] == 'TRUE':
304 self
.PostfixNotation
= []
307 # don't generate depex if all operands are architecture protocols
308 if self
.ModuleType
in [SUP_MODULE_UEFI_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_DXE_RUNTIME_DRIVER
, SUP_MODULE_DXE_SAL_DRIVER
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
] and \
310 self
.ArchProtocols
== set([GuidStructureStringToGuidString(Guid
) for Guid
in AllOperand
]):
311 self
.PostfixNotation
= []
314 if len(NewOperand
) == 0:
315 self
.TokenList
= list(AllOperand
)
319 self
.TokenList
.append(NewOperand
.pop(0))
322 self
.TokenList
.append(Op
)
323 self
.PostfixNotation
= []
324 self
.GetPostfixNotation()
327 ## Convert a GUID value in C structure format into its binary form
329 # @param Guid The GUID value in C structure format
331 # @retval array The byte array representing the GUID value
333 def GetGuidValue(self
, Guid
):
334 GuidValueString
= Guid
.replace("{", "").replace("}", "").replace(" ", "")
335 GuidValueList
= GuidValueString
.split(",")
336 if len(GuidValueList
) != 11:
337 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid GUID value string or opcode: %s" % Guid
)
338 return pack("1I2H8B", *(int(value
, 16) for value
in GuidValueList
))
340 ## Save the binary form of dependency expression in file
342 # @param File The path of file. If None is given, put the data on console
344 # @retval True If the file doesn't exist or file is changed
345 # @retval False If file exists and is not changed.
347 def Generate(self
, File
=None):
349 if len(self
.PostfixNotation
) == 0:
352 for Item
in self
.PostfixNotation
:
353 if Item
in self
.Opcode
[self
.Phase
]:
354 Buffer
.write(pack("B", self
.Opcode
[self
.Phase
][Item
]))
355 elif Item
in self
.SupportedOpcode
:
356 EdkLogger
.error("GenDepex", FORMAT_INVALID
,
357 "Opcode [%s] is not expected in %s phase" % (Item
, self
.Phase
),
358 ExtraData
=self
.ExpressionString
)
360 Buffer
.write(self
.GetGuidValue(Item
))
363 FileChangeFlag
= True
365 sys
.stdout
.write(Buffer
.getvalue())
368 FileChangeFlag
= SaveFileOnChange(File
, Buffer
.getvalue(), True)
371 return FileChangeFlag
373 versionNumber
= ("0.04" + " " + gBUILD_VERSION
)
374 __version__
= "%prog Version " + versionNumber
375 __copyright__
= "Copyright (c) 2007-2010, Intel Corporation All rights reserved."
376 __usage__
= "%prog [options] [dependency_expression_file]"
378 ## Parse command line options
380 # @retval OptionParser
383 from optparse
import OptionParser
385 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, usage
=__usage__
)
387 Parser
.add_option("-o", "--output", dest
="OutputFile", default
=None, metavar
="FILE",
388 help="Specify the name of depex file to be generated")
389 Parser
.add_option("-t", "--module-type", dest
="ModuleType", default
=None,
390 help="The type of module for which the dependency expression serves")
391 Parser
.add_option("-e", "--dependency-expression", dest
="Expression", default
="",
392 help="The string of dependency expression. If this option presents, the input file will be ignored.")
393 Parser
.add_option("-m", "--optimize", dest
="Optimize", default
=False, action
="store_true",
394 help="Do some simple optimization on the expression.")
395 Parser
.add_option("-v", "--verbose", dest
="verbose", default
=False, action
="store_true",
396 help="build with verbose information")
397 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
398 Parser
.add_option("-q", "--quiet", dest
="quiet", default
=False, action
="store_true",
399 help="build with little information")
401 return Parser
.parse_args()
406 # @retval 0 Tool was successful
407 # @retval 1 Tool failed
410 EdkLogger
.Initialize()
411 Option
, Input
= GetOptions()
415 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
417 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
418 elif Option
.debug
is not None:
419 EdkLogger
.SetLevel(Option
.debug
+ 1)
421 EdkLogger
.SetLevel(EdkLogger
.INFO
)
424 if Option
.ModuleType
is None or Option
.ModuleType
not in gType2Phase
:
425 EdkLogger
.error("GenDepex", OPTION_MISSING
, "Module type is not specified or supported")
428 if len(Input
) > 0 and Option
.Expression
== "":
430 DxsString
= open(DxsFile
, 'r').read().replace("\n", " ").replace("\r", " ")
431 DxsString
= gStartClosePattern
.sub("\\1", DxsString
)
432 elif Option
.Expression
!= "":
433 if Option
.Expression
[0] == '"':
434 DxsString
= Option
.Expression
[1:-1]
436 DxsString
= Option
.Expression
438 EdkLogger
.error("GenDepex", OPTION_MISSING
, "No expression string or file given")
440 Dpx
= DependencyExpression(DxsString
, Option
.ModuleType
, Option
.Optimize
)
441 if Option
.OutputFile
is not None:
442 FileChangeFlag
= Dpx
.Generate(Option
.OutputFile
)
443 if not FileChangeFlag
and DxsFile
:
445 # Touch the output file if its time stamp is older than the original
446 # DXS file to avoid re-invoke this tool for the dependency check in build rule.
448 if os
.stat(DxsFile
)[8] > os
.stat(Option
.OutputFile
)[8]:
449 os
.utime(Option
.OutputFile
, None)
452 except BaseException
, X
:
454 if Option
is not None and Option
.debug
is not None:
455 EdkLogger
.quiet(traceback
.format_exc())
457 EdkLogger
.quiet(str(X
))
462 if __name__
== '__main__':