4 # Copyright (c) 2007 - 2019, 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
44 import Common
.DataType
as DataType
45 from struct
import Struct
47 ## Version and Copyright
48 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
49 __version__
= "%prog Version " + versionNumber
50 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
52 ## Tool entrance method
54 # This method mainly dispatch specific methods per the command line options.
55 # If no error found, return zero value so the caller of this tool can know
56 # if it's executed successfully or not.
58 # @retval 0 Tool was successful
59 # @retval 1 Tool failed
63 Options
= myOptionParser()
64 EdkLogger
.Initialize()
65 return GenFdsApi(OptionsToCommandDict(Options
))
67 def resetFdsGlobalVariable():
68 GenFdsGlobalVariable
.FvDir
= ''
69 GenFdsGlobalVariable
.OutputDirDict
= {}
70 GenFdsGlobalVariable
.BinDir
= ''
71 # will be FvDir + os.sep + 'Ffs'
72 GenFdsGlobalVariable
.FfsDir
= ''
73 GenFdsGlobalVariable
.FdfParser
= None
74 GenFdsGlobalVariable
.LibDir
= ''
75 GenFdsGlobalVariable
.WorkSpace
= None
76 GenFdsGlobalVariable
.WorkSpaceDir
= ''
77 GenFdsGlobalVariable
.ConfDir
= ''
78 GenFdsGlobalVariable
.OutputDirFromDscDict
= {}
79 GenFdsGlobalVariable
.TargetName
= ''
80 GenFdsGlobalVariable
.ToolChainTag
= ''
81 GenFdsGlobalVariable
.RuleDict
= {}
82 GenFdsGlobalVariable
.ArchList
= None
83 GenFdsGlobalVariable
.ActivePlatform
= None
84 GenFdsGlobalVariable
.FvAddressFileName
= ''
85 GenFdsGlobalVariable
.VerboseMode
= False
86 GenFdsGlobalVariable
.DebugLevel
= -1
87 GenFdsGlobalVariable
.SharpCounter
= 0
88 GenFdsGlobalVariable
.SharpNumberPerLine
= 40
89 GenFdsGlobalVariable
.FdfFile
= ''
90 GenFdsGlobalVariable
.FdfFileTimeStamp
= 0
91 GenFdsGlobalVariable
.FixedLoadAddress
= False
92 GenFdsGlobalVariable
.PlatformName
= ''
94 GenFdsGlobalVariable
.BuildRuleFamily
= DataType
.TAB_COMPILER_MSFT
95 GenFdsGlobalVariable
.ToolChainFamily
= DataType
.TAB_COMPILER_MSFT
96 GenFdsGlobalVariable
.__BuildRuleDatabase
= None
97 GenFdsGlobalVariable
.GuidToolDefinition
= {}
98 GenFdsGlobalVariable
.FfsCmdDict
= {}
99 GenFdsGlobalVariable
.SecCmdList
= []
100 GenFdsGlobalVariable
.CopyList
= []
101 GenFdsGlobalVariable
.ModuleFile
= ''
102 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= False
104 GenFdsGlobalVariable
.LargeFileInFvFlags
= []
105 GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
= '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'
106 GenFdsGlobalVariable
.LARGE_FILE_SIZE
= 0x1000000
108 GenFdsGlobalVariable
.SectionHeader
= Struct("3B 1B")
110 # FvName, FdName, CapName in FDF, Image file name
111 GenFdsGlobalVariable
.ImageBinDict
= {}
113 def GenFdsApi(FdsCommandDict
, WorkSpaceDataBase
=None):
118 resetFdsGlobalVariable()
121 if FdsCommandDict
.get("verbose"):
122 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
123 GenFdsGlobalVariable
.VerboseMode
= True
125 if FdsCommandDict
.get("FixedAddress"):
126 GenFdsGlobalVariable
.FixedLoadAddress
= True
128 if FdsCommandDict
.get("quiet"):
129 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
130 if FdsCommandDict
.get("debug"):
131 EdkLogger
.SetLevel(FdsCommandDict
.get("debug") + 1)
132 GenFdsGlobalVariable
.DebugLevel
= FdsCommandDict
.get("debug")
134 EdkLogger
.SetLevel(EdkLogger
.INFO
)
136 if not FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')):
137 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
138 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
139 elif not os
.path
.exists(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE'))):
140 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
141 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
143 Workspace
= os
.path
.normcase(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')))
144 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
145 if FdsCommandDict
.get("debug"):
146 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
147 if FdsCommandDict
.get("GenfdsMultiThread"):
148 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
149 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
151 # set multiple workspace
152 PackagesPath
= os
.getenv("PACKAGES_PATH")
153 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
155 if FdsCommandDict
.get("fdf_file"):
156 FdfFilename
= FdsCommandDict
.get("fdf_file")[0].Path
157 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
159 if FdfFilename
[0:2] == '..':
160 FdfFilename
= os
.path
.realpath(FdfFilename
)
161 if not os
.path
.isabs(FdfFilename
):
162 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
163 if not os
.path
.exists(FdfFilename
):
164 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
166 GenFdsGlobalVariable
.FdfFile
= FdfFilename
167 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
169 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
171 if FdsCommandDict
.get("build_target"):
172 GenFdsGlobalVariable
.TargetName
= FdsCommandDict
.get("build_target")
174 if FdsCommandDict
.get("toolchain_tag"):
175 GenFdsGlobalVariable
.ToolChainTag
= FdsCommandDict
.get("toolchain_tag")
177 if FdsCommandDict
.get("active_platform"):
178 ActivePlatform
= FdsCommandDict
.get("active_platform")
179 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
181 if ActivePlatform
[0:2] == '..':
182 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
184 if not os
.path
.isabs (ActivePlatform
):
185 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
187 if not os
.path
.exists(ActivePlatform
):
188 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
190 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
192 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
194 if FdsCommandDict
.get("conf_directory"):
195 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
196 ConfDirectoryPath
= os
.path
.normpath(FdsCommandDict
.get("conf_directory"))
197 if ConfDirectoryPath
.startswith('"'):
198 ConfDirectoryPath
= ConfDirectoryPath
[1:]
199 if ConfDirectoryPath
.endswith('"'):
200 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
201 if not os
.path
.isabs(ConfDirectoryPath
):
202 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
203 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
204 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
206 if "CONF_PATH" in os
.environ
:
207 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
209 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
210 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
211 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
212 if not GlobalData
.gConfDirectory
:
213 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
214 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
215 if os
.path
.isfile(BuildConfigurationFile
) == True:
216 TargetTxt
= TargetTxtClassObject()
217 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
218 # if no build target given in command line, get it from target.txt
219 if not GenFdsGlobalVariable
.TargetName
:
220 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
221 if len(BuildTargetList
) != 1:
222 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
223 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
225 # if no tool chain given in command line, get it from target.txt
226 if not GenFdsGlobalVariable
.ToolChainTag
:
227 ToolChainList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
228 if ToolChainList
is None or len(ToolChainList
) == 0:
229 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
230 if len(ToolChainList
) != 1:
231 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
232 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
234 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
236 #Set global flag for build mode
237 GlobalData
.gIgnoreSource
= FdsCommandDict
.get("IgnoreSources")
239 if FdsCommandDict
.get("macro"):
240 for Pair
in FdsCommandDict
.get("macro"):
241 if Pair
.startswith('"'):
243 if Pair
.endswith('"'):
245 List
= Pair
.split('=')
247 if not List
[1].strip():
248 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
249 if List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
250 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
252 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
254 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
255 os
.environ
["WORKSPACE"] = Workspace
257 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
258 if "TARGET" not in GlobalData
.gGlobalDefines
:
259 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
260 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
261 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
262 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
263 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
265 """call Workspace build create database"""
266 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
268 if WorkSpaceDataBase
:
269 BuildWorkSpace
= WorkSpaceDataBase
271 BuildWorkSpace
= WorkspaceDatabase()
273 # Get files real name in workspace dir
275 GlobalData
.gAllFiles
= DirCache(Workspace
)
276 GlobalData
.gWorkspace
= Workspace
278 if FdsCommandDict
.get("build_architecture_list"):
279 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
281 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
283 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
284 if len(TargetArchList
) == 0:
285 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
287 for Arch
in ArchList
:
288 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
290 # assign platform name based on last entry in ArchList
291 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
293 if FdsCommandDict
.get("platform_build_directory"):
294 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
295 if not os
.path
.isabs (OutputDirFromCommandLine
):
296 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
297 for Arch
in ArchList
:
298 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
300 for Arch
in ArchList
:
301 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
303 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
304 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
305 if OutputDir
[0:2] == '..':
306 OutputDir
= os
.path
.realpath(OutputDir
)
308 if OutputDir
[1] != ':':
309 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
311 if not os
.path
.exists(OutputDir
):
312 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
313 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
315 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
316 if WorkSpaceDataBase
:
317 FdfParserObj
= GlobalData
.gFdfParser
319 FdfParserObj
= FdfParser(FdfFilename
)
320 FdfParserObj
.ParseFile()
322 if FdfParserObj
.CycleReferenceCheck():
323 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
325 if FdsCommandDict
.get("fd"):
326 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
327 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
329 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
330 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
332 if FdsCommandDict
.get("fv"):
333 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
334 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
336 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
337 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
339 if FdsCommandDict
.get("cap"):
340 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
341 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
343 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
344 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
346 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
348 GenFdsGlobalVariable
.ArchList
= ArchList
350 # Dsc Build Data will handle Pcd Settings from CommandLine.
352 """Modify images from build output if the feature of loading driver at fixed address is on."""
353 if GenFdsGlobalVariable
.FixedLoadAddress
:
354 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
356 # Record the FV Region info that may specific in the FD
357 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
358 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
359 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
360 for RegionObj
in FdObj
.RegionList
:
361 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
363 for RegionData
in RegionObj
.RegionDataList
:
364 if FvObj
.UiFvName
.upper() == RegionData
.upper():
365 if not FvObj
.BaseAddress
:
366 FvObj
.BaseAddress
= '0x%x' % (int(FdObj
.BaseAddress
, 0) + RegionObj
.Offset
)
367 if FvObj
.FvRegionInFD
:
368 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
369 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
371 FvObj
.FvRegionInFD
= RegionObj
.Size
372 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
375 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
377 """Generate GUID cross reference file"""
378 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
380 """Display FV space info."""
381 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
384 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
385 ReturnCode
= FORMAT_INVALID
386 except FatalError
as X
:
387 if FdsCommandDict
.get("debug") is not None:
389 EdkLogger
.quiet(traceback
.format_exc())
390 ReturnCode
= X
.args
[0]
396 "Tools code failure",
397 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
400 EdkLogger
.quiet(traceback
.format_exc())
401 ReturnCode
= CODE_ERROR
406 def OptionsToCommandDict(Options
):
408 FdsCommandDict
["verbose"] = Options
.verbose
409 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
410 FdsCommandDict
["quiet"] = Options
.quiet
411 FdsCommandDict
["debug"] = Options
.debug
412 FdsCommandDict
["Workspace"] = Options
.Workspace
413 FdsCommandDict
["GenfdsMultiThread"] = Options
.GenfdsMultiThread
414 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
415 FdsCommandDict
["build_target"] = Options
.BuildTarget
416 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
417 FdsCommandDict
["active_platform"] = Options
.activePlatform
418 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
419 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
420 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
421 FdsCommandDict
["macro"] = Options
.Macros
422 FdsCommandDict
["build_architecture_list"] = Options
.archList
423 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
424 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
425 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
426 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
427 return FdsCommandDict
431 def SingleCheckCallback(option
, opt_str
, value
, parser
):
432 if option
not in gParamCheck
:
433 setattr(parser
.values
, option
.dest
, value
)
434 gParamCheck
.append(option
)
436 parser
.error("Option %s only allows one instance in command line!" % option
)
438 ## Parse command line options
440 # Using standard Python module optparse to parse command line option of this tool.
442 # @retval Opt A optparse.Values object containing the parsed options
444 def myOptionParser():
445 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
446 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
447 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
448 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")
449 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
450 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
451 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
452 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
453 action
="callback", callback
=SingleCheckCallback
)
454 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
455 action
="callback", callback
=SingleCheckCallback
)
456 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
457 action
="callback", callback
=SingleCheckCallback
)
458 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
459 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
460 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
461 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
462 action
="callback", callback
=SingleCheckCallback
)
463 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
464 action
="callback", callback
=SingleCheckCallback
)
465 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
466 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
467 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
468 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
469 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
470 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
472 Options
, _
= Parser
.parse_args()
475 ## The class implementing the EDK2 flash image generation process
477 # This process includes:
478 # 1. Collect workspace information, includes platform and module information
479 # 2. Call methods of Fd class to generate FD
480 # 3. Call methods of Fv class to generate FV that not belong to FD
482 class GenFds(object):
484 OnlyGenerateThisFd
= None
485 OnlyGenerateThisFv
= None
486 OnlyGenerateThisCap
= None
490 # @param OutputDir Output directory
491 # @param FdfParserObject FDF contents parser
492 # @param Workspace The directory of workspace
493 # @param ArchList The Arch list of platform
496 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
497 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
499 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
500 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
501 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
502 if CapsuleObj
is not None:
503 CapsuleObj
.GenCapsule()
506 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
507 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
508 if FdObj
is not None:
511 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
512 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
515 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
516 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
517 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
518 if FvObj
is not None:
520 FvObj
.AddToBuffer(Buffer
)
523 elif GenFds
.OnlyGenerateThisFv
is None:
524 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
526 FvObj
.AddToBuffer(Buffer
)
529 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
530 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
531 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
532 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
533 CapsuleObj
.GenCapsule()
535 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
536 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
537 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
538 OptRomObj
.AddToBuffer(None)
541 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
542 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
543 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
544 FdObj
.GenFd(Flag
=True)
546 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
547 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
549 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
550 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
551 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
553 return GenFdsGlobalVariable
.FfsCmdDict
557 # @param FvObj Whose block size to get
558 # @retval int Block size value
561 def GetFvBlockSize(FvObj
):
562 DefaultBlockSize
= 0x1
564 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
565 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
567 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
568 for ElementRegion
in ElementFd
.RegionList
:
569 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
570 for ElementRegionData
in ElementRegion
.RegionDataList
:
571 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
572 if FvObj
.BlockSizeList
!= []:
573 return FvObj
.BlockSizeList
[0][0]
575 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
576 if FvObj
.BlockSizeList
!= []:
577 return FvObj
.BlockSizeList
[0][0]
578 return DefaultBlockSize
580 for ElementRegion
in FdObj
.RegionList
:
581 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
582 for ElementRegionData
in ElementRegion
.RegionDataList
:
583 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
584 if FvObj
.BlockSizeList
!= []:
585 return FvObj
.BlockSizeList
[0][0]
587 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
588 return DefaultBlockSize
590 ## DisplayFvSpaceInfo()
592 # @param FvObj Whose block size to get
596 def DisplayFvSpaceInfo(FdfParserObject
):
600 for FvName
in FdfParserObject
.Profile
.FvDict
:
601 if len(FvName
) > MaxFvNameLength
:
602 MaxFvNameLength
= len(FvName
)
603 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
604 if os
.path
.exists(FvSpaceInfoFileName
):
605 FileLinesList
= getlines(FvSpaceInfoFileName
)
612 for Line
in FileLinesList
:
613 NameValue
= Line
.split('=')
614 if len(NameValue
) == 2:
615 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
617 Total
= NameValue
[1].strip()
618 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
620 Used
= NameValue
[1].strip()
621 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
623 Free
= NameValue
[1].strip()
625 if TotalFound
and UsedFound
and FreeFound
:
626 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
628 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
629 for FvSpaceInfo
in FvSpaceInfoList
:
630 Name
= FvSpaceInfo
[0]
631 TotalSizeValue
= int(FvSpaceInfo
[1], 0)
632 UsedSizeValue
= int(FvSpaceInfo
[2], 0)
633 FreeSizeValue
= int(FvSpaceInfo
[3], 0)
634 if UsedSizeValue
== TotalSizeValue
:
637 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
639 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
643 # @param BuildDb Database from build meta data files
644 # @param DscFile modules from dsc file will be preprocessed
648 def PreprocessImage(BuildDb
, DscFile
):
649 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
652 PcdObj
= PcdDict
[Key
]
653 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
654 PcdValue
= PcdObj
.DefaultValue
660 Int64PcdValue
= int(PcdValue
, 0)
661 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
665 if Int64PcdValue
> 0:
666 TopAddress
= Int64PcdValue
668 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
669 for Key
in ModuleDict
:
670 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
671 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
674 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
675 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
681 VariableGuidSet
= set()
682 for Arch
in ArchList
:
683 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
684 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
686 PkgGuidDict
.update(P
.Guids
)
687 for Name
, Guid
in PlatformDataBase
.Pcds
:
688 Pcd
= PlatformDataBase
.Pcds
[Name
, Guid
]
689 if Pcd
.Type
in [TAB_PCDS_DYNAMIC_HII
, TAB_PCDS_DYNAMIC_EX_HII
]:
690 for SkuId
in Pcd
.SkuInfoList
:
691 Sku
= Pcd
.SkuInfoList
[SkuId
]
692 if Sku
.VariableGuid
in VariableGuidSet
:continue
693 VariableGuidSet
.add(Sku
.VariableGuid
)
694 if Sku
.VariableGuid
and Sku
.VariableGuid
in PkgGuidDict
.keys():
695 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
696 for ModuleFile
in PlatformDataBase
.Modules
:
697 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
698 if Module
in ModuleList
:
701 ModuleList
.append(Module
)
702 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
703 GuidXRefFile
.append("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
705 GuidXRefFile
.append("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
706 GuidDict
.update(Module
.Protocols
)
707 GuidDict
.update(Module
.Guids
)
708 GuidDict
.update(Module
.Ppis
)
709 for FvName
in FdfParserObj
.Profile
.FvDict
:
710 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
711 if not isinstance(FfsObj
, FileStatement
):
712 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
713 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
714 if FdfModule
in ModuleList
:
717 ModuleList
.append(FdfModule
)
718 GuidXRefFile
.append("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
719 GuidDict
.update(FdfModule
.Protocols
)
720 GuidDict
.update(FdfModule
.Guids
)
721 GuidDict
.update(FdfModule
.Ppis
)
723 FileStatementGuid
= FfsObj
.NameGuid
724 if FileStatementGuid
in FileGuidList
:
727 FileGuidList
.append(FileStatementGuid
)
729 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
730 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
733 if not os
.path
.exists(FfsPath
[0]):
736 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
737 FileList
= os
.listdir(FfsPath
[0])
738 for File
in FileList
:
739 Match
= ReFileEnds
.search(File
)
741 for Index
in range(1, 8):
742 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
743 MatchDict
[Match
.group(Index
)].append(File
)
744 elif Match
.group(Index
):
745 MatchDict
[Match
.group(Index
)] = [File
]
748 if '.ui' in MatchDict
:
749 for File
in MatchDict
['.ui']:
750 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
754 TmpStr
= unpack('%dh' % ((length
- 4) // 2), F
.read())
755 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
758 if 'fv.sec.txt' in MatchDict
:
759 FileList
= MatchDict
['fv.sec.txt']
760 elif '.pe32.txt' in MatchDict
:
761 FileList
= MatchDict
['.pe32.txt']
762 elif '.te.txt' in MatchDict
:
763 FileList
= MatchDict
['.te.txt']
764 elif '.pic.txt' in MatchDict
:
765 FileList
= MatchDict
['.pic.txt']
766 elif '.raw.txt' in MatchDict
:
767 FileList
= MatchDict
['.raw.txt']
768 elif '.ffs.txt' in MatchDict
:
769 FileList
= MatchDict
['.ffs.txt']
772 for File
in FileList
:
773 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
774 Name
.append((F
.read().split()[-1]))
778 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
779 GuidXRefFile
.append("%s %s\n" %(FileStatementGuid
, Name
))
781 # Append GUIDs, Protocols, and PPIs to the Xref file
782 GuidXRefFile
.append("\n")
783 for key
, item
in GuidDict
.items():
784 GuidXRefFile
.append("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
787 GuidXRefFile
= ''.join(GuidXRefFile
)
788 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
, False)
789 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
790 elif os
.path
.exists(GuidXRefFileName
):
791 os
.remove(GuidXRefFileName
)
794 if __name__
== '__main__':
796 ## 0-127 is a safe return range, and 1 is a standard default error