]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/GenFds.py
BaseTools: Change RealPath to AbsPath
[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,gDefaultTargetTxtFile
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.abspath(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.abspath(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, gDefaultTargetTxtFile))
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.abspath(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] '\
637 + str(TotalSizeValue) + ' (' + hex(TotalSizeValue) + ')' + ' total, '\
638 + str(UsedSizeValue) + ' (' + hex(UsedSizeValue) + ')' + ' used, '\
639 + str(FreeSizeValue) + ' (' + hex(FreeSizeValue) + ')' + ' free')
640
641 ## PreprocessImage()
642 #
643 # @param BuildDb Database from build meta data files
644 # @param DscFile modules from dsc file will be preprocessed
645 # @retval None
646 #
647 @staticmethod
648 def PreprocessImage(BuildDb, DscFile):
649 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds
650 PcdValue = ''
651 for Key in PcdDict:
652 PcdObj = PcdDict[Key]
653 if PcdObj.TokenCName == 'PcdBsBaseAddress':
654 PcdValue = PcdObj.DefaultValue
655 break
656
657 if PcdValue == '':
658 return
659
660 Int64PcdValue = int(PcdValue, 0)
661 if Int64PcdValue == 0 or Int64PcdValue < -1:
662 return
663
664 TopAddress = 0
665 if Int64PcdValue > 0:
666 TopAddress = Int64PcdValue
667
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)
672
673 @staticmethod
674 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):
675 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")
676 GuidXRefFile = []
677 PkgGuidDict = {}
678 GuidDict = {}
679 ModuleList = []
680 FileGuidList = []
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)
685 for P in PkgList:
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:
699 continue
700 else:
701 ModuleList.append(Module)
702 if GlobalData.gGuidPattern.match(ModuleFile.BaseName):
703 GuidXRefFile.append("%s %s\n" % (ModuleFile.BaseName, Module.BaseName))
704 else:
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:
715 continue
716 else:
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)
722 else:
723 FileStatementGuid = FfsObj.NameGuid
724 if FileStatementGuid in FileGuidList:
725 continue
726 else:
727 FileGuidList.append(FileStatementGuid)
728 Name = []
729 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
730 FfsPath = glob(os.path.join(FfsPath, FileStatementGuid) + TAB_STAR)
731 if not FfsPath:
732 continue
733 if not os.path.exists(FfsPath[0]):
734 continue
735 MatchDict = {}
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)
740 if Match:
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]
746 if not MatchDict:
747 continue
748 if '.ui' in MatchDict:
749 for File in MatchDict['.ui']:
750 with open(os.path.join(FfsPath[0], File), 'rb') as F:
751 F.read()
752 length = F.tell()
753 F.seek(4)
754 TmpStr = unpack('%dh' % ((length - 4) // 2), F.read())
755 Name = ''.join(chr(c) for c in TmpStr[:-1])
756 else:
757 FileList = []
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']
770 else:
771 pass
772 for File in FileList:
773 with open(os.path.join(FfsPath[0], File), 'r') as F:
774 Name.append((F.read().split()[-1]))
775 if not Name:
776 continue
777
778 Name = ' '.join(Name) if isinstance(Name, type([])) else Name
779 GuidXRefFile.append("%s %s\n" %(FileStatementGuid, Name))
780
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))
785
786 if GuidXRefFile:
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)
792
793
794 if __name__ == '__main__':
795 r = main()
796 ## 0-127 is a safe return range, and 1 is a standard default error
797 if r < 0 or r > 127:
798 r = 1
799 exit(r)
800