4 # Copyright (c) 2007 - 2018, 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 __future__
import print_function
19 from __future__
import absolute_import
20 from re
import compile
21 from optparse
import OptionParser
24 from struct
import unpack
25 from linecache
import getlines
26 from io
import BytesIO
28 import Common
.LongFilePathOs
as os
29 from Common
.TargetTxtClassObject
import TargetTxtClassObject
30 from Common
.DataType
import *
31 import Common
.GlobalData
as GlobalData
32 from Common
import EdkLogger
33 from Common
.StringUtils
import NormPath
34 from Common
.Misc
import DirCache
, PathClass
, GuidStructureStringToGuidString
35 from Common
.Misc
import SaveFileOnChange
, ClearDuplicatedInf
36 from Common
.BuildVersion
import gBUILD_VERSION
37 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
38 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
39 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
41 from .FdfParser
import FdfParser
, Warning
42 from .GenFdsGlobalVariable
import GenFdsGlobalVariable
43 from .FfsFileStatement
import FileStatement
45 ## Version and Copyright
46 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
47 __version__
= "%prog Version " + versionNumber
48 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
50 ## Tool entrance method
52 # This method mainly dispatch specific methods per the command line options.
53 # If no error found, return zero value so the caller of this tool can know
54 # if it's executed successfully or not.
56 # @retval 0 Tool was successful
57 # @retval 1 Tool failed
61 Options
= myOptionParser()
62 EdkLogger
.Initialize()
63 return GenFdsApi(OptionsToCommandDict(Options
))
65 def GenFdsApi(FdsCommandDict
, WorkSpaceDataBase
=None):
72 if FdsCommandDict
.get("verbose"):
73 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
74 GenFdsGlobalVariable
.VerboseMode
= True
76 if FdsCommandDict
.get("FixedAddress"):
77 GenFdsGlobalVariable
.FixedLoadAddress
= True
79 if FdsCommandDict
.get("quiet"):
80 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
81 if FdsCommandDict
.get("debug"):
82 EdkLogger
.SetLevel(FdsCommandDict
.get("debug") + 1)
83 GenFdsGlobalVariable
.DebugLevel
= FdsCommandDict
.get("debug")
85 EdkLogger
.SetLevel(EdkLogger
.INFO
)
87 if not FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')):
88 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
89 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
90 elif not os
.path
.exists(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE'))):
91 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
92 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
94 Workspace
= os
.path
.normcase(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')))
95 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
96 if 'EDK_SOURCE' in os
.environ
:
97 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
98 if FdsCommandDict
.get("debug"):
99 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
100 if FdsCommandDict
.get("GenfdsMultiThread"):
101 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
102 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
104 # set multiple workspace
105 PackagesPath
= os
.getenv("PACKAGES_PATH")
106 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
108 if FdsCommandDict
.get("fdf_file"):
109 FdfFilename
= FdsCommandDict
.get("fdf_file")[0].Path
110 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
112 if FdfFilename
[0:2] == '..':
113 FdfFilename
= os
.path
.realpath(FdfFilename
)
114 if not os
.path
.isabs(FdfFilename
):
115 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
116 if not os
.path
.exists(FdfFilename
):
117 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
119 GenFdsGlobalVariable
.FdfFile
= FdfFilename
120 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
122 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
124 if FdsCommandDict
.get("build_target"):
125 GenFdsGlobalVariable
.TargetName
= FdsCommandDict
.get("build_target")
127 if FdsCommandDict
.get("toolchain_tag"):
128 GenFdsGlobalVariable
.ToolChainTag
= FdsCommandDict
.get("toolchain_tag")
130 if FdsCommandDict
.get("active_platform"):
131 ActivePlatform
= FdsCommandDict
.get("active_platform")
132 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
134 if ActivePlatform
[0:2] == '..':
135 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
137 if not os
.path
.isabs (ActivePlatform
):
138 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
140 if not os
.path
.exists(ActivePlatform
):
141 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
143 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
145 GlobalData
.BuildOptionPcd
= FdsCommandDict
.get("OptionPcd") if FdsCommandDict
.get("OptionPcd") else {}
146 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
148 if FdsCommandDict
.get("conf_directory"):
149 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
150 ConfDirectoryPath
= os
.path
.normpath(FdsCommandDict
.get("conf_directory"))
151 if ConfDirectoryPath
.startswith('"'):
152 ConfDirectoryPath
= ConfDirectoryPath
[1:]
153 if ConfDirectoryPath
.endswith('"'):
154 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
155 if not os
.path
.isabs(ConfDirectoryPath
):
156 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
157 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
158 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
160 if "CONF_PATH" in os
.environ
:
161 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
163 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
164 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
165 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
166 if not GlobalData
.gConfDirectory
:
167 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
168 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
169 if os
.path
.isfile(BuildConfigurationFile
) == True:
170 TargetTxt
= TargetTxtClassObject()
171 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
172 # if no build target given in command line, get it from target.txt
173 if not GenFdsGlobalVariable
.TargetName
:
174 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
175 if len(BuildTargetList
) != 1:
176 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
177 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
179 # if no tool chain given in command line, get it from target.txt
180 if not GenFdsGlobalVariable
.ToolChainTag
:
181 ToolChainList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
182 if ToolChainList
is None or len(ToolChainList
) == 0:
183 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
184 if len(ToolChainList
) != 1:
185 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
186 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
188 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
190 #Set global flag for build mode
191 GlobalData
.gIgnoreSource
= FdsCommandDict
.get("IgnoreSources")
193 if FdsCommandDict
.get("macro"):
194 for Pair
in FdsCommandDict
.get("macro"):
195 if Pair
.startswith('"'):
197 if Pair
.endswith('"'):
199 List
= Pair
.split('=')
201 if not List
[1].strip():
202 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
203 if List
[0].strip() == "EFI_SOURCE":
204 GlobalData
.gEfiSource
= List
[1].strip()
205 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
207 elif List
[0].strip() == "EDK_SOURCE":
208 GlobalData
.gEdkSource
= List
[1].strip()
209 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
211 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
212 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
214 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
216 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
217 os
.environ
["WORKSPACE"] = Workspace
219 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
220 if "TARGET" not in GlobalData
.gGlobalDefines
:
221 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
222 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
223 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
224 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
225 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
227 """call Workspace build create database"""
228 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
229 if WorkSpaceDataBase
:
230 BuildWorkSpace
= WorkSpaceDataBase
232 BuildWorkSpace
= WorkspaceDatabase(GlobalData
.gDatabasePath
)
233 BuildWorkSpace
.InitDatabase()
236 # Get files real name in workspace dir
238 GlobalData
.gAllFiles
= DirCache(Workspace
)
239 GlobalData
.gWorkspace
= Workspace
241 if FdsCommandDict
.get("build_architecture_list"):
242 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
244 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
246 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
247 if len(TargetArchList
) == 0:
248 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
250 for Arch
in ArchList
:
251 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
253 # assign platform name based on last entry in ArchList
254 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
256 if FdsCommandDict
.get("platform_build_directory"):
257 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
258 if not os
.path
.isabs (OutputDirFromCommandLine
):
259 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
260 for Arch
in ArchList
:
261 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
263 for Arch
in ArchList
:
264 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
266 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
267 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
268 if OutputDir
[0:2] == '..':
269 OutputDir
= os
.path
.realpath(OutputDir
)
271 if OutputDir
[1] != ':':
272 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
274 if not os
.path
.exists(OutputDir
):
275 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
276 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
278 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
279 if WorkSpaceDataBase
:
280 FdfParserObj
= GlobalData
.gFdfParser
282 FdfParserObj
= FdfParser(FdfFilename
)
283 FdfParserObj
.ParseFile()
285 if FdfParserObj
.CycleReferenceCheck():
286 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
288 if FdsCommandDict
.get("fd"):
289 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
290 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
292 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
293 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
295 if FdsCommandDict
.get("fv"):
296 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
297 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
299 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
300 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
302 if FdsCommandDict
.get("cap"):
303 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
304 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
306 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
307 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
309 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
311 GenFdsGlobalVariable
.ArchList
= ArchList
313 # Dsc Build Data will handle Pcd Settings from CommandLine.
315 """Modify images from build output if the feature of loading driver at fixed address is on."""
316 if GenFdsGlobalVariable
.FixedLoadAddress
:
317 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
319 # Record the FV Region info that may specific in the FD
320 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
321 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
322 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
323 for RegionObj
in FdObj
.RegionList
:
324 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
326 for RegionData
in RegionObj
.RegionDataList
:
327 if FvObj
.UiFvName
.upper() == RegionData
.upper():
328 if FvObj
.FvRegionInFD
:
329 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
330 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
332 FvObj
.FvRegionInFD
= RegionObj
.Size
333 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
336 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
338 """Generate GUID cross reference file"""
339 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
341 """Display FV space info."""
342 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
345 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
346 ReturnCode
= FORMAT_INVALID
347 except FatalError
as X
:
348 if FdsCommandDict
.get("debug") is not None:
350 EdkLogger
.quiet(traceback
.format_exc())
351 ReturnCode
= X
.args
[0]
357 "Tools code failure",
358 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
361 EdkLogger
.quiet(traceback
.format_exc())
362 ReturnCode
= CODE_ERROR
367 def OptionsToCommandDict(Options
):
369 FdsCommandDict
["verbose"] = Options
.verbose
370 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
371 FdsCommandDict
["quiet"] = Options
.quiet
372 FdsCommandDict
["debug"] = Options
.debug
373 FdsCommandDict
["Workspace"] = Options
.Workspace
374 FdsCommandDict
["GenfdsMultiThread"] = Options
.GenfdsMultiThread
375 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
376 FdsCommandDict
["build_target"] = Options
.BuildTarget
377 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
378 FdsCommandDict
["active_platform"] = Options
.activePlatform
379 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
380 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
381 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
382 FdsCommandDict
["macro"] = Options
.Macros
383 FdsCommandDict
["build_architecture_list"] = Options
.archList
384 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
385 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
386 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
387 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
388 return FdsCommandDict
392 def SingleCheckCallback(option
, opt_str
, value
, parser
):
393 if option
not in gParamCheck
:
394 setattr(parser
.values
, option
.dest
, value
)
395 gParamCheck
.append(option
)
397 parser
.error("Option %s only allows one instance in command line!" % option
)
399 ## Parse command line options
401 # Using standard Python module optparse to parse command line option of this tool.
403 # @retval Opt A optparse.Values object containing the parsed options
405 def myOptionParser():
406 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
407 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
408 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
409 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")
410 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
411 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
412 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
413 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
414 action
="callback", callback
=SingleCheckCallback
)
415 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
416 action
="callback", callback
=SingleCheckCallback
)
417 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
418 action
="callback", callback
=SingleCheckCallback
)
419 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
420 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
421 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
422 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
423 action
="callback", callback
=SingleCheckCallback
)
424 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
425 action
="callback", callback
=SingleCheckCallback
)
426 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
427 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
428 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
429 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
430 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
431 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
433 Options
, _
= Parser
.parse_args()
436 ## The class implementing the EDK2 flash image generation process
438 # This process includes:
439 # 1. Collect workspace information, includes platform and module information
440 # 2. Call methods of Fd class to generate FD
441 # 3. Call methods of Fv class to generate FV that not belong to FD
443 class GenFds(object):
445 OnlyGenerateThisFd
= None
446 OnlyGenerateThisFv
= None
447 OnlyGenerateThisCap
= None
451 # @param OutputDir Output directory
452 # @param FdfParserObject FDF contents parser
453 # @param Workspace The directory of workspace
454 # @param ArchList The Arch list of platform
457 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
458 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
460 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
461 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
462 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
463 if CapsuleObj
is not None:
464 CapsuleObj
.GenCapsule()
467 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
468 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
469 if FdObj
is not None:
472 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
473 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
476 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
477 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
478 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
479 if FvObj
is not None:
481 FvObj
.AddToBuffer(Buffer
)
484 elif GenFds
.OnlyGenerateThisFv
is None:
485 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
487 FvObj
.AddToBuffer(Buffer
)
490 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
491 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
492 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
493 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
494 CapsuleObj
.GenCapsule()
496 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
497 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
498 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
499 OptRomObj
.AddToBuffer(None)
502 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
503 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
504 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
505 FdObj
.GenFd(Flag
=True)
507 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
508 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
510 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
511 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
512 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
514 return GenFdsGlobalVariable
.FfsCmdDict
518 # @param FvObj Whose block size to get
519 # @retval int Block size value
522 def GetFvBlockSize(FvObj
):
523 DefaultBlockSize
= 0x1
525 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
526 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
528 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
529 for ElementRegion
in ElementFd
.RegionList
:
530 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
531 for ElementRegionData
in ElementRegion
.RegionDataList
:
532 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
533 if FvObj
.BlockSizeList
!= []:
534 return FvObj
.BlockSizeList
[0][0]
536 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
537 if FvObj
.BlockSizeList
!= []:
538 return FvObj
.BlockSizeList
[0][0]
539 return DefaultBlockSize
541 for ElementRegion
in FdObj
.RegionList
:
542 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
543 for ElementRegionData
in ElementRegion
.RegionDataList
:
544 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
545 if FvObj
.BlockSizeList
!= []:
546 return FvObj
.BlockSizeList
[0][0]
548 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
549 return DefaultBlockSize
551 ## DisplayFvSpaceInfo()
553 # @param FvObj Whose block size to get
557 def DisplayFvSpaceInfo(FdfParserObject
):
561 for FvName
in FdfParserObject
.Profile
.FvDict
:
562 if len(FvName
) > MaxFvNameLength
:
563 MaxFvNameLength
= len(FvName
)
564 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
565 if os
.path
.exists(FvSpaceInfoFileName
):
566 FileLinesList
= getlines(FvSpaceInfoFileName
)
573 for Line
in FileLinesList
:
574 NameValue
= Line
.split('=')
575 if len(NameValue
) == 2:
576 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
578 Total
= NameValue
[1].strip()
579 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
581 Used
= NameValue
[1].strip()
582 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
584 Free
= NameValue
[1].strip()
586 if TotalFound
and UsedFound
and FreeFound
:
587 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
589 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
590 for FvSpaceInfo
in FvSpaceInfoList
:
591 Name
= FvSpaceInfo
[0]
592 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
593 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
594 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
595 if UsedSizeValue
== TotalSizeValue
:
598 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
600 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
604 # @param BuildDb Database from build meta data files
605 # @param DscFile modules from dsc file will be preprocessed
609 def PreprocessImage(BuildDb
, DscFile
):
610 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
613 PcdObj
= PcdDict
[Key
]
614 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
615 PcdValue
= PcdObj
.DefaultValue
621 Int64PcdValue
= long(PcdValue
, 0)
622 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
626 if Int64PcdValue
> 0:
627 TopAddress
= Int64PcdValue
629 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
630 for Key
in ModuleDict
:
631 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
632 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
635 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
636 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
637 GuidXRefFile
= BytesIO('')
642 for Arch
in ArchList
:
643 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
644 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
646 PkgGuidDict
.update(P
.Guids
)
647 for Name
, Guid
in PlatformDataBase
.Pcds
:
648 Pcd
= PlatformDataBase
.Pcds
[Name
, Guid
]
649 if Pcd
.Type
in [TAB_PCDS_DYNAMIC_HII
, TAB_PCDS_DYNAMIC_EX_HII
]:
650 for SkuId
in Pcd
.SkuInfoList
:
651 Sku
= Pcd
.SkuInfoList
[SkuId
]
652 if Sku
.VariableGuid
and Sku
.VariableGuid
in PkgGuidDict
.keys():
653 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
654 for ModuleFile
in PlatformDataBase
.Modules
:
655 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
656 if Module
in ModuleList
:
659 ModuleList
.append(Module
)
660 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
661 GuidXRefFile
.write("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
663 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
664 GuidDict
.update(Module
.Protocols
)
665 GuidDict
.update(Module
.Guids
)
666 GuidDict
.update(Module
.Ppis
)
667 for FvName
in FdfParserObj
.Profile
.FvDict
:
668 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
669 if not isinstance(FfsObj
, FileStatement
):
670 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
671 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
672 if FdfModule
in ModuleList
:
675 ModuleList
.append(FdfModule
)
676 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
677 GuidDict
.update(FdfModule
.Protocols
)
678 GuidDict
.update(FdfModule
.Guids
)
679 GuidDict
.update(FdfModule
.Ppis
)
681 FileStatementGuid
= FfsObj
.NameGuid
682 if FileStatementGuid
in FileGuidList
:
685 FileGuidList
.append(FileStatementGuid
)
687 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
688 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
691 if not os
.path
.exists(FfsPath
[0]):
694 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
695 FileList
= os
.listdir(FfsPath
[0])
696 for File
in FileList
:
697 Match
= ReFileEnds
.search(File
)
699 for Index
in range(1, 8):
700 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
701 MatchDict
[Match
.group(Index
)].append(File
)
702 elif Match
.group(Index
):
703 MatchDict
[Match
.group(Index
)] = [File
]
706 if '.ui' in MatchDict
:
707 for File
in MatchDict
['.ui']:
708 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
712 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
713 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
716 if 'fv.sec.txt' in MatchDict
:
717 FileList
= MatchDict
['fv.sec.txt']
718 elif '.pe32.txt' in MatchDict
:
719 FileList
= MatchDict
['.pe32.txt']
720 elif '.te.txt' in MatchDict
:
721 FileList
= MatchDict
['.te.txt']
722 elif '.pic.txt' in MatchDict
:
723 FileList
= MatchDict
['.pic.txt']
724 elif '.raw.txt' in MatchDict
:
725 FileList
= MatchDict
['.raw.txt']
726 elif '.ffs.txt' in MatchDict
:
727 FileList
= MatchDict
['.ffs.txt']
730 for File
in FileList
:
731 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
732 Name
.append((F
.read().split()[-1]))
736 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
737 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
739 # Append GUIDs, Protocols, and PPIs to the Xref file
740 GuidXRefFile
.write("\n")
741 for key
, item
in GuidDict
.items():
742 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
744 if GuidXRefFile
.getvalue():
745 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
746 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
747 elif os
.path
.exists(GuidXRefFileName
):
748 os
.remove(GuidXRefFileName
)
752 if __name__
== '__main__':
754 ## 0-127 is a safe return range, and 1 is a standard default error