2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 from __future__
import absolute_import
18 import Common
.LongFilePathOs
as os
27 from random
import sample
28 from struct
import pack
29 from UserDict
import IterableUserDict
30 from UserList
import UserList
32 from Common
import EdkLogger
as EdkLogger
33 from Common
import GlobalData
as GlobalData
34 from .DataType
import *
35 from .BuildToolError
import *
36 from CommonDataClass
.DataClass
import *
37 from .Parsing
import GetSplitValueList
38 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
39 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
41 from CommonDataClass
.Exceptions
import BadExpression
42 from Common
.caching
import cached_property
44 from collections
import OrderedDict
45 ## Regular expression used to find out place holders in string template
46 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
48 ## regular expressions for map file processing
49 startPatternGeneral
= re
.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
50 addressPatternGeneral
= re
.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
51 valuePatternGcc
= re
.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
52 pcdPatternGcc
= re
.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
53 secReGeneral
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
55 StructPattern
= re
.compile(r
'[_a-zA-Z][0-9A-Za-z_]*$')
57 ## Dictionary used to store file time stamp for quick re-access
58 gFileTimeStampCache
= {} # {file path : file time stamp}
60 ## Dictionary used to store dependencies of files
61 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
64 # If a module is built more than once with different PCDs or library classes
65 # a temporary INF file with same content is created, the temporary file is removed
70 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
71 """ Parse map file to get variable offset in current EFI file
72 @param mapfilepath Map file absolution path
73 @param efifilepath: EFI binary file full path
74 @param varnames iteratable container whose elements are variable names to be searched
76 @return List whos elements are tuple with variable name and raw offset
80 f
= open(mapfilepath
, 'r')
86 if len(lines
) == 0: return None
87 firstline
= lines
[0].strip()
88 if (firstline
.startswith("Archive member included ") and
89 firstline
.endswith(" file (symbol)")):
90 return _parseForGCC(lines
, efifilepath
, varnames
)
91 if firstline
.startswith("# Path:"):
92 return _parseForXcode(lines
, efifilepath
, varnames
)
93 return _parseGeneral(lines
, efifilepath
, varnames
)
95 def _parseForXcode(lines
, efifilepath
, varnames
):
100 if status
== 0 and line
== "# Symbols:":
103 if status
== 1 and len(line
) != 0:
104 for varname
in varnames
:
106 # cannot pregenerate this RegEx since it uses varname from varnames.
107 m
= re
.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname
, line
)
109 ret
.append((varname
, m
.group(1)))
112 def _parseForGCC(lines
, efifilepath
, varnames
):
113 """ Parse map file generated by GCC linker """
117 for index
, line
in enumerate(lines
):
119 # status machine transection
120 if status
== 0 and line
== "Memory Configuration":
123 elif status
== 1 and line
== 'Linker script and memory map':
126 elif status
==2 and line
== 'START GROUP':
132 m
= valuePatternGcc
.match(line
)
134 sections
.append(m
.groups(0))
135 for varname
in varnames
:
137 m
= re
.match("^.data.(%s)" % varname
, line
)
139 m
= re
.match(".data.(%s)$" % varname
, line
)
141 Str
= lines
[index
+ 1]
143 Str
= line
[len(".data.%s" % varname
):]
145 m
= pcdPatternGcc
.match(Str
.strip())
147 varoffset
.append((varname
, int(m
.groups(0)[0], 16), int(sections
[-1][1], 16), sections
[-1][0]))
151 # get section information from efi file
152 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
153 if efisecs
is None or len(efisecs
) == 0:
157 for efisec
in efisecs
:
158 for section
in sections
:
159 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
160 redirection
= int(section
[1], 16) - efisec
[1]
163 for var
in varoffset
:
164 for efisec
in efisecs
:
165 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
166 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
169 def _parseGeneral(lines
, efifilepath
, varnames
):
170 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
171 secs
= [] # key = section name
173 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
177 if startPatternGeneral
.match(line
):
180 if addressPatternGeneral
.match(line
):
183 if line
.startswith("entry point at"):
186 if status
== 1 and len(line
) != 0:
187 m
= secReGeneral
.match(line
)
188 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
189 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
190 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
191 if status
== 2 and len(line
) != 0:
192 for varname
in varnames
:
193 m
= symRe
.match(line
)
194 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
195 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
196 sec_no
= int(sec_no
, 16)
197 sym_offset
= int(sym_offset
, 16)
198 vir_addr
= int(vir_addr
, 16)
199 # cannot pregenerate this RegEx since it uses varname from varnames.
200 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
202 # fond a binary pcd entry in map file
204 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
205 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
207 if not varoffset
: return []
209 # get section information from efi file
210 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
211 if efisecs
is None or len(efisecs
) == 0:
215 for var
in varoffset
:
217 for efisec
in efisecs
:
219 if var
[1].strip() == efisec
[0].strip():
220 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
221 elif var
[4] == index
:
222 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
226 ## Routine to process duplicated INF
228 # This function is called by following two cases:
231 # Pkg/module/module.inf
232 # Pkg/module/module.inf {
234 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
237 # INF Pkg/module/module.inf
238 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
240 # This function copies Pkg/module/module.inf to
241 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
243 # @param Path Original PathClass object
244 # @param BaseName New file base name
246 # @retval return the new PathClass object
248 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
249 Filename
= os
.path
.split(Path
.File
)[1]
251 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
253 Filename
= BaseName
+ Path
.BaseName
256 # If -N is specified on command line, cache is disabled
257 # The directory has to be created
259 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
260 if not os
.path
.exists(DbDir
):
263 # A temporary INF is copied to database path which must have write permission
264 # The temporary will be removed at the end of build
265 # In case of name conflict, the file name is
266 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
268 TempFullPath
= os
.path
.join(DbDir
,
270 RtPath
= PathClass(Path
.File
, Workspace
)
272 # Modify the full path to temporary path, keep other unchanged
274 # To build same module more than once, the module path with FILE_GUID overridden has
275 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
276 # in DSC which is used as relative path by C files and other files in INF.
277 # A trick was used: all module paths are PathClass instances, after the initialization
278 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
280 # The reason for creating a temporary INF is:
281 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
282 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
283 # A different key for the same module is needed to create different output directory,
284 # retrieve overridden PCDs, library instances.
286 # The BaseName is the FILE_GUID which is also the output directory name.
289 RtPath
.Path
= TempFullPath
290 RtPath
.BaseName
= BaseName
292 # If file exists, compare contents
294 if os
.path
.exists(TempFullPath
):
295 with
open(str(Path
), 'rb') as f1
, open(TempFullPath
, 'rb') as f2
:
296 if f1
.read() == f2
.read():
298 _TempInfs
.append(TempFullPath
)
299 shutil
.copy2(str(Path
), TempFullPath
)
302 ## Remove temporary created INFs whose paths were saved in _TempInfs
304 def ClearDuplicatedInf():
306 File
= _TempInfs
.pop()
307 if os
.path
.exists(File
):
310 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
312 # @param Guid The GUID string
314 # @retval string The GUID string in C structure style
316 def GuidStringToGuidStructureString(Guid
):
317 GuidList
= Guid
.split('-')
319 for Index
in range(0, 3, 1):
320 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
321 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
322 for Index
in range(0, 12, 2):
323 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
327 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
329 # @param GuidValue The GUID value in byte array
331 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
333 def GuidStructureByteArrayToGuidString(GuidValue
):
334 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
335 guidValueList
= guidValueString
.split(",")
336 if len(guidValueList
) != 16:
338 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
340 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
341 int(guidValueList
[3], 16),
342 int(guidValueList
[2], 16),
343 int(guidValueList
[1], 16),
344 int(guidValueList
[0], 16),
345 int(guidValueList
[5], 16),
346 int(guidValueList
[4], 16),
347 int(guidValueList
[7], 16),
348 int(guidValueList
[6], 16),
349 int(guidValueList
[8], 16),
350 int(guidValueList
[9], 16),
351 int(guidValueList
[10], 16),
352 int(guidValueList
[11], 16),
353 int(guidValueList
[12], 16),
354 int(guidValueList
[13], 16),
355 int(guidValueList
[14], 16),
356 int(guidValueList
[15], 16)
361 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
363 # @param GuidValue The GUID value in C structure format
365 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
367 def GuidStructureStringToGuidString(GuidValue
):
368 if not GlobalData
.gGuidCFormatPattern
.match(GuidValue
):
370 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
371 guidValueList
= guidValueString
.split(",")
372 if len(guidValueList
) != 11:
374 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
376 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
377 int(guidValueList
[0], 16),
378 int(guidValueList
[1], 16),
379 int(guidValueList
[2], 16),
380 int(guidValueList
[3], 16),
381 int(guidValueList
[4], 16),
382 int(guidValueList
[5], 16),
383 int(guidValueList
[6], 16),
384 int(guidValueList
[7], 16),
385 int(guidValueList
[8], 16),
386 int(guidValueList
[9], 16),
387 int(guidValueList
[10], 16)
392 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
394 # @param GuidValue The GUID value in C structure format
396 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
398 def GuidStructureStringToGuidValueName(GuidValue
):
399 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
400 guidValueList
= guidValueString
.split(",")
401 if len(guidValueList
) != 11:
402 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
403 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
404 int(guidValueList
[0], 16),
405 int(guidValueList
[1], 16),
406 int(guidValueList
[2], 16),
407 int(guidValueList
[3], 16),
408 int(guidValueList
[4], 16),
409 int(guidValueList
[5], 16),
410 int(guidValueList
[6], 16),
411 int(guidValueList
[7], 16),
412 int(guidValueList
[8], 16),
413 int(guidValueList
[9], 16),
414 int(guidValueList
[10], 16)
417 ## Create directories
419 # @param Directory The directory name
421 def CreateDirectory(Directory
):
422 if Directory
is None or Directory
.strip() == "":
425 if not os
.access(Directory
, os
.F_OK
):
426 os
.makedirs(Directory
)
431 ## Remove directories, including files and sub-directories in it
433 # @param Directory The directory name
435 def RemoveDirectory(Directory
, Recursively
=False):
436 if Directory
is None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
439 CurrentDirectory
= os
.getcwd()
441 for File
in os
.listdir("."):
442 if os
.path
.isdir(File
):
443 RemoveDirectory(File
, Recursively
)
446 os
.chdir(CurrentDirectory
)
449 ## Store content in file
451 # This method is used to save file only when its content is changed. This is
452 # quite useful for "make" system to decide what will be re-built and what won't.
454 # @param File The path of file
455 # @param Content The new content of the file
456 # @param IsBinaryFile The flag indicating if the file is binary file or not
458 # @retval True If the file content is changed and the file is renewed
459 # @retval False If the file content is the same
461 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
463 Content
= Content
.replace("\n", os
.linesep
)
465 if os
.path
.exists(File
):
467 if Content
== open(File
, "rb").read():
470 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
472 DirName
= os
.path
.dirname(File
)
473 if not CreateDirectory(DirName
):
474 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
477 DirName
= os
.getcwd()
478 if not os
.access(DirName
, os
.W_OK
):
479 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
482 Fd
= open(File
, "wb")
486 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
490 ## Retrieve and cache the real path name in file system
492 # @param Root The root directory of path relative to
494 # @retval str The path string if the path exists
495 # @retval None If path doesn't exist
501 def __init__(self
, Root
):
503 for F
in os
.listdir(Root
):
505 self
._UPPER
_CACHE
_[F
.upper()] = F
508 def __getitem__(self
, Path
):
509 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
512 if Path
and Path
[0] == os
.path
.sep
:
514 if Path
in self
._CACHE
_:
515 return os
.path
.join(self
._Root
, Path
)
516 UpperPath
= Path
.upper()
517 if UpperPath
in self
._UPPER
_CACHE
_:
518 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
522 SepIndex
= Path
.find(os
.path
.sep
)
524 Parent
= UpperPath
[:SepIndex
]
525 if Parent
not in self
._UPPER
_CACHE
_:
527 LastSepIndex
= SepIndex
528 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
530 if LastSepIndex
== -1:
535 SepIndex
= LastSepIndex
537 Parent
= Path
[:SepIndex
]
538 ParentKey
= UpperPath
[:SepIndex
]
539 if ParentKey
not in self
._UPPER
_CACHE
_:
543 if Parent
in self
._CACHE
_:
546 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
547 for F
in os
.listdir(ParentDir
):
548 Dir
= os
.path
.join(ParentDir
, F
)
549 self
._CACHE
_.add(Dir
)
550 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
552 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
555 if Path
in self
._CACHE
_:
556 return os
.path
.join(self
._Root
, Path
)
557 elif UpperPath
in self
._UPPER
_CACHE
_:
558 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
561 def RealPath(File
, Dir
='', OverrideDir
=''):
562 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
563 NewFile
= GlobalData
.gAllFiles
[NewFile
]
564 if not NewFile
and OverrideDir
:
565 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
566 NewFile
= GlobalData
.gAllFiles
[NewFile
]
569 ## Get GUID value from given packages
571 # @param CName The CName of the GUID
572 # @param PackageList List of packages looking-up in
573 # @param Inffile The driver file
575 # @retval GuidValue if the CName is found in any given package
576 # @retval None if the CName is not found in all given packages
578 def GuidValue(CName
, PackageList
, Inffile
= None):
579 for P
in PackageList
:
580 GuidKeys
= P
.Guids
.keys()
581 if Inffile
and P
._PrivateGuids
:
582 if not Inffile
.startswith(P
.MetaFile
.Dir
):
583 GuidKeys
= [x
for x
in P
.Guids
if x
not in P
._PrivateGuids
]
584 if CName
in GuidKeys
:
585 return P
.Guids
[CName
]
588 ## A string template class
590 # This class implements a template for string replacement. A string template
591 # looks like following
593 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
595 # The string between ${BEGIN} and ${END} will be repeated as many times as the
596 # length of "placeholder_name", which is a list passed through a dict. The
597 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
598 # be not used and, in this case, the "placeholder_name" must not a list and it
599 # will just be replaced once.
601 class TemplateString(object):
602 _REPEAT_START_FLAG
= "BEGIN"
603 _REPEAT_END_FLAG
= "END"
605 class Section(object):
606 _LIST_TYPES
= [type([]), type(set()), type((0,))]
608 def __init__(self
, TemplateSection
, PlaceHolderList
):
609 self
._Template
= TemplateSection
610 self
._PlaceHolderList
= []
612 # Split the section into sub-sections according to the position of placeholders
614 self
._SubSectionList
= []
617 # The placeholders passed in must be in the format of
619 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
621 for PlaceHolder
, Start
, End
in PlaceHolderList
:
622 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
623 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
624 self
._PlaceHolderList
.append(PlaceHolder
)
625 SubSectionStart
= End
626 if SubSectionStart
< len(TemplateSection
):
627 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
629 self
._SubSectionList
= [TemplateSection
]
632 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
634 def Instantiate(self
, PlaceHolderValues
):
636 RepeatPlaceHolders
= {}
637 NonRepeatPlaceHolders
= {}
639 for PlaceHolder
in self
._PlaceHolderList
:
640 if PlaceHolder
not in PlaceHolderValues
:
642 Value
= PlaceHolderValues
[PlaceHolder
]
643 if type(Value
) in self
._LIST
_TYPES
:
645 RepeatTime
= len(Value
)
646 elif RepeatTime
!= len(Value
):
650 "${%s} has different repeat time from others!" % PlaceHolder
,
651 ExtraData
=str(self
._Template
)
653 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
655 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
657 if NonRepeatPlaceHolders
:
659 for S
in self
._SubSectionList
:
660 if S
not in NonRepeatPlaceHolders
:
663 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
665 StringList
= self
._SubSectionList
667 if RepeatPlaceHolders
:
669 for Index
in range(RepeatTime
):
671 if S
not in RepeatPlaceHolders
:
672 TempStringList
.append(S
)
674 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
675 StringList
= TempStringList
677 return "".join(StringList
)
680 def __init__(self
, Template
=None):
682 self
.IsBinary
= False
683 self
._Template
= Template
684 self
._TemplateSectionList
= self
._Parse
(Template
)
688 # @retval string The string replaced
691 return "".join(self
.String
)
693 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
695 # @retval list A list of TemplateString.Section objects
697 def _Parse(self
, Template
):
702 TemplateSectionList
= []
704 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
706 if MatchEnd
<= len(Template
):
707 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
708 TemplateSectionList
.append(TemplateSection
)
711 MatchString
= MatchObj
.group(1)
712 MatchStart
= MatchObj
.start()
713 MatchEnd
= MatchObj
.end()
715 if MatchString
== self
._REPEAT
_START
_FLAG
:
716 if MatchStart
> SectionStart
:
717 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
718 TemplateSectionList
.append(TemplateSection
)
719 SectionStart
= MatchEnd
721 elif MatchString
== self
._REPEAT
_END
_FLAG
:
722 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
723 TemplateSectionList
.append(TemplateSection
)
724 SectionStart
= MatchEnd
727 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
728 SearchFrom
= MatchEnd
729 return TemplateSectionList
731 ## Replace the string template with dictionary of placeholders and append it to previous one
733 # @param AppendString The string template to append
734 # @param Dictionary The placeholder dictionaries
736 def Append(self
, AppendString
, Dictionary
=None):
738 SectionList
= self
._Parse
(AppendString
)
739 self
.String
.append( "".join(S
.Instantiate(Dictionary
) for S
in SectionList
))
741 if isinstance(AppendString
,list):
742 self
.String
.extend(AppendString
)
744 self
.String
.append(AppendString
)
746 ## Replace the string template with dictionary of placeholders
748 # @param Dictionary The placeholder dictionaries
750 # @retval str The string replaced with placeholder values
752 def Replace(self
, Dictionary
=None):
753 return "".join(S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
)
755 ## Progress indicator class
757 # This class makes use of thread to print progress on console.
760 # for avoiding deadloop
762 _ProgressThread
= None
763 _CheckInterval
= 0.25
767 # @param OpenMessage The string printed before progress charaters
768 # @param CloseMessage The string printed after progress charaters
769 # @param ProgressChar The charater used to indicate the progress
770 # @param Interval The interval in seconds between two progress charaters
772 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
773 self
.PromptMessage
= OpenMessage
774 self
.CodaMessage
= CloseMessage
775 self
.ProgressChar
= ProgressChar
776 self
.Interval
= Interval
777 if Progressor
._StopFlag
is None:
778 Progressor
._StopFlag
= threading
.Event()
780 ## Start to print progress charater
782 # @param OpenMessage The string printed before progress charaters
784 def Start(self
, OpenMessage
=None):
785 if OpenMessage
is not None:
786 self
.PromptMessage
= OpenMessage
787 Progressor
._StopFlag
.clear()
788 if Progressor
._ProgressThread
is None:
789 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
790 Progressor
._ProgressThread
.setDaemon(False)
791 Progressor
._ProgressThread
.start()
793 ## Stop printing progress charater
795 # @param CloseMessage The string printed after progress charaters
797 def Stop(self
, CloseMessage
=None):
798 OriginalCodaMessage
= self
.CodaMessage
799 if CloseMessage
is not None:
800 self
.CodaMessage
= CloseMessage
802 self
.CodaMessage
= OriginalCodaMessage
804 ## Thread entry method
805 def _ProgressThreadEntry(self
):
806 sys
.stdout
.write(self
.PromptMessage
+ " ")
809 while not Progressor
._StopFlag
.isSet():
811 sys
.stdout
.write(self
.ProgressChar
)
813 TimeUp
= self
.Interval
814 time
.sleep(self
._CheckInterval
)
815 TimeUp
-= self
._CheckInterval
816 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
819 ## Abort the progress display
822 if Progressor
._StopFlag
is not None:
823 Progressor
._StopFlag
.set()
824 if Progressor
._ProgressThread
is not None:
825 Progressor
._ProgressThread
.join()
826 Progressor
._ProgressThread
= None
828 ## A dict which can access its keys and/or values orderly
830 # The class implements a new kind of dict which its keys or values can be
831 # accessed in the order they are added into the dict. It guarantees the order
832 # by making use of an internal list to keep a copy of keys.
834 class sdict(IterableUserDict
):
837 IterableUserDict
.__init
__(self
)
841 def __setitem__(self
, key
, value
):
842 if key
not in self
._key
_list
:
843 self
._key
_list
.append(key
)
844 IterableUserDict
.__setitem
__(self
, key
, value
)
847 def __delitem__(self
, key
):
848 self
._key
_list
.remove(key
)
849 IterableUserDict
.__delitem
__(self
, key
)
851 ## used in "for k in dict" loop to ensure the correct order
853 return self
.iterkeys()
857 return len(self
._key
_list
)
860 def __contains__(self
, key
):
861 return key
in self
._key
_list
864 def index(self
, key
):
865 return self
._key
_list
.index(key
)
868 def insert(self
, key
, newkey
, newvalue
, order
):
869 index
= self
._key
_list
.index(key
)
870 if order
== 'BEFORE':
871 self
._key
_list
.insert(index
, newkey
)
872 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
873 elif order
== 'AFTER':
874 self
._key
_list
.insert(index
+ 1, newkey
)
875 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
878 def append(self
, sdict
):
880 if key
not in self
._key
_list
:
881 self
._key
_list
.append(key
)
882 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
884 def has_key(self
, key
):
885 return key
in self
._key
_list
890 IterableUserDict
.clear(self
)
892 ## Return a copy of keys
895 for key
in self
._key
_list
:
899 ## Return a copy of values
902 for key
in self
._key
_list
:
903 values
.append(self
[key
])
906 ## Return a copy of (key, value) list
909 for key
in self
._key
_list
:
910 items
.append((key
, self
[key
]))
915 return iter(self
.items())
917 ## Keys interation support
919 return iter(self
.keys())
921 ## Values interation support
922 def itervalues(self
):
923 return iter(self
.values())
925 ## Return value related to a key, and remove the (key, value) from the dict
926 def pop(self
, key
, *dv
):
928 if key
in self
._key
_list
:
930 self
.__delitem
__(key
)
935 ## Return (key, value) pair, and remove the (key, value) from the dict
937 key
= self
._key
_list
[-1]
939 self
.__delitem
__(key
)
942 def update(self
, dict=None, **kwargs
):
944 for k
, v
in dict.items():
947 for k
, v
in kwargs
.items():
950 ## Dictionary with restricted keys
954 def __init__(self
, KeyList
):
956 dict.__setitem
__(self
, Key
, "")
959 def __setitem__(self
, key
, value
):
961 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
962 ExtraData
=", ".join(dict.keys(self
)))
963 dict.__setitem
__(self
, key
, value
)
966 def __getitem__(self
, key
):
969 return dict.__getitem
__(self
, key
)
972 def __delitem__(self
, key
):
973 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
978 self
.__setitem
__(Key
, "")
980 ## Return value related to a key, and remove the (key, value) from the dict
981 def pop(self
, key
, *dv
):
982 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
984 ## Return (key, value) pair, and remove the (key, value) from the dict
986 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
988 ## Dictionary using prioritized list as key
992 _TupleType
= type(())
994 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', TAB_STAR
, 'PLATFORM']
996 def __init__(self
, _Single_
=False, _Level_
=2):
997 self
._Level
_ = _Level_
999 self
._Single
_ = _Single_
1002 def __getitem__(self
, key
):
1005 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1009 elif self
._Level
_ > 1:
1010 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1013 if self
._Level
_ > 1:
1014 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1016 if FirstKey
is None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1017 FirstKey
= self
._Wildcard
1020 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1022 return self
._GetAllValues
(FirstKey
, RestKeys
)
1024 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1026 #print "%s-%s" % (FirstKey, self._Level_) ,
1027 if self
._Level
_ > 1:
1028 if FirstKey
== self
._Wildcard
:
1029 if FirstKey
in self
.data
:
1030 Value
= self
.data
[FirstKey
][RestKeys
]
1032 for Key
in self
.data
:
1033 Value
= self
.data
[Key
][RestKeys
]
1034 if Value
is not None: break
1036 if FirstKey
in self
.data
:
1037 Value
= self
.data
[FirstKey
][RestKeys
]
1038 if Value
is None and self
._Wildcard
in self
.data
:
1040 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1042 if FirstKey
== self
._Wildcard
:
1043 if FirstKey
in self
.data
:
1044 Value
= self
.data
[FirstKey
]
1046 for Key
in self
.data
:
1047 Value
= self
.data
[Key
]
1048 if Value
is not None: break
1050 if FirstKey
in self
.data
:
1051 Value
= self
.data
[FirstKey
]
1052 elif self
._Wildcard
in self
.data
:
1053 Value
= self
.data
[self
._Wildcard
]
1056 def _GetAllValues(self
, FirstKey
, RestKeys
):
1058 if self
._Level
_ > 1:
1059 if FirstKey
== self
._Wildcard
:
1060 for Key
in self
.data
:
1061 Value
+= self
.data
[Key
][RestKeys
]
1063 if FirstKey
in self
.data
:
1064 Value
+= self
.data
[FirstKey
][RestKeys
]
1065 if self
._Wildcard
in self
.data
:
1066 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1068 if FirstKey
== self
._Wildcard
:
1069 for Key
in self
.data
:
1070 Value
.append(self
.data
[Key
])
1072 if FirstKey
in self
.data
:
1073 Value
.append(self
.data
[FirstKey
])
1074 if self
._Wildcard
in self
.data
:
1075 Value
.append(self
.data
[self
._Wildcard
])
1079 def __setitem__(self
, key
, value
):
1082 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1087 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1090 if self
._Level
_ > 1:
1091 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1093 if FirstKey
in self
._ValidWildcardList
:
1094 FirstKey
= self
._Wildcard
1096 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1097 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1099 if self
._Level
_ > 1:
1100 self
.data
[FirstKey
][RestKeys
] = value
1102 self
.data
[FirstKey
] = value
1104 def SetGreedyMode(self
):
1105 self
._Single
_ = False
1106 if self
._Level
_ > 1:
1107 for Key
in self
.data
:
1108 self
.data
[Key
].SetGreedyMode()
1110 def SetSingleMode(self
):
1111 self
._Single
_ = True
1112 if self
._Level
_ > 1:
1113 for Key
in self
.data
:
1114 self
.data
[Key
].SetSingleMode()
1116 def GetKeys(self
, KeyIndex
=0):
1117 assert KeyIndex
>= 0
1119 return set(self
.data
.keys())
1122 for Key
in self
.data
:
1123 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1126 def AnalyzePcdExpression(Setting
):
1127 RanStr
= ''.join(sample(string
.ascii_letters
+ string
.digits
, 8))
1128 Setting
= Setting
.replace('\\\\', RanStr
).strip()
1129 # There might be escaped quote in a string: \", \\\" , \', \\\'
1131 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1133 InSingleQuoteStr
= False
1134 InDoubleQuoteStr
= False
1136 for Index
, ch
in enumerate(Data
):
1137 if ch
== '"' and not InSingleQuoteStr
:
1138 if Data
[Index
- 1] != '\\':
1139 InDoubleQuoteStr
= not InDoubleQuoteStr
1140 elif ch
== "'" and not InDoubleQuoteStr
:
1141 if Data
[Index
- 1] != '\\':
1142 InSingleQuoteStr
= not InSingleQuoteStr
1143 elif ch
== '(' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1145 elif ch
== ')' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1148 if (Pair
> 0 or InSingleQuoteStr
or InDoubleQuoteStr
) and ch
== TAB_VALUE_SPLIT
:
1155 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1157 FieldList
.append(Setting
[StartPos
:].strip())
1159 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1161 for i
, ch
in enumerate(FieldList
):
1163 FieldList
[i
] = ch
.replace(RanStr
,'\\\\')
1166 def ParseFieldValue (Value
):
1167 def ParseDevPathValue (Value
):
1169 Value
.replace('\\', '/').replace(' ', '')
1171 Cmd
= 'DevicePath ' + '"' + Value
+ '"'
1173 p
= subprocess
.Popen(Cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
1174 out
, err
= p
.communicate()
1175 except Exception as X
:
1176 raise BadExpression("DevicePath: %s" % (str(X
)) )
1178 subprocess
._cleanup
()
1182 raise BadExpression("DevicePath: %s" % str(err
))
1183 Size
= len(out
.split())
1184 out
= ','.join(out
.split())
1185 return '{' + out
+ '}', Size
1187 if "{CODE(" in Value
:
1188 return Value
, len(Value
.split(","))
1189 if isinstance(Value
, type(0)):
1190 return Value
, (Value
.bit_length() + 7) / 8
1191 if not isinstance(Value
, type('')):
1192 raise BadExpression('Type %s is %s' %(Value
, type(Value
)))
1193 Value
= Value
.strip()
1194 if Value
.startswith(TAB_UINT8
) and Value
.endswith(')'):
1195 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1197 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1199 if Value
.startswith(TAB_UINT16
) and Value
.endswith(')'):
1200 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1202 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1204 if Value
.startswith(TAB_UINT32
) and Value
.endswith(')'):
1205 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1207 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1209 if Value
.startswith(TAB_UINT64
) and Value
.endswith(')'):
1210 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1212 raise BadExpression('Value (%s) Size larger than %d' % (Value
, Size
))
1214 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1215 Value
= Value
.split('(', 1)[1][:-1].strip()
1216 if Value
[0] == '{' and Value
[-1] == '}':
1217 TmpValue
= GuidStructureStringToGuidString(Value
)
1219 raise BadExpression("Invalid GUID value string %s" % Value
)
1221 if Value
[0] == '"' and Value
[-1] == '"':
1224 Value
= "'" + uuid
.UUID(Value
).get_bytes_le() + "'"
1225 except ValueError as Message
:
1226 raise BadExpression(Message
)
1227 Value
, Size
= ParseFieldValue(Value
)
1229 if Value
.startswith('L"') and Value
.endswith('"'):
1231 # translate escape character
1241 Value
= (Value
<< 16) |
ord(Char
)
1242 return Value
, (len(List
) + 1) * 2
1243 if Value
.startswith('"') and Value
.endswith('"'):
1245 # translate escape character
1254 Value
= (Value
<< 8) |
ord(Char
)
1255 return Value
, len(List
) + 1
1256 if Value
.startswith("L'") and Value
.endswith("'"):
1257 # Unicode Character Constant
1258 # translate escape character
1266 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1270 Value
= (Value
<< 16) |
ord(Char
)
1271 return Value
, len(List
) * 2
1272 if Value
.startswith("'") and Value
.endswith("'"):
1273 # Character constant
1274 # translate escape character
1281 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1285 Value
= (Value
<< 8) |
ord(Char
)
1286 return Value
, len(List
)
1287 if Value
.startswith('{') and Value
.endswith('}'):
1290 List
= [Item
.strip() for Item
in Value
.split(',')]
1295 ItemValue
, Size
= ParseFieldValue(Item
)
1297 for I
in range(Size
):
1298 Value
= (Value
<< 8) |
((ItemValue
>> 8 * I
) & 0xff)
1299 return Value
, RetSize
1300 if Value
.startswith('DEVICE_PATH(') and Value
.endswith(')'):
1301 Value
= Value
.replace("DEVICE_PATH(", '').rstrip(')')
1302 Value
= Value
.strip().strip('"')
1303 return ParseDevPathValue(Value
)
1304 if Value
.lower().startswith('0x'):
1306 Value
= int(Value
, 16)
1308 raise BadExpression("invalid hex value: %s" % Value
)
1311 return Value
, (Value
.bit_length() + 7) / 8
1312 if Value
[0].isdigit():
1313 Value
= int(Value
, 10)
1316 return Value
, (Value
.bit_length() + 7) / 8
1317 if Value
.lower() == 'true':
1319 if Value
.lower() == 'false':
1325 # Analyze DSC PCD value, since there is no data type info in DSC
1326 # This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1327 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1328 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1329 # 3. Dynamic default:
1330 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1331 # TokenSpace.PcdCName|PcdValue
1333 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1334 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1336 # TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue]
1337 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1338 # there might have "|" operator, also in string value.
1340 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1341 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1342 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1344 # ValueList: A List contain fields described above
1345 # IsValid: True if conforming EBNF, otherwise False
1346 # Index: The index where PcdValue is in ValueList
1348 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1349 FieldList
= AnalyzePcdExpression(Setting
)
1352 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1353 Value
= FieldList
[0]
1355 if len(FieldList
) > 1 and FieldList
[1]:
1356 DataType
= FieldList
[1]
1357 if FieldList
[1] != TAB_VOID
and StructPattern
.match(FieldList
[1]) is None:
1359 if len(FieldList
) > 2:
1363 IsValid
= (len(FieldList
) <= 1)
1365 IsValid
= (len(FieldList
) <= 3)
1369 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1373 return [str(Value
), DataType
, str(Size
)], IsValid
, 0
1374 elif PcdType
== MODEL_PCD_FEATURE_FLAG
:
1375 Value
= FieldList
[0]
1377 IsValid
= (len(FieldList
) <= 1)
1378 return [Value
, DataType
, str(Size
)], IsValid
, 0
1379 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1380 VpdOffset
= FieldList
[0]
1382 if not DataType
== TAB_VOID
:
1383 if len(FieldList
) > 1:
1384 Value
= FieldList
[1]
1386 if len(FieldList
) > 1:
1388 if len(FieldList
) > 2:
1389 Value
= FieldList
[2]
1391 IsValid
= (len(FieldList
) <= 1)
1393 IsValid
= (len(FieldList
) <= 3)
1396 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1400 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1401 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1402 IsValid
= (3 <= len(FieldList
) <= 5)
1403 HiiString
= FieldList
[0]
1404 Guid
= Offset
= Value
= Attribute
= ''
1405 if len(FieldList
) > 1:
1407 if len(FieldList
) > 2:
1408 Offset
= FieldList
[2]
1409 if len(FieldList
) > 3:
1410 Value
= FieldList
[3]
1411 if len(FieldList
) > 4:
1412 Attribute
= FieldList
[4]
1413 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1418 # Analyze the pcd Value, Datum type and TokenNumber.
1419 # Used to avoid split issue while the value string contain "|" character
1421 # @param[in] Setting: A String contain value/datum type/token number information;
1423 # @retval ValueList: A List contain value, datum type and toke number.
1425 def AnalyzePcdData(Setting
):
1426 ValueList
= ['', '', '']
1428 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1429 PtrValue
= ValueRe
.findall(Setting
)
1431 ValueUpdateFlag
= False
1433 if len(PtrValue
) >= 1:
1434 Setting
= re
.sub(ValueRe
, '', Setting
)
1435 ValueUpdateFlag
= True
1437 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1438 ValueList
[0:len(TokenList
)] = TokenList
1441 ValueList
[0] = PtrValue
[0]
1445 ## check format of PCD value against its the datum type
1447 # For PCD value setting
1449 def CheckPcdDatum(Type
, Value
):
1450 if Type
== TAB_VOID
:
1451 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1452 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1453 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1455 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1456 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1457 elif ValueRe
.match(Value
):
1458 # Check the chars in UnicodeString or CString is printable
1459 if Value
.startswith("L"):
1463 Printset
= set(string
.printable
)
1464 Printset
.remove(TAB_PRINTCHAR_VT
)
1465 Printset
.add(TAB_PRINTCHAR_BS
)
1466 Printset
.add(TAB_PRINTCHAR_NUL
)
1467 if not set(Value
).issubset(Printset
):
1468 PrintList
= sorted(Printset
)
1469 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1470 elif Type
== 'BOOLEAN':
1471 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1472 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1473 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1474 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1475 if Value
and int(Value
, 0) < 0:
1476 return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value
, Type
)
1478 Value
= long(Value
, 0)
1479 if Value
> MAX_VAL_TYPE
[Type
]:
1480 return False, "Too large PCD value[%s] for datum type [%s]" % (Value
, Type
)
1482 return False, "Invalid value [%s] of type [%s];"\
1483 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1485 return True, "StructurePcd"
1489 def CommonPath(PathList
):
1490 P1
= min(PathList
).split(os
.path
.sep
)
1491 P2
= max(PathList
).split(os
.path
.sep
)
1492 for Index
in xrange(min(len(P1
), len(P2
))):
1493 if P1
[Index
] != P2
[Index
]:
1494 return os
.path
.sep
.join(P1
[:Index
])
1495 return os
.path
.sep
.join(P1
)
1497 class PathClass(object):
1498 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1499 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1501 self
.File
= str(File
)
1502 if os
.path
.isabs(self
.File
):
1506 self
.Root
= str(Root
)
1507 self
.AlterRoot
= str(AlterRoot
)
1509 # Remove any '.' and '..' in path
1511 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1512 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1513 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1514 # eliminate the side-effect of 'C:'
1515 if self
.Root
[-1] == ':':
1516 self
.Root
+= os
.path
.sep
1517 # file path should not start with path separator
1518 if self
.Root
[-1] == os
.path
.sep
:
1519 self
.File
= self
.Path
[len(self
.Root
):]
1521 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1523 self
.Path
= os
.path
.normpath(self
.File
)
1525 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1526 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1530 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1532 self
.Dir
= self
.Root
1534 self
.Dir
= self
.SubDir
1539 self
.Type
= self
.Ext
.lower()
1541 self
.IsBinary
= IsBinary
1542 self
.Target
= Target
1543 self
.TagName
= TagName
1544 self
.ToolCode
= ToolCode
1545 self
.ToolChainFamily
= ToolChainFamily
1547 ## Convert the object of this class to a string
1549 # Convert member Path of the class to a string
1551 # @retval string Formatted String
1556 ## Override __eq__ function
1558 # Check whether PathClass are the same
1560 # @retval False The two PathClass are different
1561 # @retval True The two PathClass are the same
1563 def __eq__(self
, Other
):
1564 return self
.Path
== str(Other
)
1566 ## Override __cmp__ function
1568 # Customize the comparsion operation of two PathClass
1570 # @retval 0 The two PathClass are different
1571 # @retval -1 The first PathClass is less than the second PathClass
1572 # @retval 1 The first PathClass is Bigger than the second PathClass
1573 def __cmp__(self
, Other
):
1574 OtherKey
= str(Other
)
1577 if SelfKey
== OtherKey
:
1579 elif SelfKey
> OtherKey
:
1584 ## Override __hash__ function
1586 # Use Path as key in hash table
1588 # @retval string Key for hash table
1591 return hash(self
.Path
)
1595 return self
.Path
.upper()
1598 def TimeStamp(self
):
1599 return os
.stat(self
.Path
)[8]
1601 def Validate(self
, Type
='', CaseSensitive
=True):
1602 def RealPath2(File
, Dir
='', OverrideDir
=''):
1605 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
1607 if OverrideDir
[-1] == os
.path
.sep
:
1608 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
1610 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
1611 if GlobalData
.gAllFiles
:
1612 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
1614 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
1615 if not os
.path
.exists(NewFile
):
1619 if Dir
[-1] == os
.path
.sep
:
1620 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
1622 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
1628 if GlobalData
.gCaseInsensitive
:
1629 CaseSensitive
= False
1630 if Type
and Type
.lower() != self
.Type
:
1631 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1633 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1634 if not RealRoot
and not RealFile
:
1635 RealFile
= self
.File
1637 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1639 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1640 if len (mws
.getPkgPath()) == 0:
1641 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1643 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1647 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1648 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1649 ErrorCode
= FILE_CASE_MISMATCH
1650 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1652 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1653 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1655 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1658 self
.File
= RealFile
1659 self
.Root
= RealRoot
1660 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1661 return ErrorCode
, ErrorInfo
1663 ## Parse PE image to get the required PE informaion.
1665 class PeImageClass():
1668 # @param File FilePath of PeImage
1670 def __init__(self
, PeFile
):
1671 self
.FileName
= PeFile
1672 self
.IsValid
= False
1675 self
.SectionAlignment
= 0
1676 self
.SectionHeaderList
= []
1679 PeObject
= open(PeFile
, 'rb')
1681 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1684 ByteArray
= array
.array('B')
1685 ByteArray
.fromfile(PeObject
, 0x3E)
1686 ByteList
= ByteArray
.tolist()
1687 # DOS signature should be 'MZ'
1688 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1689 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1692 # Read 4 byte PE Signature
1693 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1694 PeObject
.seek(PeOffset
)
1695 ByteArray
= array
.array('B')
1696 ByteArray
.fromfile(PeObject
, 4)
1697 # PE signature should be 'PE\0\0'
1698 if ByteArray
.tostring() != 'PE\0\0':
1699 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1702 # Read PE file header
1703 ByteArray
= array
.array('B')
1704 ByteArray
.fromfile(PeObject
, 0x14)
1705 ByteList
= ByteArray
.tolist()
1706 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1708 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1711 # Read PE optional header
1712 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1713 ByteArray
= array
.array('B')
1714 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1715 ByteList
= ByteArray
.tolist()
1716 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1717 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1718 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1720 # Read each Section Header
1721 for Index
in range(SecNumber
):
1722 ByteArray
= array
.array('B')
1723 ByteArray
.fromfile(PeObject
, 0x28)
1724 ByteList
= ByteArray
.tolist()
1725 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1726 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1727 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1728 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1729 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1733 def _ByteListToStr(self
, ByteList
):
1735 for index
in range(len(ByteList
)):
1736 if ByteList
[index
] == 0:
1738 String
+= chr(ByteList
[index
])
1741 def _ByteListToInt(self
, ByteList
):
1743 for index
in range(len(ByteList
) - 1, -1, -1):
1744 Value
= (Value
<< 8) |
int(ByteList
[index
])
1747 class DefaultStore():
1748 def __init__(self
, DefaultStores
):
1750 self
.DefaultStores
= DefaultStores
1751 def DefaultStoreID(self
, DefaultStoreName
):
1752 for key
, value
in self
.DefaultStores
.items():
1753 if value
== DefaultStoreName
:
1756 def GetDefaultDefault(self
):
1757 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1758 return "0", TAB_DEFAULT_STORES_DEFAULT
1760 minvalue
= min(int(value_str
) for value_str
in self
.DefaultStores
)
1761 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1762 def GetMin(self
, DefaultSIdList
):
1763 if not DefaultSIdList
:
1764 return TAB_DEFAULT_STORES_DEFAULT
1765 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1768 minid
= min(storeidset
)
1769 for sid
, name
in self
.DefaultStores
.values():
1778 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1782 for SkuName
in SkuIds
:
1783 SkuId
= SkuIds
[SkuName
][0]
1784 skuid_num
= int(SkuId
, 16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1785 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1786 EdkLogger
.error("build", PARAMETER_INVALID
,
1787 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1790 self
.AvailableSkuIds
= sdict()
1792 self
.SkuIdNumberSet
= []
1793 self
.SkuData
= SkuIds
1794 self
._SkuInherit
= {}
1795 self
._SkuIdentifier
= SkuIdentifier
1796 if SkuIdentifier
== '' or SkuIdentifier
is None:
1797 self
.SkuIdSet
= ['DEFAULT']
1798 self
.SkuIdNumberSet
= ['0U']
1799 elif SkuIdentifier
== 'ALL':
1800 self
.SkuIdSet
= SkuIds
.keys()
1801 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1803 r
= SkuIdentifier
.split('|')
1804 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1807 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1809 EdkLogger
.error("build", PARAMETER_INVALID
,
1810 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1811 % (k
, " | ".join(SkuIds
.keys())))
1812 for each
in self
.SkuIdSet
:
1814 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1816 EdkLogger
.error("build", PARAMETER_INVALID
,
1817 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1818 % (each
, " | ".join(SkuIds
.keys())))
1819 if self
.SkuUsageType
!= SkuClass
.SINGLE
:
1820 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1822 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1823 if 'COMMON' in GlobalData
.gSkuids
:
1824 GlobalData
.gSkuids
.remove('COMMON')
1825 if self
.SkuUsageType
== self
.SINGLE
:
1826 if len(GlobalData
.gSkuids
) != 1:
1827 if 'DEFAULT' in GlobalData
.gSkuids
:
1828 GlobalData
.gSkuids
.remove('DEFAULT')
1829 if GlobalData
.gSkuids
:
1830 GlobalData
.gSkuids
.sort()
1832 def GetNextSkuId(self
, skuname
):
1833 if not self
._SkuInherit
:
1834 self
._SkuInherit
= {}
1835 for item
in self
.SkuData
.values():
1836 self
._SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
1837 return self
._SkuInherit
.get(skuname
, "DEFAULT")
1839 def GetSkuChain(self
, sku
):
1840 if sku
== "DEFAULT":
1845 nextsku
= self
.GetNextSkuId(nextsku
)
1846 skulist
.append(nextsku
)
1847 if nextsku
== "DEFAULT":
1851 def SkuOverrideOrder(self
):
1853 for skuname
in self
.SkuIdSet
:
1854 skuorderset
.append(self
.GetSkuChain(skuname
))
1857 for index
in range(max(len(item
) for item
in skuorderset
)):
1858 for subset
in skuorderset
:
1859 if index
> len(subset
)-1:
1861 if subset
[index
] in skuorder
:
1863 skuorder
.append(subset
[index
])
1868 def SkuUsageType(self
):
1869 if self
._SkuIdentifier
.upper() == "ALL":
1870 return SkuClass
.MULTIPLE
1872 if len(self
.SkuIdSet
) == 1:
1873 if self
.SkuIdSet
[0] == 'DEFAULT':
1874 return SkuClass
.DEFAULT
1875 return SkuClass
.SINGLE
1876 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
:
1877 return SkuClass
.SINGLE
1878 return SkuClass
.MULTIPLE
1880 def DumpSkuIdArrary(self
):
1881 if self
.SkuUsageType
== SkuClass
.SINGLE
:
1884 for skuname
in self
.AvailableSkuIds
:
1885 if skuname
== "COMMON":
1887 while skuname
!= "DEFAULT":
1888 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
1889 skuname
= self
.GetNextSkuId(skuname
)
1890 ArrayStrList
.append("0x0")
1891 return "{{{myList}}}".format(myList
=",".join(ArrayStrList
))
1894 def AvailableSkuIdSet(self
):
1895 return self
.AvailableSkuIds
1898 def SystemSkuId(self
):
1899 if self
.SkuUsageType
== SkuClass
.SINGLE
:
1900 if len(self
.SkuIdSet
) == 1:
1901 return self
.SkuIdSet
[0]
1903 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
1907 ## Get the integer value from string like "14U" or integer like 2
1909 # @param Input The object that may be either a integer value or a string
1911 # @retval Value The integer value that the input represents
1913 def GetIntegerValue(Input
):
1914 if type(Input
) in (int, long):
1917 if String
.endswith("U"):
1918 String
= String
[:-1]
1919 if String
.endswith("ULL"):
1920 String
= String
[:-3]
1921 if String
.endswith("LL"):
1922 String
= String
[:-2]
1924 if String
.startswith("0x") or String
.startswith("0X"):
1925 return int(String
, 16)
1932 # Pack a GUID (registry format) list into a buffer and return it
1935 return pack(PACK_PATTERN_GUID
,
1939 int(Guid
[3][-4:-2], 16),
1940 int(Guid
[3][-2:], 16),
1941 int(Guid
[4][-12:-10], 16),
1942 int(Guid
[4][-10:-8], 16),
1943 int(Guid
[4][-8:-6], 16),
1944 int(Guid
[4][-6:-4], 16),
1945 int(Guid
[4][-4:-2], 16),
1946 int(Guid
[4][-2:], 16)
1950 # Pack a GUID (byte) list into a buffer and return it
1952 def PackByteFormatGUID(Guid
):
1953 return pack(PACK_PATTERN_GUID
,
1967 ## DeepCopy dict/OrderedDict recusively
1969 # @param ori_dict a nested dict or ordereddict
1971 # @retval new dict or orderdict
1973 def CopyDict(ori_dict
):
1974 dict_type
= ori_dict
.__class
__
1975 if dict_type
not in (dict,OrderedDict
):
1977 new_dict
= dict_type()
1978 for key
in ori_dict
:
1979 if isinstance(ori_dict
[key
],(dict,OrderedDict
)):
1980 new_dict
[key
] = CopyDict(ori_dict
[key
])
1982 new_dict
[key
] = ori_dict
[key
]
1986 # Remove the c/c++ comments: // and /* */
1988 def RemoveCComments(ctext
):
1989 return re
.sub('//.*?\n|/\*.*?\*/', '\n', ctext
, flags
=re
.S
)
1992 # This acts like the main() function for the script, unless it is 'import'ed into another
1995 if __name__
== '__main__':