2 # This file is used to generate DEPEX file for module's dependency expression
4 # Copyright (c) 2007, Intel Corporation
5 # All rights reserved. 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.
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
28 ## Regular expression for matching "DEPENDENCY_START ... DEPENDENCY_END"
29 gStartClosePattern
= re
.compile(".*DEPENDENCY_START(.+)DEPENDENCY_END.*", re
.S
)
31 ## Mapping between module type and EFI phase
39 "DXE_SMM_DRIVER" : "DXE",
40 "DXE_RUNTIME_DRIVER": "DXE",
41 "DXE_SAL_DRIVER" : "DXE",
42 "UEFI_DRIVER" : "DXE",
43 "UEFI_APPLICATION" : "DXE",
47 ## Convert dependency expression string into EFI internal representation
49 # DependencyExpression class is used to parse dependency expression string and
50 # convert it into its binary form.
52 class DependencyExpression
:
55 '665e3ff6-46cc-11d4-9a38-0090273fc14d', # 'gEfiBdsArchProtocolGuid'
56 '26baccb1-6f42-11d4-bce7-0080c73c8881', # 'gEfiCpuArchProtocolGuid'
57 '26baccb2-6f42-11d4-bce7-0080c73c8881', # 'gEfiMetronomeArchProtocolGuid'
58 '1da97072-bddc-4b30-99f1-72a0b56fff2a', # 'gEfiMonotonicCounterArchProtocolGuid'
59 '27cfac87-46cc-11d4-9a38-0090273fc14d', # 'gEfiRealTimeClockArchProtocolGuid'
60 '27cfac88-46cc-11d4-9a38-0090273fc14d', # 'gEfiResetArchProtocolGuid'
61 'b7dfb4e1-052f-449f-87be-9818fc91b733', # 'gEfiRuntimeArchProtocolGuid'
62 'a46423e3-4617-49f1-b9ff-d1bfa9115839', # 'gEfiSecurityArchProtocolGuid'
63 '26baccb3-6f42-11d4-bce7-0080c73c8881', # 'gEfiTimerArchProtocolGuid'
64 '6441f818-6362-4e44-b570-7dba31dd2453', # 'gEfiVariableWriteArchProtocolGuid'
65 '1e5668e2-8481-11d4-bcf1-0080c73c8881', # 'gEfiVariableArchProtocolGuid'
66 '665e3ff5-46cc-11d4-9a38-0090273fc14d' # 'gEfiWatchdogTimerArchProtocolGuid'
104 # all supported op codes and operands
105 SupportedOpcode
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "END", "SOR"]
106 SupportedOperand
= ["TRUE", "FALSE"]
108 OpcodeWithSingleOperand
= ['NOT', 'BEFORE', 'AFTER']
109 OpcodeWithTwoOperand
= ['AND', 'OR']
111 # op code that should not be the last one
112 NonEndingOpcode
= ["AND", "OR", "NOT", 'SOR']
113 # op code must not present at the same time
114 ExclusiveOpcode
= ["BEFORE", "AFTER"]
115 # op code that should be the first one if it presents
116 AboveAllOpcode
= ["SOR", "BEFORE", "AFTER"]
119 # open and close brace must be taken as individual tokens
121 TokenPattern
= re
.compile("(\(|\)|\{[^{}]+\{?[^{}]+\}?[ ]*\}|\w+)")
125 # @param Expression The list or string of dependency expression
126 # @param ModuleType The type of the module using the dependency expression
128 def __init__(self
, Expression
, ModuleType
, Optimize
=False):
129 self
.ModuleType
= ModuleType
130 self
.Phase
= gType2Phase
[ModuleType
]
131 if type(Expression
) == type([]):
132 self
.ExpressionString
= " ".join(Expression
)
133 self
.TokenList
= Expression
135 self
.ExpressionString
= Expression
136 self
.GetExpressionTokenList()
138 self
.PostfixNotation
= []
141 self
.GetPostfixNotation()
142 self
.ValidateOpcode()
144 EdkLogger
.debug(EdkLogger
.DEBUG_8
, repr(self
))
147 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "\n Optimized: " + repr(self
))
150 return " ".join(self
.TokenList
)
154 for Token
in self
.PostfixNotation
:
155 if Token
in self
.SupportedOpcode
:
156 WellForm
+= "\n " + Token
158 WellForm
+= ' ' + Token
161 ## Split the expression string into token list
162 def GetExpressionTokenList(self
):
163 self
.TokenList
= self
.TokenPattern
.findall(self
.ExpressionString
)
165 ## Convert token list into postfix notation
166 def GetPostfixNotation(self
):
169 for Token
in self
.TokenList
:
171 if LastToken
not in self
.SupportedOpcode
+ ['(', '', None]:
172 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operator before open parentheses",
173 ExtraData
="Near %s" % LastToken
)
177 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: mismatched parentheses",
179 elif LastToken
in self
.SupportedOpcode
+ ['', None]:
180 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operand before close parentheses",
181 ExtraData
="Near %s" % LastToken
)
182 while len(Stack
) > 0:
186 self
.PostfixNotation
.append(Stack
.pop())
187 elif Token
in self
.OpcodePriority
:
189 if LastToken
not in self
.SupportedOpcode
+ ['(', '', None]:
190 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operator before NOT",
191 ExtraData
="Near %s" % LastToken
)
192 elif LastToken
in self
.SupportedOpcode
+ ['(', '', None]:
193 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operand before " + Token
,
194 ExtraData
="Near %s" % LastToken
)
196 while len(Stack
) > 0:
197 if Stack
[-1] == "(" or self
.OpcodePriority
[Token
] >= self
.OpcodePriority
[Stack
[-1]]:
199 self
.PostfixNotation
.append(Stack
.pop())
201 self
.OpcodeList
.append(Token
)
203 if Token
not in self
.SupportedOpcode
:
204 # not OP, take it as GUID
205 if LastToken
not in self
.SupportedOpcode
+ ['(', '', None]:
206 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: missing operator before %s" % Token
,
207 ExtraData
="Near %s" % LastToken
)
208 if len(self
.OpcodeList
) == 0 or self
.OpcodeList
[-1] not in self
.ExclusiveOpcode
:
209 if Token
not in self
.SupportedOperand
:
210 self
.PostfixNotation
.append("PUSH")
211 # check if OP is valid in this phase
212 elif Token
in self
.Opcode
[self
.Phase
]:
215 self
.OpcodeList
.append(Token
)
217 EdkLogger
.error("GenDepex", PARSER_ERROR
,
218 "Opcode=%s doesn't supported in %s stage " % (Token
, self
.Phase
),
220 self
.PostfixNotation
.append(Token
)
223 # there should not be parentheses in Stack
224 if '(' in Stack
or ')' in Stack
:
225 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid dependency expression: mismatched parentheses",
227 while len(Stack
) > 0:
228 self
.PostfixNotation
.append(Stack
.pop())
229 if self
.PostfixNotation
[-1] != 'END':
230 self
.PostfixNotation
.append("END")
232 ## Validate the dependency expression
233 def ValidateOpcode(self
):
234 for Op
in self
.AboveAllOpcode
:
235 if Op
in self
.PostfixNotation
:
236 if Op
!= self
.PostfixNotation
[0]:
237 EdkLogger
.error("GenDepex", PARSER_ERROR
, "%s should be the first opcode in the expression" % Op
,
239 if len(self
.PostfixNotation
) < 3:
240 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Missing operand for %s" % Op
,
242 for Op
in self
.ExclusiveOpcode
:
243 if Op
in self
.OpcodeList
:
244 if len(self
.OpcodeList
) > 1:
245 EdkLogger
.error("GenDepex", PARSER_ERROR
, "%s should be the only opcode in the expression" % Op
,
247 if len(self
.PostfixNotation
) < 3:
248 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Missing operand for %s" % Op
,
250 if self
.TokenList
[-1] != 'END' and self
.TokenList
[-1] in self
.NonEndingOpcode
:
251 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Extra %s at the end of the dependency expression" % self
.TokenList
[-1],
253 if self
.TokenList
[-1] == 'END' and self
.TokenList
[-2] in self
.NonEndingOpcode
:
254 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Extra %s at the end of the dependency expression" % self
.TokenList
[-2],
256 if "END" in self
.TokenList
and "END" != self
.TokenList
[-1]:
257 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Extra expressions after END",
260 ## Simply optimize the dependency expression by removing duplicated operands
262 ValidOpcode
= list(set(self
.OpcodeList
))
263 if len(ValidOpcode
) != 1 or ValidOpcode
[0] not in ['AND', 'OR']:
268 for Token
in self
.PostfixNotation
:
269 if Token
in self
.SupportedOpcode
or Token
in NewOperand
:
271 AllOperand
.add(Token
)
276 NewOperand
.append(Token
)
278 elif Token
== 'FALSE':
282 NewOperand
.append(Token
)
284 NewOperand
.append(Token
)
286 # don't generate depex if only TRUE operand left
287 if self
.ModuleType
== 'PEIM' and len(NewOperand
) == 1 and NewOperand
[0] == 'TRUE':
288 self
.PostfixNotation
= []
291 # don't generate depex if all operands are architecture protocols
292 if self
.ModuleType
in ['UEFI_DRIVER', 'DXE_DRIVER', 'DXE_RUNTIME_DRIVER', 'DXE_SAL_DRIVER', 'DXE_SMM_DRIVER'] and \
294 self
.ArchProtocols
== set([GuidStructureStringToGuidString(Guid
) for Guid
in AllOperand
]):
295 self
.PostfixNotation
= []
298 if len(NewOperand
) == 0:
299 self
.TokenList
= list(AllOperand
)
303 self
.TokenList
.append(NewOperand
.pop(0))
306 self
.TokenList
.append(Op
)
307 self
.PostfixNotation
= []
308 self
.GetPostfixNotation()
311 ## Convert a GUID value in C structure format into its binary form
313 # @param Guid The GUID value in C structure format
315 # @retval array The byte array representing the GUID value
317 def GetGuidValue(self
, Guid
):
318 GuidValueString
= Guid
.replace("{", "").replace("}", "").replace(" ", "")
319 GuidValueList
= GuidValueString
.split(",")
320 if len(GuidValueList
) != 11:
321 EdkLogger
.error("GenDepex", PARSER_ERROR
, "Invalid GUID value string or opcode: %s" % Guid
)
322 return pack("1I2H8B", *(int(value
, 16) for value
in GuidValueList
))
324 ## Save the binary form of dependency expression in file
326 # @param File The path of file. If None is given, put the data on console
328 # @retval True If the file doesn't exist or file is changed
329 # @retval False If file exists and is not changed.
331 def Generate(self
, File
=None):
333 if len(self
.PostfixNotation
) == 0:
336 for Item
in self
.PostfixNotation
:
337 if Item
in self
.Opcode
[self
.Phase
]:
338 Buffer
.write(pack("B", self
.Opcode
[self
.Phase
][Item
]))
339 elif Item
in self
.SupportedOpcode
:
340 EdkLogger
.error("GenDepex", FORMAT_INVALID
,
341 "Opcode [%s] is not expected in %s phase" % (Item
, self
.Phase
),
342 ExtraData
=self
.ExpressionString
)
344 Buffer
.write(self
.GetGuidValue(Item
))
347 FileChangeFlag
= True
349 sys
.stdout
.write(Buffer
.getvalue())
352 FileChangeFlag
= SaveFileOnChange(File
, Buffer
.getvalue(), True)
355 return FileChangeFlag
357 versionNumber
= "0.04"
358 __version__
= "%prog Version " + versionNumber
359 __copyright__
= "Copyright (c) 2007-2008, Intel Corporation All rights reserved."
360 __usage__
= "%prog [options] [dependency_expression_file]"
362 ## Parse command line options
364 # @retval OptionParser
367 from optparse
import OptionParser
369 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, usage
=__usage__
)
371 Parser
.add_option("-o", "--output", dest
="OutputFile", default
=None, metavar
="FILE",
372 help="Specify the name of depex file to be generated")
373 Parser
.add_option("-t", "--module-type", dest
="ModuleType", default
=None,
374 help="The type of module for which the dependency expression serves")
375 Parser
.add_option("-e", "--dependency-expression", dest
="Expression", default
="",
376 help="The string of dependency expression. If this option presents, the input file will be ignored.")
377 Parser
.add_option("-m", "--optimize", dest
="Optimize", default
=False, action
="store_true",
378 help="Do some simple optimization on the expression.")
379 Parser
.add_option("-v", "--verbose", dest
="verbose", default
=False, action
="store_true",
380 help="build with verbose information")
381 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
382 Parser
.add_option("-q", "--quiet", dest
="quiet", default
=False, action
="store_true",
383 help="build with little information")
385 return Parser
.parse_args()
390 # @retval 0 Tool was successful
391 # @retval 1 Tool failed
394 EdkLogger
.Initialize()
395 Option
, Input
= GetOptions()
399 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
401 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
402 elif Option
.debug
!= None:
403 EdkLogger
.SetLevel(Option
.debug
+ 1)
405 EdkLogger
.SetLevel(EdkLogger
.INFO
)
408 if Option
.ModuleType
== None or Option
.ModuleType
not in gType2Phase
:
409 EdkLogger
.error("GenDepex", OPTION_MISSING
, "Module type is not specified or supported")
412 if len(Input
) > 0 and Option
.Expression
== "":
414 DxsString
= open(DxsFile
, 'r').read().replace("\n", " ").replace("\r", " ")
415 DxsString
= gStartClosePattern
.sub("\\1", DxsString
)
416 elif Option
.Expression
!= "":
417 if Option
.Expression
[0] == '"':
418 DxsString
= Option
.Expression
[1:-1]
420 DxsString
= Option
.Expression
422 EdkLogger
.error("GenDepex", OPTION_MISSING
, "No expression string or file given")
424 Dpx
= DependencyExpression(DxsString
, Option
.ModuleType
, Option
.Optimize
)
425 if Option
.OutputFile
!= None:
426 Dpx
.Generate(Option
.OutputFile
)
429 except BaseException
, X
:
431 if Option
!= None and Option
.debug
!= None:
432 EdkLogger
.quiet(traceback
.format_exc())
434 EdkLogger
.quiet(str(X
))
439 if __name__
== '__main__':