2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2015, 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 import Common
.LongFilePathOs
as os
27 from UserDict
import IterableUserDict
28 from UserList
import UserList
30 from Common
import EdkLogger
as EdkLogger
31 from Common
import GlobalData
as GlobalData
32 from DataType
import *
33 from BuildToolError
import *
34 from CommonDataClass
.DataClass
import *
35 from Parsing
import GetSplitValueList
36 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 ## Regular expression used to find out place holders in string template
39 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE|re
.UNICODE
)
41 ## Dictionary used to store file time stamp for quick re-access
42 gFileTimeStampCache
= {} # {file path : file time stamp}
44 ## Dictionary used to store dependencies of files
45 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
47 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
48 """ Parse map file to get variable offset in current EFI file
49 @param mapfilepath Map file absolution path
50 @param efifilepath: EFI binary file full path
51 @param varnames iteratable container whose elements are variable names to be searched
53 @return List whos elements are tuple with variable name and raw offset
57 f
= open(mapfilepath
, 'r')
63 if len(lines
) == 0: return None
64 firstline
= lines
[0].strip()
65 if (firstline
.startswith("Archive member included ") and
66 firstline
.endswith(" file (symbol)")):
67 return _parseForGCC(lines
, efifilepath
, varnames
)
68 return _parseGeneral(lines
, efifilepath
, varnames
)
70 def _parseForGCC(lines
, efifilepath
, varnames
):
71 """ Parse map file generated by GCC linker """
77 # status machine transection
78 if status
== 0 and line
== "Memory Configuration":
81 elif status
== 1 and line
== 'Linker script and memory map':
84 elif status
==2 and line
== 'START GROUP':
90 m
= re
.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line
)
92 sections
.append(m
.groups(0))
93 for varname
in varnames
:
94 m
= re
.match("^([\da-fA-Fx]+) +[_]*(%s)$" % varname
, line
)
96 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
100 # get section information from efi file
101 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
102 if efisecs
== None or len(efisecs
) == 0:
106 for efisec
in efisecs
:
107 for section
in sections
:
108 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
109 redirection
= int(section
[1], 16) - efisec
[1]
112 for var
in varoffset
:
113 for efisec
in efisecs
:
114 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
115 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
118 def _parseGeneral(lines
, efifilepath
, varnames
):
119 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
120 secs
= [] # key = section name
122 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
123 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
127 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
130 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
133 if re
.match("^entry point at", line
):
136 if status
== 1 and len(line
) != 0:
137 m
= secRe
.match(line
)
138 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
139 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
140 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
141 if status
== 2 and len(line
) != 0:
142 for varname
in varnames
:
143 m
= symRe
.match(line
)
144 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
145 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
146 sec_no
= int(sec_no
, 16)
147 sym_offset
= int(sym_offset
, 16)
148 vir_addr
= int(vir_addr
, 16)
149 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
151 # fond a binary pcd entry in map file
153 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
154 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
156 if not varoffset
: return []
158 # get section information from efi file
159 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
160 if efisecs
== None or len(efisecs
) == 0:
164 for var
in varoffset
:
166 for efisec
in efisecs
:
168 if var
[1].strip() == efisec
[0].strip():
169 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
170 elif var
[4] == index
:
171 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
175 ## Routine to process duplicated INF
177 # This function is called by following two cases:
180 # Pkg/module/module.inf
181 # Pkg/module/module.inf {
183 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
186 # INF Pkg/module/module.inf
187 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
189 # This function copies Pkg/module/module.inf to
190 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
192 # @param Path Original PathClass object
193 # @param BaseName New file base name
195 # @retval return the new PathClass object
197 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
198 Filename
= os
.path
.split(Path
.File
)[1]
200 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
202 Filename
= BaseName
+ Path
.BaseName
205 # If -N is specified on command line, cache is disabled
206 # The directory has to be created
208 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
209 if not os
.path
.exists(DbDir
):
212 # A temporary INF is copied to database path which must have write permission
213 # The temporary will be removed at the end of build
214 # In case of name conflict, the file name is
215 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
217 TempFullPath
= os
.path
.join(DbDir
,
219 RtPath
= PathClass(Path
.File
, Workspace
)
221 # Modify the full path to temporary path, keep other unchanged
223 # To build same module more than once, the module path with FILE_GUID overridden has
224 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
225 # in DSC which is used as relative path by C files and other files in INF.
226 # A trick was used: all module paths are PathClass instances, after the initialization
227 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
229 # The reason for creating a temporary INF is:
230 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
231 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
232 # A different key for the same module is needed to create different output directory,
233 # retrieve overridden PCDs, library instances.
235 # The BaseName is the FILE_GUID which is also the output directory name.
238 RtPath
.Path
= TempFullPath
239 RtPath
.BaseName
= BaseName
241 # If file exists, compare contents
243 if os
.path
.exists(TempFullPath
):
244 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
245 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
248 GlobalData
.gTempInfs
.append(TempFullPath
)
249 shutil
.copy2(str(Path
), TempFullPath
)
252 ## Remove temporary created INFs whose paths were saved in gTempInfs
254 def ClearDuplicatedInf():
255 for File
in GlobalData
.gTempInfs
:
256 if os
.path
.exists(File
):
259 ## callback routine for processing variable option
261 # This function can be used to process variable number of option values. The
262 # typical usage of it is specify architecure list on command line.
263 # (e.g. <tool> -a IA32 X64 IPF)
265 # @param Option Standard callback function parameter
266 # @param OptionString Standard callback function parameter
267 # @param Value Standard callback function parameter
268 # @param Parser Standard callback function parameter
272 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
275 RawArgs
= Parser
.rargs
278 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
279 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
283 setattr(Parser
.values
, Option
.dest
, Value
)
285 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
287 # @param Guid The GUID string
289 # @retval string The GUID string in C structure style
291 def GuidStringToGuidStructureString(Guid
):
292 GuidList
= Guid
.split('-')
294 for Index
in range(0,3,1):
295 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
296 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
297 for Index
in range(0,12,2):
298 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+2]
302 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
304 # @param GuidValue The GUID value in byte array
306 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
308 def GuidStructureByteArrayToGuidString(GuidValue
):
309 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
310 guidValueList
= guidValueString
.split(",")
311 if len(guidValueList
) != 16:
313 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
315 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
316 int(guidValueList
[3], 16),
317 int(guidValueList
[2], 16),
318 int(guidValueList
[1], 16),
319 int(guidValueList
[0], 16),
320 int(guidValueList
[5], 16),
321 int(guidValueList
[4], 16),
322 int(guidValueList
[7], 16),
323 int(guidValueList
[6], 16),
324 int(guidValueList
[8], 16),
325 int(guidValueList
[9], 16),
326 int(guidValueList
[10], 16),
327 int(guidValueList
[11], 16),
328 int(guidValueList
[12], 16),
329 int(guidValueList
[13], 16),
330 int(guidValueList
[14], 16),
331 int(guidValueList
[15], 16)
336 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
338 # @param GuidValue The GUID value in C structure format
340 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
342 def GuidStructureStringToGuidString(GuidValue
):
343 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
344 guidValueList
= guidValueString
.split(",")
345 if len(guidValueList
) != 11:
347 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
349 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
350 int(guidValueList
[0], 16),
351 int(guidValueList
[1], 16),
352 int(guidValueList
[2], 16),
353 int(guidValueList
[3], 16),
354 int(guidValueList
[4], 16),
355 int(guidValueList
[5], 16),
356 int(guidValueList
[6], 16),
357 int(guidValueList
[7], 16),
358 int(guidValueList
[8], 16),
359 int(guidValueList
[9], 16),
360 int(guidValueList
[10], 16)
365 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
367 # @param GuidValue The GUID value in C structure format
369 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
371 def GuidStructureStringToGuidValueName(GuidValue
):
372 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
373 guidValueList
= guidValueString
.split(",")
374 if len(guidValueList
) != 11:
375 EdkLogger
.error(None, FORMAT_INVALID
, "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)
390 ## Create directories
392 # @param Directory The directory name
394 def CreateDirectory(Directory
):
395 if Directory
== None or Directory
.strip() == "":
398 if not os
.access(Directory
, os
.F_OK
):
399 os
.makedirs(Directory
)
404 ## Remove directories, including files and sub-directories in it
406 # @param Directory The directory name
408 def RemoveDirectory(Directory
, Recursively
=False):
409 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
412 CurrentDirectory
= os
.getcwd()
414 for File
in os
.listdir("."):
415 if os
.path
.isdir(File
):
416 RemoveDirectory(File
, Recursively
)
419 os
.chdir(CurrentDirectory
)
422 ## Check if given file is changed or not
424 # This method is used to check if a file is changed or not between two build
425 # actions. It makes use a cache to store files timestamp.
427 # @param File The path of file
429 # @retval True If the given file is changed, doesn't exist, or can't be
430 # found in timestamp cache
431 # @retval False If the given file is changed
434 if not os
.path
.exists(File
):
437 FileState
= os
.stat(File
)
438 TimeStamp
= FileState
[-2]
440 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
444 gFileTimeStampCache
[File
] = TimeStamp
448 ## Store content in file
450 # This method is used to save file only when its content is changed. This is
451 # quite useful for "make" system to decide what will be re-built and what won't.
453 # @param File The path of file
454 # @param Content The new content of the file
455 # @param IsBinaryFile The flag indicating if the file is binary file or not
457 # @retval True If the file content is changed and the file is renewed
458 # @retval False If the file content is the same
460 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
462 Content
= Content
.replace("\n", os
.linesep
)
464 if os
.path
.exists(File
):
466 if Content
== open(File
, "rb").read():
469 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
471 DirName
= os
.path
.dirname(File
)
472 if not CreateDirectory(DirName
):
473 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
476 DirName
= os
.getcwd()
477 if not os
.access(DirName
, os
.W_OK
):
478 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
481 if GlobalData
.gIsWindows
:
483 from PyUtility
import SaveFileToDisk
484 if not SaveFileToDisk(File
, Content
):
485 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
487 Fd
= open(File
, "wb")
491 Fd
= open(File
, "wb")
495 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s'%X)
499 ## Make a Python object persistent on file system
501 # @param Data The object to be stored in file
502 # @param File The path of file to store the object
504 def DataDump(Data
, File
):
507 Fd
= open(File
, 'wb')
508 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
510 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
515 ## Restore a Python object from a file
517 # @param File The path of file stored the object
519 # @retval object A python object
520 # @retval None If failure in file operation
522 def DataRestore(File
):
526 Fd
= open(File
, 'rb')
527 Data
= cPickle
.load(Fd
)
529 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
536 ## Retrieve and cache the real path name in file system
538 # @param Root The root directory of path relative to
540 # @retval str The path string if the path exists
541 # @retval None If path doesn't exist
547 def __init__(self
, Root
):
549 for F
in os
.listdir(Root
):
551 self
._UPPER
_CACHE
_[F
.upper()] = F
554 def __getitem__(self
, Path
):
555 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
558 if Path
and Path
[0] == os
.path
.sep
:
560 if Path
in self
._CACHE
_:
561 return os
.path
.join(self
._Root
, Path
)
562 UpperPath
= Path
.upper()
563 if UpperPath
in self
._UPPER
_CACHE
_:
564 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
568 SepIndex
= Path
.find(os
.path
.sep
)
570 Parent
= UpperPath
[:SepIndex
]
571 if Parent
not in self
._UPPER
_CACHE
_:
573 LastSepIndex
= SepIndex
574 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
576 if LastSepIndex
== -1:
581 SepIndex
= LastSepIndex
583 Parent
= Path
[:SepIndex
]
584 ParentKey
= UpperPath
[:SepIndex
]
585 if ParentKey
not in self
._UPPER
_CACHE
_:
589 if Parent
in self
._CACHE
_:
592 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
593 for F
in os
.listdir(ParentDir
):
594 Dir
= os
.path
.join(ParentDir
, F
)
595 self
._CACHE
_.add(Dir
)
596 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
598 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
601 if Path
in self
._CACHE
_:
602 return os
.path
.join(self
._Root
, Path
)
603 elif UpperPath
in self
._UPPER
_CACHE
_:
604 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
607 ## Get all files of a directory
609 # @param Root: Root dir
610 # @param SkipList : The files need be skipped
612 # @retval A list of all files
614 def GetFiles(Root
, SkipList
=None, FullPath
= True):
617 for Root
, Dirs
, Files
in os
.walk(Root
):
619 for Item
in SkipList
:
624 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
626 File
= File
[len(OriPath
) + 1:]
627 FileList
.append(File
)
631 ## Check if gvien file exists or not
633 # @param File File name or path to be checked
634 # @param Dir The directory the file is relative to
636 # @retval True if file exists
637 # @retval False if file doesn't exists
639 def ValidFile(File
, Ext
=None):
641 Dummy
, FileExt
= os
.path
.splitext(File
)
642 if FileExt
.lower() != Ext
.lower():
644 if not os
.path
.exists(File
):
648 def RealPath(File
, Dir
='', OverrideDir
=''):
649 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
650 NewFile
= GlobalData
.gAllFiles
[NewFile
]
651 if not NewFile
and OverrideDir
:
652 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
653 NewFile
= GlobalData
.gAllFiles
[NewFile
]
656 def RealPath2(File
, Dir
='', OverrideDir
=''):
659 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
661 if OverrideDir
[-1] == os
.path
.sep
:
662 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
664 return NewFile
[len(OverrideDir
)+1:], NewFile
[0:len(OverrideDir
)]
665 if GlobalData
.gAllFiles
:
666 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
668 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
669 if not os
.path
.exists(NewFile
):
673 if Dir
[-1] == os
.path
.sep
:
674 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
676 return NewFile
[len(Dir
)+1:], NewFile
[0:len(Dir
)]
682 ## Check if gvien file exists or not
685 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
688 Dummy
, FileExt
= os
.path
.splitext(File
)
689 if FileExt
.lower() != Ext
.lower():
692 # Replace the Edk macros
693 if OverrideDir
!= '' and OverrideDir
!= None:
694 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
695 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
696 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
697 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
699 # Replace the default dir to current dir
702 Dir
= Dir
[len(Workspace
)+1:]
704 # First check if File has Edk definition itself
705 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
706 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
707 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
708 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
712 # Second check the path with override value
713 if OverrideDir
!= '' and OverrideDir
!= None:
714 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
718 # Last check the path with normal definitions
719 File
= os
.path
.join(Dir
, File
)
720 NewFile
= AllFiles
[os
.path
.normpath(File
)]
726 ## Check if gvien file exists or not
729 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
730 # Replace the Edk macros
731 if OverrideDir
!= '' and OverrideDir
!= None:
732 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
733 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
734 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
735 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
737 # Replace the default dir to current dir
738 # Dir is current module dir related to workspace
741 Dir
= Dir
[len(Workspace
)+1:]
744 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
745 NewRelaPath
= RelaPath
748 # First check if File has Edk definition itself
749 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
750 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
751 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
752 NewFile
= AllFiles
[os
.path
.normpath(File
)]
754 NewRelaPath
= os
.path
.dirname(NewFile
)
755 File
= os
.path
.basename(NewFile
)
756 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
759 # Second check the path with override value
760 if OverrideDir
!= '' and OverrideDir
!= None:
761 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
763 #NewRelaPath = os.path.dirname(NewFile)
764 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
767 # Last check the path with normal definitions
768 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
775 return NewRelaPath
, RelaPath
, File
778 def GetRelPath(Path1
, Path2
):
779 FileName
= os
.path
.basename(Path2
)
780 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
781 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
782 for Index
in range(0, len(L1
)):
783 if L1
[Index
] != L2
[Index
]:
784 FileName
= '../' * (len(L1
) - Index
)
785 for Index2
in range(Index
, len(L2
)):
786 FileName
= os
.path
.join(FileName
, L2
[Index2
])
788 return os
.path
.normpath(FileName
)
791 ## Get GUID value from given packages
793 # @param CName The CName of the GUID
794 # @param PackageList List of packages looking-up in
796 # @retval GuidValue if the CName is found in any given package
797 # @retval None if the CName is not found in all given packages
799 def GuidValue(CName
, PackageList
):
800 for P
in PackageList
:
802 return P
.Guids
[CName
]
805 ## Get Protocol value from given packages
807 # @param CName The CName of the GUID
808 # @param PackageList List of packages looking-up in
810 # @retval GuidValue if the CName is found in any given package
811 # @retval None if the CName is not found in all given packages
813 def ProtocolValue(CName
, PackageList
):
814 for P
in PackageList
:
815 if CName
in P
.Protocols
:
816 return P
.Protocols
[CName
]
819 ## Get PPI value from given packages
821 # @param CName The CName of the GUID
822 # @param PackageList List of packages looking-up in
824 # @retval GuidValue if the CName is found in any given package
825 # @retval None if the CName is not found in all given packages
827 def PpiValue(CName
, PackageList
):
828 for P
in PackageList
:
833 ## A string template class
835 # This class implements a template for string replacement. A string template
836 # looks like following
838 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
840 # The string between ${BEGIN} and ${END} will be repeated as many times as the
841 # length of "placeholder_name", which is a list passed through a dict. The
842 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
843 # be not used and, in this case, the "placeholder_name" must not a list and it
844 # will just be replaced once.
846 class TemplateString(object):
847 _REPEAT_START_FLAG
= "BEGIN"
848 _REPEAT_END_FLAG
= "END"
850 class Section(object):
851 _LIST_TYPES
= [type([]), type(set()), type((0,))]
853 def __init__(self
, TemplateSection
, PlaceHolderList
):
854 self
._Template
= TemplateSection
855 self
._PlaceHolderList
= []
857 # Split the section into sub-sections according to the position of placeholders
859 self
._SubSectionList
= []
862 # The placeholders passed in must be in the format of
864 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
866 for PlaceHolder
,Start
,End
in PlaceHolderList
:
867 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
868 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
869 self
._PlaceHolderList
.append(PlaceHolder
)
870 SubSectionStart
= End
871 if SubSectionStart
< len(TemplateSection
):
872 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
874 self
._SubSectionList
= [TemplateSection
]
877 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
879 def Instantiate(self
, PlaceHolderValues
):
881 RepeatPlaceHolders
= {}
882 NonRepeatPlaceHolders
= {}
884 for PlaceHolder
in self
._PlaceHolderList
:
885 if PlaceHolder
not in PlaceHolderValues
:
887 Value
= PlaceHolderValues
[PlaceHolder
]
888 if type(Value
) in self
._LIST
_TYPES
:
890 RepeatTime
= len(Value
)
891 elif RepeatTime
!= len(Value
):
895 "${%s} has different repeat time from others!" % PlaceHolder
,
896 ExtraData
=str(self
._Template
)
898 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
900 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
902 if NonRepeatPlaceHolders
:
904 for S
in self
._SubSectionList
:
905 if S
not in NonRepeatPlaceHolders
:
908 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
910 StringList
= self
._SubSectionList
912 if RepeatPlaceHolders
:
914 for Index
in range(RepeatTime
):
916 if S
not in RepeatPlaceHolders
:
917 TempStringList
.append(S
)
919 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
920 StringList
= TempStringList
922 return "".join(StringList
)
925 def __init__(self
, Template
=None):
927 self
.IsBinary
= False
928 self
._Template
= Template
929 self
._TemplateSectionList
= self
._Parse
(Template
)
933 # @retval string The string replaced
938 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
940 # @retval list A list of TemplateString.Section objects
942 def _Parse(self
, Template
):
947 TemplateSectionList
= []
949 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
951 if MatchEnd
<= len(Template
):
952 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
953 TemplateSectionList
.append(TemplateSection
)
956 MatchString
= MatchObj
.group(1)
957 MatchStart
= MatchObj
.start()
958 MatchEnd
= MatchObj
.end()
960 if MatchString
== self
._REPEAT
_START
_FLAG
:
961 if MatchStart
> SectionStart
:
962 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
963 TemplateSectionList
.append(TemplateSection
)
964 SectionStart
= MatchEnd
966 elif MatchString
== self
._REPEAT
_END
_FLAG
:
967 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
968 TemplateSectionList
.append(TemplateSection
)
969 SectionStart
= MatchEnd
972 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
973 SearchFrom
= MatchEnd
974 return TemplateSectionList
976 ## Replace the string template with dictionary of placeholders and append it to previous one
978 # @param AppendString The string template to append
979 # @param Dictionary The placeholder dictionaries
981 def Append(self
, AppendString
, Dictionary
=None):
983 SectionList
= self
._Parse
(AppendString
)
984 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
986 self
.String
+= AppendString
988 ## Replace the string template with dictionary of placeholders
990 # @param Dictionary The placeholder dictionaries
992 # @retval str The string replaced with placeholder values
994 def Replace(self
, Dictionary
=None):
995 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
997 ## Progress indicator class
999 # This class makes use of thread to print progress on console.
1002 # for avoiding deadloop
1004 _ProgressThread
= None
1005 _CheckInterval
= 0.25
1009 # @param OpenMessage The string printed before progress charaters
1010 # @param CloseMessage The string printed after progress charaters
1011 # @param ProgressChar The charater used to indicate the progress
1012 # @param Interval The interval in seconds between two progress charaters
1014 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
1015 self
.PromptMessage
= OpenMessage
1016 self
.CodaMessage
= CloseMessage
1017 self
.ProgressChar
= ProgressChar
1018 self
.Interval
= Interval
1019 if Progressor
._StopFlag
== None:
1020 Progressor
._StopFlag
= threading
.Event()
1022 ## Start to print progress charater
1024 # @param OpenMessage The string printed before progress charaters
1026 def Start(self
, OpenMessage
=None):
1027 if OpenMessage
!= None:
1028 self
.PromptMessage
= OpenMessage
1029 Progressor
._StopFlag
.clear()
1030 if Progressor
._ProgressThread
== None:
1031 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
1032 Progressor
._ProgressThread
.setDaemon(False)
1033 Progressor
._ProgressThread
.start()
1035 ## Stop printing progress charater
1037 # @param CloseMessage The string printed after progress charaters
1039 def Stop(self
, CloseMessage
=None):
1040 OriginalCodaMessage
= self
.CodaMessage
1041 if CloseMessage
!= None:
1042 self
.CodaMessage
= CloseMessage
1044 self
.CodaMessage
= OriginalCodaMessage
1046 ## Thread entry method
1047 def _ProgressThreadEntry(self
):
1048 sys
.stdout
.write(self
.PromptMessage
+ " ")
1051 while not Progressor
._StopFlag
.isSet():
1053 sys
.stdout
.write(self
.ProgressChar
)
1055 TimeUp
= self
.Interval
1056 time
.sleep(self
._CheckInterval
)
1057 TimeUp
-= self
._CheckInterval
1058 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
1061 ## Abort the progress display
1064 if Progressor
._StopFlag
!= None:
1065 Progressor
._StopFlag
.set()
1066 if Progressor
._ProgressThread
!= None:
1067 Progressor
._ProgressThread
.join()
1068 Progressor
._ProgressThread
= None
1070 ## A dict which can access its keys and/or values orderly
1072 # The class implements a new kind of dict which its keys or values can be
1073 # accessed in the order they are added into the dict. It guarantees the order
1074 # by making use of an internal list to keep a copy of keys.
1076 class sdict(IterableUserDict
):
1079 IterableUserDict
.__init
__(self
)
1083 def __setitem__(self
, key
, value
):
1084 if key
not in self
._key
_list
:
1085 self
._key
_list
.append(key
)
1086 IterableUserDict
.__setitem
__(self
, key
, value
)
1089 def __delitem__(self
, key
):
1090 self
._key
_list
.remove(key
)
1091 IterableUserDict
.__delitem
__(self
, key
)
1093 ## used in "for k in dict" loop to ensure the correct order
1095 return self
.iterkeys()
1099 return len(self
._key
_list
)
1101 ## "in" test support
1102 def __contains__(self
, key
):
1103 return key
in self
._key
_list
1106 def index(self
, key
):
1107 return self
._key
_list
.index(key
)
1110 def insert(self
, key
, newkey
, newvalue
, order
):
1111 index
= self
._key
_list
.index(key
)
1112 if order
== 'BEFORE':
1113 self
._key
_list
.insert(index
, newkey
)
1114 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1115 elif order
== 'AFTER':
1116 self
._key
_list
.insert(index
+ 1, newkey
)
1117 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1120 def append(self
, sdict
):
1122 if key
not in self
._key
_list
:
1123 self
._key
_list
.append(key
)
1124 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
1126 def has_key(self
, key
):
1127 return key
in self
._key
_list
1132 IterableUserDict
.clear(self
)
1134 ## Return a copy of keys
1137 for key
in self
._key
_list
:
1141 ## Return a copy of values
1144 for key
in self
._key
_list
:
1145 values
.append(self
[key
])
1148 ## Return a copy of (key, value) list
1151 for key
in self
._key
_list
:
1152 items
.append((key
, self
[key
]))
1155 ## Iteration support
1156 def iteritems(self
):
1157 return iter(self
.items())
1159 ## Keys interation support
1161 return iter(self
.keys())
1163 ## Values interation support
1164 def itervalues(self
):
1165 return iter(self
.values())
1167 ## Return value related to a key, and remove the (key, value) from the dict
1168 def pop(self
, key
, *dv
):
1170 if key
in self
._key
_list
:
1172 self
.__delitem
__(key
)
1177 ## Return (key, value) pair, and remove the (key, value) from the dict
1179 key
= self
._key
_list
[-1]
1181 self
.__delitem
__(key
)
1184 def update(self
, dict=None, **kwargs
):
1186 for k
, v
in dict.items():
1189 for k
, v
in kwargs
.items():
1192 ## Dictionary with restricted keys
1196 def __init__(self
, KeyList
):
1198 dict.__setitem
__(self
, Key
, "")
1201 def __setitem__(self
, key
, value
):
1203 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1204 ExtraData
=", ".join(dict.keys(self
)))
1205 dict.__setitem
__(self
, key
, value
)
1208 def __getitem__(self
, key
):
1211 return dict.__getitem
__(self
, key
)
1214 def __delitem__(self
, key
):
1215 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1220 self
.__setitem
__(Key
, "")
1222 ## Return value related to a key, and remove the (key, value) from the dict
1223 def pop(self
, key
, *dv
):
1224 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1226 ## Return (key, value) pair, and remove the (key, value) from the dict
1228 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1230 ## Dictionary using prioritized list as key
1233 _ListType
= type([])
1234 _TupleType
= type(())
1235 _Wildcard
= 'COMMON'
1236 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1238 def __init__(self
, _Single_
=False, _Level_
=2):
1239 self
._Level
_ = _Level_
1241 self
._Single
_ = _Single_
1244 def __getitem__(self
, key
):
1247 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1251 elif self
._Level
_ > 1:
1252 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1255 if self
._Level
_ > 1:
1256 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1258 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1259 FirstKey
= self
._Wildcard
1262 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1264 return self
._GetAllValues
(FirstKey
, RestKeys
)
1266 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1268 #print "%s-%s" % (FirstKey, self._Level_) ,
1269 if self
._Level
_ > 1:
1270 if FirstKey
== self
._Wildcard
:
1271 if FirstKey
in self
.data
:
1272 Value
= self
.data
[FirstKey
][RestKeys
]
1274 for Key
in self
.data
:
1275 Value
= self
.data
[Key
][RestKeys
]
1276 if Value
!= None: break
1278 if FirstKey
in self
.data
:
1279 Value
= self
.data
[FirstKey
][RestKeys
]
1280 if Value
== None and self
._Wildcard
in self
.data
:
1282 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1284 if FirstKey
== self
._Wildcard
:
1285 if FirstKey
in self
.data
:
1286 Value
= self
.data
[FirstKey
]
1288 for Key
in self
.data
:
1289 Value
= self
.data
[Key
]
1290 if Value
!= None: break
1292 if FirstKey
in self
.data
:
1293 Value
= self
.data
[FirstKey
]
1294 elif self
._Wildcard
in self
.data
:
1295 Value
= self
.data
[self
._Wildcard
]
1298 def _GetAllValues(self
, FirstKey
, RestKeys
):
1300 if self
._Level
_ > 1:
1301 if FirstKey
== self
._Wildcard
:
1302 for Key
in self
.data
:
1303 Value
+= self
.data
[Key
][RestKeys
]
1305 if FirstKey
in self
.data
:
1306 Value
+= self
.data
[FirstKey
][RestKeys
]
1307 if self
._Wildcard
in self
.data
:
1308 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1310 if FirstKey
== self
._Wildcard
:
1311 for Key
in self
.data
:
1312 Value
.append(self
.data
[Key
])
1314 if FirstKey
in self
.data
:
1315 Value
.append(self
.data
[FirstKey
])
1316 if self
._Wildcard
in self
.data
:
1317 Value
.append(self
.data
[self
._Wildcard
])
1321 def __setitem__(self
, key
, value
):
1324 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1329 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1332 if self
._Level
_ > 1:
1333 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1335 if FirstKey
in self
._ValidWildcardList
:
1336 FirstKey
= self
._Wildcard
1338 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1339 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1341 if self
._Level
_ > 1:
1342 self
.data
[FirstKey
][RestKeys
] = value
1344 self
.data
[FirstKey
] = value
1346 def SetGreedyMode(self
):
1347 self
._Single
_ = False
1348 if self
._Level
_ > 1:
1349 for Key
in self
.data
:
1350 self
.data
[Key
].SetGreedyMode()
1352 def SetSingleMode(self
):
1353 self
._Single
_ = True
1354 if self
._Level
_ > 1:
1355 for Key
in self
.data
:
1356 self
.data
[Key
].SetSingleMode()
1358 def GetKeys(self
, KeyIndex
=0):
1359 assert KeyIndex
>= 0
1361 return set(self
.data
.keys())
1364 for Key
in self
.data
:
1365 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1368 ## Boolean chain list
1370 class Blist(UserList
):
1371 def __init__(self
, initlist
=None):
1372 UserList
.__init
__(self
, initlist
)
1373 def __setitem__(self
, i
, item
):
1374 if item
not in [True, False]:
1380 def _GetResult(self
):
1382 for item
in self
.data
:
1385 Result
= property(_GetResult
)
1387 def ParseConsoleLog(Filename
):
1388 Opr
= open(os
.path
.normpath(Filename
), 'r')
1389 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1390 for Line
in Opr
.readlines():
1391 if Line
.find('.efi') > -1:
1392 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1393 Opw
.write('%s\n' % Line
)
1400 # Analyze DSC PCD value, since there is no data type info in DSC
1401 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1402 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1403 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1404 # 3. Dynamic default:
1405 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1406 # TokenSpace.PcdCName|PcdValue
1408 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1409 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1411 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1412 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1413 # there might have "|" operator, also in string value.
1415 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1416 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1417 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1419 # ValueList: A List contain fields described above
1420 # IsValid: True if conforming EBNF, otherwise False
1421 # Index: The index where PcdValue is in ValueList
1423 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1424 Setting
= Setting
.strip()
1425 # There might be escaped quote in a string: \", \\\"
1426 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1427 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1434 elif ch
== '(' and not InStr
:
1436 elif ch
== ')' and not InStr
:
1439 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1446 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1448 FieldList
.append(Setting
[StartPos
:].strip())
1450 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1454 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1455 Value
= FieldList
[0]
1457 if len(FieldList
) > 1:
1459 # Fix the PCD type when no DataType input
1464 if len(FieldList
) > 2:
1466 if DataType
== 'VOID*':
1467 IsValid
= (len(FieldList
) <= 3)
1469 IsValid
= (len(FieldList
) <= 1)
1470 return [Value
, '', Size
], IsValid
, 0
1471 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1472 Value
= FieldList
[0]
1474 if len(FieldList
) > 1:
1478 if len(FieldList
) > 2:
1482 if Value
.startswith("L"):
1483 Size
= str((len(Value
)- 3 + 1) * 2)
1484 elif Value
.startswith("{"):
1485 Size
= str(len(Value
.split(",")))
1487 Size
= str(len(Value
) -2 + 1 )
1488 if DataType
== 'VOID*':
1489 IsValid
= (len(FieldList
) <= 3)
1491 IsValid
= (len(FieldList
) <= 1)
1492 return [Value
, Type
, Size
], IsValid
, 0
1493 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1494 VpdOffset
= FieldList
[0]
1496 if not DataType
== 'VOID*':
1497 if len(FieldList
) > 1:
1498 Value
= FieldList
[1]
1500 if len(FieldList
) > 1:
1502 if len(FieldList
) > 2:
1503 Value
= FieldList
[2]
1504 if DataType
== 'VOID*':
1505 IsValid
= (len(FieldList
) <= 3)
1507 IsValid
= (len(FieldList
) <= 2)
1508 return [VpdOffset
, Size
, Value
], IsValid
, 2
1509 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1510 HiiString
= FieldList
[0]
1511 Guid
= Offset
= Value
= Attribute
= ''
1512 if len(FieldList
) > 1:
1514 if len(FieldList
) > 2:
1515 Offset
= FieldList
[2]
1516 if len(FieldList
) > 3:
1517 Value
= FieldList
[3]
1518 if len(FieldList
) > 4:
1519 Attribute
= FieldList
[4]
1520 IsValid
= (3 <= len(FieldList
) <= 5)
1521 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1526 # Analyze the pcd Value, Datum type and TokenNumber.
1527 # Used to avoid split issue while the value string contain "|" character
1529 # @param[in] Setting: A String contain value/datum type/token number information;
1531 # @retval ValueList: A List contain value, datum type and toke number.
1533 def AnalyzePcdData(Setting
):
1534 ValueList
= ['', '', '']
1536 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1537 PtrValue
= ValueRe
.findall(Setting
)
1539 ValueUpdateFlag
= False
1541 if len(PtrValue
) >= 1:
1542 Setting
= re
.sub(ValueRe
, '', Setting
)
1543 ValueUpdateFlag
= True
1545 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1546 ValueList
[0:len(TokenList
)] = TokenList
1549 ValueList
[0] = PtrValue
[0]
1553 ## AnalyzeHiiPcdData
1555 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1556 # Used to avoid split issue while the value string contain "|" character
1558 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1560 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1562 def AnalyzeHiiPcdData(Setting
):
1563 ValueList
= ['', '', '', '']
1565 TokenList
= GetSplitValueList(Setting
)
1566 ValueList
[0:len(TokenList
)] = TokenList
1570 ## AnalyzeVpdPcdData
1572 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1573 # Used to avoid split issue while the value string contain "|" character
1575 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1577 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1579 def AnalyzeVpdPcdData(Setting
):
1580 ValueList
= ['', '', '']
1582 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1583 PtrValue
= ValueRe
.findall(Setting
)
1585 ValueUpdateFlag
= False
1587 if len(PtrValue
) >= 1:
1588 Setting
= re
.sub(ValueRe
, '', Setting
)
1589 ValueUpdateFlag
= True
1591 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1592 ValueList
[0:len(TokenList
)] = TokenList
1595 ValueList
[2] = PtrValue
[0]
1599 ## check format of PCD value against its the datum type
1601 # For PCD value setting
1603 def CheckPcdDatum(Type
, Value
):
1605 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1606 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1607 or (Value
.startswith('{') and Value
.endswith('}'))
1609 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1610 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1611 elif ValueRe
.match(Value
):
1612 # Check the chars in UnicodeString or CString is printable
1613 if Value
.startswith("L"):
1617 Printset
= set(string
.printable
)
1618 Printset
.remove(TAB_PRINTCHAR_VT
)
1619 Printset
.add(TAB_PRINTCHAR_BS
)
1620 Printset
.add(TAB_PRINTCHAR_NUL
)
1621 if not set(Value
).issubset(Printset
):
1622 PrintList
= list(Printset
)
1624 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1625 elif Type
== 'BOOLEAN':
1626 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1627 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1628 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1629 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1631 Value
= long(Value
, 0)
1633 return False, "Invalid value [%s] of type [%s];"\
1634 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1636 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1640 ## Split command line option string to list
1642 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1643 # in non-windows platform to launch command
1645 def SplitOption(OptionString
):
1650 for Index
in range(0, len(OptionString
)):
1651 CurrentChar
= OptionString
[Index
]
1652 if CurrentChar
in ['"', "'"]:
1653 if QuotationMark
== CurrentChar
:
1655 elif QuotationMark
== "":
1656 QuotationMark
= CurrentChar
1661 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1662 if Index
> OptionStart
:
1663 OptionList
.append(OptionString
[OptionStart
:Index
-1])
1665 LastChar
= CurrentChar
1666 OptionList
.append(OptionString
[OptionStart
:])
1669 def CommonPath(PathList
):
1670 P1
= min(PathList
).split(os
.path
.sep
)
1671 P2
= max(PathList
).split(os
.path
.sep
)
1672 for Index
in xrange(min(len(P1
), len(P2
))):
1673 if P1
[Index
] != P2
[Index
]:
1674 return os
.path
.sep
.join(P1
[:Index
])
1675 return os
.path
.sep
.join(P1
)
1678 # Convert string to C format array
1680 def ConvertStringToByteArray(Value
):
1681 Value
= Value
.strip()
1685 if not Value
.endswith('}'):
1687 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1688 ValFields
= Value
.split(',')
1690 for Index
in range(len(ValFields
)):
1691 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1694 Value
= '{' + ','.join(ValFields
) + '}'
1698 if Value
.startswith('L"'):
1699 if not Value
.endswith('"'):
1703 elif not Value
.startswith('"') or not Value
.endswith('"'):
1706 Value
= eval(Value
) # translate escape character
1708 for Index
in range(0,len(Value
)):
1710 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1712 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1713 Value
= NewValue
+ '0}'
1716 class PathClass(object):
1717 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1718 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1720 self
.File
= str(File
)
1721 if os
.path
.isabs(self
.File
):
1725 self
.Root
= str(Root
)
1726 self
.AlterRoot
= str(AlterRoot
)
1728 # Remove any '.' and '..' in path
1730 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1731 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1732 # eliminate the side-effect of 'C:'
1733 if self
.Root
[-1] == ':':
1734 self
.Root
+= os
.path
.sep
1735 # file path should not start with path separator
1736 if self
.Root
[-1] == os
.path
.sep
:
1737 self
.File
= self
.Path
[len(self
.Root
):]
1739 self
.File
= self
.Path
[len(self
.Root
)+1:]
1741 self
.Path
= os
.path
.normpath(self
.File
)
1743 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1744 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1748 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1750 self
.Dir
= self
.Root
1752 self
.Dir
= self
.SubDir
1757 self
.Type
= self
.Ext
.lower()
1759 self
.IsBinary
= IsBinary
1760 self
.Target
= Target
1761 self
.TagName
= TagName
1762 self
.ToolCode
= ToolCode
1763 self
.ToolChainFamily
= ToolChainFamily
1767 ## Convert the object of this class to a string
1769 # Convert member Path of the class to a string
1771 # @retval string Formatted String
1776 ## Override __eq__ function
1778 # Check whether PathClass are the same
1780 # @retval False The two PathClass are different
1781 # @retval True The two PathClass are the same
1783 def __eq__(self
, Other
):
1784 if type(Other
) == type(self
):
1785 return self
.Path
== Other
.Path
1787 return self
.Path
== str(Other
)
1789 ## Override __cmp__ function
1791 # Customize the comparsion operation of two PathClass
1793 # @retval 0 The two PathClass are different
1794 # @retval -1 The first PathClass is less than the second PathClass
1795 # @retval 1 The first PathClass is Bigger than the second PathClass
1796 def __cmp__(self
, Other
):
1797 if type(Other
) == type(self
):
1798 OtherKey
= Other
.Path
1800 OtherKey
= str(Other
)
1803 if SelfKey
== OtherKey
:
1805 elif SelfKey
> OtherKey
:
1810 ## Override __hash__ function
1812 # Use Path as key in hash table
1814 # @retval string Key for hash table
1817 return hash(self
.Path
)
1819 def _GetFileKey(self
):
1820 if self
._Key
== None:
1821 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1824 def _GetTimeStamp(self
):
1825 return os
.stat(self
.Path
)[8]
1827 def Validate(self
, Type
='', CaseSensitive
=True):
1828 if GlobalData
.gCaseInsensitive
:
1829 CaseSensitive
= False
1830 if Type
and Type
.lower() != self
.Type
:
1831 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1833 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1834 if not RealRoot
and not RealFile
:
1835 RealFile
= self
.File
1837 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1839 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1840 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1844 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1845 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1846 ErrorCode
= FILE_CASE_MISMATCH
1847 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1849 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1850 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1852 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1855 self
.File
= RealFile
1856 self
.Root
= RealRoot
1857 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1858 return ErrorCode
, ErrorInfo
1860 Key
= property(_GetFileKey
)
1861 TimeStamp
= property(_GetTimeStamp
)
1863 ## Parse PE image to get the required PE informaion.
1865 class PeImageClass():
1868 # @param File FilePath of PeImage
1870 def __init__(self
, PeFile
):
1871 self
.FileName
= PeFile
1872 self
.IsValid
= False
1875 self
.SectionAlignment
= 0
1876 self
.SectionHeaderList
= []
1879 PeObject
= open(PeFile
, 'rb')
1881 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1884 ByteArray
= array
.array('B')
1885 ByteArray
.fromfile(PeObject
, 0x3E)
1886 ByteList
= ByteArray
.tolist()
1887 # DOS signature should be 'MZ'
1888 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1889 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1892 # Read 4 byte PE Signature
1893 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1894 PeObject
.seek(PeOffset
)
1895 ByteArray
= array
.array('B')
1896 ByteArray
.fromfile(PeObject
, 4)
1897 # PE signature should be 'PE\0\0'
1898 if ByteArray
.tostring() != 'PE\0\0':
1899 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1902 # Read PE file header
1903 ByteArray
= array
.array('B')
1904 ByteArray
.fromfile(PeObject
, 0x14)
1905 ByteList
= ByteArray
.tolist()
1906 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1908 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1911 # Read PE optional header
1912 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1913 ByteArray
= array
.array('B')
1914 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1915 ByteList
= ByteArray
.tolist()
1916 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1917 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1918 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1920 # Read each Section Header
1921 for Index
in range(SecNumber
):
1922 ByteArray
= array
.array('B')
1923 ByteArray
.fromfile(PeObject
, 0x28)
1924 ByteList
= ByteArray
.tolist()
1925 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1926 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1927 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1928 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1929 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1933 def _ByteListToStr(self
, ByteList
):
1935 for index
in range(len(ByteList
)):
1936 if ByteList
[index
] == 0:
1938 String
+= chr(ByteList
[index
])
1941 def _ByteListToInt(self
, ByteList
):
1943 for index
in range(len(ByteList
) - 1, -1, -1):
1944 Value
= (Value
<< 8) |
int(ByteList
[index
])
1954 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1956 self
.AvailableSkuIds
= sdict()
1958 self
.SkuIdNumberSet
= []
1959 if SkuIdentifier
== '' or SkuIdentifier
is None:
1960 self
.SkuIdSet
= ['DEFAULT']
1961 self
.SkuIdNumberSet
= ['0U']
1962 elif SkuIdentifier
== 'ALL':
1963 self
.SkuIdSet
= SkuIds
.keys()
1964 self
.SkuIdNumberSet
= [num
.strip() + 'U' for num
in SkuIds
.values()]
1966 r
= SkuIdentifier
.split('|')
1967 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
1970 self
.SkuIdNumberSet
= [SkuIds
[k
].strip() + 'U' for k
in self
.SkuIdSet
]
1972 EdkLogger
.error("build", PARAMETER_INVALID
,
1973 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1974 % (k
, " ".join(SkuIds
.keys())))
1975 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
1976 self
.SkuIdSet
.remove('DEFAULT')
1977 self
.SkuIdNumberSet
.remove('0U')
1978 for each
in self
.SkuIdSet
:
1980 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
1982 EdkLogger
.error("build", PARAMETER_INVALID
,
1983 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1984 % (each
, " ".join(SkuIds
.keys())))
1986 def __SkuUsageType(self
):
1988 if len(self
.SkuIdSet
) == 1:
1989 if self
.SkuIdSet
[0] == 'DEFAULT':
1990 return SkuClass
.DEFAULT
1992 return SkuClass
.SINGLE
1994 return SkuClass
.MULTIPLE
1996 def __GetAvailableSkuIds(self
):
1997 return self
.AvailableSkuIds
1999 def __GetSystemSkuID(self
):
2000 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2001 return self
.SkuIdSet
[0]
2004 def __GetAvailableSkuIdNumber(self
):
2005 return self
.SkuIdNumberSet
2006 SystemSkuId
= property(__GetSystemSkuID
)
2007 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2008 SkuUsageType
= property(__SkuUsageType
)
2009 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2012 # This acts like the main() function for the script, unless it is 'import'ed into another
2015 if __name__
== '__main__':