]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/AutoGen/GenDepex.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / GenDepex.py
... / ...
CommitLineData
1## @file\r
2# This file is used to generate DEPEX file for module's dependency expression\r
3#\r
4# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
5# SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7## Import Modules\r
8#\r
9import sys\r
10import Common.LongFilePathOs as os\r
11import re\r
12import traceback\r
13from Common.LongFilePathSupport import OpenLongFilePath as open\r
14from io import BytesIO\r
15from struct import pack\r
16from Common.BuildToolError import *\r
17from Common.Misc import SaveFileOnChange\r
18from Common.Misc import GuidStructureStringToGuidString\r
19from Common.Misc import GuidStructureByteArrayToGuidString\r
20from Common.Misc import GuidStringToGuidStructureString\r
21from Common import EdkLogger as EdkLogger\r
22from Common.BuildVersion import gBUILD_VERSION\r
23from Common.DataType import *\r
24\r
25## Regular expression for matching "DEPENDENCY_START ... DEPENDENCY_END"\r
26gStartClosePattern = re.compile(".*DEPENDENCY_START(.+)DEPENDENCY_END.*", re.S)\r
27\r
28## Mapping between module type and EFI phase\r
29gType2Phase = {\r
30 SUP_MODULE_BASE : None,\r
31 SUP_MODULE_SEC : "PEI",\r
32 SUP_MODULE_PEI_CORE : "PEI",\r
33 SUP_MODULE_PEIM : "PEI",\r
34 SUP_MODULE_DXE_CORE : "DXE",\r
35 SUP_MODULE_DXE_DRIVER : "DXE",\r
36 SUP_MODULE_DXE_SMM_DRIVER : "DXE",\r
37 SUP_MODULE_DXE_RUNTIME_DRIVER: "DXE",\r
38 SUP_MODULE_DXE_SAL_DRIVER : "DXE",\r
39 SUP_MODULE_UEFI_DRIVER : "DXE",\r
40 SUP_MODULE_UEFI_APPLICATION : "DXE",\r
41 SUP_MODULE_SMM_CORE : "DXE",\r
42 SUP_MODULE_MM_STANDALONE : "MM",\r
43 SUP_MODULE_MM_CORE_STANDALONE : "MM",\r
44}\r
45\r
46## Convert dependency expression string into EFI internal representation\r
47#\r
48# DependencyExpression class is used to parse dependency expression string and\r
49# convert it into its binary form.\r
50#\r
51class DependencyExpression:\r
52\r
53 ArchProtocols = {\r
54 '665e3ff6-46cc-11d4-9a38-0090273fc14d', # 'gEfiBdsArchProtocolGuid'\r
55 '26baccb1-6f42-11d4-bce7-0080c73c8881', # 'gEfiCpuArchProtocolGuid'\r
56 '26baccb2-6f42-11d4-bce7-0080c73c8881', # 'gEfiMetronomeArchProtocolGuid'\r
57 '1da97072-bddc-4b30-99f1-72a0b56fff2a', # 'gEfiMonotonicCounterArchProtocolGuid'\r
58 '27cfac87-46cc-11d4-9a38-0090273fc14d', # 'gEfiRealTimeClockArchProtocolGuid'\r
59 '27cfac88-46cc-11d4-9a38-0090273fc14d', # 'gEfiResetArchProtocolGuid'\r
60 'b7dfb4e1-052f-449f-87be-9818fc91b733', # 'gEfiRuntimeArchProtocolGuid'\r
61 'a46423e3-4617-49f1-b9ff-d1bfa9115839', # 'gEfiSecurityArchProtocolGuid'\r
62 '26baccb3-6f42-11d4-bce7-0080c73c8881', # 'gEfiTimerArchProtocolGuid'\r
63 '6441f818-6362-4e44-b570-7dba31dd2453', # 'gEfiVariableWriteArchProtocolGuid'\r
64 '1e5668e2-8481-11d4-bcf1-0080c73c8881', # 'gEfiVariableArchProtocolGuid'\r
65 '665e3ff5-46cc-11d4-9a38-0090273fc14d' # 'gEfiWatchdogTimerArchProtocolGuid'\r
66 }\r
67\r
68 OpcodePriority = {\r
69 DEPEX_OPCODE_AND : 1,\r
70 DEPEX_OPCODE_OR : 1,\r
71 DEPEX_OPCODE_NOT : 2,\r
72 }\r
73\r
74 Opcode = {\r
75 "PEI" : {\r
76 DEPEX_OPCODE_PUSH : 0x02,\r
77 DEPEX_OPCODE_AND : 0x03,\r
78 DEPEX_OPCODE_OR : 0x04,\r
79 DEPEX_OPCODE_NOT : 0x05,\r
80 DEPEX_OPCODE_TRUE : 0x06,\r
81 DEPEX_OPCODE_FALSE : 0x07,\r
82 DEPEX_OPCODE_END : 0x08\r
83 },\r
84\r
85 "DXE" : {\r
86 DEPEX_OPCODE_BEFORE: 0x00,\r
87 DEPEX_OPCODE_AFTER : 0x01,\r
88 DEPEX_OPCODE_PUSH : 0x02,\r
89 DEPEX_OPCODE_AND : 0x03,\r
90 DEPEX_OPCODE_OR : 0x04,\r
91 DEPEX_OPCODE_NOT : 0x05,\r
92 DEPEX_OPCODE_TRUE : 0x06,\r
93 DEPEX_OPCODE_FALSE : 0x07,\r
94 DEPEX_OPCODE_END : 0x08,\r
95 DEPEX_OPCODE_SOR : 0x09\r
96 },\r
97\r
98 "MM" : {\r
99 DEPEX_OPCODE_BEFORE: 0x00,\r
100 DEPEX_OPCODE_AFTER : 0x01,\r
101 DEPEX_OPCODE_PUSH : 0x02,\r
102 DEPEX_OPCODE_AND : 0x03,\r
103 DEPEX_OPCODE_OR : 0x04,\r
104 DEPEX_OPCODE_NOT : 0x05,\r
105 DEPEX_OPCODE_TRUE : 0x06,\r
106 DEPEX_OPCODE_FALSE : 0x07,\r
107 DEPEX_OPCODE_END : 0x08,\r
108 DEPEX_OPCODE_SOR : 0x09\r
109 }\r
110 }\r
111\r
112 # all supported op codes and operands\r
113 SupportedOpcode = [DEPEX_OPCODE_BEFORE, DEPEX_OPCODE_AFTER, DEPEX_OPCODE_PUSH, DEPEX_OPCODE_AND, DEPEX_OPCODE_OR, DEPEX_OPCODE_NOT, DEPEX_OPCODE_END, DEPEX_OPCODE_SOR]\r
114 SupportedOperand = [DEPEX_OPCODE_TRUE, DEPEX_OPCODE_FALSE]\r
115\r
116 OpcodeWithSingleOperand = [DEPEX_OPCODE_NOT, DEPEX_OPCODE_BEFORE, DEPEX_OPCODE_AFTER]\r
117 OpcodeWithTwoOperand = [DEPEX_OPCODE_AND, DEPEX_OPCODE_OR]\r
118\r
119 # op code that should not be the last one\r
120 NonEndingOpcode = [DEPEX_OPCODE_AND, DEPEX_OPCODE_OR, DEPEX_OPCODE_NOT, DEPEX_OPCODE_SOR]\r
121 # op code must not present at the same time\r
122 ExclusiveOpcode = [DEPEX_OPCODE_BEFORE, DEPEX_OPCODE_AFTER]\r
123 # op code that should be the first one if it presents\r
124 AboveAllOpcode = [DEPEX_OPCODE_SOR, DEPEX_OPCODE_BEFORE, DEPEX_OPCODE_AFTER]\r
125\r
126 #\r
127 # open and close brace must be taken as individual tokens\r
128 #\r
129 TokenPattern = re.compile("(\(|\)|\{[^{}]+\{?[^{}]+\}?[ ]*\}|\w+)")\r
130\r
131 ## Constructor\r
132 #\r
133 # @param Expression The list or string of dependency expression\r
134 # @param ModuleType The type of the module using the dependency expression\r
135 #\r
136 def __init__(self, Expression, ModuleType, Optimize=False):\r
137 self.ModuleType = ModuleType\r
138 self.Phase = gType2Phase[ModuleType]\r
139 if isinstance(Expression, type([])):\r
140 self.ExpressionString = " ".join(Expression)\r
141 self.TokenList = Expression\r
142 else:\r
143 self.ExpressionString = Expression\r
144 self.GetExpressionTokenList()\r
145\r
146 self.PostfixNotation = []\r
147 self.OpcodeList = []\r
148\r
149 self.GetPostfixNotation()\r
150 self.ValidateOpcode()\r
151\r
152 EdkLogger.debug(EdkLogger.DEBUG_8, repr(self))\r
153 if Optimize:\r
154 self.Optimize()\r
155 EdkLogger.debug(EdkLogger.DEBUG_8, "\n Optimized: " + repr(self))\r
156\r
157 def __str__(self):\r
158 return " ".join(self.TokenList)\r
159\r
160 def __repr__(self):\r
161 WellForm = ''\r
162 for Token in self.PostfixNotation:\r
163 if Token in self.SupportedOpcode:\r
164 WellForm += "\n " + Token\r
165 else:\r
166 WellForm += ' ' + Token\r
167 return WellForm\r
168\r
169 ## Split the expression string into token list\r
170 def GetExpressionTokenList(self):\r
171 self.TokenList = self.TokenPattern.findall(self.ExpressionString)\r
172\r
173 ## Convert token list into postfix notation\r
174 def GetPostfixNotation(self):\r
175 Stack = []\r
176 LastToken = ''\r
177 for Token in self.TokenList:\r
178 if Token == "(":\r
179 if LastToken not in self.SupportedOpcode + ['(', '', None]:\r
180 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before open parentheses",\r
181 ExtraData="Near %s" % LastToken)\r
182 Stack.append(Token)\r
183 elif Token == ")":\r
184 if '(' not in Stack:\r
185 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: mismatched parentheses",\r
186 ExtraData=str(self))\r
187 elif LastToken in self.SupportedOpcode + ['', None]:\r
188 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operand before close parentheses",\r
189 ExtraData="Near %s" % LastToken)\r
190 while len(Stack) > 0:\r
191 if Stack[-1] == '(':\r
192 Stack.pop()\r
193 break\r
194 self.PostfixNotation.append(Stack.pop())\r
195 elif Token in self.OpcodePriority:\r
196 if Token == DEPEX_OPCODE_NOT:\r
197 if LastToken not in self.SupportedOpcode + ['(', '', None]:\r
198 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before NOT",\r
199 ExtraData="Near %s" % LastToken)\r
200 elif LastToken in self.SupportedOpcode + ['(', '', None]:\r
201 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operand before " + Token,\r
202 ExtraData="Near %s" % LastToken)\r
203\r
204 while len(Stack) > 0:\r
205 if Stack[-1] == "(" or self.OpcodePriority[Token] >= self.OpcodePriority[Stack[-1]]:\r
206 break\r
207 self.PostfixNotation.append(Stack.pop())\r
208 Stack.append(Token)\r
209 self.OpcodeList.append(Token)\r
210 else:\r
211 if Token not in self.SupportedOpcode:\r
212 # not OP, take it as GUID\r
213 if LastToken not in self.SupportedOpcode + ['(', '', None]:\r
214 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before %s" % Token,\r
215 ExtraData="Near %s" % LastToken)\r
216 if len(self.OpcodeList) == 0 or self.OpcodeList[-1] not in self.ExclusiveOpcode:\r
217 if Token not in self.SupportedOperand:\r
218 self.PostfixNotation.append(DEPEX_OPCODE_PUSH)\r
219 # check if OP is valid in this phase\r
220 elif Token in self.Opcode[self.Phase]:\r
221 if Token == DEPEX_OPCODE_END:\r
222 break\r
223 self.OpcodeList.append(Token)\r
224 else:\r
225 EdkLogger.error("GenDepex", PARSER_ERROR,\r
226 "Opcode=%s doesn't supported in %s stage " % (Token, self.Phase),\r
227 ExtraData=str(self))\r
228 self.PostfixNotation.append(Token)\r
229 LastToken = Token\r
230\r
231 # there should not be parentheses in Stack\r
232 if '(' in Stack or ')' in Stack:\r
233 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: mismatched parentheses",\r
234 ExtraData=str(self))\r
235 while len(Stack) > 0:\r
236 self.PostfixNotation.append(Stack.pop())\r
237 if self.PostfixNotation[-1] != DEPEX_OPCODE_END:\r
238 self.PostfixNotation.append(DEPEX_OPCODE_END)\r
239\r
240 ## Validate the dependency expression\r
241 def ValidateOpcode(self):\r
242 for Op in self.AboveAllOpcode:\r
243 if Op in self.PostfixNotation:\r
244 if Op != self.PostfixNotation[0]:\r
245 EdkLogger.error("GenDepex", PARSER_ERROR, "%s should be the first opcode in the expression" % Op,\r
246 ExtraData=str(self))\r
247 if len(self.PostfixNotation) < 3:\r
248 EdkLogger.error("GenDepex", PARSER_ERROR, "Missing operand for %s" % Op,\r
249 ExtraData=str(self))\r
250 for Op in self.ExclusiveOpcode:\r
251 if Op in self.OpcodeList:\r
252 if len(self.OpcodeList) > 1:\r
253 EdkLogger.error("GenDepex", PARSER_ERROR, "%s should be the only opcode in the expression" % Op,\r
254 ExtraData=str(self))\r
255 if len(self.PostfixNotation) < 3:\r
256 EdkLogger.error("GenDepex", PARSER_ERROR, "Missing operand for %s" % Op,\r
257 ExtraData=str(self))\r
258 if self.TokenList[-1] != DEPEX_OPCODE_END and self.TokenList[-1] in self.NonEndingOpcode:\r
259 EdkLogger.error("GenDepex", PARSER_ERROR, "Extra %s at the end of the dependency expression" % self.TokenList[-1],\r
260 ExtraData=str(self))\r
261 if self.TokenList[-1] == DEPEX_OPCODE_END and self.TokenList[-2] in self.NonEndingOpcode:\r
262 EdkLogger.error("GenDepex", PARSER_ERROR, "Extra %s at the end of the dependency expression" % self.TokenList[-2],\r
263 ExtraData=str(self))\r
264 if DEPEX_OPCODE_END in self.TokenList and DEPEX_OPCODE_END != self.TokenList[-1]:\r
265 EdkLogger.error("GenDepex", PARSER_ERROR, "Extra expressions after END",\r
266 ExtraData=str(self))\r
267\r
268 ## Simply optimize the dependency expression by removing duplicated operands\r
269 def Optimize(self):\r
270 OpcodeSet = set(self.OpcodeList)\r
271 # if there are isn't one in the set, return\r
272 if len(OpcodeSet) != 1:\r
273 return\r
274 Op = OpcodeSet.pop()\r
275 #if Op isn't either OR or AND, return\r
276 if Op not in [DEPEX_OPCODE_AND, DEPEX_OPCODE_OR]:\r
277 return\r
278 NewOperand = []\r
279 AllOperand = set()\r
280 for Token in self.PostfixNotation:\r
281 if Token in self.SupportedOpcode or Token in NewOperand:\r
282 continue\r
283 AllOperand.add(Token)\r
284 if Token == DEPEX_OPCODE_TRUE:\r
285 if Op == DEPEX_OPCODE_AND:\r
286 continue\r
287 else:\r
288 NewOperand.append(Token)\r
289 break\r
290 elif Token == DEPEX_OPCODE_FALSE:\r
291 if Op == DEPEX_OPCODE_OR:\r
292 continue\r
293 else:\r
294 NewOperand.append(Token)\r
295 break\r
296 NewOperand.append(Token)\r
297\r
298 # don't generate depex if only TRUE operand left\r
299 if self.ModuleType == SUP_MODULE_PEIM and len(NewOperand) == 1 and NewOperand[0] == DEPEX_OPCODE_TRUE:\r
300 self.PostfixNotation = []\r
301 return\r
302\r
303 # don't generate depex if all operands are architecture protocols\r
304 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 \\r
305 Op == DEPEX_OPCODE_AND and \\r
306 self.ArchProtocols == set(GuidStructureStringToGuidString(Guid) for Guid in AllOperand):\r
307 self.PostfixNotation = []\r
308 return\r
309\r
310 if len(NewOperand) == 0:\r
311 self.TokenList = list(AllOperand)\r
312 else:\r
313 self.TokenList = []\r
314 while True:\r
315 self.TokenList.append(NewOperand.pop(0))\r
316 if NewOperand == []:\r
317 break\r
318 self.TokenList.append(Op)\r
319 self.PostfixNotation = []\r
320 self.GetPostfixNotation()\r
321\r
322\r
323 ## Convert a GUID value in C structure format into its binary form\r
324 #\r
325 # @param Guid The GUID value in C structure format\r
326 #\r
327 # @retval array The byte array representing the GUID value\r
328 #\r
329 def GetGuidValue(self, Guid):\r
330 GuidValueString = Guid.replace("{", "").replace("}", "").replace(" ", "")\r
331 GuidValueList = GuidValueString.split(",")\r
332 if len(GuidValueList) != 11 and len(GuidValueList) == 16:\r
333 GuidValueString = GuidStringToGuidStructureString(GuidStructureByteArrayToGuidString(Guid))\r
334 GuidValueString = GuidValueString.replace("{", "").replace("}", "").replace(" ", "")\r
335 GuidValueList = GuidValueString.split(",")\r
336 if len(GuidValueList) != 11:\r
337 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid GUID value string or opcode: %s" % Guid)\r
338 return pack("1I2H8B", *(int(value, 16) for value in GuidValueList))\r
339\r
340 ## Save the binary form of dependency expression in file\r
341 #\r
342 # @param File The path of file. If None is given, put the data on console\r
343 #\r
344 # @retval True If the file doesn't exist or file is changed\r
345 # @retval False If file exists and is not changed.\r
346 #\r
347 def Generate(self, File=None):\r
348 Buffer = BytesIO()\r
349 if len(self.PostfixNotation) == 0:\r
350 return False\r
351\r
352 for Item in self.PostfixNotation:\r
353 if Item in self.Opcode[self.Phase]:\r
354 Buffer.write(pack("B", self.Opcode[self.Phase][Item]))\r
355 elif Item in self.SupportedOpcode:\r
356 EdkLogger.error("GenDepex", FORMAT_INVALID,\r
357 "Opcode [%s] is not expected in %s phase" % (Item, self.Phase),\r
358 ExtraData=self.ExpressionString)\r
359 else:\r
360 Buffer.write(self.GetGuidValue(Item))\r
361\r
362 FilePath = ""\r
363 FileChangeFlag = True\r
364 if File is None:\r
365 sys.stdout.write(Buffer.getvalue())\r
366 FilePath = "STDOUT"\r
367 else:\r
368 FileChangeFlag = SaveFileOnChange(File, Buffer.getvalue(), True)\r
369\r
370 Buffer.close()\r
371 return FileChangeFlag\r
372\r
373versionNumber = ("0.04" + " " + gBUILD_VERSION)\r
374__version__ = "%prog Version " + versionNumber\r
375__copyright__ = "Copyright (c) 2007-2018, Intel Corporation All rights reserved."\r
376__usage__ = "%prog [options] [dependency_expression_file]"\r
377\r
378## Parse command line options\r
379#\r
380# @retval OptionParser\r
381#\r
382def GetOptions():\r
383 from optparse import OptionParser\r
384\r
385 Parser = OptionParser(description=__copyright__, version=__version__, usage=__usage__)\r
386\r
387 Parser.add_option("-o", "--output", dest="OutputFile", default=None, metavar="FILE",\r
388 help="Specify the name of depex file to be generated")\r
389 Parser.add_option("-t", "--module-type", dest="ModuleType", default=None,\r
390 help="The type of module for which the dependency expression serves")\r
391 Parser.add_option("-e", "--dependency-expression", dest="Expression", default="",\r
392 help="The string of dependency expression. If this option presents, the input file will be ignored.")\r
393 Parser.add_option("-m", "--optimize", dest="Optimize", default=False, action="store_true",\r
394 help="Do some simple optimization on the expression.")\r
395 Parser.add_option("-v", "--verbose", dest="verbose", default=False, action="store_true",\r
396 help="build with verbose information")\r
397 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
398 Parser.add_option("-q", "--quiet", dest="quiet", default=False, action="store_true",\r
399 help="build with little information")\r
400\r
401 return Parser.parse_args()\r
402\r
403\r
404## Entrance method\r
405#\r
406# @retval 0 Tool was successful\r
407# @retval 1 Tool failed\r
408#\r
409def Main():\r
410 EdkLogger.Initialize()\r
411 Option, Input = GetOptions()\r
412\r
413 # Set log level\r
414 if Option.quiet:\r
415 EdkLogger.SetLevel(EdkLogger.QUIET)\r
416 elif Option.verbose:\r
417 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
418 elif Option.debug is not None:\r
419 EdkLogger.SetLevel(Option.debug + 1)\r
420 else:\r
421 EdkLogger.SetLevel(EdkLogger.INFO)\r
422\r
423 try:\r
424 if Option.ModuleType is None or Option.ModuleType not in gType2Phase:\r
425 EdkLogger.error("GenDepex", OPTION_MISSING, "Module type is not specified or supported")\r
426\r
427 DxsFile = ''\r
428 if len(Input) > 0 and Option.Expression == "":\r
429 DxsFile = Input[0]\r
430 DxsString = open(DxsFile, 'r').read().replace("\n", " ").replace("\r", " ")\r
431 DxsString = gStartClosePattern.sub("\\1", DxsString)\r
432 elif Option.Expression != "":\r
433 if Option.Expression[0] == '"':\r
434 DxsString = Option.Expression[1:-1]\r
435 else:\r
436 DxsString = Option.Expression\r
437 else:\r
438 EdkLogger.error("GenDepex", OPTION_MISSING, "No expression string or file given")\r
439\r
440 Dpx = DependencyExpression(DxsString, Option.ModuleType, Option.Optimize)\r
441 if Option.OutputFile is not None:\r
442 FileChangeFlag = Dpx.Generate(Option.OutputFile)\r
443 if not FileChangeFlag and DxsFile:\r
444 #\r
445 # Touch the output file if its time stamp is older than the original\r
446 # DXS file to avoid re-invoke this tool for the dependency check in build rule.\r
447 #\r
448 if os.stat(DxsFile)[8] > os.stat(Option.OutputFile)[8]:\r
449 os.utime(Option.OutputFile, None)\r
450 else:\r
451 Dpx.Generate()\r
452 except BaseException as X:\r
453 EdkLogger.quiet("")\r
454 if Option is not None and Option.debug is not None:\r
455 EdkLogger.quiet(traceback.format_exc())\r
456 else:\r
457 EdkLogger.quiet(str(X))\r
458 return 1\r
459\r
460 return 0\r
461\r
462if __name__ == '__main__':\r
463 sys.exit(Main())\r
464\r