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
39 ## Regular expression used to find out place holders in string template
40 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE|re
.UNICODE
)
42 ## Dictionary used to store file time stamp for quick re-access
43 gFileTimeStampCache
= {} # {file path : file time stamp}
45 ## Dictionary used to store dependencies of files
46 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
48 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
49 """ Parse map file to get variable offset in current EFI file
50 @param mapfilepath Map file absolution path
51 @param efifilepath: EFI binary file full path
52 @param varnames iteratable container whose elements are variable names to be searched
54 @return List whos elements are tuple with variable name and raw offset
58 f
= open(mapfilepath
, 'r')
64 if len(lines
) == 0: return None
65 firstline
= lines
[0].strip()
66 if (firstline
.startswith("Archive member included ") and
67 firstline
.endswith(" file (symbol)")):
68 return _parseForGCC(lines
, efifilepath
, varnames
)
69 return _parseGeneral(lines
, efifilepath
, varnames
)
71 def _parseForGCC(lines
, efifilepath
, varnames
):
72 """ Parse map file generated by GCC linker """
78 # status machine transection
79 if status
== 0 and line
== "Memory Configuration":
82 elif status
== 1 and line
== 'Linker script and memory map':
85 elif status
==2 and line
== 'START GROUP':
91 m
= re
.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line
)
93 sections
.append(m
.groups(0))
94 for varname
in varnames
:
95 m
= re
.match("^([\da-fA-Fx]+) +[_]*(%s)$" % varname
, line
)
97 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
101 # get section information from efi file
102 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
103 if efisecs
== None or len(efisecs
) == 0:
107 for efisec
in efisecs
:
108 for section
in sections
:
109 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
110 redirection
= int(section
[1], 16) - efisec
[1]
113 for var
in varoffset
:
114 for efisec
in efisecs
:
115 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
116 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
119 def _parseGeneral(lines
, efifilepath
, varnames
):
120 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
121 secs
= [] # key = section name
123 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
124 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
128 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
131 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
134 if re
.match("^entry point at", line
):
137 if status
== 1 and len(line
) != 0:
138 m
= secRe
.match(line
)
139 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
140 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
141 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
142 if status
== 2 and len(line
) != 0:
143 for varname
in varnames
:
144 m
= symRe
.match(line
)
145 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
146 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
147 sec_no
= int(sec_no
, 16)
148 sym_offset
= int(sym_offset
, 16)
149 vir_addr
= int(vir_addr
, 16)
150 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
152 # fond a binary pcd entry in map file
154 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
155 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
157 if not varoffset
: return []
159 # get section information from efi file
160 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
161 if efisecs
== None or len(efisecs
) == 0:
165 for var
in varoffset
:
167 for efisec
in efisecs
:
169 if var
[1].strip() == efisec
[0].strip():
170 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
171 elif var
[4] == index
:
172 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
176 ## Routine to process duplicated INF
178 # This function is called by following two cases:
181 # Pkg/module/module.inf
182 # Pkg/module/module.inf {
184 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
187 # INF Pkg/module/module.inf
188 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
190 # This function copies Pkg/module/module.inf to
191 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
193 # @param Path Original PathClass object
194 # @param BaseName New file base name
196 # @retval return the new PathClass object
198 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
199 Filename
= os
.path
.split(Path
.File
)[1]
201 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
203 Filename
= BaseName
+ Path
.BaseName
206 # If -N is specified on command line, cache is disabled
207 # The directory has to be created
209 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
210 if not os
.path
.exists(DbDir
):
213 # A temporary INF is copied to database path which must have write permission
214 # The temporary will be removed at the end of build
215 # In case of name conflict, the file name is
216 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
218 TempFullPath
= os
.path
.join(DbDir
,
220 RtPath
= PathClass(Path
.File
, Workspace
)
222 # Modify the full path to temporary path, keep other unchanged
224 # To build same module more than once, the module path with FILE_GUID overridden has
225 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
226 # in DSC which is used as relative path by C files and other files in INF.
227 # A trick was used: all module paths are PathClass instances, after the initialization
228 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
230 # The reason for creating a temporary INF is:
231 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
232 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
233 # A different key for the same module is needed to create different output directory,
234 # retrieve overridden PCDs, library instances.
236 # The BaseName is the FILE_GUID which is also the output directory name.
239 RtPath
.Path
= TempFullPath
240 RtPath
.BaseName
= BaseName
242 # If file exists, compare contents
244 if os
.path
.exists(TempFullPath
):
245 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
246 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
249 GlobalData
.gTempInfs
.append(TempFullPath
)
250 shutil
.copy2(str(Path
), TempFullPath
)
253 ## Remove temporary created INFs whose paths were saved in gTempInfs
255 def ClearDuplicatedInf():
256 for File
in GlobalData
.gTempInfs
:
257 if os
.path
.exists(File
):
260 ## callback routine for processing variable option
262 # This function can be used to process variable number of option values. The
263 # typical usage of it is specify architecure list on command line.
264 # (e.g. <tool> -a IA32 X64 IPF)
266 # @param Option Standard callback function parameter
267 # @param OptionString Standard callback function parameter
268 # @param Value Standard callback function parameter
269 # @param Parser Standard callback function parameter
273 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
276 RawArgs
= Parser
.rargs
279 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
280 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
284 setattr(Parser
.values
, Option
.dest
, Value
)
286 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
288 # @param Guid The GUID string
290 # @retval string The GUID string in C structure style
292 def GuidStringToGuidStructureString(Guid
):
293 GuidList
= Guid
.split('-')
295 for Index
in range(0,3,1):
296 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
297 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
298 for Index
in range(0,12,2):
299 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+2]
303 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
305 # @param GuidValue The GUID value in byte array
307 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
309 def GuidStructureByteArrayToGuidString(GuidValue
):
310 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
311 guidValueList
= guidValueString
.split(",")
312 if len(guidValueList
) != 16:
314 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
316 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
317 int(guidValueList
[3], 16),
318 int(guidValueList
[2], 16),
319 int(guidValueList
[1], 16),
320 int(guidValueList
[0], 16),
321 int(guidValueList
[5], 16),
322 int(guidValueList
[4], 16),
323 int(guidValueList
[7], 16),
324 int(guidValueList
[6], 16),
325 int(guidValueList
[8], 16),
326 int(guidValueList
[9], 16),
327 int(guidValueList
[10], 16),
328 int(guidValueList
[11], 16),
329 int(guidValueList
[12], 16),
330 int(guidValueList
[13], 16),
331 int(guidValueList
[14], 16),
332 int(guidValueList
[15], 16)
337 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
339 # @param GuidValue The GUID value in C structure format
341 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
343 def GuidStructureStringToGuidString(GuidValue
):
344 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
345 guidValueList
= guidValueString
.split(",")
346 if len(guidValueList
) != 11:
348 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
350 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
351 int(guidValueList
[0], 16),
352 int(guidValueList
[1], 16),
353 int(guidValueList
[2], 16),
354 int(guidValueList
[3], 16),
355 int(guidValueList
[4], 16),
356 int(guidValueList
[5], 16),
357 int(guidValueList
[6], 16),
358 int(guidValueList
[7], 16),
359 int(guidValueList
[8], 16),
360 int(guidValueList
[9], 16),
361 int(guidValueList
[10], 16)
366 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
368 # @param GuidValue The GUID value in C structure format
370 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
372 def GuidStructureStringToGuidValueName(GuidValue
):
373 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
374 guidValueList
= guidValueString
.split(",")
375 if len(guidValueList
) != 11:
376 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
377 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
378 int(guidValueList
[0], 16),
379 int(guidValueList
[1], 16),
380 int(guidValueList
[2], 16),
381 int(guidValueList
[3], 16),
382 int(guidValueList
[4], 16),
383 int(guidValueList
[5], 16),
384 int(guidValueList
[6], 16),
385 int(guidValueList
[7], 16),
386 int(guidValueList
[8], 16),
387 int(guidValueList
[9], 16),
388 int(guidValueList
[10], 16)
391 ## Create directories
393 # @param Directory The directory name
395 def CreateDirectory(Directory
):
396 if Directory
== None or Directory
.strip() == "":
399 if not os
.access(Directory
, os
.F_OK
):
400 os
.makedirs(Directory
)
405 ## Remove directories, including files and sub-directories in it
407 # @param Directory The directory name
409 def RemoveDirectory(Directory
, Recursively
=False):
410 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
413 CurrentDirectory
= os
.getcwd()
415 for File
in os
.listdir("."):
416 if os
.path
.isdir(File
):
417 RemoveDirectory(File
, Recursively
)
420 os
.chdir(CurrentDirectory
)
423 ## Check if given file is changed or not
425 # This method is used to check if a file is changed or not between two build
426 # actions. It makes use a cache to store files timestamp.
428 # @param File The path of file
430 # @retval True If the given file is changed, doesn't exist, or can't be
431 # found in timestamp cache
432 # @retval False If the given file is changed
435 if not os
.path
.exists(File
):
438 FileState
= os
.stat(File
)
439 TimeStamp
= FileState
[-2]
441 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
445 gFileTimeStampCache
[File
] = TimeStamp
449 ## Store content in file
451 # This method is used to save file only when its content is changed. This is
452 # quite useful for "make" system to decide what will be re-built and what won't.
454 # @param File The path of file
455 # @param Content The new content of the file
456 # @param IsBinaryFile The flag indicating if the file is binary file or not
458 # @retval True If the file content is changed and the file is renewed
459 # @retval False If the file content is the same
461 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
463 Content
= Content
.replace("\n", os
.linesep
)
465 if os
.path
.exists(File
):
467 if Content
== open(File
, "rb").read():
470 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
472 DirName
= os
.path
.dirname(File
)
473 if not CreateDirectory(DirName
):
474 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
477 DirName
= os
.getcwd()
478 if not os
.access(DirName
, os
.W_OK
):
479 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
482 if GlobalData
.gIsWindows
:
484 from PyUtility
import SaveFileToDisk
485 if not SaveFileToDisk(File
, Content
):
486 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
488 Fd
= open(File
, "wb")
492 Fd
= open(File
, "wb")
496 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s'%X)
500 ## Make a Python object persistent on file system
502 # @param Data The object to be stored in file
503 # @param File The path of file to store the object
505 def DataDump(Data
, File
):
508 Fd
= open(File
, 'wb')
509 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
511 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
516 ## Restore a Python object from a file
518 # @param File The path of file stored the object
520 # @retval object A python object
521 # @retval None If failure in file operation
523 def DataRestore(File
):
527 Fd
= open(File
, 'rb')
528 Data
= cPickle
.load(Fd
)
530 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
537 ## Retrieve and cache the real path name in file system
539 # @param Root The root directory of path relative to
541 # @retval str The path string if the path exists
542 # @retval None If path doesn't exist
548 def __init__(self
, Root
):
550 for F
in os
.listdir(Root
):
552 self
._UPPER
_CACHE
_[F
.upper()] = F
555 def __getitem__(self
, Path
):
556 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
559 if Path
and Path
[0] == os
.path
.sep
:
561 if Path
in self
._CACHE
_:
562 return os
.path
.join(self
._Root
, Path
)
563 UpperPath
= Path
.upper()
564 if UpperPath
in self
._UPPER
_CACHE
_:
565 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
569 SepIndex
= Path
.find(os
.path
.sep
)
571 Parent
= UpperPath
[:SepIndex
]
572 if Parent
not in self
._UPPER
_CACHE
_:
574 LastSepIndex
= SepIndex
575 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
577 if LastSepIndex
== -1:
582 SepIndex
= LastSepIndex
584 Parent
= Path
[:SepIndex
]
585 ParentKey
= UpperPath
[:SepIndex
]
586 if ParentKey
not in self
._UPPER
_CACHE
_:
590 if Parent
in self
._CACHE
_:
593 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
594 for F
in os
.listdir(ParentDir
):
595 Dir
= os
.path
.join(ParentDir
, F
)
596 self
._CACHE
_.add(Dir
)
597 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
599 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
602 if Path
in self
._CACHE
_:
603 return os
.path
.join(self
._Root
, Path
)
604 elif UpperPath
in self
._UPPER
_CACHE
_:
605 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
608 ## Get all files of a directory
610 # @param Root: Root dir
611 # @param SkipList : The files need be skipped
613 # @retval A list of all files
615 def GetFiles(Root
, SkipList
=None, FullPath
= True):
618 for Root
, Dirs
, Files
in os
.walk(Root
):
620 for Item
in SkipList
:
625 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
627 File
= File
[len(OriPath
) + 1:]
628 FileList
.append(File
)
632 ## Check if gvien file exists or not
634 # @param File File name or path to be checked
635 # @param Dir The directory the file is relative to
637 # @retval True if file exists
638 # @retval False if file doesn't exists
640 def ValidFile(File
, Ext
=None):
642 Dummy
, FileExt
= os
.path
.splitext(File
)
643 if FileExt
.lower() != Ext
.lower():
645 if not os
.path
.exists(File
):
649 def RealPath(File
, Dir
='', OverrideDir
=''):
650 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
651 NewFile
= GlobalData
.gAllFiles
[NewFile
]
652 if not NewFile
and OverrideDir
:
653 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
654 NewFile
= GlobalData
.gAllFiles
[NewFile
]
657 def RealPath2(File
, Dir
='', OverrideDir
=''):
660 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
662 if OverrideDir
[-1] == os
.path
.sep
:
663 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
665 return NewFile
[len(OverrideDir
)+1:], NewFile
[0:len(OverrideDir
)]
666 if GlobalData
.gAllFiles
:
667 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
669 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
670 if not os
.path
.exists(NewFile
):
674 if Dir
[-1] == os
.path
.sep
:
675 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
677 return NewFile
[len(Dir
)+1:], NewFile
[0:len(Dir
)]
683 ## Check if gvien file exists or not
686 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
689 Dummy
, FileExt
= os
.path
.splitext(File
)
690 if FileExt
.lower() != Ext
.lower():
693 # Replace the Edk macros
694 if OverrideDir
!= '' and OverrideDir
!= None:
695 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
696 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
697 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
698 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
700 # Replace the default dir to current dir
703 Dir
= Dir
[len(Workspace
)+1:]
705 # First check if File has Edk definition itself
706 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
707 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
708 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
709 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
713 # Second check the path with override value
714 if OverrideDir
!= '' and OverrideDir
!= None:
715 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
719 # Last check the path with normal definitions
720 File
= os
.path
.join(Dir
, File
)
721 NewFile
= AllFiles
[os
.path
.normpath(File
)]
727 ## Check if gvien file exists or not
730 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
731 # Replace the Edk macros
732 if OverrideDir
!= '' and OverrideDir
!= None:
733 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
734 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
735 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
736 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
738 # Replace the default dir to current dir
739 # Dir is current module dir related to workspace
742 Dir
= Dir
[len(Workspace
)+1:]
745 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
746 NewRelaPath
= RelaPath
749 # First check if File has Edk definition itself
750 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
751 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
752 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
753 NewFile
= AllFiles
[os
.path
.normpath(File
)]
755 NewRelaPath
= os
.path
.dirname(NewFile
)
756 File
= os
.path
.basename(NewFile
)
757 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
760 # Second check the path with override value
761 if OverrideDir
!= '' and OverrideDir
!= None:
762 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
764 #NewRelaPath = os.path.dirname(NewFile)
765 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
768 # Last check the path with normal definitions
769 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
776 return NewRelaPath
, RelaPath
, File
779 def GetRelPath(Path1
, Path2
):
780 FileName
= os
.path
.basename(Path2
)
781 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
782 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
783 for Index
in range(0, len(L1
)):
784 if L1
[Index
] != L2
[Index
]:
785 FileName
= '../' * (len(L1
) - Index
)
786 for Index2
in range(Index
, len(L2
)):
787 FileName
= os
.path
.join(FileName
, L2
[Index2
])
789 return os
.path
.normpath(FileName
)
792 ## Get GUID value from given packages
794 # @param CName The CName of the GUID
795 # @param PackageList List of packages looking-up in
797 # @retval GuidValue if the CName is found in any given package
798 # @retval None if the CName is not found in all given packages
800 def GuidValue(CName
, PackageList
):
801 for P
in PackageList
:
803 return P
.Guids
[CName
]
806 ## Get Protocol value from given packages
808 # @param CName The CName of the GUID
809 # @param PackageList List of packages looking-up in
811 # @retval GuidValue if the CName is found in any given package
812 # @retval None if the CName is not found in all given packages
814 def ProtocolValue(CName
, PackageList
):
815 for P
in PackageList
:
816 if CName
in P
.Protocols
:
817 return P
.Protocols
[CName
]
820 ## Get PPI value from given packages
822 # @param CName The CName of the GUID
823 # @param PackageList List of packages looking-up in
825 # @retval GuidValue if the CName is found in any given package
826 # @retval None if the CName is not found in all given packages
828 def PpiValue(CName
, PackageList
):
829 for P
in PackageList
:
834 ## A string template class
836 # This class implements a template for string replacement. A string template
837 # looks like following
839 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
841 # The string between ${BEGIN} and ${END} will be repeated as many times as the
842 # length of "placeholder_name", which is a list passed through a dict. The
843 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
844 # be not used and, in this case, the "placeholder_name" must not a list and it
845 # will just be replaced once.
847 class TemplateString(object):
848 _REPEAT_START_FLAG
= "BEGIN"
849 _REPEAT_END_FLAG
= "END"
851 class Section(object):
852 _LIST_TYPES
= [type([]), type(set()), type((0,))]
854 def __init__(self
, TemplateSection
, PlaceHolderList
):
855 self
._Template
= TemplateSection
856 self
._PlaceHolderList
= []
858 # Split the section into sub-sections according to the position of placeholders
860 self
._SubSectionList
= []
863 # The placeholders passed in must be in the format of
865 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
867 for PlaceHolder
,Start
,End
in PlaceHolderList
:
868 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
869 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
870 self
._PlaceHolderList
.append(PlaceHolder
)
871 SubSectionStart
= End
872 if SubSectionStart
< len(TemplateSection
):
873 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
875 self
._SubSectionList
= [TemplateSection
]
878 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
880 def Instantiate(self
, PlaceHolderValues
):
882 RepeatPlaceHolders
= {}
883 NonRepeatPlaceHolders
= {}
885 for PlaceHolder
in self
._PlaceHolderList
:
886 if PlaceHolder
not in PlaceHolderValues
:
888 Value
= PlaceHolderValues
[PlaceHolder
]
889 if type(Value
) in self
._LIST
_TYPES
:
891 RepeatTime
= len(Value
)
892 elif RepeatTime
!= len(Value
):
896 "${%s} has different repeat time from others!" % PlaceHolder
,
897 ExtraData
=str(self
._Template
)
899 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
901 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
903 if NonRepeatPlaceHolders
:
905 for S
in self
._SubSectionList
:
906 if S
not in NonRepeatPlaceHolders
:
909 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
911 StringList
= self
._SubSectionList
913 if RepeatPlaceHolders
:
915 for Index
in range(RepeatTime
):
917 if S
not in RepeatPlaceHolders
:
918 TempStringList
.append(S
)
920 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
921 StringList
= TempStringList
923 return "".join(StringList
)
926 def __init__(self
, Template
=None):
928 self
.IsBinary
= False
929 self
._Template
= Template
930 self
._TemplateSectionList
= self
._Parse
(Template
)
934 # @retval string The string replaced
939 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
941 # @retval list A list of TemplateString.Section objects
943 def _Parse(self
, Template
):
948 TemplateSectionList
= []
950 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
952 if MatchEnd
<= len(Template
):
953 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
954 TemplateSectionList
.append(TemplateSection
)
957 MatchString
= MatchObj
.group(1)
958 MatchStart
= MatchObj
.start()
959 MatchEnd
= MatchObj
.end()
961 if MatchString
== self
._REPEAT
_START
_FLAG
:
962 if MatchStart
> SectionStart
:
963 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
964 TemplateSectionList
.append(TemplateSection
)
965 SectionStart
= MatchEnd
967 elif MatchString
== self
._REPEAT
_END
_FLAG
:
968 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
969 TemplateSectionList
.append(TemplateSection
)
970 SectionStart
= MatchEnd
973 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
974 SearchFrom
= MatchEnd
975 return TemplateSectionList
977 ## Replace the string template with dictionary of placeholders and append it to previous one
979 # @param AppendString The string template to append
980 # @param Dictionary The placeholder dictionaries
982 def Append(self
, AppendString
, Dictionary
=None):
984 SectionList
= self
._Parse
(AppendString
)
985 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
987 self
.String
+= AppendString
989 ## Replace the string template with dictionary of placeholders
991 # @param Dictionary The placeholder dictionaries
993 # @retval str The string replaced with placeholder values
995 def Replace(self
, Dictionary
=None):
996 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
998 ## Progress indicator class
1000 # This class makes use of thread to print progress on console.
1003 # for avoiding deadloop
1005 _ProgressThread
= None
1006 _CheckInterval
= 0.25
1010 # @param OpenMessage The string printed before progress charaters
1011 # @param CloseMessage The string printed after progress charaters
1012 # @param ProgressChar The charater used to indicate the progress
1013 # @param Interval The interval in seconds between two progress charaters
1015 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
1016 self
.PromptMessage
= OpenMessage
1017 self
.CodaMessage
= CloseMessage
1018 self
.ProgressChar
= ProgressChar
1019 self
.Interval
= Interval
1020 if Progressor
._StopFlag
== None:
1021 Progressor
._StopFlag
= threading
.Event()
1023 ## Start to print progress charater
1025 # @param OpenMessage The string printed before progress charaters
1027 def Start(self
, OpenMessage
=None):
1028 if OpenMessage
!= None:
1029 self
.PromptMessage
= OpenMessage
1030 Progressor
._StopFlag
.clear()
1031 if Progressor
._ProgressThread
== None:
1032 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
1033 Progressor
._ProgressThread
.setDaemon(False)
1034 Progressor
._ProgressThread
.start()
1036 ## Stop printing progress charater
1038 # @param CloseMessage The string printed after progress charaters
1040 def Stop(self
, CloseMessage
=None):
1041 OriginalCodaMessage
= self
.CodaMessage
1042 if CloseMessage
!= None:
1043 self
.CodaMessage
= CloseMessage
1045 self
.CodaMessage
= OriginalCodaMessage
1047 ## Thread entry method
1048 def _ProgressThreadEntry(self
):
1049 sys
.stdout
.write(self
.PromptMessage
+ " ")
1052 while not Progressor
._StopFlag
.isSet():
1054 sys
.stdout
.write(self
.ProgressChar
)
1056 TimeUp
= self
.Interval
1057 time
.sleep(self
._CheckInterval
)
1058 TimeUp
-= self
._CheckInterval
1059 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
1062 ## Abort the progress display
1065 if Progressor
._StopFlag
!= None:
1066 Progressor
._StopFlag
.set()
1067 if Progressor
._ProgressThread
!= None:
1068 Progressor
._ProgressThread
.join()
1069 Progressor
._ProgressThread
= None
1071 ## A dict which can access its keys and/or values orderly
1073 # The class implements a new kind of dict which its keys or values can be
1074 # accessed in the order they are added into the dict. It guarantees the order
1075 # by making use of an internal list to keep a copy of keys.
1077 class sdict(IterableUserDict
):
1080 IterableUserDict
.__init
__(self
)
1084 def __setitem__(self
, key
, value
):
1085 if key
not in self
._key
_list
:
1086 self
._key
_list
.append(key
)
1087 IterableUserDict
.__setitem
__(self
, key
, value
)
1090 def __delitem__(self
, key
):
1091 self
._key
_list
.remove(key
)
1092 IterableUserDict
.__delitem
__(self
, key
)
1094 ## used in "for k in dict" loop to ensure the correct order
1096 return self
.iterkeys()
1100 return len(self
._key
_list
)
1102 ## "in" test support
1103 def __contains__(self
, key
):
1104 return key
in self
._key
_list
1107 def index(self
, key
):
1108 return self
._key
_list
.index(key
)
1111 def insert(self
, key
, newkey
, newvalue
, order
):
1112 index
= self
._key
_list
.index(key
)
1113 if order
== 'BEFORE':
1114 self
._key
_list
.insert(index
, newkey
)
1115 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1116 elif order
== 'AFTER':
1117 self
._key
_list
.insert(index
+ 1, newkey
)
1118 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
1121 def append(self
, sdict
):
1123 if key
not in self
._key
_list
:
1124 self
._key
_list
.append(key
)
1125 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
1127 def has_key(self
, key
):
1128 return key
in self
._key
_list
1133 IterableUserDict
.clear(self
)
1135 ## Return a copy of keys
1138 for key
in self
._key
_list
:
1142 ## Return a copy of values
1145 for key
in self
._key
_list
:
1146 values
.append(self
[key
])
1149 ## Return a copy of (key, value) list
1152 for key
in self
._key
_list
:
1153 items
.append((key
, self
[key
]))
1156 ## Iteration support
1157 def iteritems(self
):
1158 return iter(self
.items())
1160 ## Keys interation support
1162 return iter(self
.keys())
1164 ## Values interation support
1165 def itervalues(self
):
1166 return iter(self
.values())
1168 ## Return value related to a key, and remove the (key, value) from the dict
1169 def pop(self
, key
, *dv
):
1171 if key
in self
._key
_list
:
1173 self
.__delitem
__(key
)
1178 ## Return (key, value) pair, and remove the (key, value) from the dict
1180 key
= self
._key
_list
[-1]
1182 self
.__delitem
__(key
)
1185 def update(self
, dict=None, **kwargs
):
1187 for k
, v
in dict.items():
1190 for k
, v
in kwargs
.items():
1193 ## Dictionary with restricted keys
1197 def __init__(self
, KeyList
):
1199 dict.__setitem
__(self
, Key
, "")
1202 def __setitem__(self
, key
, value
):
1204 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1205 ExtraData
=", ".join(dict.keys(self
)))
1206 dict.__setitem
__(self
, key
, value
)
1209 def __getitem__(self
, key
):
1212 return dict.__getitem
__(self
, key
)
1215 def __delitem__(self
, key
):
1216 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1221 self
.__setitem
__(Key
, "")
1223 ## Return value related to a key, and remove the (key, value) from the dict
1224 def pop(self
, key
, *dv
):
1225 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1227 ## Return (key, value) pair, and remove the (key, value) from the dict
1229 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1231 ## Dictionary using prioritized list as key
1234 _ListType
= type([])
1235 _TupleType
= type(())
1236 _Wildcard
= 'COMMON'
1237 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1239 def __init__(self
, _Single_
=False, _Level_
=2):
1240 self
._Level
_ = _Level_
1242 self
._Single
_ = _Single_
1245 def __getitem__(self
, key
):
1248 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1252 elif self
._Level
_ > 1:
1253 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1256 if self
._Level
_ > 1:
1257 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1259 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1260 FirstKey
= self
._Wildcard
1263 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1265 return self
._GetAllValues
(FirstKey
, RestKeys
)
1267 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1269 #print "%s-%s" % (FirstKey, self._Level_) ,
1270 if self
._Level
_ > 1:
1271 if FirstKey
== self
._Wildcard
:
1272 if FirstKey
in self
.data
:
1273 Value
= self
.data
[FirstKey
][RestKeys
]
1275 for Key
in self
.data
:
1276 Value
= self
.data
[Key
][RestKeys
]
1277 if Value
!= None: break
1279 if FirstKey
in self
.data
:
1280 Value
= self
.data
[FirstKey
][RestKeys
]
1281 if Value
== None and self
._Wildcard
in self
.data
:
1283 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1285 if FirstKey
== self
._Wildcard
:
1286 if FirstKey
in self
.data
:
1287 Value
= self
.data
[FirstKey
]
1289 for Key
in self
.data
:
1290 Value
= self
.data
[Key
]
1291 if Value
!= None: break
1293 if FirstKey
in self
.data
:
1294 Value
= self
.data
[FirstKey
]
1295 elif self
._Wildcard
in self
.data
:
1296 Value
= self
.data
[self
._Wildcard
]
1299 def _GetAllValues(self
, FirstKey
, RestKeys
):
1301 if self
._Level
_ > 1:
1302 if FirstKey
== self
._Wildcard
:
1303 for Key
in self
.data
:
1304 Value
+= self
.data
[Key
][RestKeys
]
1306 if FirstKey
in self
.data
:
1307 Value
+= self
.data
[FirstKey
][RestKeys
]
1308 if self
._Wildcard
in self
.data
:
1309 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1311 if FirstKey
== self
._Wildcard
:
1312 for Key
in self
.data
:
1313 Value
.append(self
.data
[Key
])
1315 if FirstKey
in self
.data
:
1316 Value
.append(self
.data
[FirstKey
])
1317 if self
._Wildcard
in self
.data
:
1318 Value
.append(self
.data
[self
._Wildcard
])
1322 def __setitem__(self
, key
, value
):
1325 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1330 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1333 if self
._Level
_ > 1:
1334 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1336 if FirstKey
in self
._ValidWildcardList
:
1337 FirstKey
= self
._Wildcard
1339 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1340 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1342 if self
._Level
_ > 1:
1343 self
.data
[FirstKey
][RestKeys
] = value
1345 self
.data
[FirstKey
] = value
1347 def SetGreedyMode(self
):
1348 self
._Single
_ = False
1349 if self
._Level
_ > 1:
1350 for Key
in self
.data
:
1351 self
.data
[Key
].SetGreedyMode()
1353 def SetSingleMode(self
):
1354 self
._Single
_ = True
1355 if self
._Level
_ > 1:
1356 for Key
in self
.data
:
1357 self
.data
[Key
].SetSingleMode()
1359 def GetKeys(self
, KeyIndex
=0):
1360 assert KeyIndex
>= 0
1362 return set(self
.data
.keys())
1365 for Key
in self
.data
:
1366 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1369 ## Boolean chain list
1371 class Blist(UserList
):
1372 def __init__(self
, initlist
=None):
1373 UserList
.__init
__(self
, initlist
)
1374 def __setitem__(self
, i
, item
):
1375 if item
not in [True, False]:
1381 def _GetResult(self
):
1383 for item
in self
.data
:
1386 Result
= property(_GetResult
)
1388 def ParseConsoleLog(Filename
):
1389 Opr
= open(os
.path
.normpath(Filename
), 'r')
1390 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1391 for Line
in Opr
.readlines():
1392 if Line
.find('.efi') > -1:
1393 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1394 Opw
.write('%s\n' % Line
)
1401 # Analyze DSC PCD value, since there is no data type info in DSC
1402 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1403 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1404 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1405 # 3. Dynamic default:
1406 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1407 # TokenSpace.PcdCName|PcdValue
1409 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1410 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1412 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1413 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1414 # there might have "|" operator, also in string value.
1416 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1417 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1418 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1420 # ValueList: A List contain fields described above
1421 # IsValid: True if conforming EBNF, otherwise False
1422 # Index: The index where PcdValue is in ValueList
1424 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1425 Setting
= Setting
.strip()
1426 # There might be escaped quote in a string: \", \\\"
1427 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1428 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1435 elif ch
== '(' and not InStr
:
1437 elif ch
== ')' and not InStr
:
1440 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1447 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1449 FieldList
.append(Setting
[StartPos
:].strip())
1451 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1455 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1456 Value
= FieldList
[0]
1458 if len(FieldList
) > 1:
1460 # Fix the PCD type when no DataType input
1465 if len(FieldList
) > 2:
1467 if DataType
== 'VOID*':
1468 IsValid
= (len(FieldList
) <= 3)
1470 IsValid
= (len(FieldList
) <= 1)
1471 return [Value
, '', Size
], IsValid
, 0
1472 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1473 Value
= FieldList
[0]
1475 if len(FieldList
) > 1:
1479 if len(FieldList
) > 2:
1483 if Value
.startswith("L"):
1484 Size
= str((len(Value
)- 3 + 1) * 2)
1485 elif Value
.startswith("{"):
1486 Size
= str(len(Value
.split(",")))
1488 Size
= str(len(Value
) -2 + 1 )
1489 if DataType
== 'VOID*':
1490 IsValid
= (len(FieldList
) <= 3)
1492 IsValid
= (len(FieldList
) <= 1)
1493 return [Value
, Type
, Size
], IsValid
, 0
1494 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1495 VpdOffset
= FieldList
[0]
1497 if not DataType
== 'VOID*':
1498 if len(FieldList
) > 1:
1499 Value
= FieldList
[1]
1501 if len(FieldList
) > 1:
1503 if len(FieldList
) > 2:
1504 Value
= FieldList
[2]
1505 if DataType
== 'VOID*':
1506 IsValid
= (len(FieldList
) <= 3)
1508 IsValid
= (len(FieldList
) <= 2)
1509 return [VpdOffset
, Size
, Value
], IsValid
, 2
1510 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1511 HiiString
= FieldList
[0]
1512 Guid
= Offset
= Value
= Attribute
= ''
1513 if len(FieldList
) > 1:
1515 if len(FieldList
) > 2:
1516 Offset
= FieldList
[2]
1517 if len(FieldList
) > 3:
1518 Value
= FieldList
[3]
1519 if len(FieldList
) > 4:
1520 Attribute
= FieldList
[4]
1521 IsValid
= (3 <= len(FieldList
) <= 5)
1522 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1527 # Analyze the pcd Value, Datum type and TokenNumber.
1528 # Used to avoid split issue while the value string contain "|" character
1530 # @param[in] Setting: A String contain value/datum type/token number information;
1532 # @retval ValueList: A List contain value, datum type and toke number.
1534 def AnalyzePcdData(Setting
):
1535 ValueList
= ['', '', '']
1537 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1538 PtrValue
= ValueRe
.findall(Setting
)
1540 ValueUpdateFlag
= False
1542 if len(PtrValue
) >= 1:
1543 Setting
= re
.sub(ValueRe
, '', Setting
)
1544 ValueUpdateFlag
= True
1546 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1547 ValueList
[0:len(TokenList
)] = TokenList
1550 ValueList
[0] = PtrValue
[0]
1554 ## AnalyzeHiiPcdData
1556 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1557 # Used to avoid split issue while the value string contain "|" character
1559 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1561 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1563 def AnalyzeHiiPcdData(Setting
):
1564 ValueList
= ['', '', '', '']
1566 TokenList
= GetSplitValueList(Setting
)
1567 ValueList
[0:len(TokenList
)] = TokenList
1571 ## AnalyzeVpdPcdData
1573 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1574 # Used to avoid split issue while the value string contain "|" character
1576 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1578 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1580 def AnalyzeVpdPcdData(Setting
):
1581 ValueList
= ['', '', '']
1583 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1584 PtrValue
= ValueRe
.findall(Setting
)
1586 ValueUpdateFlag
= False
1588 if len(PtrValue
) >= 1:
1589 Setting
= re
.sub(ValueRe
, '', Setting
)
1590 ValueUpdateFlag
= True
1592 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1593 ValueList
[0:len(TokenList
)] = TokenList
1596 ValueList
[2] = PtrValue
[0]
1600 ## check format of PCD value against its the datum type
1602 # For PCD value setting
1604 def CheckPcdDatum(Type
, Value
):
1606 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1607 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1608 or (Value
.startswith('{') and Value
.endswith('}'))
1610 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1611 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1612 elif ValueRe
.match(Value
):
1613 # Check the chars in UnicodeString or CString is printable
1614 if Value
.startswith("L"):
1618 Printset
= set(string
.printable
)
1619 Printset
.remove(TAB_PRINTCHAR_VT
)
1620 Printset
.add(TAB_PRINTCHAR_BS
)
1621 Printset
.add(TAB_PRINTCHAR_NUL
)
1622 if not set(Value
).issubset(Printset
):
1623 PrintList
= list(Printset
)
1625 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1626 elif Type
== 'BOOLEAN':
1627 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1628 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1629 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1630 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1632 Value
= long(Value
, 0)
1634 return False, "Invalid value [%s] of type [%s];"\
1635 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1637 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1641 ## Split command line option string to list
1643 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1644 # in non-windows platform to launch command
1646 def SplitOption(OptionString
):
1651 for Index
in range(0, len(OptionString
)):
1652 CurrentChar
= OptionString
[Index
]
1653 if CurrentChar
in ['"', "'"]:
1654 if QuotationMark
== CurrentChar
:
1656 elif QuotationMark
== "":
1657 QuotationMark
= CurrentChar
1662 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1663 if Index
> OptionStart
:
1664 OptionList
.append(OptionString
[OptionStart
:Index
-1])
1666 LastChar
= CurrentChar
1667 OptionList
.append(OptionString
[OptionStart
:])
1670 def CommonPath(PathList
):
1671 P1
= min(PathList
).split(os
.path
.sep
)
1672 P2
= max(PathList
).split(os
.path
.sep
)
1673 for Index
in xrange(min(len(P1
), len(P2
))):
1674 if P1
[Index
] != P2
[Index
]:
1675 return os
.path
.sep
.join(P1
[:Index
])
1676 return os
.path
.sep
.join(P1
)
1679 # Convert string to C format array
1681 def ConvertStringToByteArray(Value
):
1682 Value
= Value
.strip()
1686 if not Value
.endswith('}'):
1688 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1689 ValFields
= Value
.split(',')
1691 for Index
in range(len(ValFields
)):
1692 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1695 Value
= '{' + ','.join(ValFields
) + '}'
1699 if Value
.startswith('L"'):
1700 if not Value
.endswith('"'):
1704 elif not Value
.startswith('"') or not Value
.endswith('"'):
1707 Value
= eval(Value
) # translate escape character
1709 for Index
in range(0,len(Value
)):
1711 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1713 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1714 Value
= NewValue
+ '0}'
1717 class PathClass(object):
1718 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1719 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1721 self
.File
= str(File
)
1722 if os
.path
.isabs(self
.File
):
1726 self
.Root
= str(Root
)
1727 self
.AlterRoot
= str(AlterRoot
)
1729 # Remove any '.' and '..' in path
1731 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1732 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1733 # eliminate the side-effect of 'C:'
1734 if self
.Root
[-1] == ':':
1735 self
.Root
+= os
.path
.sep
1736 # file path should not start with path separator
1737 if self
.Root
[-1] == os
.path
.sep
:
1738 self
.File
= self
.Path
[len(self
.Root
):]
1740 self
.File
= self
.Path
[len(self
.Root
)+1:]
1742 self
.Path
= os
.path
.normpath(self
.File
)
1744 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1745 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1749 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1751 self
.Dir
= self
.Root
1753 self
.Dir
= self
.SubDir
1758 self
.Type
= self
.Ext
.lower()
1760 self
.IsBinary
= IsBinary
1761 self
.Target
= Target
1762 self
.TagName
= TagName
1763 self
.ToolCode
= ToolCode
1764 self
.ToolChainFamily
= ToolChainFamily
1768 ## Convert the object of this class to a string
1770 # Convert member Path of the class to a string
1772 # @retval string Formatted String
1777 ## Override __eq__ function
1779 # Check whether PathClass are the same
1781 # @retval False The two PathClass are different
1782 # @retval True The two PathClass are the same
1784 def __eq__(self
, Other
):
1785 if type(Other
) == type(self
):
1786 return self
.Path
== Other
.Path
1788 return self
.Path
== str(Other
)
1790 ## Override __cmp__ function
1792 # Customize the comparsion operation of two PathClass
1794 # @retval 0 The two PathClass are different
1795 # @retval -1 The first PathClass is less than the second PathClass
1796 # @retval 1 The first PathClass is Bigger than the second PathClass
1797 def __cmp__(self
, Other
):
1798 if type(Other
) == type(self
):
1799 OtherKey
= Other
.Path
1801 OtherKey
= str(Other
)
1804 if SelfKey
== OtherKey
:
1806 elif SelfKey
> OtherKey
:
1811 ## Override __hash__ function
1813 # Use Path as key in hash table
1815 # @retval string Key for hash table
1818 return hash(self
.Path
)
1820 def _GetFileKey(self
):
1821 if self
._Key
== None:
1822 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1825 def _GetTimeStamp(self
):
1826 return os
.stat(self
.Path
)[8]
1828 def Validate(self
, Type
='', CaseSensitive
=True):
1829 if GlobalData
.gCaseInsensitive
:
1830 CaseSensitive
= False
1831 if Type
and Type
.lower() != self
.Type
:
1832 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1834 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1835 if not RealRoot
and not RealFile
:
1836 RealFile
= self
.File
1838 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1840 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1841 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1845 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1846 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1847 ErrorCode
= FILE_CASE_MISMATCH
1848 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1850 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1851 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1853 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1856 self
.File
= RealFile
1857 self
.Root
= RealRoot
1858 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1859 return ErrorCode
, ErrorInfo
1861 Key
= property(_GetFileKey
)
1862 TimeStamp
= property(_GetTimeStamp
)
1864 ## Parse PE image to get the required PE informaion.
1866 class PeImageClass():
1869 # @param File FilePath of PeImage
1871 def __init__(self
, PeFile
):
1872 self
.FileName
= PeFile
1873 self
.IsValid
= False
1876 self
.SectionAlignment
= 0
1877 self
.SectionHeaderList
= []
1880 PeObject
= open(PeFile
, 'rb')
1882 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1885 ByteArray
= array
.array('B')
1886 ByteArray
.fromfile(PeObject
, 0x3E)
1887 ByteList
= ByteArray
.tolist()
1888 # DOS signature should be 'MZ'
1889 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1890 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1893 # Read 4 byte PE Signature
1894 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1895 PeObject
.seek(PeOffset
)
1896 ByteArray
= array
.array('B')
1897 ByteArray
.fromfile(PeObject
, 4)
1898 # PE signature should be 'PE\0\0'
1899 if ByteArray
.tostring() != 'PE\0\0':
1900 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1903 # Read PE file header
1904 ByteArray
= array
.array('B')
1905 ByteArray
.fromfile(PeObject
, 0x14)
1906 ByteList
= ByteArray
.tolist()
1907 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1909 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1912 # Read PE optional header
1913 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1914 ByteArray
= array
.array('B')
1915 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1916 ByteList
= ByteArray
.tolist()
1917 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1918 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1919 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1921 # Read each Section Header
1922 for Index
in range(SecNumber
):
1923 ByteArray
= array
.array('B')
1924 ByteArray
.fromfile(PeObject
, 0x28)
1925 ByteList
= ByteArray
.tolist()
1926 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1927 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1928 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1929 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1930 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1934 def _ByteListToStr(self
, ByteList
):
1936 for index
in range(len(ByteList
)):
1937 if ByteList
[index
] == 0:
1939 String
+= chr(ByteList
[index
])
1942 def _ByteListToInt(self
, ByteList
):
1944 for index
in range(len(ByteList
) - 1, -1, -1):
1945 Value
= (Value
<< 8) |
int(ByteList
[index
])
1955 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1957 self
.AvailableSkuIds
= sdict()
1959 self
.SkuIdNumberSet
= []
1960 if SkuIdentifier
== '' or SkuIdentifier
is None:
1961 self
.SkuIdSet
= ['DEFAULT']
1962 self
.SkuIdNumberSet
= ['0U']
1963 elif SkuIdentifier
== 'ALL':
1964 self
.SkuIdSet
= SkuIds
.keys()
1965 self
.SkuIdNumberSet
= [num
.strip() + 'U' for num
in SkuIds
.values()]
1967 r
= SkuIdentifier
.split('|')
1968 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
1971 self
.SkuIdNumberSet
= [SkuIds
[k
].strip() + 'U' for k
in self
.SkuIdSet
]
1973 EdkLogger
.error("build", PARAMETER_INVALID
,
1974 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1975 % (k
, " ".join(SkuIds
.keys())))
1976 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
1977 self
.SkuIdSet
.remove('DEFAULT')
1978 self
.SkuIdNumberSet
.remove('0U')
1979 for each
in self
.SkuIdSet
:
1981 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
1983 EdkLogger
.error("build", PARAMETER_INVALID
,
1984 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1985 % (each
, " ".join(SkuIds
.keys())))
1987 def __SkuUsageType(self
):
1989 if len(self
.SkuIdSet
) == 1:
1990 if self
.SkuIdSet
[0] == 'DEFAULT':
1991 return SkuClass
.DEFAULT
1993 return SkuClass
.SINGLE
1995 return SkuClass
.MULTIPLE
1997 def __GetAvailableSkuIds(self
):
1998 return self
.AvailableSkuIds
2000 def __GetSystemSkuID(self
):
2001 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2002 return self
.SkuIdSet
[0]
2005 def __GetAvailableSkuIdNumber(self
):
2006 return self
.SkuIdNumberSet
2007 SystemSkuId
= property(__GetSystemSkuID
)
2008 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2009 SkuUsageType
= property(__SkuUsageType
)
2010 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2013 # Pack a registry format GUID
2015 def PackRegistryFormatGuid(Guid
):
2016 Guid
= Guid
.split('-')
2017 return pack('=LHHBBBBBBBB',
2021 int(Guid
[3][-4:-2], 16),
2022 int(Guid
[3][-2:], 16),
2023 int(Guid
[4][-12:-10], 16),
2024 int(Guid
[4][-10:-8], 16),
2025 int(Guid
[4][-8:-6], 16),
2026 int(Guid
[4][-6:-4], 16),
2027 int(Guid
[4][-4:-2], 16),
2028 int(Guid
[4][-2:], 16)
2033 # This acts like the main() function for the script, unless it is 'import'ed into another
2036 if __name__
== '__main__':