]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/GenFds.py
2efb2edd9ab1d9fda2f931379cb09832b0e7f376
[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 GenFdsGlobalVariable.ActivePlatform = PathClass(NormPath(ActivePlatform))
193
194 if FdsCommandDict.get("conf_directory"):
195 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
196 ConfDirectoryPath = os.path.normpath(FdsCommandDict.get("conf_directory"))
197 if ConfDirectoryPath.startswith('"'):
198 ConfDirectoryPath = ConfDirectoryPath[1:]
199 if ConfDirectoryPath.endswith('"'):
200 ConfDirectoryPath = ConfDirectoryPath[:-1]
201 if not os.path.isabs(ConfDirectoryPath):
202 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
203 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
204 ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ConfDirectoryPath)
205 else:
206 if "CONF_PATH" in os.environ:
207 ConfDirectoryPath = os.path.normcase(os.environ["CONF_PATH"])
208 else:
209 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
210 ConfDirectoryPath = mws.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf')
211 GenFdsGlobalVariable.ConfDir = ConfDirectoryPath
212 if not GlobalData.gConfDirectory:
213 GlobalData.gConfDirectory = GenFdsGlobalVariable.ConfDir
214 BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt"))
215 if os.path.isfile(BuildConfigurationFile) == True:
216 TargetTxt = TargetTxtClassObject()
217 TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
218 # if no build target given in command line, get it from target.txt
219 if not GenFdsGlobalVariable.TargetName:
220 BuildTargetList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]
221 if len(BuildTargetList) != 1:
222 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for Target.")
223 GenFdsGlobalVariable.TargetName = BuildTargetList[0]
224
225 # if no tool chain given in command line, get it from target.txt
226 if not GenFdsGlobalVariable.ToolChainTag:
227 ToolChainList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
228 if ToolChainList is None or len(ToolChainList) == 0:
229 EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.")
230 if len(ToolChainList) != 1:
231 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for ToolChain.")
232 GenFdsGlobalVariable.ToolChainTag = ToolChainList[0]
233 else:
234 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
235
236 #Set global flag for build mode
237 GlobalData.gIgnoreSource = FdsCommandDict.get("IgnoreSources")
238
239 if FdsCommandDict.get("macro"):
240 for Pair in FdsCommandDict.get("macro"):
241 if Pair.startswith('"'):
242 Pair = Pair[1:]
243 if Pair.endswith('"'):
244 Pair = Pair[:-1]
245 List = Pair.split('=')
246 if len(List) == 2:
247 if not List[1].strip():
248 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="No Value given for Macro %s" %List[0])
249 if List[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
250 GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip()
251 else:
252 GlobalData.gCommandLineDefines[List[0].strip()] = List[1].strip()
253 else:
254 GlobalData.gCommandLineDefines[List[0].strip()] = "TRUE"
255 os.environ["WORKSPACE"] = Workspace
256
257 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
258 if "TARGET" not in GlobalData.gGlobalDefines:
259 GlobalData.gGlobalDefines["TARGET"] = GenFdsGlobalVariable.TargetName
260 if "TOOLCHAIN" not in GlobalData.gGlobalDefines:
261 GlobalData.gGlobalDefines["TOOLCHAIN"] = GenFdsGlobalVariable.ToolChainTag
262 if "TOOL_CHAIN_TAG" not in GlobalData.gGlobalDefines:
263 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable.ToolChainTag
264
265 """call Workspace build create database"""
266 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))
267
268 if WorkSpaceDataBase:
269 BuildWorkSpace = WorkSpaceDataBase
270 else:
271 BuildWorkSpace = WorkspaceDatabase()
272 #
273 # Get files real name in workspace dir
274 #
275 GlobalData.gAllFiles = DirCache(Workspace)
276 GlobalData.gWorkspace = Workspace
277
278 if FdsCommandDict.get("build_architecture_list"):
279 ArchList = FdsCommandDict.get("build_architecture_list").split(',')
280 else:
281 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList
282
283 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList) & set(ArchList)
284 if len(TargetArchList) == 0:
285 EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON].SupArchList)))
286
287 for Arch in ArchList:
288 GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].OutputDirectory)
289
290 # assign platform name based on last entry in ArchList
291 GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, ArchList[-1], FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].PlatformName
292
293 if FdsCommandDict.get("platform_build_directory"):
294 OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdsCommandDict.get("platform_build_directory"))
295 if not os.path.isabs (OutputDirFromCommandLine):
296 OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine)
297 for Arch in ArchList:
298 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine
299 else:
300 for Arch in ArchList:
301 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)
302
303 for Key in GenFdsGlobalVariable.OutputDirDict:
304 OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]
305 if OutputDir[0:2] == '..':
306 OutputDir = os.path.realpath(OutputDir)
307
308 if OutputDir[1] != ':':
309 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)
310
311 if not os.path.exists(OutputDir):
312 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir)
313 GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir
314
315 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
316 if WorkSpaceDataBase:
317 FdfParserObj = GlobalData.gFdfParser
318 else:
319 FdfParserObj = FdfParser(FdfFilename)
320 FdfParserObj.ParseFile()
321
322 if FdfParserObj.CycleReferenceCheck():
323 EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")
324
325 if FdsCommandDict.get("fd"):
326 if FdsCommandDict.get("fd")[0].upper() in FdfParserObj.Profile.FdDict:
327 GenFds.OnlyGenerateThisFd = FdsCommandDict.get("fd")[0]
328 else:
329 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
330 "No such an FD in FDF file: %s" % FdsCommandDict.get("fd")[0])
331
332 if FdsCommandDict.get("fv"):
333 if FdsCommandDict.get("fv")[0].upper() in FdfParserObj.Profile.FvDict:
334 GenFds.OnlyGenerateThisFv = FdsCommandDict.get("fv")[0]
335 else:
336 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
337 "No such an FV in FDF file: %s" % FdsCommandDict.get("fv")[0])
338
339 if FdsCommandDict.get("cap"):
340 if FdsCommandDict.get("cap")[0].upper() in FdfParserObj.Profile.CapsuleDict:
341 GenFds.OnlyGenerateThisCap = FdsCommandDict.get("cap")[0]
342 else:
343 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
344 "No such a Capsule in FDF file: %s" % FdsCommandDict.get("cap")[0])
345
346 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace
347 if ArchList:
348 GenFdsGlobalVariable.ArchList = ArchList
349
350 # Dsc Build Data will handle Pcd Settings from CommandLine.
351
352 """Modify images from build output if the feature of loading driver at fixed address is on."""
353 if GenFdsGlobalVariable.FixedLoadAddress:
354 GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform)
355
356 # Record the FV Region info that may specific in the FD
357 if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict:
358 for FvObj in FdfParserObj.Profile.FvDict.values():
359 for FdObj in FdfParserObj.Profile.FdDict.values():
360 for RegionObj in FdObj.RegionList:
361 if RegionObj.RegionType != BINARY_FILE_TYPE_FV:
362 continue
363 for RegionData in RegionObj.RegionDataList:
364 if FvObj.UiFvName.upper() == RegionData.upper():
365 if not FvObj.BaseAddress:
366 FvObj.BaseAddress = '0x%x' % (int(FdObj.BaseAddress, 0) + RegionObj.Offset)
367 if FvObj.FvRegionInFD:
368 if FvObj.FvRegionInFD != RegionObj.Size:
369 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName)
370 else:
371 FvObj.FvRegionInFD = RegionObj.Size
372 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)
373
374 """Call GenFds"""
375 GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)
376
377 """Generate GUID cross reference file"""
378 GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj)
379
380 """Display FV space info."""
381 GenFds.DisplayFvSpaceInfo(FdfParserObj)
382
383 except Warning as X:
384 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
385 ReturnCode = FORMAT_INVALID
386 except FatalError as X:
387 if FdsCommandDict.get("debug") is not None:
388 import traceback
389 EdkLogger.quiet(traceback.format_exc())
390 ReturnCode = X.args[0]
391 except:
392 import traceback
393 EdkLogger.error(
394 "\nPython",
395 CODE_ERROR,
396 "Tools code failure",
397 ExtraData="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
398 RaiseError=False
399 )
400 EdkLogger.quiet(traceback.format_exc())
401 ReturnCode = CODE_ERROR
402 finally:
403 ClearDuplicatedInf()
404 return ReturnCode
405
406 def OptionsToCommandDict(Options):
407 FdsCommandDict = {}
408 FdsCommandDict["verbose"] = Options.verbose
409 FdsCommandDict["FixedAddress"] = Options.FixedAddress
410 FdsCommandDict["quiet"] = Options.quiet
411 FdsCommandDict["debug"] = Options.debug
412 FdsCommandDict["Workspace"] = Options.Workspace
413 FdsCommandDict["GenfdsMultiThread"] = Options.GenfdsMultiThread
414 FdsCommandDict["fdf_file"] = [PathClass(Options.filename)] if Options.filename else []
415 FdsCommandDict["build_target"] = Options.BuildTarget
416 FdsCommandDict["toolchain_tag"] = Options.ToolChain
417 FdsCommandDict["active_platform"] = Options.activePlatform
418 FdsCommandDict["OptionPcd"] = Options.OptionPcd
419 FdsCommandDict["conf_directory"] = Options.ConfDirectory
420 FdsCommandDict["IgnoreSources"] = Options.IgnoreSources
421 FdsCommandDict["macro"] = Options.Macros
422 FdsCommandDict["build_architecture_list"] = Options.archList
423 FdsCommandDict["platform_build_directory"] = Options.outputDir
424 FdsCommandDict["fd"] = [Options.uiFdName] if Options.uiFdName else []
425 FdsCommandDict["fv"] = [Options.uiFvName] if Options.uiFvName else []
426 FdsCommandDict["cap"] = [Options.uiCapName] if Options.uiCapName else []
427 return FdsCommandDict
428
429
430 gParamCheck = []
431 def SingleCheckCallback(option, opt_str, value, parser):
432 if option not in gParamCheck:
433 setattr(parser.values, option.dest, value)
434 gParamCheck.append(option)
435 else:
436 parser.error("Option %s only allows one instance in command line!" % option)
437
438 ## Parse command line options
439 #
440 # Using standard Python module optparse to parse command line option of this tool.
441 #
442 # @retval Opt A optparse.Values object containing the parsed options
443 #
444 def myOptionParser():
445 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
446 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))
447 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)
448 Parser.add_option("-a", "--arch", dest="archList", help="comma separated list containing one or more of: IA32, X64, IPF, ARM, AARCH64 or EBC which should be built, overrides target.txt?s TARGET_ARCH")
449 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
450 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
451 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
452 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
453 action="callback", callback=SingleCheckCallback)
454 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",
455 action="callback", callback=SingleCheckCallback)
456 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",
457 action="callback", callback=SingleCheckCallback)
458 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
459 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
460 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
461 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
462 action="callback", callback=SingleCheckCallback)
463 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
464 action="callback", callback=SingleCheckCallback)
465 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
466 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")
467 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
468 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
469 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
470 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
471
472 Options, _ = Parser.parse_args()
473 return Options
474
475 ## The class implementing the EDK2 flash image generation process
476 #
477 # This process includes:
478 # 1. Collect workspace information, includes platform and module information
479 # 2. Call methods of Fd class to generate FD
480 # 3. Call methods of Fv class to generate FV that not belong to FD
481 #
482 class GenFds(object):
483 FdfParsef = None
484 OnlyGenerateThisFd = None
485 OnlyGenerateThisFv = None
486 OnlyGenerateThisCap = None
487
488 ## GenFd()
489 #
490 # @param OutputDir Output directory
491 # @param FdfParserObject FDF contents parser
492 # @param Workspace The directory of workspace
493 # @param ArchList The Arch list of platform
494 #
495 @staticmethod
496 def GenFd (OutputDir, FdfParserObject, WorkSpace, ArchList):
497 GenFdsGlobalVariable.SetDir ('', FdfParserObject, WorkSpace, ArchList)
498
499 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
500 if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict:
501 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[GenFds.OnlyGenerateThisCap.upper()]
502 if CapsuleObj is not None:
503 CapsuleObj.GenCapsule()
504 return
505
506 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
507 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
508 if FdObj is not None:
509 FdObj.GenFd()
510 return
511 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None:
512 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
513 FdObj.GenFd()
514
515 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")
516 if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict:
517 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[GenFds.OnlyGenerateThisFv.upper()]
518 if FvObj is not None:
519 Buffer = BytesIO()
520 FvObj.AddToBuffer(Buffer)
521 Buffer.close()
522 return
523 elif GenFds.OnlyGenerateThisFv is None:
524 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():
525 Buffer = BytesIO('')
526 FvObj.AddToBuffer(Buffer)
527 Buffer.close()
528
529 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None:
530 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:
531 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")
532 for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values():
533 CapsuleObj.GenCapsule()
534
535 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
536 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")
537 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():
538 OptRomObj.AddToBuffer(None)
539
540 @staticmethod
541 def GenFfsMakefile(OutputDir, FdfParserObject, WorkSpace, ArchList, GlobalData):
542 GenFdsGlobalVariable.SetEnv(FdfParserObject, WorkSpace, ArchList, GlobalData)
543 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
544 FdObj.GenFd(Flag=True)
545
546 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():
547 FvObj.AddToBuffer(Buffer=None, Flag=True)
548
549 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
550 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():
551 OptRomObj.AddToBuffer(Buffer=None, Flag=True)
552
553 return GenFdsGlobalVariable.FfsCmdDict
554
555 ## GetFvBlockSize()
556 #
557 # @param FvObj Whose block size to get
558 # @retval int Block size value
559 #
560 @staticmethod
561 def GetFvBlockSize(FvObj):
562 DefaultBlockSize = 0x1
563 FdObj = None
564 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
565 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
566 if FdObj is None:
567 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
568 for ElementRegion in ElementFd.RegionList:
569 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:
570 for ElementRegionData in ElementRegion.RegionDataList:
571 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
572 if FvObj.BlockSizeList != []:
573 return FvObj.BlockSizeList[0][0]
574 else:
575 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
576 if FvObj.BlockSizeList != []:
577 return FvObj.BlockSizeList[0][0]
578 return DefaultBlockSize
579 else:
580 for ElementRegion in FdObj.RegionList:
581 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:
582 for ElementRegionData in ElementRegion.RegionDataList:
583 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
584 if FvObj.BlockSizeList != []:
585 return FvObj.BlockSizeList[0][0]
586 else:
587 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
588 return DefaultBlockSize
589
590 ## DisplayFvSpaceInfo()
591 #
592 # @param FvObj Whose block size to get
593 # @retval None
594 #
595 @staticmethod
596 def DisplayFvSpaceInfo(FdfParserObject):
597
598 FvSpaceInfoList = []
599 MaxFvNameLength = 0
600 for FvName in FdfParserObject.Profile.FvDict:
601 if len(FvName) > MaxFvNameLength:
602 MaxFvNameLength = len(FvName)
603 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')
604 if os.path.exists(FvSpaceInfoFileName):
605 FileLinesList = getlines(FvSpaceInfoFileName)
606 TotalFound = False
607 Total = ''
608 UsedFound = False
609 Used = ''
610 FreeFound = False
611 Free = ''
612 for Line in FileLinesList:
613 NameValue = Line.split('=')
614 if len(NameValue) == 2:
615 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
616 TotalFound = True
617 Total = NameValue[1].strip()
618 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
619 UsedFound = True
620 Used = NameValue[1].strip()
621 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
622 FreeFound = True
623 Free = NameValue[1].strip()
624
625 if TotalFound and UsedFound and FreeFound:
626 FvSpaceInfoList.append((FvName, Total, Used, Free))
627
628 GenFdsGlobalVariable.InfLogger('\nFV Space Information')
629 for FvSpaceInfo in FvSpaceInfoList:
630 Name = FvSpaceInfo[0]
631 TotalSizeValue = int(FvSpaceInfo[1], 0)
632 UsedSizeValue = int(FvSpaceInfo[2], 0)
633 FreeSizeValue = int(FvSpaceInfo[3], 0)
634 if UsedSizeValue == TotalSizeValue:
635 Percentage = '100'
636 else:
637 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')
638
639 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(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 = BytesIO('')
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.write("%s %s\n" % (ModuleFile.BaseName, Module.BaseName))
704 else:
705 GuidXRefFile.write("%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.write("%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.write("%s %s\n" %(FileStatementGuid, Name))
780
781 # Append GUIDs, Protocols, and PPIs to the Xref file
782 GuidXRefFile.write("\n")
783 for key, item in GuidDict.items():
784 GuidXRefFile.write("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))
785
786 if GuidXRefFile.getvalue():
787 SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False)
788 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)
789 elif os.path.exists(GuidXRefFileName):
790 os.remove(GuidXRefFileName)
791 GuidXRefFile.close()
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