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