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