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