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
))
230 if WorkSpaceDataBase
:
231 BuildWorkSpace
= WorkSpaceDataBase
233 BuildWorkSpace
= WorkspaceDatabase()
235 # Get files real name in workspace dir
237 GlobalData
.gAllFiles
= DirCache(Workspace
)
238 GlobalData
.gWorkspace
= Workspace
240 if FdsCommandDict
.get("build_architecture_list"):
241 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
243 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
245 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
246 if len(TargetArchList
) == 0:
247 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
249 for Arch
in ArchList
:
250 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
252 # assign platform name based on last entry in ArchList
253 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
255 if FdsCommandDict
.get("platform_build_directory"):
256 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
257 if not os
.path
.isabs (OutputDirFromCommandLine
):
258 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
259 for Arch
in ArchList
:
260 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
262 for Arch
in ArchList
:
263 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
265 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
266 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
267 if OutputDir
[0:2] == '..':
268 OutputDir
= os
.path
.realpath(OutputDir
)
270 if OutputDir
[1] != ':':
271 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
273 if not os
.path
.exists(OutputDir
):
274 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
275 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
277 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
278 if WorkSpaceDataBase
:
279 FdfParserObj
= GlobalData
.gFdfParser
281 FdfParserObj
= FdfParser(FdfFilename
)
282 FdfParserObj
.ParseFile()
284 if FdfParserObj
.CycleReferenceCheck():
285 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
287 if FdsCommandDict
.get("fd"):
288 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
289 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
291 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
292 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
294 if FdsCommandDict
.get("fv"):
295 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
296 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
298 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
299 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
301 if FdsCommandDict
.get("cap"):
302 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
303 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
305 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
306 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
308 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
310 GenFdsGlobalVariable
.ArchList
= ArchList
312 # Dsc Build Data will handle Pcd Settings from CommandLine.
314 """Modify images from build output if the feature of loading driver at fixed address is on."""
315 if GenFdsGlobalVariable
.FixedLoadAddress
:
316 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
318 # Record the FV Region info that may specific in the FD
319 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
320 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
321 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
322 for RegionObj
in FdObj
.RegionList
:
323 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
325 for RegionData
in RegionObj
.RegionDataList
:
326 if FvObj
.UiFvName
.upper() == RegionData
.upper():
327 if FvObj
.FvRegionInFD
:
328 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
329 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
331 FvObj
.FvRegionInFD
= RegionObj
.Size
332 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
335 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
337 """Generate GUID cross reference file"""
338 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
340 """Display FV space info."""
341 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
344 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
345 ReturnCode
= FORMAT_INVALID
346 except FatalError
as X
:
347 if FdsCommandDict
.get("debug") is not None:
349 EdkLogger
.quiet(traceback
.format_exc())
350 ReturnCode
= X
.args
[0]
356 "Tools code failure",
357 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
360 EdkLogger
.quiet(traceback
.format_exc())
361 ReturnCode
= CODE_ERROR
366 def OptionsToCommandDict(Options
):
368 FdsCommandDict
["verbose"] = Options
.verbose
369 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
370 FdsCommandDict
["quiet"] = Options
.quiet
371 FdsCommandDict
["debug"] = Options
.debug
372 FdsCommandDict
["Workspace"] = Options
.Workspace
373 FdsCommandDict
["GenfdsMultiThread"] = Options
.GenfdsMultiThread
374 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
375 FdsCommandDict
["build_target"] = Options
.BuildTarget
376 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
377 FdsCommandDict
["active_platform"] = Options
.activePlatform
378 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
379 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
380 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
381 FdsCommandDict
["macro"] = Options
.Macros
382 FdsCommandDict
["build_architecture_list"] = Options
.archList
383 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
384 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
385 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
386 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
387 return FdsCommandDict
391 def SingleCheckCallback(option
, opt_str
, value
, parser
):
392 if option
not in gParamCheck
:
393 setattr(parser
.values
, option
.dest
, value
)
394 gParamCheck
.append(option
)
396 parser
.error("Option %s only allows one instance in command line!" % option
)
398 ## Parse command line options
400 # Using standard Python module optparse to parse command line option of this tool.
402 # @retval Opt A optparse.Values object containing the parsed options
404 def myOptionParser():
405 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
406 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
407 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
408 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")
409 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
410 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
411 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
412 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
413 action
="callback", callback
=SingleCheckCallback
)
414 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
415 action
="callback", callback
=SingleCheckCallback
)
416 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
417 action
="callback", callback
=SingleCheckCallback
)
418 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
419 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
420 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
421 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
422 action
="callback", callback
=SingleCheckCallback
)
423 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
424 action
="callback", callback
=SingleCheckCallback
)
425 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
426 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
427 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
428 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
429 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
430 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
432 Options
, _
= Parser
.parse_args()
435 ## The class implementing the EDK2 flash image generation process
437 # This process includes:
438 # 1. Collect workspace information, includes platform and module information
439 # 2. Call methods of Fd class to generate FD
440 # 3. Call methods of Fv class to generate FV that not belong to FD
442 class GenFds(object):
444 OnlyGenerateThisFd
= None
445 OnlyGenerateThisFv
= None
446 OnlyGenerateThisCap
= None
450 # @param OutputDir Output directory
451 # @param FdfParserObject FDF contents parser
452 # @param Workspace The directory of workspace
453 # @param ArchList The Arch list of platform
456 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
457 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
459 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
460 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
461 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
462 if CapsuleObj
is not None:
463 CapsuleObj
.GenCapsule()
466 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
467 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
468 if FdObj
is not None:
471 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
472 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
475 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
476 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
477 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
478 if FvObj
is not None:
480 FvObj
.AddToBuffer(Buffer
)
483 elif GenFds
.OnlyGenerateThisFv
is None:
484 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
486 FvObj
.AddToBuffer(Buffer
)
489 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
490 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
491 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
492 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
493 CapsuleObj
.GenCapsule()
495 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
496 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
497 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
498 OptRomObj
.AddToBuffer(None)
501 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
502 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
503 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
504 FdObj
.GenFd(Flag
=True)
506 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
507 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
509 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
510 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
511 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
513 return GenFdsGlobalVariable
.FfsCmdDict
517 # @param FvObj Whose block size to get
518 # @retval int Block size value
521 def GetFvBlockSize(FvObj
):
522 DefaultBlockSize
= 0x1
524 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
525 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
527 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
528 for ElementRegion
in ElementFd
.RegionList
:
529 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
530 for ElementRegionData
in ElementRegion
.RegionDataList
:
531 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
532 if FvObj
.BlockSizeList
!= []:
533 return FvObj
.BlockSizeList
[0][0]
535 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
536 if FvObj
.BlockSizeList
!= []:
537 return FvObj
.BlockSizeList
[0][0]
538 return DefaultBlockSize
540 for ElementRegion
in FdObj
.RegionList
:
541 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
542 for ElementRegionData
in ElementRegion
.RegionDataList
:
543 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
544 if FvObj
.BlockSizeList
!= []:
545 return FvObj
.BlockSizeList
[0][0]
547 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
548 return DefaultBlockSize
550 ## DisplayFvSpaceInfo()
552 # @param FvObj Whose block size to get
556 def DisplayFvSpaceInfo(FdfParserObject
):
560 for FvName
in FdfParserObject
.Profile
.FvDict
:
561 if len(FvName
) > MaxFvNameLength
:
562 MaxFvNameLength
= len(FvName
)
563 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
564 if os
.path
.exists(FvSpaceInfoFileName
):
565 FileLinesList
= getlines(FvSpaceInfoFileName
)
572 for Line
in FileLinesList
:
573 NameValue
= Line
.split('=')
574 if len(NameValue
) == 2:
575 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
577 Total
= NameValue
[1].strip()
578 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
580 Used
= NameValue
[1].strip()
581 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
583 Free
= NameValue
[1].strip()
585 if TotalFound
and UsedFound
and FreeFound
:
586 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
588 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
589 for FvSpaceInfo
in FvSpaceInfoList
:
590 Name
= FvSpaceInfo
[0]
591 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
592 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
593 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
594 if UsedSizeValue
== TotalSizeValue
:
597 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
599 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
603 # @param BuildDb Database from build meta data files
604 # @param DscFile modules from dsc file will be preprocessed
608 def PreprocessImage(BuildDb
, DscFile
):
609 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
612 PcdObj
= PcdDict
[Key
]
613 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
614 PcdValue
= PcdObj
.DefaultValue
620 Int64PcdValue
= long(PcdValue
, 0)
621 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
625 if Int64PcdValue
> 0:
626 TopAddress
= Int64PcdValue
628 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
629 for Key
in ModuleDict
:
630 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
631 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
634 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
635 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
636 GuidXRefFile
= BytesIO('')
641 for Arch
in ArchList
:
642 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
643 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
645 PkgGuidDict
.update(P
.Guids
)
646 for Name
, Guid
in PlatformDataBase
.Pcds
:
647 Pcd
= PlatformDataBase
.Pcds
[Name
, Guid
]
648 if Pcd
.Type
in [TAB_PCDS_DYNAMIC_HII
, TAB_PCDS_DYNAMIC_EX_HII
]:
649 for SkuId
in Pcd
.SkuInfoList
:
650 Sku
= Pcd
.SkuInfoList
[SkuId
]
651 if Sku
.VariableGuid
and Sku
.VariableGuid
in PkgGuidDict
.keys():
652 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
653 for ModuleFile
in PlatformDataBase
.Modules
:
654 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
655 if Module
in ModuleList
:
658 ModuleList
.append(Module
)
659 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
660 GuidXRefFile
.write("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
662 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
663 GuidDict
.update(Module
.Protocols
)
664 GuidDict
.update(Module
.Guids
)
665 GuidDict
.update(Module
.Ppis
)
666 for FvName
in FdfParserObj
.Profile
.FvDict
:
667 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
668 if not isinstance(FfsObj
, FileStatement
):
669 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
670 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
671 if FdfModule
in ModuleList
:
674 ModuleList
.append(FdfModule
)
675 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
676 GuidDict
.update(FdfModule
.Protocols
)
677 GuidDict
.update(FdfModule
.Guids
)
678 GuidDict
.update(FdfModule
.Ppis
)
680 FileStatementGuid
= FfsObj
.NameGuid
681 if FileStatementGuid
in FileGuidList
:
684 FileGuidList
.append(FileStatementGuid
)
686 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
687 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
690 if not os
.path
.exists(FfsPath
[0]):
693 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
694 FileList
= os
.listdir(FfsPath
[0])
695 for File
in FileList
:
696 Match
= ReFileEnds
.search(File
)
698 for Index
in range(1, 8):
699 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
700 MatchDict
[Match
.group(Index
)].append(File
)
701 elif Match
.group(Index
):
702 MatchDict
[Match
.group(Index
)] = [File
]
705 if '.ui' in MatchDict
:
706 for File
in MatchDict
['.ui']:
707 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
711 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
712 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
715 if 'fv.sec.txt' in MatchDict
:
716 FileList
= MatchDict
['fv.sec.txt']
717 elif '.pe32.txt' in MatchDict
:
718 FileList
= MatchDict
['.pe32.txt']
719 elif '.te.txt' in MatchDict
:
720 FileList
= MatchDict
['.te.txt']
721 elif '.pic.txt' in MatchDict
:
722 FileList
= MatchDict
['.pic.txt']
723 elif '.raw.txt' in MatchDict
:
724 FileList
= MatchDict
['.raw.txt']
725 elif '.ffs.txt' in MatchDict
:
726 FileList
= MatchDict
['.ffs.txt']
729 for File
in FileList
:
730 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
731 Name
.append((F
.read().split()[-1]))
735 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
736 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
738 # Append GUIDs, Protocols, and PPIs to the Xref file
739 GuidXRefFile
.write("\n")
740 for key
, item
in GuidDict
.items():
741 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
743 if GuidXRefFile
.getvalue():
744 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
745 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
746 elif os
.path
.exists(GuidXRefFileName
):
747 os
.remove(GuidXRefFileName
)
751 if __name__
== '__main__':
753 ## 0-127 is a safe return range, and 1 is a standard default error