4 # Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 from optparse
import OptionParser
20 import Common
.LongFilePathOs
as os
23 import Common
.BuildToolError
as BuildToolError
24 from GenFdsGlobalVariable
import GenFdsGlobalVariable
25 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
26 from Workspace
.BuildClassObject
import PcdClassObject
27 from Workspace
.BuildClassObject
import ModuleBuildClassObject
28 import RuleComplexFile
29 from EfiSection
import EfiSection
31 import Common
.TargetTxtClassObject
as TargetTxtClassObject
32 import Common
.ToolDefClassObject
as ToolDefClassObject
33 from Common
.DataType
import *
34 import Common
.GlobalData
as GlobalData
35 from Common
import EdkLogger
36 from Common
.String
import *
37 from Common
.Misc
import DirCache
, PathClass
38 from Common
.Misc
import SaveFileOnChange
39 from Common
.Misc
import ClearDuplicatedInf
40 from Common
.Misc
import GuidStructureStringToGuidString
41 from Common
.Misc
import CheckPcdDatum
42 from Common
.Misc
import BuildOptionPcdValueFormat
43 from Common
.BuildVersion
import gBUILD_VERSION
44 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
45 import FfsFileStatement
47 from struct
import unpack
49 ## Version and Copyright
50 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
51 __version__
= "%prog Version " + versionNumber
52 __copyright__
= "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
54 ## Tool entrance method
56 # This method mainly dispatch specific methods per the command line options.
57 # If no error found, return zero value so the caller of this tool can know
58 # if it's executed successfully or not.
60 # @retval 0 Tool was successful
61 # @retval 1 Tool failed
65 Options
= myOptionParser()
72 EdkLogger
.Initialize()
74 if Options
.verbose
!= None:
75 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
76 GenFdsGlobalVariable
.VerboseMode
= True
78 if Options
.FixedAddress
!= None:
79 GenFdsGlobalVariable
.FixedLoadAddress
= True
81 if Options
.quiet
!= None:
82 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
83 if Options
.debug
!= None:
84 EdkLogger
.SetLevel(Options
.debug
+ 1)
85 GenFdsGlobalVariable
.DebugLevel
= Options
.debug
87 EdkLogger
.SetLevel(EdkLogger
.INFO
)
89 if (Options
.Workspace
== None):
90 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
91 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
92 elif not os
.path
.exists(Options
.Workspace
):
93 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
94 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
96 Workspace
= os
.path
.normcase(Options
.Workspace
)
97 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
98 if 'EDK_SOURCE' in os
.environ
.keys():
99 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
101 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
102 if Options
.GenfdsMultiThread
:
103 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
104 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
106 # set multiple workspace
107 PackagesPath
= os
.getenv("PACKAGES_PATH")
108 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
110 if (Options
.filename
):
111 FdfFilename
= Options
.filename
112 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
114 if FdfFilename
[0:2] == '..':
115 FdfFilename
= os
.path
.realpath(FdfFilename
)
116 if not os
.path
.isabs(FdfFilename
):
117 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
118 if not os
.path
.exists(FdfFilename
):
119 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
121 GenFdsGlobalVariable
.FdfFile
= FdfFilename
122 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
124 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
126 if (Options
.BuildTarget
):
127 GenFdsGlobalVariable
.TargetName
= Options
.BuildTarget
129 if (Options
.ToolChain
):
130 GenFdsGlobalVariable
.ToolChainTag
= Options
.ToolChain
132 if (Options
.activePlatform
):
133 ActivePlatform
= Options
.activePlatform
134 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
136 if ActivePlatform
[0:2] == '..':
137 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
139 if not os
.path
.isabs (ActivePlatform
):
140 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
142 if not os
.path
.exists(ActivePlatform
) :
143 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
145 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
147 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
149 if (Options
.ConfDirectory
):
150 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
151 ConfDirectoryPath
= os
.path
.normpath(Options
.ConfDirectory
)
152 if ConfDirectoryPath
.startswith('"'):
153 ConfDirectoryPath
= ConfDirectoryPath
[1:]
154 if ConfDirectoryPath
.endswith('"'):
155 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
156 if not os
.path
.isabs(ConfDirectoryPath
):
157 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
158 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
159 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
161 if "CONF_PATH" in os
.environ
.keys():
162 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
164 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
165 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
166 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
167 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
168 if os
.path
.isfile(BuildConfigurationFile
) == True:
169 TargetTxt
= TargetTxtClassObject
.TargetTxtClassObject()
170 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
171 # if no build target given in command line, get it from target.txt
172 if not GenFdsGlobalVariable
.TargetName
:
173 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
174 if len(BuildTargetList
) != 1:
175 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
176 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
178 # if no tool chain given in command line, get it from target.txt
179 if not GenFdsGlobalVariable
.ToolChainTag
:
180 ToolChainList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
181 if ToolChainList
== None or len(ToolChainList
) == 0:
182 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
183 if len(ToolChainList
) != 1:
184 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
185 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
187 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
189 #Set global flag for build mode
190 GlobalData
.gIgnoreSource
= Options
.IgnoreSources
193 for Pair
in Options
.Macros
:
194 if Pair
.startswith('"'):
196 if Pair
.endswith('"'):
198 List
= Pair
.split('=')
200 if not List
[1].strip():
201 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
202 if List
[0].strip() == "EFI_SOURCE":
203 GlobalData
.gEfiSource
= List
[1].strip()
204 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
206 elif List
[0].strip() == "EDK_SOURCE":
207 GlobalData
.gEdkSource
= List
[1].strip()
208 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
210 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
211 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
213 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
215 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
216 os
.environ
["WORKSPACE"] = Workspace
218 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
219 if "TARGET" not in GlobalData
.gGlobalDefines
.keys():
220 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
221 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
.keys():
222 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
223 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
.keys():
224 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
226 """call Workspace build create database"""
227 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
228 BuildWorkSpace
= WorkspaceDatabase(GlobalData
.gDatabasePath
)
229 BuildWorkSpace
.InitDatabase()
232 # Get files real name in workspace dir
234 GlobalData
.gAllFiles
= DirCache(Workspace
)
235 GlobalData
.gWorkspace
= Workspace
237 if (Options
.archList
) :
238 ArchList
= Options
.archList
.split(',')
240 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
241 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
243 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
) & set(ArchList
)
244 if len(TargetArchList
) == 0:
245 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON'].SupArchList
)))
247 for Arch
in ArchList
:
248 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].OutputDirectory
)
249 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].PlatformName
251 if (Options
.outputDir
):
252 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(Options
.outputDir
)
253 if not os
.path
.isabs (OutputDirFromCommandLine
):
254 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
255 for Arch
in ArchList
:
256 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
258 for Arch
in ArchList
:
259 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
261 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
262 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
263 if OutputDir
[0:2] == '..':
264 OutputDir
= os
.path
.realpath(OutputDir
)
266 if OutputDir
[1] != ':':
267 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
269 if not os
.path
.exists(OutputDir
):
270 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
271 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
273 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
274 FdfParserObj
= FdfParser
.FdfParser(FdfFilename
)
275 FdfParserObj
.ParseFile()
277 if FdfParserObj
.CycleReferenceCheck():
278 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
280 if (Options
.uiFdName
) :
281 if Options
.uiFdName
.upper() in FdfParserObj
.Profile
.FdDict
.keys():
282 GenFds
.OnlyGenerateThisFd
= Options
.uiFdName
284 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
285 "No such an FD in FDF file: %s" % Options
.uiFdName
)
287 if (Options
.uiFvName
) :
288 if Options
.uiFvName
.upper() in FdfParserObj
.Profile
.FvDict
.keys():
289 GenFds
.OnlyGenerateThisFv
= Options
.uiFvName
291 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
292 "No such an FV in FDF file: %s" % Options
.uiFvName
)
294 if (Options
.uiCapName
) :
295 if Options
.uiCapName
.upper() in FdfParserObj
.Profile
.CapsuleDict
.keys():
296 GenFds
.OnlyGenerateThisCap
= Options
.uiCapName
298 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
299 "No such a Capsule in FDF file: %s" % Options
.uiCapName
)
301 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
303 GenFdsGlobalVariable
.ArchList
= ArchList
305 # Dsc Build Data will handle Pcd Settings from CommandLine.
307 """Modify images from build output if the feature of loading driver at fixed address is on."""
308 if GenFdsGlobalVariable
.FixedLoadAddress
:
309 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
311 # Record the FV Region info that may specific in the FD
312 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
313 for Fv
in FdfParserObj
.Profile
.FvDict
:
314 FvObj
= FdfParserObj
.Profile
.FvDict
[Fv
]
315 for Fd
in FdfParserObj
.Profile
.FdDict
:
316 FdObj
= FdfParserObj
.Profile
.FdDict
[Fd
]
317 for RegionObj
in FdObj
.RegionList
:
318 if RegionObj
.RegionType
!= 'FV':
320 for RegionData
in RegionObj
.RegionDataList
:
321 if FvObj
.UiFvName
.upper() == RegionData
.upper():
322 if FvObj
.FvRegionInFD
:
323 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
324 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
326 FvObj
.FvRegionInFD
= RegionObj
.Size
327 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
330 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
332 """Generate GUID cross reference file"""
333 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
335 """Display FV space info."""
336 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
338 except FdfParser
.Warning, X
:
339 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
340 ReturnCode
= FORMAT_INVALID
341 except FatalError
, X
:
342 if Options
.debug
!= None:
344 EdkLogger
.quiet(traceback
.format_exc())
345 ReturnCode
= X
.args
[0]
351 "Tools code failure",
352 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
355 EdkLogger
.quiet(traceback
.format_exc())
356 ReturnCode
= CODE_ERROR
362 def SingleCheckCallback(option
, opt_str
, value
, parser
):
363 if option
not in gParamCheck
:
364 setattr(parser
.values
, option
.dest
, value
)
365 gParamCheck
.append(option
)
367 parser
.error("Option %s only allows one instance in command line!" % option
)
369 def CheckBuildOptionPcd():
370 for Arch
in GenFdsGlobalVariable
.ArchList
:
371 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
372 for i
, pcd
in enumerate(GlobalData
.BuildOptionPcd
):
373 if type(pcd
) is tuple:
375 (pcdname
, pcdvalue
) = pcd
.split('=')
377 EdkLogger
.error('GenFds', OPTION_MISSING
, "No Value specified for the PCD %s." % (pcdname
))
379 (TokenSpaceGuidCName
, TokenCName
) = pcdname
.split('.')
383 TokenSpaceGuidCName
= ''
384 HasTokenSpace
= False
385 TokenSpaceGuidCNameList
= []
389 for package
in PkgList
:
390 for key
in package
.Pcds
:
391 PcdItem
= package
.Pcds
[key
]
393 if (PcdItem
.TokenCName
, PcdItem
.TokenSpaceGuidCName
) == (TokenCName
, TokenSpaceGuidCName
):
394 PcdDatumType
= PcdItem
.DatumType
395 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
398 if PcdItem
.TokenCName
== TokenCName
:
399 if not PcdItem
.TokenSpaceGuidCName
in TokenSpaceGuidCNameList
:
400 if len (TokenSpaceGuidCNameList
) < 1:
401 TokenSpaceGuidCNameList
.append(PcdItem
.TokenSpaceGuidCName
)
402 PcdDatumType
= PcdItem
.DatumType
403 TokenSpaceGuidCName
= PcdItem
.TokenSpaceGuidCName
404 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
409 PCD_VALIDATION_INFO_ERROR
,
410 "The Pcd %s is found under multiple different TokenSpaceGuid: %s and %s." % (TokenCName
, PcdItem
.TokenSpaceGuidCName
, TokenSpaceGuidCNameList
[0])
413 GlobalData
.BuildOptionPcd
[i
] = (TokenSpaceGuidCName
, TokenCName
, NewValue
)
418 # Find location of tools to process data
420 # @param KeyStringList Filter for inputs of section generation
421 # @param CurrentArchList Arch list
422 # @param NameGuid The Guid name
424 def FindExtendTool(KeyStringList
, CurrentArchList
, NameGuid
):
425 ToolDb
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDatabase
426 # if user not specify filter, try to deduce it from global data.
427 if KeyStringList
== None or KeyStringList
== []:
428 Target
= GenFdsGlobalVariable
.TargetName
429 ToolChain
= GenFdsGlobalVariable
.ToolChainTag
430 if ToolChain
not in ToolDb
['TOOL_CHAIN_TAG']:
431 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain
)
432 KeyStringList
= [Target
+ '_' + ToolChain
+ '_' + CurrentArchList
[0]]
433 for Arch
in CurrentArchList
:
434 if Target
+ '_' + ToolChain
+ '_' + Arch
not in KeyStringList
:
435 KeyStringList
.append(Target
+ '_' + ToolChain
+ '_' + Arch
)
437 if GenFdsGlobalVariable
.GuidToolDefinition
:
438 if NameGuid
in GenFdsGlobalVariable
.GuidToolDefinition
.keys():
439 return GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
]
441 ToolDefinition
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDictionary
447 for ToolDef
in ToolDefinition
.items():
448 if NameGuid
== ToolDef
[1]:
449 KeyList
= ToolDef
[0].split('_')
455 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
456 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
457 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
458 ToolPath
= ToolDefinition
.get(ToolPathKey
)
459 ToolOption
= ToolDefinition
.get(ToolOptionKey
)
460 if ToolPathTmp
== None:
461 ToolPathTmp
= ToolPath
463 if ToolPathTmp
!= ToolPath
:
464 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp
, ToolPath
))
467 for Arch
in CurrentArchList
:
468 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
469 # key is (ToolChainFamily, ToolChain, CodeBase)
470 for item
in Platform
.BuildOptions
:
471 if '_PATH' in item
[1] or '_FLAGS' in item
[1] or '_GUID' in item
[1]:
472 if not item
[0] or (item
[0] and GenFdsGlobalVariable
.ToolChainFamily
== item
[0]):
473 if item
[1] not in BuildOption
:
474 BuildOption
[item
[1]] = Platform
.BuildOptions
[item
]
476 ToolList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
]
477 for Index
in range(2, -1, -1):
478 for Key
in dict(BuildOption
):
479 List
= Key
.split('_')
480 if List
[Index
] == '*':
481 for String
in ToolDb
[ToolList
[Index
]]:
482 if String
in [Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]:
484 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
485 if NewKey
not in BuildOption
:
486 BuildOption
[NewKey
] = BuildOption
[Key
]
489 elif List
[Index
] not in ToolDb
[ToolList
[Index
]]:
493 for Op
in BuildOption
:
494 if NameGuid
== BuildOption
[Op
]:
495 KeyList
= Op
.split('_')
496 Key
= KeyList
[0] + '_' + KeyList
[1] +'_' + KeyList
[2]
497 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
498 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
499 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
500 if ToolPathKey
in BuildOption
.keys():
501 ToolPathTmp
= BuildOption
.get(ToolPathKey
)
502 if ToolOptionKey
in BuildOption
.keys():
503 ToolOption
= BuildOption
.get(ToolOptionKey
)
505 GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
] = (ToolPathTmp
, ToolOption
)
506 return ToolPathTmp
, ToolOption
508 ## Parse command line options
510 # Using standard Python module optparse to parse command line option of this tool.
512 # @retval Opt A optparse.Values object containing the parsed options
513 # @retval Args Target of build command
515 def myOptionParser():
516 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
517 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
518 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
519 Parser
.add_option("-a", "--arch", dest
="archList", help="comma separated list containing one or more of: IA32, X64, IPF, ARM, AARCH64 or EBC which should be built, overrides target.txt?s TARGET_ARCH")
520 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
521 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
522 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
523 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
524 action
="callback", callback
=SingleCheckCallback
)
525 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
526 action
="callback", callback
=SingleCheckCallback
)
527 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
528 action
="callback", callback
=SingleCheckCallback
)
529 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
530 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
531 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
532 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
533 action
="callback", callback
=SingleCheckCallback
)
534 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
535 action
="callback", callback
=SingleCheckCallback
)
536 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
537 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
538 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
539 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
540 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
541 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
543 (Options
, args
) = Parser
.parse_args()
546 ## The class implementing the EDK2 flash image generation process
548 # This process includes:
549 # 1. Collect workspace information, includes platform and module information
550 # 2. Call methods of Fd class to generate FD
551 # 3. Call methods of Fv class to generate FV that not belong to FD
555 # FvName, FdName, CapName in FDF, Image file name
557 OnlyGenerateThisFd
= None
558 OnlyGenerateThisFv
= None
559 OnlyGenerateThisCap
= None
563 # @param OutputDir Output directory
564 # @param FdfParser FDF contents parser
565 # @param Workspace The directory of workspace
566 # @param ArchList The Arch list of platform
568 def GenFd (OutputDir
, FdfParser
, WorkSpace
, ArchList
):
569 GenFdsGlobalVariable
.SetDir ('', FdfParser
, WorkSpace
, ArchList
)
571 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
572 if GenFds
.OnlyGenerateThisCap
!= None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
573 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.get(GenFds
.OnlyGenerateThisCap
.upper())
574 if CapsuleObj
!= None:
575 CapsuleObj
.GenCapsule()
578 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
579 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.get(GenFds
.OnlyGenerateThisFd
.upper())
583 elif GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisFv
== None:
584 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
585 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
588 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
589 if GenFds
.OnlyGenerateThisFv
!= None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
590 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.get(GenFds
.OnlyGenerateThisFv
.upper())
592 Buffer
= StringIO
.StringIO()
593 FvObj
.AddToBuffer(Buffer
)
596 elif GenFds
.OnlyGenerateThisFv
== None:
597 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
598 Buffer
= StringIO
.StringIO('')
599 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
600 FvObj
.AddToBuffer(Buffer
)
603 if GenFds
.OnlyGenerateThisFv
== None and GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisCap
== None:
604 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
605 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
606 for CapsuleName
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
607 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[CapsuleName
]
608 CapsuleObj
.GenCapsule()
610 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
611 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
612 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
613 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
614 OptRomObj
.AddToBuffer(None)
616 def GenFfsMakefile(OutputDir
, FdfParser
, WorkSpace
, ArchList
, GlobalData
):
617 GenFdsGlobalVariable
.SetEnv(FdfParser
, WorkSpace
, ArchList
, GlobalData
)
618 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
619 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
620 FdObj
.GenFd(Flag
=True)
622 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
623 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
624 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
626 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
627 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
628 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
629 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
631 return GenFdsGlobalVariable
.FfsCmdDict
635 # @param FvObj Whose block size to get
636 # @retval int Block size value
638 def GetFvBlockSize(FvObj
):
639 DefaultBlockSize
= 0x1
641 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
642 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
644 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
645 for ElementRegion
in ElementFd
.RegionList
:
646 if ElementRegion
.RegionType
== 'FV':
647 for ElementRegionData
in ElementRegion
.RegionDataList
:
648 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
649 if FvObj
.BlockSizeList
!= []:
650 return FvObj
.BlockSizeList
[0][0]
652 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
653 if FvObj
.BlockSizeList
!= []:
654 return FvObj
.BlockSizeList
[0][0]
655 return DefaultBlockSize
657 for ElementRegion
in FdObj
.RegionList
:
658 if ElementRegion
.RegionType
== 'FV':
659 for ElementRegionData
in ElementRegion
.RegionDataList
:
660 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
661 if FvObj
.BlockSizeList
!= []:
662 return FvObj
.BlockSizeList
[0][0]
664 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
665 return DefaultBlockSize
667 ## DisplayFvSpaceInfo()
669 # @param FvObj Whose block size to get
672 def DisplayFvSpaceInfo(FdfParser
):
676 for FvName
in FdfParser
.Profile
.FvDict
:
677 if len(FvName
) > MaxFvNameLength
:
678 MaxFvNameLength
= len(FvName
)
679 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
680 if os
.path
.exists(FvSpaceInfoFileName
):
681 FileLinesList
= linecache
.getlines(FvSpaceInfoFileName
)
688 for Line
in FileLinesList
:
689 NameValue
= Line
.split('=')
690 if len(NameValue
) == 2:
691 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
693 Total
= NameValue
[1].strip()
694 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
696 Used
= NameValue
[1].strip()
697 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
699 Free
= NameValue
[1].strip()
701 if TotalFound
and UsedFound
and FreeFound
:
702 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
704 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
705 for FvSpaceInfo
in FvSpaceInfoList
:
706 Name
= FvSpaceInfo
[0]
707 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
708 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
709 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
710 if UsedSizeValue
== TotalSizeValue
:
713 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
715 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
719 # @param BuildDb Database from build meta data files
720 # @param DscFile modules from dsc file will be preprocessed
723 def PreprocessImage(BuildDb
, DscFile
):
724 PcdDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
727 PcdObj
= PcdDict
[Key
]
728 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
729 PcdValue
= PcdObj
.DefaultValue
735 Int64PcdValue
= long(PcdValue
, 0)
736 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
740 if Int64PcdValue
> 0:
741 TopAddress
= Int64PcdValue
743 ModuleDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
744 for Key
in ModuleDict
:
745 ModuleObj
= BuildDb
.BuildObject
[Key
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
746 print ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
748 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
749 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
750 GuidXRefFile
= StringIO
.StringIO('')
754 for Arch
in ArchList
:
755 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
756 for ModuleFile
in PlatformDataBase
.Modules
:
757 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
758 if Module
in ModuleList
:
761 ModuleList
.append(Module
)
762 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
763 for key
, item
in Module
.Protocols
.items():
765 for key
, item
in Module
.Guids
.items():
767 for key
, item
in Module
.Ppis
.items():
769 for FvName
in FdfParserObj
.Profile
.FvDict
:
770 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
771 if not isinstance(FfsObj
, FfsFileStatement
.FileStatement
):
772 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
773 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
774 if FdfModule
in ModuleList
:
777 ModuleList
.append(FdfModule
)
778 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
779 for key
, item
in FdfModule
.Protocols
.items():
781 for key
, item
in FdfModule
.Guids
.items():
783 for key
, item
in FdfModule
.Ppis
.items():
786 FileStatementGuid
= FfsObj
.NameGuid
787 if FileStatementGuid
in FileGuidList
:
790 FileGuidList
.append(FileStatementGuid
)
792 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
793 FfsPath
= glob
.glob(os
.path
.join(FfsPath
, FileStatementGuid
) + '*')
796 if not os
.path
.exists(FfsPath
[0]):
799 ReFileEnds
= re
.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
800 FileList
= os
.listdir(FfsPath
[0])
801 for File
in FileList
:
802 Match
= ReFileEnds
.search(File
)
804 for Index
in range(1, 8):
805 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
806 MatchDict
[Match
.group(Index
)].append(File
)
807 elif Match
.group(Index
):
808 MatchDict
[Match
.group(Index
)] = [File
]
811 if '.ui' in MatchDict
:
812 for File
in MatchDict
['.ui']:
813 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
817 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
818 Name
= ''.join([chr(c
) for c
in TmpStr
[:-1]])
821 if 'fv.sec.txt' in MatchDict
:
822 FileList
= MatchDict
['fv.sec.txt']
823 elif '.pe32.txt' in MatchDict
:
824 FileList
= MatchDict
['.pe32.txt']
825 elif '.te.txt' in MatchDict
:
826 FileList
= MatchDict
['.te.txt']
827 elif '.pic.txt' in MatchDict
:
828 FileList
= MatchDict
['.pic.txt']
829 elif '.raw.txt' in MatchDict
:
830 FileList
= MatchDict
['.raw.txt']
831 elif '.ffs.txt' in MatchDict
:
832 FileList
= MatchDict
['.ffs.txt']
835 for File
in FileList
:
836 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
837 Name
.append((F
.read().split()[-1]))
841 Name
= ' '.join(Name
) if type(Name
) == type([]) else Name
842 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
844 # Append GUIDs, Protocols, and PPIs to the Xref file
845 GuidXRefFile
.write("\n")
846 for key
, item
in GuidDict
.items():
847 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
849 if GuidXRefFile
.getvalue():
850 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
851 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
852 elif os
.path
.exists(GuidXRefFileName
):
853 os
.remove(GuidXRefFileName
)
856 ##Define GenFd as static function
857 GenFd
= staticmethod(GenFd
)
858 GetFvBlockSize
= staticmethod(GetFvBlockSize
)
859 DisplayFvSpaceInfo
= staticmethod(DisplayFvSpaceInfo
)
860 PreprocessImage
= staticmethod(PreprocessImage
)
861 GenerateGuidXRefFile
= staticmethod(GenerateGuidXRefFile
)
863 if __name__
== '__main__':
865 ## 0-127 is a safe return range, and 1 is a standard default error
866 if r
< 0 or r
> 127: r
= 1