]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/Common/Misc.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / Python / Common / Misc.py
... / ...
CommitLineData
1## @file\r
2# Common routines used by all tools\r
3#\r
4# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>\r
5# SPDX-License-Identifier: BSD-2-Clause-Patent\r
6#\r
7\r
8##\r
9# Import Modules\r
10#\r
11from __future__ import absolute_import\r
12\r
13import sys\r
14import string\r
15import threading\r
16import time\r
17import re\r
18import pickle\r
19import array\r
20import shutil\r
21import filecmp\r
22from random import sample\r
23from struct import pack\r
24import uuid\r
25import subprocess\r
26import tempfile\r
27from collections import OrderedDict\r
28\r
29import Common.LongFilePathOs as os\r
30from Common import EdkLogger as EdkLogger\r
31from Common import GlobalData as GlobalData\r
32from Common.DataType import *\r
33from Common.BuildToolError import *\r
34from CommonDataClass.DataClass import *\r
35from Common.Parsing import GetSplitValueList\r
36from Common.LongFilePathSupport import OpenLongFilePath as open\r
37from Common.LongFilePathSupport import CopyLongFilePath as CopyLong\r
38from Common.LongFilePathSupport import LongFilePath as LongFilePath\r
39from Common.MultipleWorkspace import MultipleWorkspace as mws\r
40from CommonDataClass.Exceptions import BadExpression\r
41from Common.caching import cached_property\r
42import struct\r
43\r
44ArrayIndex = re.compile("\[\s*[0-9a-fA-FxX]*\s*\]")\r
45## Regular expression used to find out place holders in string template\r
46gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE)\r
47\r
48## regular expressions for map file processing\r
49startPatternGeneral = re.compile("^Start[' ']+Length[' ']+Name[' ']+Class")\r
50addressPatternGeneral = re.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")\r
51valuePatternGcc = re.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')\r
52pcdPatternGcc = re.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')\r
53secReGeneral = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE)\r
54\r
55StructPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*$')\r
56\r
57## Dictionary used to store dependencies of files\r
58gDependencyDatabase = {} # arch : {file path : [dependent files list]}\r
59\r
60#\r
61# If a module is built more than once with different PCDs or library classes\r
62# a temporary INF file with same content is created, the temporary file is removed\r
63# when build exits.\r
64#\r
65_TempInfs = []\r
66\r
67def GetVariableOffset(mapfilepath, efifilepath, varnames):\r
68 """ Parse map file to get variable offset in current EFI file\r
69 @param mapfilepath Map file absolution path\r
70 @param efifilepath: EFI binary file full path\r
71 @param varnames iteratable container whose elements are variable names to be searched\r
72\r
73 @return List whos elements are tuple with variable name and raw offset\r
74 """\r
75 lines = []\r
76 try:\r
77 f = open(mapfilepath, 'r')\r
78 lines = f.readlines()\r
79 f.close()\r
80 except:\r
81 return None\r
82\r
83 if len(lines) == 0: return None\r
84 firstline = lines[0].strip()\r
85 if re.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', firstline):\r
86 return _parseForXcodeAndClang9(lines, efifilepath, varnames)\r
87 if (firstline.startswith("Archive member included ") and\r
88 firstline.endswith(" file (symbol)")):\r
89 return _parseForGCC(lines, efifilepath, varnames)\r
90 if firstline.startswith("# Path:"):\r
91 return _parseForXcodeAndClang9(lines, efifilepath, varnames)\r
92 return _parseGeneral(lines, efifilepath, varnames)\r
93\r
94def _parseForXcodeAndClang9(lines, efifilepath, varnames):\r
95 status = 0\r
96 ret = []\r
97 for line in lines:\r
98 line = line.strip()\r
99 if status == 0 and (re.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', line) \\r
100 or line == "# Symbols:"):\r
101 status = 1\r
102 continue\r
103 if status == 1 and len(line) != 0:\r
104 for varname in varnames:\r
105 if varname in line:\r
106 # cannot pregenerate this RegEx since it uses varname from varnames.\r
107 m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line)\r
108 if m is not None:\r
109 ret.append((varname, m.group(1)))\r
110 return ret\r
111\r
112def _parseForGCC(lines, efifilepath, varnames):\r
113 """ Parse map file generated by GCC linker """\r
114 status = 0\r
115 sections = []\r
116 varoffset = []\r
117 for index, line in enumerate(lines):\r
118 line = line.strip()\r
119 # status machine transection\r
120 if status == 0 and line == "Memory Configuration":\r
121 status = 1\r
122 continue\r
123 elif status == 1 and line == 'Linker script and memory map':\r
124 status = 2\r
125 continue\r
126 elif status ==2 and line == 'START GROUP':\r
127 status = 3\r
128 continue\r
129\r
130 # status handler\r
131 if status == 3:\r
132 m = valuePatternGcc.match(line)\r
133 if m is not None:\r
134 sections.append(m.groups(0))\r
135 for varname in varnames:\r
136 Str = ''\r
137 m = re.match("^.data.(%s)" % varname, line)\r
138 if m is not None:\r
139 m = re.match(".data.(%s)$" % varname, line)\r
140 if m is not None:\r
141 Str = lines[index + 1]\r
142 else:\r
143 Str = line[len(".data.%s" % varname):]\r
144 if Str:\r
145 m = pcdPatternGcc.match(Str.strip())\r
146 if m is not None:\r
147 varoffset.append((varname, int(m.groups(0)[0], 16), int(sections[-1][1], 16), sections[-1][0]))\r
148\r
149 if not varoffset:\r
150 return []\r
151 # get section information from efi file\r
152 efisecs = PeImageClass(efifilepath).SectionHeaderList\r
153 if efisecs is None or len(efisecs) == 0:\r
154 return []\r
155 #redirection\r
156 redirection = 0\r
157 for efisec in efisecs:\r
158 for section in sections:\r
159 if section[0].strip() == efisec[0].strip() and section[0].strip() == '.text':\r
160 redirection = int(section[1], 16) - efisec[1]\r
161\r
162 ret = []\r
163 for var in varoffset:\r
164 for efisec in efisecs:\r
165 if var[1] >= efisec[1] and var[1] < efisec[1]+efisec[3]:\r
166 ret.append((var[0], hex(efisec[2] + var[1] - efisec[1] - redirection)))\r
167 return ret\r
168\r
169def _parseGeneral(lines, efifilepath, varnames):\r
170 status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table\r
171 secs = [] # key = section name\r
172 varoffset = []\r
173 symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$-]+) +([\da-fA-F]+)', re.UNICODE)\r
174\r
175 for line in lines:\r
176 line = line.strip()\r
177 if startPatternGeneral.match(line):\r
178 status = 1\r
179 continue\r
180 if addressPatternGeneral.match(line):\r
181 status = 2\r
182 continue\r
183 if line.startswith("entry point at"):\r
184 status = 3\r
185 continue\r
186 if status == 1 and len(line) != 0:\r
187 m = secReGeneral.match(line)\r
188 assert m is not None, "Fail to parse the section in map file , line is %s" % line\r
189 sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0)\r
190 secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class])\r
191 if status == 2 and len(line) != 0:\r
192 for varname in varnames:\r
193 m = symRe.match(line)\r
194 assert m is not None, "Fail to parse the symbol in map file, line is %s" % line\r
195 sec_no, sym_offset, sym_name, vir_addr = m.groups(0)\r
196 sec_no = int(sec_no, 16)\r
197 sym_offset = int(sym_offset, 16)\r
198 vir_addr = int(vir_addr, 16)\r
199 # cannot pregenerate this RegEx since it uses varname from varnames.\r
200 m2 = re.match('^[_]*(%s)' % varname, sym_name)\r
201 if m2 is not None:\r
202 # fond a binary pcd entry in map file\r
203 for sec in secs:\r
204 if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]):\r
205 varoffset.append([varname, sec[3], sym_offset, vir_addr, sec_no])\r
206\r
207 if not varoffset: return []\r
208\r
209 # get section information from efi file\r
210 efisecs = PeImageClass(efifilepath).SectionHeaderList\r
211 if efisecs is None or len(efisecs) == 0:\r
212 return []\r
213\r
214 ret = []\r
215 for var in varoffset:\r
216 index = 0\r
217 for efisec in efisecs:\r
218 index = index + 1\r
219 if var[1].strip() == efisec[0].strip():\r
220 ret.append((var[0], hex(efisec[2] + var[2])))\r
221 elif var[4] == index:\r
222 ret.append((var[0], hex(efisec[2] + var[2])))\r
223\r
224 return ret\r
225\r
226## Routine to process duplicated INF\r
227#\r
228# This function is called by following two cases:\r
229# Case 1 in DSC:\r
230# [components.arch]\r
231# Pkg/module/module.inf\r
232# Pkg/module/module.inf {\r
233# <Defines>\r
234# FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836\r
235# }\r
236# Case 2 in FDF:\r
237# INF Pkg/module/module.inf\r
238# INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf\r
239#\r
240# This function copies Pkg/module/module.inf to\r
241# Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf\r
242#\r
243# @param Path Original PathClass object\r
244# @param BaseName New file base name\r
245#\r
246# @retval return the new PathClass object\r
247#\r
248def ProcessDuplicatedInf(Path, BaseName, Workspace):\r
249 Filename = os.path.split(Path.File)[1]\r
250 if '.' in Filename:\r
251 Filename = BaseName + Path.BaseName + Filename[Filename.rfind('.'):]\r
252 else:\r
253 Filename = BaseName + Path.BaseName\r
254\r
255 DbDir = os.path.split(GlobalData.gDatabasePath)[0]\r
256\r
257 #\r
258 # A temporary INF is copied to database path which must have write permission\r
259 # The temporary will be removed at the end of build\r
260 # In case of name conflict, the file name is\r
261 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)\r
262 #\r
263 TempFullPath = os.path.join(DbDir,\r
264 Filename)\r
265 RtPath = PathClass(Path.File, Workspace)\r
266 #\r
267 # Modify the full path to temporary path, keep other unchanged\r
268 #\r
269 # To build same module more than once, the module path with FILE_GUID overridden has\r
270 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path\r
271 # in DSC which is used as relative path by C files and other files in INF.\r
272 # A trick was used: all module paths are PathClass instances, after the initialization\r
273 # of PathClass, the PathClass.Path is overridden by the temporary INF path.\r
274 #\r
275 # The reason for creating a temporary INF is:\r
276 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,\r
277 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.\r
278 # A different key for the same module is needed to create different output directory,\r
279 # retrieve overridden PCDs, library instances.\r
280 #\r
281 # The BaseName is the FILE_GUID which is also the output directory name.\r
282 #\r
283 #\r
284 RtPath.Path = TempFullPath\r
285 RtPath.BaseName = BaseName\r
286 RtPath.OriginalPath = Path\r
287 #\r
288 # If file exists, compare contents\r
289 #\r
290 if os.path.exists(TempFullPath):\r
291 with open(str(Path), 'rb') as f1, open(TempFullPath, 'rb') as f2:\r
292 if f1.read() == f2.read():\r
293 return RtPath\r
294 _TempInfs.append(TempFullPath)\r
295 shutil.copy2(str(Path), TempFullPath)\r
296 return RtPath\r
297\r
298## Remove temporary created INFs whose paths were saved in _TempInfs\r
299#\r
300def ClearDuplicatedInf():\r
301 while _TempInfs:\r
302 File = _TempInfs.pop()\r
303 if os.path.exists(File):\r
304 os.remove(File)\r
305\r
306## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style\r
307#\r
308# @param Guid The GUID string\r
309#\r
310# @retval string The GUID string in C structure style\r
311#\r
312def GuidStringToGuidStructureString(Guid):\r
313 GuidList = Guid.split('-')\r
314 Result = '{'\r
315 for Index in range(0, 3, 1):\r
316 Result = Result + '0x' + GuidList[Index] + ', '\r
317 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]\r
318 for Index in range(0, 12, 2):\r
319 Result = Result + ', 0x' + GuidList[4][Index:Index + 2]\r
320 Result += '}}'\r
321 return Result\r
322\r
323## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
324#\r
325# @param GuidValue The GUID value in byte array\r
326#\r
327# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
328#\r
329def GuidStructureByteArrayToGuidString(GuidValue):\r
330 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")\r
331 guidValueList = guidValueString.split(",")\r
332 if len(guidValueList) != 16:\r
333 return ''\r
334 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
335 try:\r
336 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
337 int(guidValueList[3], 16),\r
338 int(guidValueList[2], 16),\r
339 int(guidValueList[1], 16),\r
340 int(guidValueList[0], 16),\r
341 int(guidValueList[5], 16),\r
342 int(guidValueList[4], 16),\r
343 int(guidValueList[7], 16),\r
344 int(guidValueList[6], 16),\r
345 int(guidValueList[8], 16),\r
346 int(guidValueList[9], 16),\r
347 int(guidValueList[10], 16),\r
348 int(guidValueList[11], 16),\r
349 int(guidValueList[12], 16),\r
350 int(guidValueList[13], 16),\r
351 int(guidValueList[14], 16),\r
352 int(guidValueList[15], 16)\r
353 )\r
354 except:\r
355 return ''\r
356\r
357## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
358#\r
359# @param GuidValue The GUID value in C structure format\r
360#\r
361# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
362#\r
363def GuidStructureStringToGuidString(GuidValue):\r
364 if not GlobalData.gGuidCFormatPattern.match(GuidValue):\r
365 return ''\r
366 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")\r
367 guidValueList = guidValueString.split(",")\r
368 if len(guidValueList) != 11:\r
369 return ''\r
370 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
371 try:\r
372 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
373 int(guidValueList[0], 16),\r
374 int(guidValueList[1], 16),\r
375 int(guidValueList[2], 16),\r
376 int(guidValueList[3], 16),\r
377 int(guidValueList[4], 16),\r
378 int(guidValueList[5], 16),\r
379 int(guidValueList[6], 16),\r
380 int(guidValueList[7], 16),\r
381 int(guidValueList[8], 16),\r
382 int(guidValueList[9], 16),\r
383 int(guidValueList[10], 16)\r
384 )\r
385 except:\r
386 return ''\r
387\r
388## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx\r
389#\r
390# @param GuidValue The GUID value in C structure format\r
391#\r
392# @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format\r
393#\r
394def GuidStructureStringToGuidValueName(GuidValue):\r
395 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")\r
396 guidValueList = guidValueString.split(",")\r
397 if len(guidValueList) != 11:\r
398 EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue)\r
399 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (\r
400 int(guidValueList[0], 16),\r
401 int(guidValueList[1], 16),\r
402 int(guidValueList[2], 16),\r
403 int(guidValueList[3], 16),\r
404 int(guidValueList[4], 16),\r
405 int(guidValueList[5], 16),\r
406 int(guidValueList[6], 16),\r
407 int(guidValueList[7], 16),\r
408 int(guidValueList[8], 16),\r
409 int(guidValueList[9], 16),\r
410 int(guidValueList[10], 16)\r
411 )\r
412\r
413## Create directories\r
414#\r
415# @param Directory The directory name\r
416#\r
417def CreateDirectory(Directory):\r
418 if Directory is None or Directory.strip() == "":\r
419 return True\r
420 try:\r
421 if not os.access(Directory, os.F_OK):\r
422 os.makedirs(Directory)\r
423 except:\r
424 return False\r
425 return True\r
426\r
427## Remove directories, including files and sub-directories in it\r
428#\r
429# @param Directory The directory name\r
430#\r
431def RemoveDirectory(Directory, Recursively=False):\r
432 if Directory is None or Directory.strip() == "" or not os.path.exists(Directory):\r
433 return\r
434 if Recursively:\r
435 CurrentDirectory = os.getcwd()\r
436 os.chdir(Directory)\r
437 for File in os.listdir("."):\r
438 if os.path.isdir(File):\r
439 RemoveDirectory(File, Recursively)\r
440 else:\r
441 os.remove(File)\r
442 os.chdir(CurrentDirectory)\r
443 os.rmdir(Directory)\r
444\r
445## Store content in file\r
446#\r
447# This method is used to save file only when its content is changed. This is\r
448# quite useful for "make" system to decide what will be re-built and what won't.\r
449#\r
450# @param File The path of file\r
451# @param Content The new content of the file\r
452# @param IsBinaryFile The flag indicating if the file is binary file or not\r
453#\r
454# @retval True If the file content is changed and the file is renewed\r
455# @retval False If the file content is the same\r
456#\r
457def SaveFileOnChange(File, Content, IsBinaryFile=True, FileLock=None):\r
458\r
459 # Convert to long file path format\r
460 File = LongFilePath(File)\r
461\r
462 if os.path.exists(File):\r
463 if IsBinaryFile:\r
464 try:\r
465 with open(File, "rb") as f:\r
466 if Content == f.read():\r
467 return False\r
468 except:\r
469 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)\r
470 else:\r
471 try:\r
472 with open(File, "r") as f:\r
473 if Content == f.read():\r
474 return False\r
475 except:\r
476 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)\r
477\r
478 DirName = os.path.dirname(File)\r
479 if not CreateDirectory(DirName):\r
480 EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)\r
481 else:\r
482 if DirName == '':\r
483 DirName = os.getcwd()\r
484 if not os.access(DirName, os.W_OK):\r
485 EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)\r
486\r
487 OpenMode = "w"\r
488 if IsBinaryFile:\r
489 OpenMode = "wb"\r
490\r
491 # use default file_lock if no input new lock\r
492 if not FileLock:\r
493 FileLock = GlobalData.file_lock\r
494 if FileLock:\r
495 FileLock.acquire()\r
496\r
497\r
498 if GlobalData.gIsWindows and not os.path.exists(File):\r
499 try:\r
500 with open(File, OpenMode) as tf:\r
501 tf.write(Content)\r
502 except IOError as X:\r
503 if GlobalData.gBinCacheSource:\r
504 EdkLogger.quiet("[cache error]:fails to save file with error: %s" % (X))\r
505 else:\r
506 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)\r
507 finally:\r
508 if FileLock:\r
509 FileLock.release()\r
510 else:\r
511 try:\r
512 with open(File, OpenMode) as Fd:\r
513 Fd.write(Content)\r
514 except IOError as X:\r
515 if GlobalData.gBinCacheSource:\r
516 EdkLogger.quiet("[cache error]:fails to save file with error: %s" % (X))\r
517 else:\r
518 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)\r
519 finally:\r
520 if FileLock:\r
521 FileLock.release()\r
522\r
523 return True\r
524\r
525## Copy source file only if it is different from the destination file\r
526#\r
527# This method is used to copy file only if the source file and destination\r
528# file content are different. This is quite useful to avoid duplicated\r
529# file writing.\r
530#\r
531# @param SrcFile The path of source file\r
532# @param Dst The path of destination file or folder\r
533#\r
534# @retval True The two files content are different and the file is copied\r
535# @retval False No copy really happen\r
536#\r
537def CopyFileOnChange(SrcFile, Dst, FileLock=None):\r
538\r
539 # Convert to long file path format\r
540 SrcFile = LongFilePath(SrcFile)\r
541 Dst = LongFilePath(Dst)\r
542\r
543 if os.path.isdir(SrcFile):\r
544 EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='CopyFileOnChange SrcFile is a dir, not a file: %s' % SrcFile)\r
545 return False\r
546\r
547 if os.path.isdir(Dst):\r
548 DstFile = os.path.join(Dst, os.path.basename(SrcFile))\r
549 else:\r
550 DstFile = Dst\r
551\r
552 if os.path.exists(DstFile) and filecmp.cmp(SrcFile, DstFile, shallow=False):\r
553 return False\r
554\r
555 DirName = os.path.dirname(DstFile)\r
556 if not CreateDirectory(DirName):\r
557 EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)\r
558 else:\r
559 if DirName == '':\r
560 DirName = os.getcwd()\r
561 if not os.access(DirName, os.W_OK):\r
562 EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)\r
563\r
564 # use default file_lock if no input new lock\r
565 if not FileLock:\r
566 FileLock = GlobalData.file_lock\r
567 if FileLock:\r
568 FileLock.acquire()\r
569\r
570 try:\r
571 CopyLong(SrcFile, DstFile)\r
572 except IOError as X:\r
573 if GlobalData.gBinCacheSource:\r
574 EdkLogger.quiet("[cache error]:fails to copy file with error: %s" % (X))\r
575 else:\r
576 EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='IOError %s' % X)\r
577 finally:\r
578 if FileLock:\r
579 FileLock.release()\r
580\r
581 return True\r
582\r
583## Retrieve and cache the real path name in file system\r
584#\r
585# @param Root The root directory of path relative to\r
586#\r
587# @retval str The path string if the path exists\r
588# @retval None If path doesn't exist\r
589#\r
590class DirCache:\r
591 _CACHE_ = set()\r
592 _UPPER_CACHE_ = {}\r
593\r
594 def __init__(self, Root):\r
595 self._Root = Root\r
596 for F in os.listdir(Root):\r
597 self._CACHE_.add(F)\r
598 self._UPPER_CACHE_[F.upper()] = F\r
599\r
600 # =[] operator\r
601 def __getitem__(self, Path):\r
602 Path = Path[len(os.path.commonprefix([Path, self._Root])):]\r
603 if not Path:\r
604 return self._Root\r
605 if Path and Path[0] == os.path.sep:\r
606 Path = Path[1:]\r
607 if Path in self._CACHE_:\r
608 return os.path.join(self._Root, Path)\r
609 UpperPath = Path.upper()\r
610 if UpperPath in self._UPPER_CACHE_:\r
611 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])\r
612\r
613 IndexList = []\r
614 LastSepIndex = -1\r
615 SepIndex = Path.find(os.path.sep)\r
616 while SepIndex > -1:\r
617 Parent = UpperPath[:SepIndex]\r
618 if Parent not in self._UPPER_CACHE_:\r
619 break\r
620 LastSepIndex = SepIndex\r
621 SepIndex = Path.find(os.path.sep, LastSepIndex + 1)\r
622\r
623 if LastSepIndex == -1:\r
624 return None\r
625\r
626 Cwd = os.getcwd()\r
627 os.chdir(self._Root)\r
628 SepIndex = LastSepIndex\r
629 while SepIndex > -1:\r
630 Parent = Path[:SepIndex]\r
631 ParentKey = UpperPath[:SepIndex]\r
632 if ParentKey not in self._UPPER_CACHE_:\r
633 os.chdir(Cwd)\r
634 return None\r
635\r
636 if Parent in self._CACHE_:\r
637 ParentDir = Parent\r
638 else:\r
639 ParentDir = self._UPPER_CACHE_[ParentKey]\r
640 for F in os.listdir(ParentDir):\r
641 Dir = os.path.join(ParentDir, F)\r
642 self._CACHE_.add(Dir)\r
643 self._UPPER_CACHE_[Dir.upper()] = Dir\r
644\r
645 SepIndex = Path.find(os.path.sep, SepIndex + 1)\r
646\r
647 os.chdir(Cwd)\r
648 if Path in self._CACHE_:\r
649 return os.path.join(self._Root, Path)\r
650 elif UpperPath in self._UPPER_CACHE_:\r
651 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])\r
652 return None\r
653\r
654def RealPath(File, Dir='', OverrideDir=''):\r
655 NewFile = os.path.normpath(os.path.join(Dir, File))\r
656 NewFile = GlobalData.gAllFiles[NewFile]\r
657 if not NewFile and OverrideDir:\r
658 NewFile = os.path.normpath(os.path.join(OverrideDir, File))\r
659 NewFile = GlobalData.gAllFiles[NewFile]\r
660 return NewFile\r
661\r
662## Get GUID value from given packages\r
663#\r
664# @param CName The CName of the GUID\r
665# @param PackageList List of packages looking-up in\r
666# @param Inffile The driver file\r
667#\r
668# @retval GuidValue if the CName is found in any given package\r
669# @retval None if the CName is not found in all given packages\r
670#\r
671def GuidValue(CName, PackageList, Inffile = None):\r
672 for P in PackageList:\r
673 GuidKeys = list(P.Guids.keys())\r
674 if Inffile and P._PrivateGuids:\r
675 if not Inffile.startswith(P.MetaFile.Dir):\r
676 GuidKeys = [x for x in P.Guids if x not in P._PrivateGuids]\r
677 if CName in GuidKeys:\r
678 return P.Guids[CName]\r
679 return None\r
680\r
681## A string template class\r
682#\r
683# This class implements a template for string replacement. A string template\r
684# looks like following\r
685#\r
686# ${BEGIN} other_string ${placeholder_name} other_string ${END}\r
687#\r
688# The string between ${BEGIN} and ${END} will be repeated as many times as the\r
689# length of "placeholder_name", which is a list passed through a dict. The\r
690# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can\r
691# be not used and, in this case, the "placeholder_name" must not a list and it\r
692# will just be replaced once.\r
693#\r
694class TemplateString(object):\r
695 _REPEAT_START_FLAG = "BEGIN"\r
696 _REPEAT_END_FLAG = "END"\r
697\r
698 class Section(object):\r
699 _LIST_TYPES = [type([]), type(set()), type((0,))]\r
700\r
701 def __init__(self, TemplateSection, PlaceHolderList):\r
702 self._Template = TemplateSection\r
703 self._PlaceHolderList = []\r
704\r
705 # Split the section into sub-sections according to the position of placeholders\r
706 if PlaceHolderList:\r
707 self._SubSectionList = []\r
708 SubSectionStart = 0\r
709 #\r
710 # The placeholders passed in must be in the format of\r
711 #\r
712 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint\r
713 #\r
714 for PlaceHolder, Start, End in PlaceHolderList:\r
715 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])\r
716 self._SubSectionList.append(TemplateSection[Start:End])\r
717 self._PlaceHolderList.append(PlaceHolder)\r
718 SubSectionStart = End\r
719 if SubSectionStart < len(TemplateSection):\r
720 self._SubSectionList.append(TemplateSection[SubSectionStart:])\r
721 else:\r
722 self._SubSectionList = [TemplateSection]\r
723\r
724 def __str__(self):\r
725 return self._Template + " : " + str(self._PlaceHolderList)\r
726\r
727 def Instantiate(self, PlaceHolderValues):\r
728 RepeatTime = -1\r
729 RepeatPlaceHolders = {}\r
730 NonRepeatPlaceHolders = {}\r
731\r
732 for PlaceHolder in self._PlaceHolderList:\r
733 if PlaceHolder not in PlaceHolderValues:\r
734 continue\r
735 Value = PlaceHolderValues[PlaceHolder]\r
736 if type(Value) in self._LIST_TYPES:\r
737 if RepeatTime < 0:\r
738 RepeatTime = len(Value)\r
739 elif RepeatTime != len(Value):\r
740 EdkLogger.error(\r
741 "TemplateString",\r
742 PARAMETER_INVALID,\r
743 "${%s} has different repeat time from others!" % PlaceHolder,\r
744 ExtraData=str(self._Template)\r
745 )\r
746 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
747 else:\r
748 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
749\r
750 if NonRepeatPlaceHolders:\r
751 StringList = []\r
752 for S in self._SubSectionList:\r
753 if S not in NonRepeatPlaceHolders:\r
754 StringList.append(S)\r
755 else:\r
756 StringList.append(str(NonRepeatPlaceHolders[S]))\r
757 else:\r
758 StringList = self._SubSectionList\r
759\r
760 if RepeatPlaceHolders:\r
761 TempStringList = []\r
762 for Index in range(RepeatTime):\r
763 for S in StringList:\r
764 if S not in RepeatPlaceHolders:\r
765 TempStringList.append(S)\r
766 else:\r
767 TempStringList.append(str(RepeatPlaceHolders[S][Index]))\r
768 StringList = TempStringList\r
769\r
770 return "".join(StringList)\r
771\r
772 ## Constructor\r
773 def __init__(self, Template=None):\r
774 self.String = []\r
775 self.IsBinary = False\r
776 self._Template = Template\r
777 self._TemplateSectionList = self._Parse(Template)\r
778\r
779 ## str() operator\r
780 #\r
781 # @retval string The string replaced\r
782 #\r
783 def __str__(self):\r
784 return "".join(self.String)\r
785\r
786 ## Split the template string into fragments per the ${BEGIN} and ${END} flags\r
787 #\r
788 # @retval list A list of TemplateString.Section objects\r
789 #\r
790 def _Parse(self, Template):\r
791 SectionStart = 0\r
792 SearchFrom = 0\r
793 MatchEnd = 0\r
794 PlaceHolderList = []\r
795 TemplateSectionList = []\r
796 while Template:\r
797 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)\r
798 if not MatchObj:\r
799 if MatchEnd <= len(Template):\r
800 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)\r
801 TemplateSectionList.append(TemplateSection)\r
802 break\r
803\r
804 MatchString = MatchObj.group(1)\r
805 MatchStart = MatchObj.start()\r
806 MatchEnd = MatchObj.end()\r
807\r
808 if MatchString == self._REPEAT_START_FLAG:\r
809 if MatchStart > SectionStart:\r
810 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
811 TemplateSectionList.append(TemplateSection)\r
812 SectionStart = MatchEnd\r
813 PlaceHolderList = []\r
814 elif MatchString == self._REPEAT_END_FLAG:\r
815 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
816 TemplateSectionList.append(TemplateSection)\r
817 SectionStart = MatchEnd\r
818 PlaceHolderList = []\r
819 else:\r
820 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))\r
821 SearchFrom = MatchEnd\r
822 return TemplateSectionList\r
823\r
824 ## Replace the string template with dictionary of placeholders and append it to previous one\r
825 #\r
826 # @param AppendString The string template to append\r
827 # @param Dictionary The placeholder dictionaries\r
828 #\r
829 def Append(self, AppendString, Dictionary=None):\r
830 if Dictionary:\r
831 SectionList = self._Parse(AppendString)\r
832 self.String.append( "".join(S.Instantiate(Dictionary) for S in SectionList))\r
833 else:\r
834 if isinstance(AppendString,list):\r
835 self.String.extend(AppendString)\r
836 else:\r
837 self.String.append(AppendString)\r
838\r
839 ## Replace the string template with dictionary of placeholders\r
840 #\r
841 # @param Dictionary The placeholder dictionaries\r
842 #\r
843 # @retval str The string replaced with placeholder values\r
844 #\r
845 def Replace(self, Dictionary=None):\r
846 return "".join(S.Instantiate(Dictionary) for S in self._TemplateSectionList)\r
847\r
848## Progress indicator class\r
849#\r
850# This class makes use of thread to print progress on console.\r
851#\r
852class Progressor:\r
853 # for avoiding deadloop\r
854 _StopFlag = None\r
855 _ProgressThread = None\r
856 _CheckInterval = 0.25\r
857\r
858 ## Constructor\r
859 #\r
860 # @param OpenMessage The string printed before progress characters\r
861 # @param CloseMessage The string printed after progress characters\r
862 # @param ProgressChar The character used to indicate the progress\r
863 # @param Interval The interval in seconds between two progress characters\r
864 #\r
865 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):\r
866 self.PromptMessage = OpenMessage\r
867 self.CodaMessage = CloseMessage\r
868 self.ProgressChar = ProgressChar\r
869 self.Interval = Interval\r
870 if Progressor._StopFlag is None:\r
871 Progressor._StopFlag = threading.Event()\r
872\r
873 ## Start to print progress character\r
874 #\r
875 # @param OpenMessage The string printed before progress characters\r
876 #\r
877 def Start(self, OpenMessage=None):\r
878 if OpenMessage is not None:\r
879 self.PromptMessage = OpenMessage\r
880 Progressor._StopFlag.clear()\r
881 if Progressor._ProgressThread is None:\r
882 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)\r
883 Progressor._ProgressThread.setDaemon(False)\r
884 Progressor._ProgressThread.start()\r
885\r
886 ## Stop printing progress character\r
887 #\r
888 # @param CloseMessage The string printed after progress characters\r
889 #\r
890 def Stop(self, CloseMessage=None):\r
891 OriginalCodaMessage = self.CodaMessage\r
892 if CloseMessage is not None:\r
893 self.CodaMessage = CloseMessage\r
894 self.Abort()\r
895 self.CodaMessage = OriginalCodaMessage\r
896\r
897 ## Thread entry method\r
898 def _ProgressThreadEntry(self):\r
899 sys.stdout.write(self.PromptMessage + " ")\r
900 sys.stdout.flush()\r
901 TimeUp = 0.0\r
902 while not Progressor._StopFlag.isSet():\r
903 if TimeUp <= 0.0:\r
904 sys.stdout.write(self.ProgressChar)\r
905 sys.stdout.flush()\r
906 TimeUp = self.Interval\r
907 time.sleep(self._CheckInterval)\r
908 TimeUp -= self._CheckInterval\r
909 sys.stdout.write(" " + self.CodaMessage + "\n")\r
910 sys.stdout.flush()\r
911\r
912 ## Abort the progress display\r
913 @staticmethod\r
914 def Abort():\r
915 if Progressor._StopFlag is not None:\r
916 Progressor._StopFlag.set()\r
917 if Progressor._ProgressThread is not None:\r
918 Progressor._ProgressThread.join()\r
919 Progressor._ProgressThread = None\r
920\r
921\r
922## Dictionary using prioritized list as key\r
923#\r
924class tdict:\r
925 _ListType = type([])\r
926 _TupleType = type(())\r
927 _Wildcard = 'COMMON'\r
928 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', TAB_STAR, 'PLATFORM']\r
929\r
930 def __init__(self, _Single_=False, _Level_=2):\r
931 self._Level_ = _Level_\r
932 self.data = {}\r
933 self._Single_ = _Single_\r
934\r
935 # =[] operator\r
936 def __getitem__(self, key):\r
937 KeyType = type(key)\r
938 RestKeys = None\r
939 if KeyType == self._ListType or KeyType == self._TupleType:\r
940 FirstKey = key[0]\r
941 if len(key) > 1:\r
942 RestKeys = key[1:]\r
943 elif self._Level_ > 1:\r
944 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
945 else:\r
946 FirstKey = key\r
947 if self._Level_ > 1:\r
948 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
949\r
950 if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList:\r
951 FirstKey = self._Wildcard\r
952\r
953 if self._Single_:\r
954 return self._GetSingleValue(FirstKey, RestKeys)\r
955 else:\r
956 return self._GetAllValues(FirstKey, RestKeys)\r
957\r
958 def _GetSingleValue(self, FirstKey, RestKeys):\r
959 Value = None\r
960 #print "%s-%s" % (FirstKey, self._Level_) ,\r
961 if self._Level_ > 1:\r
962 if FirstKey == self._Wildcard:\r
963 if FirstKey in self.data:\r
964 Value = self.data[FirstKey][RestKeys]\r
965 if Value is None:\r
966 for Key in self.data:\r
967 Value = self.data[Key][RestKeys]\r
968 if Value is not None: break\r
969 else:\r
970 if FirstKey in self.data:\r
971 Value = self.data[FirstKey][RestKeys]\r
972 if Value is None and self._Wildcard in self.data:\r
973 #print "Value=None"\r
974 Value = self.data[self._Wildcard][RestKeys]\r
975 else:\r
976 if FirstKey == self._Wildcard:\r
977 if FirstKey in self.data:\r
978 Value = self.data[FirstKey]\r
979 if Value is None:\r
980 for Key in self.data:\r
981 Value = self.data[Key]\r
982 if Value is not None: break\r
983 else:\r
984 if FirstKey in self.data:\r
985 Value = self.data[FirstKey]\r
986 elif self._Wildcard in self.data:\r
987 Value = self.data[self._Wildcard]\r
988 return Value\r
989\r
990 def _GetAllValues(self, FirstKey, RestKeys):\r
991 Value = []\r
992 if self._Level_ > 1:\r
993 if FirstKey == self._Wildcard:\r
994 for Key in self.data:\r
995 Value += self.data[Key][RestKeys]\r
996 else:\r
997 if FirstKey in self.data:\r
998 Value += self.data[FirstKey][RestKeys]\r
999 if self._Wildcard in self.data:\r
1000 Value += self.data[self._Wildcard][RestKeys]\r
1001 else:\r
1002 if FirstKey == self._Wildcard:\r
1003 for Key in self.data:\r
1004 Value.append(self.data[Key])\r
1005 else:\r
1006 if FirstKey in self.data:\r
1007 Value.append(self.data[FirstKey])\r
1008 if self._Wildcard in self.data:\r
1009 Value.append(self.data[self._Wildcard])\r
1010 return Value\r
1011\r
1012 ## []= operator\r
1013 def __setitem__(self, key, value):\r
1014 KeyType = type(key)\r
1015 RestKeys = None\r
1016 if KeyType == self._ListType or KeyType == self._TupleType:\r
1017 FirstKey = key[0]\r
1018 if len(key) > 1:\r
1019 RestKeys = key[1:]\r
1020 else:\r
1021 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
1022 else:\r
1023 FirstKey = key\r
1024 if self._Level_ > 1:\r
1025 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
1026\r
1027 if FirstKey in self._ValidWildcardList:\r
1028 FirstKey = self._Wildcard\r
1029\r
1030 if FirstKey not in self.data and self._Level_ > 0:\r
1031 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)\r
1032\r
1033 if self._Level_ > 1:\r
1034 self.data[FirstKey][RestKeys] = value\r
1035 else:\r
1036 self.data[FirstKey] = value\r
1037\r
1038 def SetGreedyMode(self):\r
1039 self._Single_ = False\r
1040 if self._Level_ > 1:\r
1041 for Key in self.data:\r
1042 self.data[Key].SetGreedyMode()\r
1043\r
1044 def SetSingleMode(self):\r
1045 self._Single_ = True\r
1046 if self._Level_ > 1:\r
1047 for Key in self.data:\r
1048 self.data[Key].SetSingleMode()\r
1049\r
1050 def GetKeys(self, KeyIndex=0):\r
1051 assert KeyIndex >= 0\r
1052 if KeyIndex == 0:\r
1053 return set(self.data.keys())\r
1054 else:\r
1055 keys = set()\r
1056 for Key in self.data:\r
1057 keys |= self.data[Key].GetKeys(KeyIndex - 1)\r
1058 return keys\r
1059\r
1060def AnalyzePcdExpression(Setting):\r
1061 RanStr = ''.join(sample(string.ascii_letters + string.digits, 8))\r
1062 Setting = Setting.replace('\\\\', RanStr).strip()\r
1063 # There might be escaped quote in a string: \", \\\" , \', \\\'\r
1064 Data = Setting\r
1065 # There might be '|' in string and in ( ... | ... ), replace it with '-'\r
1066 NewStr = ''\r
1067 InSingleQuoteStr = False\r
1068 InDoubleQuoteStr = False\r
1069 Pair = 0\r
1070 for Index, ch in enumerate(Data):\r
1071 if ch == '"' and not InSingleQuoteStr:\r
1072 if Data[Index - 1] != '\\':\r
1073 InDoubleQuoteStr = not InDoubleQuoteStr\r
1074 elif ch == "'" and not InDoubleQuoteStr:\r
1075 if Data[Index - 1] != '\\':\r
1076 InSingleQuoteStr = not InSingleQuoteStr\r
1077 elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
1078 Pair += 1\r
1079 elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
1080 Pair -= 1\r
1081\r
1082 if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT:\r
1083 NewStr += '-'\r
1084 else:\r
1085 NewStr += ch\r
1086 FieldList = []\r
1087 StartPos = 0\r
1088 while True:\r
1089 Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)\r
1090 if Pos < 0:\r
1091 FieldList.append(Setting[StartPos:].strip())\r
1092 break\r
1093 FieldList.append(Setting[StartPos:Pos].strip())\r
1094 StartPos = Pos + 1\r
1095 for i, ch in enumerate(FieldList):\r
1096 if RanStr in ch:\r
1097 FieldList[i] = ch.replace(RanStr,'\\\\')\r
1098 return FieldList\r
1099\r
1100def ParseFieldValue (Value):\r
1101 def ParseDevPathValue (Value):\r
1102 if '\\' in Value:\r
1103 Value.replace('\\', '/').replace(' ', '')\r
1104\r
1105 Cmd = 'DevicePath ' + '"' + Value + '"'\r
1106 try:\r
1107 p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
1108 out, err = p.communicate()\r
1109 except Exception as X:\r
1110 raise BadExpression("DevicePath: %s" % (str(X)) )\r
1111 finally:\r
1112 subprocess._cleanup()\r
1113 p.stdout.close()\r
1114 p.stderr.close()\r
1115 if err:\r
1116 raise BadExpression("DevicePath: %s" % str(err))\r
1117 out = out.decode()\r
1118 Size = len(out.split())\r
1119 out = ','.join(out.split())\r
1120 return '{' + out + '}', Size\r
1121\r
1122 if "{CODE(" in Value:\r
1123 return Value, len(Value.split(","))\r
1124 if isinstance(Value, type(0)):\r
1125 return Value, (Value.bit_length() + 7) // 8\r
1126 if not isinstance(Value, type('')):\r
1127 raise BadExpression('Type %s is %s' %(Value, type(Value)))\r
1128 Value = Value.strip()\r
1129 if Value.startswith(TAB_UINT8) and Value.endswith(')'):\r
1130 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1131 if Size > 1:\r
1132 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1133 return Value, 1\r
1134 if Value.startswith(TAB_UINT16) and Value.endswith(')'):\r
1135 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1136 if Size > 2:\r
1137 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1138 return Value, 2\r
1139 if Value.startswith(TAB_UINT32) and Value.endswith(')'):\r
1140 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1141 if Size > 4:\r
1142 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1143 return Value, 4\r
1144 if Value.startswith(TAB_UINT64) and Value.endswith(')'):\r
1145 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1146 if Size > 8:\r
1147 raise BadExpression('Value (%s) Size larger than %d' % (Value, Size))\r
1148 return Value, 8\r
1149 if Value.startswith(TAB_GUID) and Value.endswith(')'):\r
1150 Value = Value.split('(', 1)[1][:-1].strip()\r
1151 if Value[0] == '{' and Value[-1] == '}':\r
1152 TmpValue = GuidStructureStringToGuidString(Value)\r
1153 if not TmpValue:\r
1154 raise BadExpression("Invalid GUID value string %s" % Value)\r
1155 Value = TmpValue\r
1156 if Value[0] == '"' and Value[-1] == '"':\r
1157 Value = Value[1:-1]\r
1158 try:\r
1159 Value = uuid.UUID(Value).bytes_le\r
1160 ValueL, ValueH = struct.unpack('2Q', Value)\r
1161 Value = (ValueH << 64 ) | ValueL\r
1162\r
1163 except ValueError as Message:\r
1164 raise BadExpression(Message)\r
1165 return Value, 16\r
1166 if Value.startswith('L"') and Value.endswith('"'):\r
1167 # Unicode String\r
1168 # translate escape character\r
1169 Value = Value[1:]\r
1170 try:\r
1171 Value = eval(Value)\r
1172 except:\r
1173 Value = Value[1:-1]\r
1174 List = list(Value)\r
1175 List.reverse()\r
1176 Value = 0\r
1177 for Char in List:\r
1178 Value = (Value << 16) | ord(Char)\r
1179 return Value, (len(List) + 1) * 2\r
1180 if Value.startswith('"') and Value.endswith('"'):\r
1181 # ASCII String\r
1182 # translate escape character\r
1183 try:\r
1184 Value = eval(Value)\r
1185 except:\r
1186 Value = Value[1:-1]\r
1187 List = list(Value)\r
1188 List.reverse()\r
1189 Value = 0\r
1190 for Char in List:\r
1191 Value = (Value << 8) | ord(Char)\r
1192 return Value, len(List) + 1\r
1193 if Value.startswith("L'") and Value.endswith("'"):\r
1194 # Unicode Character Constant\r
1195 # translate escape character\r
1196 Value = Value[1:]\r
1197 try:\r
1198 Value = eval(Value)\r
1199 except:\r
1200 Value = Value[1:-1]\r
1201 List = list(Value)\r
1202 if len(List) == 0:\r
1203 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
1204 List.reverse()\r
1205 Value = 0\r
1206 for Char in List:\r
1207 Value = (Value << 16) | ord(Char)\r
1208 return Value, len(List) * 2\r
1209 if Value.startswith("'") and Value.endswith("'"):\r
1210 # Character constant\r
1211 # translate escape character\r
1212 try:\r
1213 Value = eval(Value)\r
1214 except:\r
1215 Value = Value[1:-1]\r
1216 List = list(Value)\r
1217 if len(List) == 0:\r
1218 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
1219 List.reverse()\r
1220 Value = 0\r
1221 for Char in List:\r
1222 Value = (Value << 8) | ord(Char)\r
1223 return Value, len(List)\r
1224 if Value.startswith('{') and Value.endswith('}'):\r
1225 # Byte array\r
1226 Value = Value[1:-1]\r
1227 List = [Item.strip() for Item in Value.split(',')]\r
1228 List.reverse()\r
1229 Value = 0\r
1230 RetSize = 0\r
1231 for Item in List:\r
1232 ItemValue, Size = ParseFieldValue(Item)\r
1233 RetSize += Size\r
1234 for I in range(Size):\r
1235 Value = (Value << 8) | ((ItemValue >> 8 * I) & 0xff)\r
1236 return Value, RetSize\r
1237 if Value.startswith('DEVICE_PATH(') and Value.endswith(')'):\r
1238 Value = Value.replace("DEVICE_PATH(", '').rstrip(')')\r
1239 Value = Value.strip().strip('"')\r
1240 return ParseDevPathValue(Value)\r
1241 if Value.lower().startswith('0x'):\r
1242 try:\r
1243 Value = int(Value, 16)\r
1244 except:\r
1245 raise BadExpression("invalid hex value: %s" % Value)\r
1246 if Value == 0:\r
1247 return 0, 1\r
1248 return Value, (Value.bit_length() + 7) // 8\r
1249 if Value[0].isdigit():\r
1250 Value = int(Value, 10)\r
1251 if Value == 0:\r
1252 return 0, 1\r
1253 return Value, (Value.bit_length() + 7) // 8\r
1254 if Value.lower() == 'true':\r
1255 return 1, 1\r
1256 if Value.lower() == 'false':\r
1257 return 0, 1\r
1258 return Value, 1\r
1259\r
1260## AnalyzeDscPcd\r
1261#\r
1262# Analyze DSC PCD value, since there is no data type info in DSC\r
1263# This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database\r
1264# 1. Feature flag: TokenSpace.PcdCName|PcdValue\r
1265# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]\r
1266# 3. Dynamic default:\r
1267# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]\r
1268# TokenSpace.PcdCName|PcdValue\r
1269# 4. Dynamic VPD:\r
1270# TokenSpace.PcdCName|VpdOffset[|VpdValue]\r
1271# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]\r
1272# 5. Dynamic HII:\r
1273# TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue]\r
1274# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which\r
1275# there might have "|" operator, also in string value.\r
1276#\r
1277# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped\r
1278# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII\r
1279# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL\r
1280# @retval:\r
1281# ValueList: A List contain fields described above\r
1282# IsValid: True if conforming EBNF, otherwise False\r
1283# Index: The index where PcdValue is in ValueList\r
1284#\r
1285def AnalyzeDscPcd(Setting, PcdType, DataType=''):\r
1286 FieldList = AnalyzePcdExpression(Setting)\r
1287\r
1288 IsValid = True\r
1289 if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):\r
1290 Value = FieldList[0]\r
1291 Size = ''\r
1292 if len(FieldList) > 1 and FieldList[1]:\r
1293 DataType = FieldList[1]\r
1294 if FieldList[1] != TAB_VOID and StructPattern.match(FieldList[1]) is None:\r
1295 IsValid = False\r
1296 if len(FieldList) > 2:\r
1297 Size = FieldList[2]\r
1298 if IsValid:\r
1299 if DataType == "":\r
1300 IsValid = (len(FieldList) <= 1)\r
1301 else:\r
1302 IsValid = (len(FieldList) <= 3)\r
1303\r
1304 if Size:\r
1305 try:\r
1306 int(Size, 16) if Size.upper().startswith("0X") else int(Size)\r
1307 except:\r
1308 IsValid = False\r
1309 Size = -1\r
1310 return [str(Value), DataType, str(Size)], IsValid, 0\r
1311 elif PcdType == MODEL_PCD_FEATURE_FLAG:\r
1312 Value = FieldList[0]\r
1313 Size = ''\r
1314 IsValid = (len(FieldList) <= 1)\r
1315 return [Value, DataType, str(Size)], IsValid, 0\r
1316 elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):\r
1317 VpdOffset = FieldList[0]\r
1318 Value = Size = ''\r
1319 if not DataType == TAB_VOID:\r
1320 if len(FieldList) > 1:\r
1321 Value = FieldList[1]\r
1322 else:\r
1323 if len(FieldList) > 1:\r
1324 Size = FieldList[1]\r
1325 if len(FieldList) > 2:\r
1326 Value = FieldList[2]\r
1327 if DataType == "":\r
1328 IsValid = (len(FieldList) <= 1)\r
1329 else:\r
1330 IsValid = (len(FieldList) <= 3)\r
1331 if Size:\r
1332 try:\r
1333 int(Size, 16) if Size.upper().startswith("0X") else int(Size)\r
1334 except:\r
1335 IsValid = False\r
1336 Size = -1\r
1337 return [VpdOffset, str(Size), Value], IsValid, 2\r
1338 elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):\r
1339 IsValid = (3 <= len(FieldList) <= 5)\r
1340 HiiString = FieldList[0]\r
1341 Guid = Offset = Value = Attribute = ''\r
1342 if len(FieldList) > 1:\r
1343 Guid = FieldList[1]\r
1344 if len(FieldList) > 2:\r
1345 Offset = FieldList[2]\r
1346 if len(FieldList) > 3:\r
1347 Value = FieldList[3]\r
1348 if len(FieldList) > 4:\r
1349 Attribute = FieldList[4]\r
1350 return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3\r
1351 return [], False, 0\r
1352\r
1353## AnalyzePcdData\r
1354#\r
1355# Analyze the pcd Value, Datum type and TokenNumber.\r
1356# Used to avoid split issue while the value string contain "|" character\r
1357#\r
1358# @param[in] Setting: A String contain value/datum type/token number information;\r
1359#\r
1360# @retval ValueList: A List contain value, datum type and toke number.\r
1361#\r
1362def AnalyzePcdData(Setting):\r
1363 ValueList = ['', '', '']\r
1364\r
1365 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')\r
1366 PtrValue = ValueRe.findall(Setting)\r
1367\r
1368 ValueUpdateFlag = False\r
1369\r
1370 if len(PtrValue) >= 1:\r
1371 Setting = re.sub(ValueRe, '', Setting)\r
1372 ValueUpdateFlag = True\r
1373\r
1374 TokenList = Setting.split(TAB_VALUE_SPLIT)\r
1375 ValueList[0:len(TokenList)] = TokenList\r
1376\r
1377 if ValueUpdateFlag:\r
1378 ValueList[0] = PtrValue[0]\r
1379\r
1380 return ValueList\r
1381\r
1382## check format of PCD value against its the datum type\r
1383#\r
1384# For PCD value setting\r
1385#\r
1386def CheckPcdDatum(Type, Value):\r
1387 if Type == TAB_VOID:\r
1388 ValueRe = re.compile(r'\s*L?\".*\"\s*$')\r
1389 if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))\r
1390 or (Value.startswith('{') and Value.endswith('}')) or (Value.startswith("L'") or Value.startswith("'") and Value.endswith("'"))\r
1391 ):\r
1392 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\\r
1393 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value, Type)\r
1394 elif ValueRe.match(Value):\r
1395 # Check the chars in UnicodeString or CString is printable\r
1396 if Value.startswith("L"):\r
1397 Value = Value[2:-1]\r
1398 else:\r
1399 Value = Value[1:-1]\r
1400 Printset = set(string.printable)\r
1401 Printset.remove(TAB_PRINTCHAR_VT)\r
1402 Printset.add(TAB_PRINTCHAR_BS)\r
1403 Printset.add(TAB_PRINTCHAR_NUL)\r
1404 if not set(Value).issubset(Printset):\r
1405 PrintList = sorted(Printset)\r
1406 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)\r
1407 elif Type == 'BOOLEAN':\r
1408 if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:\r
1409 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\\r
1410 ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)\r
1411 elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:\r
1412 if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'):\r
1413 Value = Value.lstrip('0')\r
1414 try:\r
1415 if Value and int(Value, 0) < 0:\r
1416 return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value, Type)\r
1417 Value = int(Value, 0)\r
1418 if Value > MAX_VAL_TYPE[Type]:\r
1419 return False, "Too large PCD value[%s] for datum type [%s]" % (Value, Type)\r
1420 except:\r
1421 return False, "Invalid value [%s] of type [%s];"\\r
1422 " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)\r
1423 else:\r
1424 return True, "StructurePcd"\r
1425\r
1426 return True, ""\r
1427\r
1428def CommonPath(PathList):\r
1429 P1 = min(PathList).split(os.path.sep)\r
1430 P2 = max(PathList).split(os.path.sep)\r
1431 for Index in range(min(len(P1), len(P2))):\r
1432 if P1[Index] != P2[Index]:\r
1433 return os.path.sep.join(P1[:Index])\r
1434 return os.path.sep.join(P1)\r
1435\r
1436class PathClass(object):\r
1437 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,\r
1438 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):\r
1439 self.Arch = Arch\r
1440 self.File = str(File)\r
1441 if os.path.isabs(self.File):\r
1442 self.Root = ''\r
1443 self.AlterRoot = ''\r
1444 else:\r
1445 self.Root = str(Root)\r
1446 self.AlterRoot = str(AlterRoot)\r
1447\r
1448 # Remove any '.' and '..' in path\r
1449 if self.Root:\r
1450 self.Root = mws.getWs(self.Root, self.File)\r
1451 self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
1452 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
1453 # eliminate the side-effect of 'C:'\r
1454 if self.Root[-1] == ':':\r
1455 self.Root += os.path.sep\r
1456 # file path should not start with path separator\r
1457 if self.Root[-1] == os.path.sep:\r
1458 self.File = self.Path[len(self.Root):]\r
1459 else:\r
1460 self.File = self.Path[len(self.Root) + 1:]\r
1461 else:\r
1462 self.Path = os.path.normpath(self.File)\r
1463\r
1464 self.SubDir, self.Name = os.path.split(self.File)\r
1465 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1466\r
1467 if self.Root:\r
1468 if self.SubDir:\r
1469 self.Dir = os.path.join(self.Root, self.SubDir)\r
1470 else:\r
1471 self.Dir = self.Root\r
1472 else:\r
1473 self.Dir = self.SubDir\r
1474\r
1475 if IsBinary:\r
1476 self.Type = Type\r
1477 else:\r
1478 self.Type = self.Ext.lower()\r
1479\r
1480 self.IsBinary = IsBinary\r
1481 self.Target = Target\r
1482 self.TagName = TagName\r
1483 self.ToolCode = ToolCode\r
1484 self.ToolChainFamily = ToolChainFamily\r
1485 self.OriginalPath = self\r
1486\r
1487 ## Convert the object of this class to a string\r
1488 #\r
1489 # Convert member Path of the class to a string\r
1490 #\r
1491 # @retval string Formatted String\r
1492 #\r
1493 def __str__(self):\r
1494 return self.Path\r
1495\r
1496 ## Override __eq__ function\r
1497 #\r
1498 # Check whether PathClass are the same\r
1499 #\r
1500 # @retval False The two PathClass are different\r
1501 # @retval True The two PathClass are the same\r
1502 #\r
1503 def __eq__(self, Other):\r
1504 return self.Path == str(Other)\r
1505\r
1506 ## Override __cmp__ function\r
1507 #\r
1508 # Customize the comparison operation of two PathClass\r
1509 #\r
1510 # @retval 0 The two PathClass are different\r
1511 # @retval -1 The first PathClass is less than the second PathClass\r
1512 # @retval 1 The first PathClass is Bigger than the second PathClass\r
1513 def __cmp__(self, Other):\r
1514 OtherKey = str(Other)\r
1515\r
1516 SelfKey = self.Path\r
1517 if SelfKey == OtherKey:\r
1518 return 0\r
1519 elif SelfKey > OtherKey:\r
1520 return 1\r
1521 else:\r
1522 return -1\r
1523\r
1524 ## Override __hash__ function\r
1525 #\r
1526 # Use Path as key in hash table\r
1527 #\r
1528 # @retval string Key for hash table\r
1529 #\r
1530 def __hash__(self):\r
1531 return hash(self.Path)\r
1532\r
1533 @cached_property\r
1534 def Key(self):\r
1535 return self.Path.upper()\r
1536\r
1537 @property\r
1538 def TimeStamp(self):\r
1539 return os.stat(self.Path)[8]\r
1540\r
1541 def Validate(self, Type='', CaseSensitive=True):\r
1542 def RealPath2(File, Dir='', OverrideDir=''):\r
1543 NewFile = None\r
1544 if OverrideDir:\r
1545 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]\r
1546 if NewFile:\r
1547 if OverrideDir[-1] == os.path.sep:\r
1548 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]\r
1549 else:\r
1550 return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)]\r
1551 if GlobalData.gAllFiles:\r
1552 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]\r
1553 if not NewFile:\r
1554 NewFile = os.path.normpath(os.path.join(Dir, File))\r
1555 if not os.path.exists(NewFile):\r
1556 return None, None\r
1557 if NewFile:\r
1558 if Dir:\r
1559 if Dir[-1] == os.path.sep:\r
1560 return NewFile[len(Dir):], NewFile[0:len(Dir)]\r
1561 else:\r
1562 return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]\r
1563 else:\r
1564 return NewFile, ''\r
1565\r
1566 return None, None\r
1567\r
1568 if GlobalData.gCaseInsensitive:\r
1569 CaseSensitive = False\r
1570 if Type and Type.lower() != self.Type:\r
1571 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)\r
1572\r
1573 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)\r
1574 if not RealRoot and not RealFile:\r
1575 RealFile = self.File\r
1576 if self.AlterRoot:\r
1577 RealFile = os.path.join(self.AlterRoot, self.File)\r
1578 elif self.Root:\r
1579 RealFile = os.path.join(self.Root, self.File)\r
1580 if len (mws.getPkgPath()) == 0:\r
1581 return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
1582 else:\r
1583 return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))\r
1584\r
1585 ErrorCode = 0\r
1586 ErrorInfo = ''\r
1587 if RealRoot != self.Root or RealFile != self.File:\r
1588 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):\r
1589 ErrorCode = FILE_CASE_MISMATCH\r
1590 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"\r
1591\r
1592 self.SubDir, self.Name = os.path.split(RealFile)\r
1593 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1594 if self.SubDir:\r
1595 self.Dir = os.path.join(RealRoot, self.SubDir)\r
1596 else:\r
1597 self.Dir = RealRoot\r
1598 self.File = RealFile\r
1599 self.Root = RealRoot\r
1600 self.Path = os.path.join(RealRoot, RealFile)\r
1601 return ErrorCode, ErrorInfo\r
1602\r
1603## Parse PE image to get the required PE information.\r
1604#\r
1605class PeImageClass():\r
1606 ## Constructor\r
1607 #\r
1608 # @param File FilePath of PeImage\r
1609 #\r
1610 def __init__(self, PeFile):\r
1611 self.FileName = PeFile\r
1612 self.IsValid = False\r
1613 self.Size = 0\r
1614 self.EntryPoint = 0\r
1615 self.SectionAlignment = 0\r
1616 self.SectionHeaderList = []\r
1617 self.ErrorInfo = ''\r
1618 try:\r
1619 PeObject = open(PeFile, 'rb')\r
1620 except:\r
1621 self.ErrorInfo = self.FileName + ' can not be found\n'\r
1622 return\r
1623 # Read DOS header\r
1624 ByteArray = array.array('B')\r
1625 ByteArray.fromfile(PeObject, 0x3E)\r
1626 ByteList = ByteArray.tolist()\r
1627 # DOS signature should be 'MZ'\r
1628 if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':\r
1629 self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'\r
1630 return\r
1631\r
1632 # Read 4 byte PE Signature\r
1633 PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])\r
1634 PeObject.seek(PeOffset)\r
1635 ByteArray = array.array('B')\r
1636 ByteArray.fromfile(PeObject, 4)\r
1637 # PE signature should be 'PE\0\0'\r
1638 if ByteArray.tolist() != [ord('P'), ord('E'), 0, 0]:\r
1639 self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'\r
1640 return\r
1641\r
1642 # Read PE file header\r
1643 ByteArray = array.array('B')\r
1644 ByteArray.fromfile(PeObject, 0x14)\r
1645 ByteList = ByteArray.tolist()\r
1646 SecNumber = self._ByteListToInt(ByteList[0x2:0x4])\r
1647 if SecNumber == 0:\r
1648 self.ErrorInfo = self.FileName + ' has no section header'\r
1649 return\r
1650\r
1651 # Read PE optional header\r
1652 OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])\r
1653 ByteArray = array.array('B')\r
1654 ByteArray.fromfile(PeObject, OptionalHeaderSize)\r
1655 ByteList = ByteArray.tolist()\r
1656 self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])\r
1657 self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])\r
1658 self.Size = self._ByteListToInt(ByteList[0x38:0x3C])\r
1659\r
1660 # Read each Section Header\r
1661 for Index in range(SecNumber):\r
1662 ByteArray = array.array('B')\r
1663 ByteArray.fromfile(PeObject, 0x28)\r
1664 ByteList = ByteArray.tolist()\r
1665 SecName = self._ByteListToStr(ByteList[0:8])\r
1666 SecVirtualSize = self._ByteListToInt(ByteList[8:12])\r
1667 SecRawAddress = self._ByteListToInt(ByteList[20:24])\r
1668 SecVirtualAddress = self._ByteListToInt(ByteList[12:16])\r
1669 self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))\r
1670 self.IsValid = True\r
1671 PeObject.close()\r
1672\r
1673 def _ByteListToStr(self, ByteList):\r
1674 String = ''\r
1675 for index in range(len(ByteList)):\r
1676 if ByteList[index] == 0:\r
1677 break\r
1678 String += chr(ByteList[index])\r
1679 return String\r
1680\r
1681 def _ByteListToInt(self, ByteList):\r
1682 Value = 0\r
1683 for index in range(len(ByteList) - 1, -1, -1):\r
1684 Value = (Value << 8) | int(ByteList[index])\r
1685 return Value\r
1686\r
1687class DefaultStore():\r
1688 def __init__(self, DefaultStores ):\r
1689\r
1690 self.DefaultStores = DefaultStores\r
1691 def DefaultStoreID(self, DefaultStoreName):\r
1692 for key, value in self.DefaultStores.items():\r
1693 if value == DefaultStoreName:\r
1694 return key\r
1695 return None\r
1696 def GetDefaultDefault(self):\r
1697 if not self.DefaultStores or "0" in self.DefaultStores:\r
1698 return "0", TAB_DEFAULT_STORES_DEFAULT\r
1699 else:\r
1700 minvalue = min(int(value_str) for value_str in self.DefaultStores)\r
1701 return (str(minvalue), self.DefaultStores[str(minvalue)])\r
1702 def GetMin(self, DefaultSIdList):\r
1703 if not DefaultSIdList:\r
1704 return TAB_DEFAULT_STORES_DEFAULT\r
1705 storeidset = {storeid for storeid, storename in self.DefaultStores.values() if storename in DefaultSIdList}\r
1706 if not storeidset:\r
1707 return ""\r
1708 minid = min(storeidset )\r
1709 for sid, name in self.DefaultStores.values():\r
1710 if sid == minid:\r
1711 return name\r
1712\r
1713class SkuClass():\r
1714 DEFAULT = 0\r
1715 SINGLE = 1\r
1716 MULTIPLE =2\r
1717\r
1718 def __init__(self,SkuIdentifier='', SkuIds=None):\r
1719 if SkuIds is None:\r
1720 SkuIds = {}\r
1721\r
1722 for SkuName in SkuIds:\r
1723 SkuId = SkuIds[SkuName][0]\r
1724 skuid_num = int(SkuId, 16) if SkuId.upper().startswith("0X") else int(SkuId)\r
1725 if skuid_num > 0xFFFFFFFFFFFFFFFF:\r
1726 EdkLogger.error("build", PARAMETER_INVALID,\r
1727 ExtraData = "SKU-ID [%s] value %s exceeds the max value of UINT64"\r
1728 % (SkuName, SkuId))\r
1729\r
1730 self.AvailableSkuIds = OrderedDict()\r
1731 self.SkuIdSet = []\r
1732 self.SkuIdNumberSet = []\r
1733 self.SkuData = SkuIds\r
1734 self._SkuInherit = {}\r
1735 self._SkuIdentifier = SkuIdentifier\r
1736 if SkuIdentifier == '' or SkuIdentifier is None:\r
1737 self.SkuIdSet = ['DEFAULT']\r
1738 self.SkuIdNumberSet = ['0U']\r
1739 elif SkuIdentifier == 'ALL':\r
1740 self.SkuIdSet = list(SkuIds.keys())\r
1741 self.SkuIdNumberSet = [num[0].strip() + 'U' for num in SkuIds.values()]\r
1742 else:\r
1743 r = SkuIdentifier.split('|')\r
1744 self.SkuIdSet=[(r[k].strip()).upper() for k in range(len(r))]\r
1745 k = None\r
1746 try:\r
1747 self.SkuIdNumberSet = [SkuIds[k][0].strip() + 'U' for k in self.SkuIdSet]\r
1748 except Exception:\r
1749 EdkLogger.error("build", PARAMETER_INVALID,\r
1750 ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
1751 % (k, " | ".join(SkuIds.keys())))\r
1752 for each in self.SkuIdSet:\r
1753 if each in SkuIds:\r
1754 self.AvailableSkuIds[each] = SkuIds[each][0]\r
1755 else:\r
1756 EdkLogger.error("build", PARAMETER_INVALID,\r
1757 ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
1758 % (each, " | ".join(SkuIds.keys())))\r
1759 if self.SkuUsageType != SkuClass.SINGLE:\r
1760 self.AvailableSkuIds.update({'DEFAULT':0, 'COMMON':0})\r
1761 if self.SkuIdSet:\r
1762 GlobalData.gSkuids = (self.SkuIdSet)\r
1763 if 'COMMON' in GlobalData.gSkuids:\r
1764 GlobalData.gSkuids.remove('COMMON')\r
1765 if self.SkuUsageType == self.SINGLE:\r
1766 if len(GlobalData.gSkuids) != 1:\r
1767 if 'DEFAULT' in GlobalData.gSkuids:\r
1768 GlobalData.gSkuids.remove('DEFAULT')\r
1769 if GlobalData.gSkuids:\r
1770 GlobalData.gSkuids.sort()\r
1771\r
1772 def GetNextSkuId(self, skuname):\r
1773 if not self._SkuInherit:\r
1774 self._SkuInherit = {}\r
1775 for item in self.SkuData.values():\r
1776 self._SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT"\r
1777 return self._SkuInherit.get(skuname, "DEFAULT")\r
1778\r
1779 def GetSkuChain(self, sku):\r
1780 if sku == "DEFAULT":\r
1781 return ["DEFAULT"]\r
1782 skulist = [sku]\r
1783 nextsku = sku\r
1784 while True:\r
1785 nextsku = self.GetNextSkuId(nextsku)\r
1786 skulist.append(nextsku)\r
1787 if nextsku == "DEFAULT":\r
1788 break\r
1789 skulist.reverse()\r
1790 return skulist\r
1791 def SkuOverrideOrder(self):\r
1792 skuorderset = []\r
1793 for skuname in self.SkuIdSet:\r
1794 skuorderset.append(self.GetSkuChain(skuname))\r
1795\r
1796 skuorder = []\r
1797 for index in range(max(len(item) for item in skuorderset)):\r
1798 for subset in skuorderset:\r
1799 if index > len(subset)-1:\r
1800 continue\r
1801 if subset[index] in skuorder:\r
1802 continue\r
1803 skuorder.append(subset[index])\r
1804\r
1805 return skuorder\r
1806\r
1807 @property\r
1808 def SkuUsageType(self):\r
1809 if self._SkuIdentifier.upper() == "ALL":\r
1810 return SkuClass.MULTIPLE\r
1811\r
1812 if len(self.SkuIdSet) == 1:\r
1813 if self.SkuIdSet[0] == 'DEFAULT':\r
1814 return SkuClass.DEFAULT\r
1815 return SkuClass.SINGLE\r
1816 if len(self.SkuIdSet) == 2 and 'DEFAULT' in self.SkuIdSet:\r
1817 return SkuClass.SINGLE\r
1818 return SkuClass.MULTIPLE\r
1819\r
1820 def DumpSkuIdArrary(self):\r
1821 if self.SkuUsageType == SkuClass.SINGLE:\r
1822 return "{0x0}"\r
1823 ArrayStrList = []\r
1824 for skuname in self.AvailableSkuIds:\r
1825 if skuname == "COMMON":\r
1826 continue\r
1827 while skuname != "DEFAULT":\r
1828 ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname])))\r
1829 skuname = self.GetNextSkuId(skuname)\r
1830 ArrayStrList.append("0x0")\r
1831 return "{{{myList}}}".format(myList=",".join(ArrayStrList))\r
1832\r
1833 @property\r
1834 def AvailableSkuIdSet(self):\r
1835 return self.AvailableSkuIds\r
1836\r
1837 @property\r
1838 def SystemSkuId(self):\r
1839 if self.SkuUsageType == SkuClass.SINGLE:\r
1840 if len(self.SkuIdSet) == 1:\r
1841 return self.SkuIdSet[0]\r
1842 else:\r
1843 return self.SkuIdSet[0] if self.SkuIdSet[0] != 'DEFAULT' else self.SkuIdSet[1]\r
1844 else:\r
1845 return 'DEFAULT'\r
1846\r
1847## Get the integer value from string like "14U" or integer like 2\r
1848#\r
1849# @param Input The object that may be either a integer value or a string\r
1850#\r
1851# @retval Value The integer value that the input represents\r
1852#\r
1853def GetIntegerValue(Input):\r
1854 if not isinstance(Input, str):\r
1855 return Input\r
1856 String = Input\r
1857 if String.endswith("U"):\r
1858 String = String[:-1]\r
1859 if String.endswith("ULL"):\r
1860 String = String[:-3]\r
1861 if String.endswith("LL"):\r
1862 String = String[:-2]\r
1863\r
1864 if String.startswith("0x") or String.startswith("0X"):\r
1865 return int(String, 16)\r
1866 elif String == '':\r
1867 return 0\r
1868 else:\r
1869 return int(String)\r
1870\r
1871#\r
1872# Pack a GUID (registry format) list into a buffer and return it\r
1873#\r
1874def PackGUID(Guid):\r
1875 return pack(PACK_PATTERN_GUID,\r
1876 int(Guid[0], 16),\r
1877 int(Guid[1], 16),\r
1878 int(Guid[2], 16),\r
1879 int(Guid[3][-4:-2], 16),\r
1880 int(Guid[3][-2:], 16),\r
1881 int(Guid[4][-12:-10], 16),\r
1882 int(Guid[4][-10:-8], 16),\r
1883 int(Guid[4][-8:-6], 16),\r
1884 int(Guid[4][-6:-4], 16),\r
1885 int(Guid[4][-4:-2], 16),\r
1886 int(Guid[4][-2:], 16)\r
1887 )\r
1888\r
1889#\r
1890# Pack a GUID (byte) list into a buffer and return it\r
1891#\r
1892def PackByteFormatGUID(Guid):\r
1893 return pack(PACK_PATTERN_GUID,\r
1894 Guid[0],\r
1895 Guid[1],\r
1896 Guid[2],\r
1897 Guid[3],\r
1898 Guid[4],\r
1899 Guid[5],\r
1900 Guid[6],\r
1901 Guid[7],\r
1902 Guid[8],\r
1903 Guid[9],\r
1904 Guid[10],\r
1905 )\r
1906\r
1907## DeepCopy dict/OrderedDict recusively\r
1908#\r
1909# @param ori_dict a nested dict or ordereddict\r
1910#\r
1911# @retval new dict or orderdict\r
1912#\r
1913def CopyDict(ori_dict):\r
1914 dict_type = ori_dict.__class__\r
1915 if dict_type not in (dict,OrderedDict):\r
1916 return ori_dict\r
1917 new_dict = dict_type()\r
1918 for key in ori_dict:\r
1919 if isinstance(ori_dict[key],(dict,OrderedDict)):\r
1920 new_dict[key] = CopyDict(ori_dict[key])\r
1921 else:\r
1922 new_dict[key] = ori_dict[key]\r
1923 return new_dict\r
1924\r
1925#\r
1926# Remove the c/c++ comments: // and /* */\r
1927#\r
1928def RemoveCComments(ctext):\r
1929 return re.sub('//.*?\n|/\*.*?\*/', '\n', ctext, flags=re.S)\r