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