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 struct
import pack
28 from UserDict
import IterableUserDict
29 from UserList
import UserList
31 from Common
import EdkLogger
as EdkLogger
32 from Common
import GlobalData
as GlobalData
33 from DataType
import *
34 from BuildToolError
import *
35 from CommonDataClass
.DataClass
import *
36 from Parsing
import GetSplitValueList
37 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
40 ## Regular expression used to find out place holders in string template
41 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
43 ## Dictionary used to store file time stamp for quick re-access
44 gFileTimeStampCache
= {} # {file path : file time stamp}
46 ## Dictionary used to store dependencies of files
47 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
49 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
50 """ Parse map file to get variable offset in current EFI file
51 @param mapfilepath Map file absolution path
52 @param efifilepath: EFI binary file full path
53 @param varnames iteratable container whose elements are variable names to be searched
55 @return List whos elements are tuple with variable name and raw offset
59 f
= open(mapfilepath
, 'r')
65 if len(lines
) == 0: return None
66 firstline
= lines
[0].strip()
67 if (firstline
.startswith("Archive member included ") and
68 firstline
.endswith(" file (symbol)")):
69 return _parseForGCC(lines
, efifilepath
, varnames
)
70 return _parseGeneral(lines
, efifilepath
, varnames
)
72 def _parseForGCC(lines
, efifilepath
, varnames
):
73 """ Parse map file generated by GCC linker """
79 # status machine transection
80 if status
== 0 and line
== "Memory Configuration":
83 elif status
== 1 and line
== 'Linker script and memory map':
86 elif status
==2 and line
== 'START GROUP':
92 m
= re
.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line
)
94 sections
.append(m
.groups(0))
95 for varname
in varnames
:
96 m
= re
.match("^([\da-fA-Fx]+) +[_]*(%s)$" % varname
, line
)
98 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
102 # get section information from efi file
103 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
104 if efisecs
== None or len(efisecs
) == 0:
108 for efisec
in efisecs
:
109 for section
in sections
:
110 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
111 redirection
= int(section
[1], 16) - efisec
[1]
114 for var
in varoffset
:
115 for efisec
in efisecs
:
116 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
117 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
120 def _parseGeneral(lines
, efifilepath
, varnames
):
121 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
122 secs
= [] # key = section name
124 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
125 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
129 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
132 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
135 if re
.match("^entry point at", line
):
138 if status
== 1 and len(line
) != 0:
139 m
= secRe
.match(line
)
140 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
141 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
142 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
143 if status
== 2 and len(line
) != 0:
144 for varname
in varnames
:
145 m
= symRe
.match(line
)
146 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
147 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
148 sec_no
= int(sec_no
, 16)
149 sym_offset
= int(sym_offset
, 16)
150 vir_addr
= int(vir_addr
, 16)
151 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
153 # fond a binary pcd entry in map file
155 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
156 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
158 if not varoffset
: return []
160 # get section information from efi file
161 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
162 if efisecs
== None or len(efisecs
) == 0:
166 for var
in varoffset
:
168 for efisec
in efisecs
:
170 if var
[1].strip() == efisec
[0].strip():
171 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
172 elif var
[4] == index
:
173 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
177 ## Routine to process duplicated INF
179 # This function is called by following two cases:
182 # Pkg/module/module.inf
183 # Pkg/module/module.inf {
185 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
188 # INF Pkg/module/module.inf
189 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
191 # This function copies Pkg/module/module.inf to
192 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
194 # @param Path Original PathClass object
195 # @param BaseName New file base name
197 # @retval return the new PathClass object
199 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
200 Filename
= os
.path
.split(Path
.File
)[1]
202 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
204 Filename
= BaseName
+ Path
.BaseName
207 # If -N is specified on command line, cache is disabled
208 # The directory has to be created
210 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
211 if not os
.path
.exists(DbDir
):
214 # A temporary INF is copied to database path which must have write permission
215 # The temporary will be removed at the end of build
216 # In case of name conflict, the file name is
217 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
219 TempFullPath
= os
.path
.join(DbDir
,
221 RtPath
= PathClass(Path
.File
, Workspace
)
223 # Modify the full path to temporary path, keep other unchanged
225 # To build same module more than once, the module path with FILE_GUID overridden has
226 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
227 # in DSC which is used as relative path by C files and other files in INF.
228 # A trick was used: all module paths are PathClass instances, after the initialization
229 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
231 # The reason for creating a temporary INF is:
232 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
233 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
234 # A different key for the same module is needed to create different output directory,
235 # retrieve overridden PCDs, library instances.
237 # The BaseName is the FILE_GUID which is also the output directory name.
240 RtPath
.Path
= TempFullPath
241 RtPath
.BaseName
= BaseName
243 # If file exists, compare contents
245 if os
.path
.exists(TempFullPath
):
246 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
247 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
250 GlobalData
.gTempInfs
.append(TempFullPath
)
251 shutil
.copy2(str(Path
), TempFullPath
)
254 ## Remove temporary created INFs whose paths were saved in gTempInfs
256 def ClearDuplicatedInf():
257 for File
in GlobalData
.gTempInfs
:
258 if os
.path
.exists(File
):
261 ## callback routine for processing variable option
263 # This function can be used to process variable number of option values. The
264 # typical usage of it is specify architecure list on command line.
265 # (e.g. <tool> -a IA32 X64 IPF)
267 # @param Option Standard callback function parameter
268 # @param OptionString Standard callback function parameter
269 # @param Value Standard callback function parameter
270 # @param Parser Standard callback function parameter
274 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
277 RawArgs
= Parser
.rargs
280 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
281 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
285 setattr(Parser
.values
, Option
.dest
, Value
)
287 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
289 # @param Guid The GUID string
291 # @retval string The GUID string in C structure style
293 def GuidStringToGuidStructureString(Guid
):
294 GuidList
= Guid
.split('-')
296 for Index
in range(0, 3, 1):
297 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
298 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
299 for Index
in range(0, 12, 2):
300 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
304 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
306 # @param GuidValue The GUID value in byte array
308 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
310 def GuidStructureByteArrayToGuidString(GuidValue
):
311 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
312 guidValueList
= guidValueString
.split(",")
313 if len(guidValueList
) != 16:
315 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
317 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
318 int(guidValueList
[3], 16),
319 int(guidValueList
[2], 16),
320 int(guidValueList
[1], 16),
321 int(guidValueList
[0], 16),
322 int(guidValueList
[5], 16),
323 int(guidValueList
[4], 16),
324 int(guidValueList
[7], 16),
325 int(guidValueList
[6], 16),
326 int(guidValueList
[8], 16),
327 int(guidValueList
[9], 16),
328 int(guidValueList
[10], 16),
329 int(guidValueList
[11], 16),
330 int(guidValueList
[12], 16),
331 int(guidValueList
[13], 16),
332 int(guidValueList
[14], 16),
333 int(guidValueList
[15], 16)
338 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
340 # @param GuidValue The GUID value in C structure format
342 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
344 def GuidStructureStringToGuidString(GuidValue
):
345 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
346 guidValueList
= guidValueString
.split(",")
347 if len(guidValueList
) != 11:
349 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
351 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
352 int(guidValueList
[0], 16),
353 int(guidValueList
[1], 16),
354 int(guidValueList
[2], 16),
355 int(guidValueList
[3], 16),
356 int(guidValueList
[4], 16),
357 int(guidValueList
[5], 16),
358 int(guidValueList
[6], 16),
359 int(guidValueList
[7], 16),
360 int(guidValueList
[8], 16),
361 int(guidValueList
[9], 16),
362 int(guidValueList
[10], 16)
367 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
369 # @param GuidValue The GUID value in C structure format
371 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
373 def GuidStructureStringToGuidValueName(GuidValue
):
374 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
375 guidValueList
= guidValueString
.split(",")
376 if len(guidValueList
) != 11:
377 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
378 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
379 int(guidValueList
[0], 16),
380 int(guidValueList
[1], 16),
381 int(guidValueList
[2], 16),
382 int(guidValueList
[3], 16),
383 int(guidValueList
[4], 16),
384 int(guidValueList
[5], 16),
385 int(guidValueList
[6], 16),
386 int(guidValueList
[7], 16),
387 int(guidValueList
[8], 16),
388 int(guidValueList
[9], 16),
389 int(guidValueList
[10], 16)
392 ## Create directories
394 # @param Directory The directory name
396 def CreateDirectory(Directory
):
397 if Directory
== None or Directory
.strip() == "":
400 if not os
.access(Directory
, os
.F_OK
):
401 os
.makedirs(Directory
)
406 ## Remove directories, including files and sub-directories in it
408 # @param Directory The directory name
410 def RemoveDirectory(Directory
, Recursively
=False):
411 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
414 CurrentDirectory
= os
.getcwd()
416 for File
in os
.listdir("."):
417 if os
.path
.isdir(File
):
418 RemoveDirectory(File
, Recursively
)
421 os
.chdir(CurrentDirectory
)
424 ## Check if given file is changed or not
426 # This method is used to check if a file is changed or not between two build
427 # actions. It makes use a cache to store files timestamp.
429 # @param File The path of file
431 # @retval True If the given file is changed, doesn't exist, or can't be
432 # found in timestamp cache
433 # @retval False If the given file is changed
436 if not os
.path
.exists(File
):
439 FileState
= os
.stat(File
)
440 TimeStamp
= FileState
[-2]
442 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
446 gFileTimeStampCache
[File
] = TimeStamp
450 ## Store content in file
452 # This method is used to save file only when its content is changed. This is
453 # quite useful for "make" system to decide what will be re-built and what won't.
455 # @param File The path of file
456 # @param Content The new content of the file
457 # @param IsBinaryFile The flag indicating if the file is binary file or not
459 # @retval True If the file content is changed and the file is renewed
460 # @retval False If the file content is the same
462 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
464 Content
= Content
.replace("\n", os
.linesep
)
466 if os
.path
.exists(File
):
468 if Content
== open(File
, "rb").read():
471 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
473 DirName
= os
.path
.dirname(File
)
474 if not CreateDirectory(DirName
):
475 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
478 DirName
= os
.getcwd()
479 if not os
.access(DirName
, os
.W_OK
):
480 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
483 if GlobalData
.gIsWindows
:
485 from PyUtility
import SaveFileToDisk
486 if not SaveFileToDisk(File
, Content
):
487 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
489 Fd
= open(File
, "wb")
493 Fd
= open(File
, "wb")
497 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
501 ## Make a Python object persistent on file system
503 # @param Data The object to be stored in file
504 # @param File The path of file to store the object
506 def DataDump(Data
, File
):
509 Fd
= open(File
, 'wb')
510 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
512 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
517 ## Restore a Python object from a file
519 # @param File The path of file stored the object
521 # @retval object A python object
522 # @retval None If failure in file operation
524 def DataRestore(File
):
528 Fd
= open(File
, 'rb')
529 Data
= cPickle
.load(Fd
)
531 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
538 ## Retrieve and cache the real path name in file system
540 # @param Root The root directory of path relative to
542 # @retval str The path string if the path exists
543 # @retval None If path doesn't exist
549 def __init__(self
, Root
):
551 for F
in os
.listdir(Root
):
553 self
._UPPER
_CACHE
_[F
.upper()] = F
556 def __getitem__(self
, Path
):
557 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
560 if Path
and Path
[0] == os
.path
.sep
:
562 if Path
in self
._CACHE
_:
563 return os
.path
.join(self
._Root
, Path
)
564 UpperPath
= Path
.upper()
565 if UpperPath
in self
._UPPER
_CACHE
_:
566 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
570 SepIndex
= Path
.find(os
.path
.sep
)
572 Parent
= UpperPath
[:SepIndex
]
573 if Parent
not in self
._UPPER
_CACHE
_:
575 LastSepIndex
= SepIndex
576 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
578 if LastSepIndex
== -1:
583 SepIndex
= LastSepIndex
585 Parent
= Path
[:SepIndex
]
586 ParentKey
= UpperPath
[:SepIndex
]
587 if ParentKey
not in self
._UPPER
_CACHE
_:
591 if Parent
in self
._CACHE
_:
594 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
595 for F
in os
.listdir(ParentDir
):
596 Dir
= os
.path
.join(ParentDir
, F
)
597 self
._CACHE
_.add(Dir
)
598 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
600 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
603 if Path
in self
._CACHE
_:
604 return os
.path
.join(self
._Root
, Path
)
605 elif UpperPath
in self
._UPPER
_CACHE
_:
606 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
609 ## Get all files of a directory
611 # @param Root: Root dir
612 # @param SkipList : The files need be skipped
614 # @retval A list of all files
616 def GetFiles(Root
, SkipList
=None, FullPath
=True):
619 for Root
, Dirs
, Files
in os
.walk(Root
):
621 for Item
in SkipList
:
626 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
628 File
= File
[len(OriPath
) + 1:]
629 FileList
.append(File
)
633 ## Check if gvien file exists or not
635 # @param File File name or path to be checked
636 # @param Dir The directory the file is relative to
638 # @retval True if file exists
639 # @retval False if file doesn't exists
641 def ValidFile(File
, Ext
=None):
643 Dummy
, FileExt
= os
.path
.splitext(File
)
644 if FileExt
.lower() != Ext
.lower():
646 if not os
.path
.exists(File
):
650 def RealPath(File
, Dir
='', OverrideDir
=''):
651 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
652 NewFile
= GlobalData
.gAllFiles
[NewFile
]
653 if not NewFile
and OverrideDir
:
654 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
655 NewFile
= GlobalData
.gAllFiles
[NewFile
]
658 def RealPath2(File
, Dir
='', OverrideDir
=''):
661 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
663 if OverrideDir
[-1] == os
.path
.sep
:
664 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
666 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
667 if GlobalData
.gAllFiles
:
668 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
670 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
671 if not os
.path
.exists(NewFile
):
675 if Dir
[-1] == os
.path
.sep
:
676 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
678 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
684 ## Check if gvien file exists or not
687 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
690 Dummy
, FileExt
= os
.path
.splitext(File
)
691 if FileExt
.lower() != Ext
.lower():
694 # Replace the Edk macros
695 if OverrideDir
!= '' and OverrideDir
!= None:
696 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
697 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
698 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
699 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
701 # Replace the default dir to current dir
704 Dir
= Dir
[len(Workspace
) + 1:]
706 # First check if File has Edk definition itself
707 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
708 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
709 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
710 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
714 # Second check the path with override value
715 if OverrideDir
!= '' and OverrideDir
!= None:
716 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
720 # Last check the path with normal definitions
721 File
= os
.path
.join(Dir
, File
)
722 NewFile
= AllFiles
[os
.path
.normpath(File
)]
728 ## Check if gvien file exists or not
731 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
732 # Replace the Edk macros
733 if OverrideDir
!= '' and OverrideDir
!= None:
734 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
735 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
736 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
737 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
739 # Replace the default dir to current dir
740 # Dir is current module dir related to workspace
743 Dir
= Dir
[len(Workspace
) + 1:]
746 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
747 NewRelaPath
= RelaPath
750 # First check if File has Edk definition itself
751 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
752 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
753 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
754 NewFile
= AllFiles
[os
.path
.normpath(File
)]
756 NewRelaPath
= os
.path
.dirname(NewFile
)
757 File
= os
.path
.basename(NewFile
)
758 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
761 # Second check the path with override value
762 if OverrideDir
!= '' and OverrideDir
!= None:
763 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
765 #NewRelaPath = os.path.dirname(NewFile)
766 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
769 # Last check the path with normal definitions
770 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
777 return NewRelaPath
, RelaPath
, File
780 def GetRelPath(Path1
, Path2
):
781 FileName
= os
.path
.basename(Path2
)
782 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
783 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
784 for Index
in range(0, len(L1
)):
785 if L1
[Index
] != L2
[Index
]:
786 FileName
= '../' * (len(L1
) - Index
)
787 for Index2
in range(Index
, len(L2
)):
788 FileName
= os
.path
.join(FileName
, L2
[Index2
])
790 return os
.path
.normpath(FileName
)
793 ## Get GUID value from given packages
795 # @param CName The CName of the GUID
796 # @param PackageList List of packages looking-up in
798 # @retval GuidValue if the CName is found in any given package
799 # @retval None if the CName is not found in all given packages
801 def GuidValue(CName
, PackageList
):
802 for P
in PackageList
:
804 return P
.Guids
[CName
]
807 ## Get Protocol value from given packages
809 # @param CName The CName of the GUID
810 # @param PackageList List of packages looking-up in
812 # @retval GuidValue if the CName is found in any given package
813 # @retval None if the CName is not found in all given packages
815 def ProtocolValue(CName
, PackageList
):
816 for P
in PackageList
:
817 if CName
in P
.Protocols
:
818 return P
.Protocols
[CName
]
821 ## Get PPI value from given packages
823 # @param CName The CName of the GUID
824 # @param PackageList List of packages looking-up in
826 # @retval GuidValue if the CName is found in any given package
827 # @retval None if the CName is not found in all given packages
829 def PpiValue(CName
, PackageList
):
830 for P
in PackageList
:
835 ## A string template class
837 # This class implements a template for string replacement. A string template
838 # looks like following
840 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
842 # The string between ${BEGIN} and ${END} will be repeated as many times as the
843 # length of "placeholder_name", which is a list passed through a dict. The
844 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
845 # be not used and, in this case, the "placeholder_name" must not a list and it
846 # will just be replaced once.
848 class TemplateString(object):
849 _REPEAT_START_FLAG
= "BEGIN"
850 _REPEAT_END_FLAG
= "END"
852 class Section(object):
853 _LIST_TYPES
= [type([]), type(set()), type((0,))]
855 def __init__(self
, TemplateSection
, PlaceHolderList
):
856 self
._Template
= TemplateSection
857 self
._PlaceHolderList
= []
859 # Split the section into sub-sections according to the position of placeholders
861 self
._SubSectionList
= []
864 # The placeholders passed in must be in the format of
866 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
868 for PlaceHolder
, Start
, End
in PlaceHolderList
:
869 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
870 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
871 self
._PlaceHolderList
.append(PlaceHolder
)
872 SubSectionStart
= End
873 if SubSectionStart
< len(TemplateSection
):
874 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
876 self
._SubSectionList
= [TemplateSection
]
879 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
881 def Instantiate(self
, PlaceHolderValues
):
883 RepeatPlaceHolders
= {}
884 NonRepeatPlaceHolders
= {}
886 for PlaceHolder
in self
._PlaceHolderList
:
887 if PlaceHolder
not in PlaceHolderValues
:
889 Value
= PlaceHolderValues
[PlaceHolder
]
890 if type(Value
) in self
._LIST
_TYPES
:
892 RepeatTime
= len(Value
)
893 elif RepeatTime
!= len(Value
):
897 "${%s} has different repeat time from others!" % PlaceHolder
,
898 ExtraData
=str(self
._Template
)
900 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
902 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
904 if NonRepeatPlaceHolders
:
906 for S
in self
._SubSectionList
:
907 if S
not in NonRepeatPlaceHolders
:
910 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
912 StringList
= self
._SubSectionList
914 if RepeatPlaceHolders
:
916 for Index
in range(RepeatTime
):
918 if S
not in RepeatPlaceHolders
:
919 TempStringList
.append(S
)
921 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
922 StringList
= TempStringList
924 return "".join(StringList
)
927 def __init__(self
, Template
=None):
929 self
.IsBinary
= False
930 self
._Template
= Template
931 self
._TemplateSectionList
= self
._Parse
(Template
)
935 # @retval string The string replaced
940 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
942 # @retval list A list of TemplateString.Section objects
944 def _Parse(self
, Template
):
949 TemplateSectionList
= []
951 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
953 if MatchEnd
<= len(Template
):
954 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
955 TemplateSectionList
.append(TemplateSection
)
958 MatchString
= MatchObj
.group(1)
959 MatchStart
= MatchObj
.start()
960 MatchEnd
= MatchObj
.end()
962 if MatchString
== self
._REPEAT
_START
_FLAG
:
963 if MatchStart
> SectionStart
:
964 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
965 TemplateSectionList
.append(TemplateSection
)
966 SectionStart
= MatchEnd
968 elif MatchString
== self
._REPEAT
_END
_FLAG
:
969 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
970 TemplateSectionList
.append(TemplateSection
)
971 SectionStart
= MatchEnd
974 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
975 SearchFrom
= MatchEnd
976 return TemplateSectionList
978 ## Replace the string template with dictionary of placeholders and append it to previous one
980 # @param AppendString The string template to append
981 # @param Dictionary The placeholder dictionaries
983 def Append(self
, AppendString
, Dictionary
=None):
985 SectionList
= self
._Parse
(AppendString
)
986 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
988 self
.String
+= AppendString
990 ## Replace the string template with dictionary of placeholders
992 # @param Dictionary The placeholder dictionaries
994 # @retval str The string replaced with placeholder values
996 def Replace(self
, Dictionary
=None):
997 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
999 ## Progress indicator class
1001 # This class makes use of thread to print progress on console.
1004 # for avoiding deadloop
1006 _ProgressThread
= None
1007 _CheckInterval
= 0.25
1011 # @param OpenMessage The string printed before progress charaters
1012 # @param CloseMessage The string printed after progress charaters
1013 # @param ProgressChar The charater used to indicate the progress
1014 # @param Interval The interval in seconds between two progress charaters
1016 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
1017 self
.PromptMessage
= OpenMessage
1018 self
.CodaMessage
= CloseMessage
1019 self
.ProgressChar
= ProgressChar
1020 self
.Interval
= Interval
1021 if Progressor
._StopFlag
== None:
1022 Progressor
._StopFlag
= threading
.Event()
1024 ## Start to print progress charater
1026 # @param OpenMessage The string printed before progress charaters
1028 def Start(self
, OpenMessage
=None):
1029 if OpenMessage
!= None:
1030 self
.PromptMessage
= OpenMessage
1031 Progressor
._StopFlag
.clear()
1032 if Progressor
._ProgressThread
== None:
1033 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
1034 Progressor
._ProgressThread
.setDaemon(False)
1035 Progressor
._ProgressThread
.start()
1037 ## Stop printing progress charater
1039 # @param CloseMessage The string printed after progress charaters
1041 def Stop(self
, CloseMessage
=None):
1042 OriginalCodaMessage
= self
.CodaMessage
1043 if CloseMessage
!= None:
1044 self
.CodaMessage
= CloseMessage
1046 self
.CodaMessage
= OriginalCodaMessage
1048 ## Thread entry method
1049 def _ProgressThreadEntry(self
):
1050 sys
.stdout
.write(self
.PromptMessage
+ " ")
1053 while not Progressor
._StopFlag
.isSet():
1055 sys
.stdout
.write(self
.ProgressChar
)
1057 TimeUp
= self
.Interval
1058 time
.sleep(self
._CheckInterval
)
1059 TimeUp
-= self
._CheckInterval
1060 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
1063 ## Abort the progress display
1066 if Progressor
._StopFlag
!= None:
1067 Progressor
._StopFlag
.set()
1068 if Progressor
._ProgressThread
!= None:
1069 Progressor
._ProgressThread
.join()
1070 Progressor
._ProgressThread
= None
1072 ## A dict which can access its keys and/or values orderly
1074 # The class implements a new kind of dict which its keys or values can be
1075 # accessed in the order they are added into the dict. It guarantees the order
1076 # by making use of an internal list to keep a copy of keys.
1078 class sdict(IterableUserDict
):
1081 IterableUserDict
.__init
__(self
)
1085 def __setitem__(self
, key
, value
):
1086 if key
not in self
._key
_list
:
1087 self
._key
_list
.append(key
)
1088 IterableUserDict
.__setitem
__(self
, key
, value
)
1091 def __delitem__(self
, key
):
1092 self
._key
_list
.remove(key
)
1093 IterableUserDict
.__delitem
__(self
, key
)
1095 ## used in "for k in dict" loop to ensure the correct order
1097 return self
.iterkeys()
1101 return len(self
._key
_list
)
1103 ## "in" test support
1104 def __contains__(self
, key
):
1105 return key
in self
._key
_list
1108 def index(self
, key
):
1109 return self
._key
_list
.index(key
)
1112 def insert(self
, key
, newkey
, newvalue
, order
):
1113 index
= self
._key
_list
.index(key
)
1114 if order
== 'BEFORE':
1115 self
._key
_list
.insert(index
, newkey
)
1116 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1117 elif order
== 'AFTER':
1118 self
._key
_list
.insert(index
+ 1, newkey
)
1119 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1122 def append(self
, sdict
):
1124 if key
not in self
._key
_list
:
1125 self
._key
_list
.append(key
)
1126 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
1128 def has_key(self
, key
):
1129 return key
in self
._key
_list
1134 IterableUserDict
.clear(self
)
1136 ## Return a copy of keys
1139 for key
in self
._key
_list
:
1143 ## Return a copy of values
1146 for key
in self
._key
_list
:
1147 values
.append(self
[key
])
1150 ## Return a copy of (key, value) list
1153 for key
in self
._key
_list
:
1154 items
.append((key
, self
[key
]))
1157 ## Iteration support
1158 def iteritems(self
):
1159 return iter(self
.items())
1161 ## Keys interation support
1163 return iter(self
.keys())
1165 ## Values interation support
1166 def itervalues(self
):
1167 return iter(self
.values())
1169 ## Return value related to a key, and remove the (key, value) from the dict
1170 def pop(self
, key
, *dv
):
1172 if key
in self
._key
_list
:
1174 self
.__delitem
__(key
)
1179 ## Return (key, value) pair, and remove the (key, value) from the dict
1181 key
= self
._key
_list
[-1]
1183 self
.__delitem
__(key
)
1186 def update(self
, dict=None, **kwargs
):
1188 for k
, v
in dict.items():
1191 for k
, v
in kwargs
.items():
1194 ## Dictionary with restricted keys
1198 def __init__(self
, KeyList
):
1200 dict.__setitem
__(self
, Key
, "")
1203 def __setitem__(self
, key
, value
):
1205 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1206 ExtraData
=", ".join(dict.keys(self
)))
1207 dict.__setitem
__(self
, key
, value
)
1210 def __getitem__(self
, key
):
1213 return dict.__getitem
__(self
, key
)
1216 def __delitem__(self
, key
):
1217 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1222 self
.__setitem
__(Key
, "")
1224 ## Return value related to a key, and remove the (key, value) from the dict
1225 def pop(self
, key
, *dv
):
1226 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1228 ## Return (key, value) pair, and remove the (key, value) from the dict
1230 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1232 ## Dictionary using prioritized list as key
1235 _ListType
= type([])
1236 _TupleType
= type(())
1237 _Wildcard
= 'COMMON'
1238 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1240 def __init__(self
, _Single_
=False, _Level_
=2):
1241 self
._Level
_ = _Level_
1243 self
._Single
_ = _Single_
1246 def __getitem__(self
, key
):
1249 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1253 elif self
._Level
_ > 1:
1254 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1257 if self
._Level
_ > 1:
1258 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1260 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1261 FirstKey
= self
._Wildcard
1264 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1266 return self
._GetAllValues
(FirstKey
, RestKeys
)
1268 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1270 #print "%s-%s" % (FirstKey, self._Level_) ,
1271 if self
._Level
_ > 1:
1272 if FirstKey
== self
._Wildcard
:
1273 if FirstKey
in self
.data
:
1274 Value
= self
.data
[FirstKey
][RestKeys
]
1276 for Key
in self
.data
:
1277 Value
= self
.data
[Key
][RestKeys
]
1278 if Value
!= None: break
1280 if FirstKey
in self
.data
:
1281 Value
= self
.data
[FirstKey
][RestKeys
]
1282 if Value
== None and self
._Wildcard
in self
.data
:
1284 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1286 if FirstKey
== self
._Wildcard
:
1287 if FirstKey
in self
.data
:
1288 Value
= self
.data
[FirstKey
]
1290 for Key
in self
.data
:
1291 Value
= self
.data
[Key
]
1292 if Value
!= None: break
1294 if FirstKey
in self
.data
:
1295 Value
= self
.data
[FirstKey
]
1296 elif self
._Wildcard
in self
.data
:
1297 Value
= self
.data
[self
._Wildcard
]
1300 def _GetAllValues(self
, FirstKey
, RestKeys
):
1302 if self
._Level
_ > 1:
1303 if FirstKey
== self
._Wildcard
:
1304 for Key
in self
.data
:
1305 Value
+= self
.data
[Key
][RestKeys
]
1307 if FirstKey
in self
.data
:
1308 Value
+= self
.data
[FirstKey
][RestKeys
]
1309 if self
._Wildcard
in self
.data
:
1310 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1312 if FirstKey
== self
._Wildcard
:
1313 for Key
in self
.data
:
1314 Value
.append(self
.data
[Key
])
1316 if FirstKey
in self
.data
:
1317 Value
.append(self
.data
[FirstKey
])
1318 if self
._Wildcard
in self
.data
:
1319 Value
.append(self
.data
[self
._Wildcard
])
1323 def __setitem__(self
, key
, value
):
1326 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1331 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1334 if self
._Level
_ > 1:
1335 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1337 if FirstKey
in self
._ValidWildcardList
:
1338 FirstKey
= self
._Wildcard
1340 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1341 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1343 if self
._Level
_ > 1:
1344 self
.data
[FirstKey
][RestKeys
] = value
1346 self
.data
[FirstKey
] = value
1348 def SetGreedyMode(self
):
1349 self
._Single
_ = False
1350 if self
._Level
_ > 1:
1351 for Key
in self
.data
:
1352 self
.data
[Key
].SetGreedyMode()
1354 def SetSingleMode(self
):
1355 self
._Single
_ = True
1356 if self
._Level
_ > 1:
1357 for Key
in self
.data
:
1358 self
.data
[Key
].SetSingleMode()
1360 def GetKeys(self
, KeyIndex
=0):
1361 assert KeyIndex
>= 0
1363 return set(self
.data
.keys())
1366 for Key
in self
.data
:
1367 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1370 ## Boolean chain list
1372 class Blist(UserList
):
1373 def __init__(self
, initlist
=None):
1374 UserList
.__init
__(self
, initlist
)
1375 def __setitem__(self
, i
, item
):
1376 if item
not in [True, False]:
1382 def _GetResult(self
):
1384 for item
in self
.data
:
1387 Result
= property(_GetResult
)
1389 def ParseConsoleLog(Filename
):
1390 Opr
= open(os
.path
.normpath(Filename
), 'r')
1391 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1392 for Line
in Opr
.readlines():
1393 if Line
.find('.efi') > -1:
1394 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1395 Opw
.write('%s\n' % Line
)
1402 # Analyze DSC PCD value, since there is no data type info in DSC
1403 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1404 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1405 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1406 # 3. Dynamic default:
1407 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1408 # TokenSpace.PcdCName|PcdValue
1410 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1411 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1413 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1414 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1415 # there might have "|" operator, also in string value.
1417 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1418 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1419 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1421 # ValueList: A List contain fields described above
1422 # IsValid: True if conforming EBNF, otherwise False
1423 # Index: The index where PcdValue is in ValueList
1425 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1426 Setting
= Setting
.strip()
1427 # There might be escaped quote in a string: \", \\\"
1428 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1429 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1436 elif ch
== '(' and not InStr
:
1438 elif ch
== ')' and not InStr
:
1441 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1448 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1450 FieldList
.append(Setting
[StartPos
:].strip())
1452 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1456 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1457 Value
= FieldList
[0]
1459 if len(FieldList
) > 1:
1461 # Fix the PCD type when no DataType input
1466 if len(FieldList
) > 2:
1468 if DataType
== 'VOID*':
1469 IsValid
= (len(FieldList
) <= 3)
1471 IsValid
= (len(FieldList
) <= 1)
1472 return [Value
, '', Size
], IsValid
, 0
1473 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1474 Value
= FieldList
[0]
1476 if len(FieldList
) > 1:
1480 if len(FieldList
) > 2:
1484 if Value
.startswith("L"):
1485 Size
= str((len(Value
)- 3 + 1) * 2)
1486 elif Value
.startswith("{"):
1487 Size
= str(len(Value
.split(",")))
1489 Size
= str(len(Value
) -2 + 1 )
1490 if DataType
== 'VOID*':
1491 IsValid
= (len(FieldList
) <= 3)
1493 IsValid
= (len(FieldList
) <= 1)
1494 return [Value
, Type
, Size
], IsValid
, 0
1495 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1496 VpdOffset
= FieldList
[0]
1498 if not DataType
== 'VOID*':
1499 if len(FieldList
) > 1:
1500 Value
= FieldList
[1]
1502 if len(FieldList
) > 1:
1504 if len(FieldList
) > 2:
1505 Value
= FieldList
[2]
1506 if DataType
== 'VOID*':
1507 IsValid
= (len(FieldList
) <= 3)
1509 IsValid
= (len(FieldList
) <= 2)
1510 return [VpdOffset
, Size
, Value
], IsValid
, 2
1511 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1512 HiiString
= FieldList
[0]
1513 Guid
= Offset
= Value
= Attribute
= ''
1514 if len(FieldList
) > 1:
1516 if len(FieldList
) > 2:
1517 Offset
= FieldList
[2]
1518 if len(FieldList
) > 3:
1519 Value
= FieldList
[3]
1520 if len(FieldList
) > 4:
1521 Attribute
= FieldList
[4]
1522 IsValid
= (3 <= len(FieldList
) <= 5)
1523 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1528 # Analyze the pcd Value, Datum type and TokenNumber.
1529 # Used to avoid split issue while the value string contain "|" character
1531 # @param[in] Setting: A String contain value/datum type/token number information;
1533 # @retval ValueList: A List contain value, datum type and toke number.
1535 def AnalyzePcdData(Setting
):
1536 ValueList
= ['', '', '']
1538 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1539 PtrValue
= ValueRe
.findall(Setting
)
1541 ValueUpdateFlag
= False
1543 if len(PtrValue
) >= 1:
1544 Setting
= re
.sub(ValueRe
, '', Setting
)
1545 ValueUpdateFlag
= True
1547 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1548 ValueList
[0:len(TokenList
)] = TokenList
1551 ValueList
[0] = PtrValue
[0]
1555 ## AnalyzeHiiPcdData
1557 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1558 # Used to avoid split issue while the value string contain "|" character
1560 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1562 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1564 def AnalyzeHiiPcdData(Setting
):
1565 ValueList
= ['', '', '', '']
1567 TokenList
= GetSplitValueList(Setting
)
1568 ValueList
[0:len(TokenList
)] = TokenList
1572 ## AnalyzeVpdPcdData
1574 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1575 # Used to avoid split issue while the value string contain "|" character
1577 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1579 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1581 def AnalyzeVpdPcdData(Setting
):
1582 ValueList
= ['', '', '']
1584 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1585 PtrValue
= ValueRe
.findall(Setting
)
1587 ValueUpdateFlag
= False
1589 if len(PtrValue
) >= 1:
1590 Setting
= re
.sub(ValueRe
, '', Setting
)
1591 ValueUpdateFlag
= True
1593 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1594 ValueList
[0:len(TokenList
)] = TokenList
1597 ValueList
[2] = PtrValue
[0]
1601 ## check format of PCD value against its the datum type
1603 # For PCD value setting
1605 def CheckPcdDatum(Type
, Value
):
1607 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1608 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1609 or (Value
.startswith('{') and Value
.endswith('}'))
1611 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1612 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1613 elif ValueRe
.match(Value
):
1614 # Check the chars in UnicodeString or CString is printable
1615 if Value
.startswith("L"):
1619 Printset
= set(string
.printable
)
1620 Printset
.remove(TAB_PRINTCHAR_VT
)
1621 Printset
.add(TAB_PRINTCHAR_BS
)
1622 Printset
.add(TAB_PRINTCHAR_NUL
)
1623 if not set(Value
).issubset(Printset
):
1624 PrintList
= list(Printset
)
1626 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1627 elif Type
== 'BOOLEAN':
1628 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1629 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1630 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1631 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1633 Value
= long(Value
, 0)
1635 return False, "Invalid value [%s] of type [%s];"\
1636 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1638 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1642 ## Split command line option string to list
1644 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1645 # in non-windows platform to launch command
1647 def SplitOption(OptionString
):
1652 for Index
in range(0, len(OptionString
)):
1653 CurrentChar
= OptionString
[Index
]
1654 if CurrentChar
in ['"', "'"]:
1655 if QuotationMark
== CurrentChar
:
1657 elif QuotationMark
== "":
1658 QuotationMark
= CurrentChar
1663 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1664 if Index
> OptionStart
:
1665 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1667 LastChar
= CurrentChar
1668 OptionList
.append(OptionString
[OptionStart
:])
1671 def CommonPath(PathList
):
1672 P1
= min(PathList
).split(os
.path
.sep
)
1673 P2
= max(PathList
).split(os
.path
.sep
)
1674 for Index
in xrange(min(len(P1
), len(P2
))):
1675 if P1
[Index
] != P2
[Index
]:
1676 return os
.path
.sep
.join(P1
[:Index
])
1677 return os
.path
.sep
.join(P1
)
1680 # Convert string to C format array
1682 def ConvertStringToByteArray(Value
):
1683 Value
= Value
.strip()
1687 if not Value
.endswith('}'):
1689 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1690 ValFields
= Value
.split(',')
1692 for Index
in range(len(ValFields
)):
1693 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1696 Value
= '{' + ','.join(ValFields
) + '}'
1700 if Value
.startswith('L"'):
1701 if not Value
.endswith('"'):
1705 elif not Value
.startswith('"') or not Value
.endswith('"'):
1708 Value
= eval(Value
) # translate escape character
1710 for Index
in range(0,len(Value
)):
1712 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1714 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1715 Value
= NewValue
+ '0}'
1718 class PathClass(object):
1719 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1720 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1722 self
.File
= str(File
)
1723 if os
.path
.isabs(self
.File
):
1727 self
.Root
= str(Root
)
1728 self
.AlterRoot
= str(AlterRoot
)
1730 # Remove any '.' and '..' in path
1732 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1733 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1734 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1735 # eliminate the side-effect of 'C:'
1736 if self
.Root
[-1] == ':':
1737 self
.Root
+= os
.path
.sep
1738 # file path should not start with path separator
1739 if self
.Root
[-1] == os
.path
.sep
:
1740 self
.File
= self
.Path
[len(self
.Root
):]
1742 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1744 self
.Path
= os
.path
.normpath(self
.File
)
1746 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1747 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1751 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1753 self
.Dir
= self
.Root
1755 self
.Dir
= self
.SubDir
1760 self
.Type
= self
.Ext
.lower()
1762 self
.IsBinary
= IsBinary
1763 self
.Target
= Target
1764 self
.TagName
= TagName
1765 self
.ToolCode
= ToolCode
1766 self
.ToolChainFamily
= ToolChainFamily
1770 ## Convert the object of this class to a string
1772 # Convert member Path of the class to a string
1774 # @retval string Formatted String
1779 ## Override __eq__ function
1781 # Check whether PathClass are the same
1783 # @retval False The two PathClass are different
1784 # @retval True The two PathClass are the same
1786 def __eq__(self
, Other
):
1787 if type(Other
) == type(self
):
1788 return self
.Path
== Other
.Path
1790 return self
.Path
== str(Other
)
1792 ## Override __cmp__ function
1794 # Customize the comparsion operation of two PathClass
1796 # @retval 0 The two PathClass are different
1797 # @retval -1 The first PathClass is less than the second PathClass
1798 # @retval 1 The first PathClass is Bigger than the second PathClass
1799 def __cmp__(self
, Other
):
1800 if type(Other
) == type(self
):
1801 OtherKey
= Other
.Path
1803 OtherKey
= str(Other
)
1806 if SelfKey
== OtherKey
:
1808 elif SelfKey
> OtherKey
:
1813 ## Override __hash__ function
1815 # Use Path as key in hash table
1817 # @retval string Key for hash table
1820 return hash(self
.Path
)
1822 def _GetFileKey(self
):
1823 if self
._Key
== None:
1824 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1827 def _GetTimeStamp(self
):
1828 return os
.stat(self
.Path
)[8]
1830 def Validate(self
, Type
='', CaseSensitive
=True):
1831 if GlobalData
.gCaseInsensitive
:
1832 CaseSensitive
= False
1833 if Type
and Type
.lower() != self
.Type
:
1834 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1836 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1837 if not RealRoot
and not RealFile
:
1838 RealFile
= self
.File
1840 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1842 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1843 if len (mws
.getPkgPath()) == 0:
1844 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1846 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1850 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1851 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1852 ErrorCode
= FILE_CASE_MISMATCH
1853 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1855 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1856 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1858 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1861 self
.File
= RealFile
1862 self
.Root
= RealRoot
1863 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1864 return ErrorCode
, ErrorInfo
1866 Key
= property(_GetFileKey
)
1867 TimeStamp
= property(_GetTimeStamp
)
1869 ## Parse PE image to get the required PE informaion.
1871 class PeImageClass():
1874 # @param File FilePath of PeImage
1876 def __init__(self
, PeFile
):
1877 self
.FileName
= PeFile
1878 self
.IsValid
= False
1881 self
.SectionAlignment
= 0
1882 self
.SectionHeaderList
= []
1885 PeObject
= open(PeFile
, 'rb')
1887 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1890 ByteArray
= array
.array('B')
1891 ByteArray
.fromfile(PeObject
, 0x3E)
1892 ByteList
= ByteArray
.tolist()
1893 # DOS signature should be 'MZ'
1894 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1895 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1898 # Read 4 byte PE Signature
1899 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1900 PeObject
.seek(PeOffset
)
1901 ByteArray
= array
.array('B')
1902 ByteArray
.fromfile(PeObject
, 4)
1903 # PE signature should be 'PE\0\0'
1904 if ByteArray
.tostring() != 'PE\0\0':
1905 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1908 # Read PE file header
1909 ByteArray
= array
.array('B')
1910 ByteArray
.fromfile(PeObject
, 0x14)
1911 ByteList
= ByteArray
.tolist()
1912 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1914 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1917 # Read PE optional header
1918 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1919 ByteArray
= array
.array('B')
1920 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1921 ByteList
= ByteArray
.tolist()
1922 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1923 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1924 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1926 # Read each Section Header
1927 for Index
in range(SecNumber
):
1928 ByteArray
= array
.array('B')
1929 ByteArray
.fromfile(PeObject
, 0x28)
1930 ByteList
= ByteArray
.tolist()
1931 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1932 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1933 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1934 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1935 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1939 def _ByteListToStr(self
, ByteList
):
1941 for index
in range(len(ByteList
)):
1942 if ByteList
[index
] == 0:
1944 String
+= chr(ByteList
[index
])
1947 def _ByteListToInt(self
, ByteList
):
1949 for index
in range(len(ByteList
) - 1, -1, -1):
1950 Value
= (Value
<< 8) |
int(ByteList
[index
])
1960 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1962 self
.AvailableSkuIds
= sdict()
1964 self
.SkuIdNumberSet
= []
1965 if SkuIdentifier
== '' or SkuIdentifier
is None:
1966 self
.SkuIdSet
= ['DEFAULT']
1967 self
.SkuIdNumberSet
= ['0U']
1968 elif SkuIdentifier
== 'ALL':
1969 self
.SkuIdSet
= SkuIds
.keys()
1970 self
.SkuIdNumberSet
= [num
.strip() + 'U' for num
in SkuIds
.values()]
1972 r
= SkuIdentifier
.split('|')
1973 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
1976 self
.SkuIdNumberSet
= [SkuIds
[k
].strip() + 'U' for k
in self
.SkuIdSet
]
1978 EdkLogger
.error("build", PARAMETER_INVALID
,
1979 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1980 % (k
, " ".join(SkuIds
.keys())))
1981 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
1982 self
.SkuIdSet
.remove('DEFAULT')
1983 self
.SkuIdNumberSet
.remove('0U')
1984 for each
in self
.SkuIdSet
:
1986 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
1988 EdkLogger
.error("build", PARAMETER_INVALID
,
1989 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1990 % (each
, " ".join(SkuIds
.keys())))
1992 def __SkuUsageType(self
):
1994 if len(self
.SkuIdSet
) == 1:
1995 if self
.SkuIdSet
[0] == 'DEFAULT':
1996 return SkuClass
.DEFAULT
1998 return SkuClass
.SINGLE
2000 return SkuClass
.MULTIPLE
2002 def __GetAvailableSkuIds(self
):
2003 return self
.AvailableSkuIds
2005 def __GetSystemSkuID(self
):
2006 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2007 return self
.SkuIdSet
[0]
2010 def __GetAvailableSkuIdNumber(self
):
2011 return self
.SkuIdNumberSet
2012 SystemSkuId
= property(__GetSystemSkuID
)
2013 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2014 SkuUsageType
= property(__SkuUsageType
)
2015 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2018 # Pack a registry format GUID
2020 def PackRegistryFormatGuid(Guid
):
2021 Guid
= Guid
.split('-')
2022 return pack('=LHHBBBBBBBB',
2026 int(Guid
[3][-4:-2], 16),
2027 int(Guid
[3][-2:], 16),
2028 int(Guid
[4][-12:-10], 16),
2029 int(Guid
[4][-10:-8], 16),
2030 int(Guid
[4][-8:-6], 16),
2031 int(Guid
[4][-6:-4], 16),
2032 int(Guid
[4][-4:-2], 16),
2033 int(Guid
[4][-2:], 16)
2038 # This acts like the main() function for the script, unless it is 'import'ed into another
2041 if __name__
== '__main__':