4 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
12 from __future__
import print_function
13 from __future__
import absolute_import
14 from re
import compile
15 from optparse
import OptionParser
18 from struct
import unpack
19 from linecache
import getlines
20 from io
import BytesIO
22 import Common
.LongFilePathOs
as os
23 from Common
.TargetTxtClassObject
import TargetTxt
24 from Common
.DataType
import *
25 import Common
.GlobalData
as GlobalData
26 from Common
import EdkLogger
27 from Common
.StringUtils
import NormPath
28 from Common
.Misc
import DirCache
, PathClass
, GuidStructureStringToGuidString
29 from Common
.Misc
import SaveFileOnChange
, ClearDuplicatedInf
30 from Common
.BuildVersion
import gBUILD_VERSION
31 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
32 from Common
.BuildToolError
import FatalError
, GENFDS_ERROR
, CODE_ERROR
, FORMAT_INVALID
, RESOURCE_NOT_AVAILABLE
, FILE_NOT_FOUND
, OPTION_MISSING
, FORMAT_NOT_SUPPORTED
, OPTION_VALUE_INVALID
, PARAMETER_INVALID
33 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
35 from .FdfParser
import FdfParser
, Warning
36 from .GenFdsGlobalVariable
import GenFdsGlobalVariable
37 from .FfsFileStatement
import FileStatement
38 import Common
.DataType
as DataType
39 from struct
import Struct
41 ## Version and Copyright
42 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
43 __version__
= "%prog Version " + versionNumber
44 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
46 ## Tool entrance method
48 # This method mainly dispatch specific methods per the command line options.
49 # If no error found, return zero value so the caller of this tool can know
50 # if it's executed successfully or not.
52 # @retval 0 Tool was successful
53 # @retval 1 Tool failed
57 Options
= myOptionParser()
58 EdkLogger
.Initialize()
59 return GenFdsApi(OptionsToCommandDict(Options
))
61 def resetFdsGlobalVariable():
62 GenFdsGlobalVariable
.FvDir
= ''
63 GenFdsGlobalVariable
.OutputDirDict
= {}
64 GenFdsGlobalVariable
.BinDir
= ''
65 # will be FvDir + os.sep + 'Ffs'
66 GenFdsGlobalVariable
.FfsDir
= ''
67 GenFdsGlobalVariable
.FdfParser
= None
68 GenFdsGlobalVariable
.LibDir
= ''
69 GenFdsGlobalVariable
.WorkSpace
= None
70 GenFdsGlobalVariable
.WorkSpaceDir
= ''
71 GenFdsGlobalVariable
.ConfDir
= ''
72 GenFdsGlobalVariable
.OutputDirFromDscDict
= {}
73 GenFdsGlobalVariable
.TargetName
= ''
74 GenFdsGlobalVariable
.ToolChainTag
= ''
75 GenFdsGlobalVariable
.RuleDict
= {}
76 GenFdsGlobalVariable
.ArchList
= None
77 GenFdsGlobalVariable
.ActivePlatform
= None
78 GenFdsGlobalVariable
.FvAddressFileName
= ''
79 GenFdsGlobalVariable
.VerboseMode
= False
80 GenFdsGlobalVariable
.DebugLevel
= -1
81 GenFdsGlobalVariable
.SharpCounter
= 0
82 GenFdsGlobalVariable
.SharpNumberPerLine
= 40
83 GenFdsGlobalVariable
.FdfFile
= ''
84 GenFdsGlobalVariable
.FdfFileTimeStamp
= 0
85 GenFdsGlobalVariable
.FixedLoadAddress
= False
86 GenFdsGlobalVariable
.PlatformName
= ''
88 GenFdsGlobalVariable
.BuildRuleFamily
= DataType
.TAB_COMPILER_MSFT
89 GenFdsGlobalVariable
.ToolChainFamily
= DataType
.TAB_COMPILER_MSFT
90 GenFdsGlobalVariable
.__BuildRuleDatabase
= None
91 GenFdsGlobalVariable
.GuidToolDefinition
= {}
92 GenFdsGlobalVariable
.FfsCmdDict
= {}
93 GenFdsGlobalVariable
.SecCmdList
= []
94 GenFdsGlobalVariable
.CopyList
= []
95 GenFdsGlobalVariable
.ModuleFile
= ''
96 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
98 GenFdsGlobalVariable
.LargeFileInFvFlags
= []
99 GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
= '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'
100 GenFdsGlobalVariable
.LARGE_FILE_SIZE
= 0x1000000
102 GenFdsGlobalVariable
.SectionHeader
= Struct("3B 1B")
104 # FvName, FdName, CapName in FDF, Image file name
105 GenFdsGlobalVariable
.ImageBinDict
= {}
107 def GenFdsApi(FdsCommandDict
, WorkSpaceDataBase
=None):
112 resetFdsGlobalVariable()
115 if FdsCommandDict
.get("verbose"):
116 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
117 GenFdsGlobalVariable
.VerboseMode
= True
119 if FdsCommandDict
.get("FixedAddress"):
120 GenFdsGlobalVariable
.FixedLoadAddress
= True
122 if FdsCommandDict
.get("quiet"):
123 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
124 if FdsCommandDict
.get("debug"):
125 EdkLogger
.SetLevel(FdsCommandDict
.get("debug") + 1)
126 GenFdsGlobalVariable
.DebugLevel
= FdsCommandDict
.get("debug")
128 EdkLogger
.SetLevel(EdkLogger
.INFO
)
130 if not FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')):
131 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
132 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
133 elif not os
.path
.exists(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE'))):
134 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
135 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
137 Workspace
= os
.path
.normcase(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')))
138 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
139 if FdsCommandDict
.get("debug"):
140 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
141 if FdsCommandDict
.get("GenfdsMultiThread"):
142 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
144 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= False
145 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
147 # set multiple workspace
148 PackagesPath
= os
.getenv("PACKAGES_PATH")
149 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
151 if FdsCommandDict
.get("fdf_file"):
152 FdfFilename
= FdsCommandDict
.get("fdf_file")[0].Path
153 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
155 if FdfFilename
[0:2] == '..':
156 FdfFilename
= os
.path
.realpath(FdfFilename
)
157 if not os
.path
.isabs(FdfFilename
):
158 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
159 if not os
.path
.exists(FdfFilename
):
160 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
162 GenFdsGlobalVariable
.FdfFile
= FdfFilename
163 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
165 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
167 if FdsCommandDict
.get("build_target"):
168 GenFdsGlobalVariable
.TargetName
= FdsCommandDict
.get("build_target")
170 if FdsCommandDict
.get("toolchain_tag"):
171 GenFdsGlobalVariable
.ToolChainTag
= FdsCommandDict
.get("toolchain_tag")
173 if FdsCommandDict
.get("active_platform"):
174 ActivePlatform
= FdsCommandDict
.get("active_platform")
175 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
177 if ActivePlatform
[0:2] == '..':
178 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
180 if not os
.path
.isabs (ActivePlatform
):
181 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
183 if not os
.path
.exists(ActivePlatform
):
184 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
186 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
188 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
190 if FdsCommandDict
.get("conf_directory"):
191 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
192 ConfDirectoryPath
= os
.path
.normpath(FdsCommandDict
.get("conf_directory"))
193 if ConfDirectoryPath
.startswith('"'):
194 ConfDirectoryPath
= ConfDirectoryPath
[1:]
195 if ConfDirectoryPath
.endswith('"'):
196 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
197 if not os
.path
.isabs(ConfDirectoryPath
):
198 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
199 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
200 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
202 if "CONF_PATH" in os
.environ
:
203 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
205 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
206 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
207 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
208 if not GlobalData
.gConfDirectory
:
209 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
210 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
211 if os
.path
.isfile(BuildConfigurationFile
) == True:
212 # if no build target given in command line, get it from target.txt
213 if not GenFdsGlobalVariable
.TargetName
:
214 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
215 if len(BuildTargetList
) != 1:
216 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
217 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
219 # if no tool chain given in command line, get it from target.txt
220 if not GenFdsGlobalVariable
.ToolChainTag
:
221 ToolChainList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
222 if ToolChainList
is None or len(ToolChainList
) == 0:
223 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
224 if len(ToolChainList
) != 1:
225 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
226 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
228 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
230 #Set global flag for build mode
231 GlobalData
.gIgnoreSource
= FdsCommandDict
.get("IgnoreSources")
233 if FdsCommandDict
.get("macro"):
234 for Pair
in FdsCommandDict
.get("macro"):
235 if Pair
.startswith('"'):
237 if Pair
.endswith('"'):
239 List
= Pair
.split('=')
241 if not List
[1].strip():
242 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
243 if List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
244 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
246 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
248 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
249 os
.environ
["WORKSPACE"] = Workspace
251 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
252 if "TARGET" not in GlobalData
.gGlobalDefines
:
253 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
254 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
255 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
256 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
257 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
259 """call Workspace build create database"""
260 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
262 if WorkSpaceDataBase
:
263 BuildWorkSpace
= WorkSpaceDataBase
265 BuildWorkSpace
= WorkspaceDatabase()
267 # Get files real name in workspace dir
269 GlobalData
.gAllFiles
= DirCache(Workspace
)
270 GlobalData
.gWorkspace
= Workspace
272 if FdsCommandDict
.get("build_architecture_list"):
273 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
275 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
277 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
278 if len(TargetArchList
) == 0:
279 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
281 for Arch
in ArchList
:
282 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
284 # assign platform name based on last entry in ArchList
285 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
287 if FdsCommandDict
.get("platform_build_directory"):
288 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
289 if not os
.path
.isabs (OutputDirFromCommandLine
):
290 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
291 for Arch
in ArchList
:
292 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
294 for Arch
in ArchList
:
295 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
297 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
298 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
299 if OutputDir
[0:2] == '..':
300 OutputDir
= os
.path
.realpath(OutputDir
)
302 if OutputDir
[1] != ':':
303 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
305 if not os
.path
.exists(OutputDir
):
306 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
307 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
309 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
310 if WorkSpaceDataBase
:
311 FdfParserObj
= GlobalData
.gFdfParser
313 FdfParserObj
= FdfParser(FdfFilename
)
314 FdfParserObj
.ParseFile()
316 if FdfParserObj
.CycleReferenceCheck():
317 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
319 if FdsCommandDict
.get("fd"):
320 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
321 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
323 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
324 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
326 if FdsCommandDict
.get("fv"):
327 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
328 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
330 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
331 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
333 if FdsCommandDict
.get("cap"):
334 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
335 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
337 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
338 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
340 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
342 GenFdsGlobalVariable
.ArchList
= ArchList
344 # Dsc Build Data will handle Pcd Settings from CommandLine.
346 """Modify images from build output if the feature of loading driver at fixed address is on."""
347 if GenFdsGlobalVariable
.FixedLoadAddress
:
348 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
350 # Record the FV Region info that may specific in the FD
351 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
352 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
353 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
354 for RegionObj
in FdObj
.RegionList
:
355 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
357 for RegionData
in RegionObj
.RegionDataList
:
358 if FvObj
.UiFvName
.upper() == RegionData
.upper():
359 if not FvObj
.BaseAddress
:
360 FvObj
.BaseAddress
= '0x%x' % (int(FdObj
.BaseAddress
, 0) + RegionObj
.Offset
)
361 if FvObj
.FvRegionInFD
:
362 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
363 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
365 FvObj
.FvRegionInFD
= RegionObj
.Size
366 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
369 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
371 """Generate GUID cross reference file"""
372 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
374 """Display FV space info."""
375 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
378 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
379 ReturnCode
= FORMAT_INVALID
380 except FatalError
as X
:
381 if FdsCommandDict
.get("debug") is not None:
383 EdkLogger
.quiet(traceback
.format_exc())
384 ReturnCode
= X
.args
[0]
390 "Tools code failure",
391 ExtraData
="Please send email to %s for help, attaching following call stack trace!\n" % MSG_EDKII_MAIL_ADDR
,
394 EdkLogger
.quiet(traceback
.format_exc())
395 ReturnCode
= CODE_ERROR
400 def OptionsToCommandDict(Options
):
402 FdsCommandDict
["verbose"] = Options
.verbose
403 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
404 FdsCommandDict
["quiet"] = Options
.quiet
405 FdsCommandDict
["debug"] = Options
.debug
406 FdsCommandDict
["Workspace"] = Options
.Workspace
407 FdsCommandDict
["GenfdsMultiThread"] = not Options
.NoGenfdsMultiThread
408 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
409 FdsCommandDict
["build_target"] = Options
.BuildTarget
410 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
411 FdsCommandDict
["active_platform"] = Options
.activePlatform
412 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
413 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
414 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
415 FdsCommandDict
["macro"] = Options
.Macros
416 FdsCommandDict
["build_architecture_list"] = Options
.archList
417 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
418 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
419 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
420 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
421 return FdsCommandDict
425 def SingleCheckCallback(option
, opt_str
, value
, parser
):
426 if option
not in gParamCheck
:
427 setattr(parser
.values
, option
.dest
, value
)
428 gParamCheck
.append(option
)
430 parser
.error("Option %s only allows one instance in command line!" % option
)
432 ## Parse command line options
434 # Using standard Python module optparse to parse command line option of this tool.
436 # @retval Opt A optparse.Values object containing the parsed options
438 def myOptionParser():
439 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
440 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
441 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
442 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")
443 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
444 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
445 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
446 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
447 action
="callback", callback
=SingleCheckCallback
)
448 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
449 action
="callback", callback
=SingleCheckCallback
)
450 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
451 action
="callback", callback
=SingleCheckCallback
)
452 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
453 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
454 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
455 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
456 action
="callback", callback
=SingleCheckCallback
)
457 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
458 action
="callback", callback
=SingleCheckCallback
)
459 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
460 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
461 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
462 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
463 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
464 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=True, help="Enable GenFds multi thread to generate ffs file.")
465 Parser
.add_option("--no-genfds-multi-thread", action
="store_true", dest
="NoGenfdsMultiThread", default
=False, help="Disable GenFds multi thread to generate ffs file.")
467 Options
, _
= Parser
.parse_args()
470 ## The class implementing the EDK2 flash image generation process
472 # This process includes:
473 # 1. Collect workspace information, includes platform and module information
474 # 2. Call methods of Fd class to generate FD
475 # 3. Call methods of Fv class to generate FV that not belong to FD
477 class GenFds(object):
479 OnlyGenerateThisFd
= None
480 OnlyGenerateThisFv
= None
481 OnlyGenerateThisCap
= None
485 # @param OutputDir Output directory
486 # @param FdfParserObject FDF contents parser
487 # @param Workspace The directory of workspace
488 # @param ArchList The Arch list of platform
491 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
492 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
494 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
495 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
496 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
497 if CapsuleObj
is not None:
498 CapsuleObj
.GenCapsule()
501 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
502 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
503 if FdObj
is not None:
506 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
507 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
510 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
511 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
512 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
513 if FvObj
is not None:
515 FvObj
.AddToBuffer(Buffer
)
518 elif GenFds
.OnlyGenerateThisFv
is None:
519 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
521 FvObj
.AddToBuffer(Buffer
)
524 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
525 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
526 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
527 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
528 CapsuleObj
.GenCapsule()
530 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
531 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
532 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
533 OptRomObj
.AddToBuffer(None)
536 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
537 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
538 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
539 FdObj
.GenFd(Flag
=True)
541 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
542 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
544 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
545 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
546 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
548 return GenFdsGlobalVariable
.FfsCmdDict
552 # @param FvObj Whose block size to get
553 # @retval int Block size value
556 def GetFvBlockSize(FvObj
):
557 DefaultBlockSize
= 0x1
559 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
560 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
562 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
563 for ElementRegion
in ElementFd
.RegionList
:
564 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
565 for ElementRegionData
in ElementRegion
.RegionDataList
:
566 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
567 if FvObj
.BlockSizeList
!= []:
568 return FvObj
.BlockSizeList
[0][0]
570 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
571 if FvObj
.BlockSizeList
!= []:
572 return FvObj
.BlockSizeList
[0][0]
573 return DefaultBlockSize
575 for ElementRegion
in FdObj
.RegionList
:
576 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
577 for ElementRegionData
in ElementRegion
.RegionDataList
:
578 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
579 if FvObj
.BlockSizeList
!= []:
580 return FvObj
.BlockSizeList
[0][0]
582 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
583 return DefaultBlockSize
585 ## DisplayFvSpaceInfo()
587 # @param FvObj Whose block size to get
591 def DisplayFvSpaceInfo(FdfParserObject
):
595 for FvName
in FdfParserObject
.Profile
.FvDict
:
596 if len(FvName
) > MaxFvNameLength
:
597 MaxFvNameLength
= len(FvName
)
598 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
599 if os
.path
.exists(FvSpaceInfoFileName
):
600 FileLinesList
= getlines(FvSpaceInfoFileName
)
607 for Line
in FileLinesList
:
608 NameValue
= Line
.split('=')
609 if len(NameValue
) == 2:
610 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
612 Total
= NameValue
[1].strip()
613 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
615 Used
= NameValue
[1].strip()
616 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
618 Free
= NameValue
[1].strip()
620 if TotalFound
and UsedFound
and FreeFound
:
621 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
623 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
624 for FvSpaceInfo
in FvSpaceInfoList
:
625 Name
= FvSpaceInfo
[0]
626 TotalSizeValue
= int(FvSpaceInfo
[1], 0)
627 UsedSizeValue
= int(FvSpaceInfo
[2], 0)
628 FreeSizeValue
= int(FvSpaceInfo
[3], 0)
629 if UsedSizeValue
== TotalSizeValue
:
632 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
634 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
638 # @param BuildDb Database from build meta data files
639 # @param DscFile modules from dsc file will be preprocessed
643 def PreprocessImage(BuildDb
, DscFile
):
644 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
647 PcdObj
= PcdDict
[Key
]
648 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
649 PcdValue
= PcdObj
.DefaultValue
655 Int64PcdValue
= int(PcdValue
, 0)
656 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
660 if Int64PcdValue
> 0:
661 TopAddress
= Int64PcdValue
663 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
664 for Key
in ModuleDict
:
665 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
666 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
669 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
670 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
676 VariableGuidSet
= set()
677 for Arch
in ArchList
:
678 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
679 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
681 PkgGuidDict
.update(P
.Guids
)
682 for Name
, Guid
in PlatformDataBase
.Pcds
:
683 Pcd
= PlatformDataBase
.Pcds
[Name
, Guid
]
684 if Pcd
.Type
in [TAB_PCDS_DYNAMIC_HII
, TAB_PCDS_DYNAMIC_EX_HII
]:
685 for SkuId
in Pcd
.SkuInfoList
:
686 Sku
= Pcd
.SkuInfoList
[SkuId
]
687 if Sku
.VariableGuid
in VariableGuidSet
:continue
688 VariableGuidSet
.add(Sku
.VariableGuid
)
689 if Sku
.VariableGuid
and Sku
.VariableGuid
in PkgGuidDict
.keys():
690 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
691 for ModuleFile
in PlatformDataBase
.Modules
:
692 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
693 if Module
in ModuleList
:
696 ModuleList
.append(Module
)
697 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
698 GuidXRefFile
.append("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
700 GuidXRefFile
.append("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
701 GuidDict
.update(Module
.Protocols
)
702 GuidDict
.update(Module
.Guids
)
703 GuidDict
.update(Module
.Ppis
)
704 for FvName
in FdfParserObj
.Profile
.FvDict
:
705 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
706 if not isinstance(FfsObj
, FileStatement
):
707 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
708 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
709 if FdfModule
in ModuleList
:
712 ModuleList
.append(FdfModule
)
713 GuidXRefFile
.append("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
714 GuidDict
.update(FdfModule
.Protocols
)
715 GuidDict
.update(FdfModule
.Guids
)
716 GuidDict
.update(FdfModule
.Ppis
)
718 FileStatementGuid
= FfsObj
.NameGuid
719 if FileStatementGuid
in FileGuidList
:
722 FileGuidList
.append(FileStatementGuid
)
724 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
725 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
728 if not os
.path
.exists(FfsPath
[0]):
731 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
732 FileList
= os
.listdir(FfsPath
[0])
733 for File
in FileList
:
734 Match
= ReFileEnds
.search(File
)
736 for Index
in range(1, 8):
737 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
738 MatchDict
[Match
.group(Index
)].append(File
)
739 elif Match
.group(Index
):
740 MatchDict
[Match
.group(Index
)] = [File
]
743 if '.ui' in MatchDict
:
744 for File
in MatchDict
['.ui']:
745 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
749 TmpStr
= unpack('%dh' % ((length
- 4) // 2), F
.read())
750 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
753 if 'fv.sec.txt' in MatchDict
:
754 FileList
= MatchDict
['fv.sec.txt']
755 elif '.pe32.txt' in MatchDict
:
756 FileList
= MatchDict
['.pe32.txt']
757 elif '.te.txt' in MatchDict
:
758 FileList
= MatchDict
['.te.txt']
759 elif '.pic.txt' in MatchDict
:
760 FileList
= MatchDict
['.pic.txt']
761 elif '.raw.txt' in MatchDict
:
762 FileList
= MatchDict
['.raw.txt']
763 elif '.ffs.txt' in MatchDict
:
764 FileList
= MatchDict
['.ffs.txt']
767 for File
in FileList
:
768 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
769 Name
.append((F
.read().split()[-1]))
773 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
774 GuidXRefFile
.append("%s %s\n" %(FileStatementGuid
, Name
))
776 # Append GUIDs, Protocols, and PPIs to the Xref file
777 GuidXRefFile
.append("\n")
778 for key
, item
in GuidDict
.items():
779 GuidXRefFile
.append("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
782 GuidXRefFile
= ''.join(GuidXRefFile
)
783 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
, False)
784 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
785 elif os
.path
.exists(GuidXRefFileName
):
786 os
.remove(GuidXRefFileName
)
789 if __name__
== '__main__':
791 ## 0-127 is a safe return range, and 1 is a standard default error