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