]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/GenFds.py
BaseTools: Replace the sqlite database with list
[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
230 if WorkSpaceDataBase:
231 BuildWorkSpace = WorkSpaceDataBase
232 else:
233 BuildWorkSpace = WorkspaceDatabase()
234 #
235 # Get files real name in workspace dir
236 #
237 GlobalData.gAllFiles = DirCache(Workspace)
238 GlobalData.gWorkspace = Workspace
239
240 if FdsCommandDict.get("build_architecture_list"):
241 ArchList = FdsCommandDict.get("build_architecture_list").split(',')
242 else:
243 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList
244
245 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList) & set(ArchList)
246 if len(TargetArchList) == 0:
247 EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON].SupArchList)))
248
249 for Arch in ArchList:
250 GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].OutputDirectory)
251
252 # assign platform name based on last entry in ArchList
253 GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, ArchList[-1], FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].PlatformName
254
255 if FdsCommandDict.get("platform_build_directory"):
256 OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdsCommandDict.get("platform_build_directory"))
257 if not os.path.isabs (OutputDirFromCommandLine):
258 OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine)
259 for Arch in ArchList:
260 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine
261 else:
262 for Arch in ArchList:
263 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)
264
265 for Key in GenFdsGlobalVariable.OutputDirDict:
266 OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]
267 if OutputDir[0:2] == '..':
268 OutputDir = os.path.realpath(OutputDir)
269
270 if OutputDir[1] != ':':
271 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)
272
273 if not os.path.exists(OutputDir):
274 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir)
275 GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir
276
277 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
278 if WorkSpaceDataBase:
279 FdfParserObj = GlobalData.gFdfParser
280 else:
281 FdfParserObj = FdfParser(FdfFilename)
282 FdfParserObj.ParseFile()
283
284 if FdfParserObj.CycleReferenceCheck():
285 EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")
286
287 if FdsCommandDict.get("fd"):
288 if FdsCommandDict.get("fd")[0].upper() in FdfParserObj.Profile.FdDict:
289 GenFds.OnlyGenerateThisFd = FdsCommandDict.get("fd")[0]
290 else:
291 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
292 "No such an FD in FDF file: %s" % FdsCommandDict.get("fd")[0])
293
294 if FdsCommandDict.get("fv"):
295 if FdsCommandDict.get("fv")[0].upper() in FdfParserObj.Profile.FvDict:
296 GenFds.OnlyGenerateThisFv = FdsCommandDict.get("fv")[0]
297 else:
298 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
299 "No such an FV in FDF file: %s" % FdsCommandDict.get("fv")[0])
300
301 if FdsCommandDict.get("cap"):
302 if FdsCommandDict.get("cap")[0].upper() in FdfParserObj.Profile.CapsuleDict:
303 GenFds.OnlyGenerateThisCap = FdsCommandDict.get("cap")[0]
304 else:
305 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
306 "No such a Capsule in FDF file: %s" % FdsCommandDict.get("cap")[0])
307
308 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace
309 if ArchList:
310 GenFdsGlobalVariable.ArchList = ArchList
311
312 # Dsc Build Data will handle Pcd Settings from CommandLine.
313
314 """Modify images from build output if the feature of loading driver at fixed address is on."""
315 if GenFdsGlobalVariable.FixedLoadAddress:
316 GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform)
317
318 # Record the FV Region info that may specific in the FD
319 if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict:
320 for FvObj in FdfParserObj.Profile.FvDict.values():
321 for FdObj in FdfParserObj.Profile.FdDict.values():
322 for RegionObj in FdObj.RegionList:
323 if RegionObj.RegionType != BINARY_FILE_TYPE_FV:
324 continue
325 for RegionData in RegionObj.RegionDataList:
326 if FvObj.UiFvName.upper() == RegionData.upper():
327 if FvObj.FvRegionInFD:
328 if FvObj.FvRegionInFD != RegionObj.Size:
329 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName)
330 else:
331 FvObj.FvRegionInFD = RegionObj.Size
332 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)
333
334 """Call GenFds"""
335 GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)
336
337 """Generate GUID cross reference file"""
338 GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj)
339
340 """Display FV space info."""
341 GenFds.DisplayFvSpaceInfo(FdfParserObj)
342
343 except Warning as X:
344 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
345 ReturnCode = FORMAT_INVALID
346 except FatalError as X:
347 if FdsCommandDict.get("debug") is not None:
348 import traceback
349 EdkLogger.quiet(traceback.format_exc())
350 ReturnCode = X.args[0]
351 except:
352 import traceback
353 EdkLogger.error(
354 "\nPython",
355 CODE_ERROR,
356 "Tools code failure",
357 ExtraData="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
358 RaiseError=False
359 )
360 EdkLogger.quiet(traceback.format_exc())
361 ReturnCode = CODE_ERROR
362 finally:
363 ClearDuplicatedInf()
364 return ReturnCode
365
366 def OptionsToCommandDict(Options):
367 FdsCommandDict = {}
368 FdsCommandDict["verbose"] = Options.verbose
369 FdsCommandDict["FixedAddress"] = Options.FixedAddress
370 FdsCommandDict["quiet"] = Options.quiet
371 FdsCommandDict["debug"] = Options.debug
372 FdsCommandDict["Workspace"] = Options.Workspace
373 FdsCommandDict["GenfdsMultiThread"] = Options.GenfdsMultiThread
374 FdsCommandDict["fdf_file"] = [PathClass(Options.filename)] if Options.filename else []
375 FdsCommandDict["build_target"] = Options.BuildTarget
376 FdsCommandDict["toolchain_tag"] = Options.ToolChain
377 FdsCommandDict["active_platform"] = Options.activePlatform
378 FdsCommandDict["OptionPcd"] = Options.OptionPcd
379 FdsCommandDict["conf_directory"] = Options.ConfDirectory
380 FdsCommandDict["IgnoreSources"] = Options.IgnoreSources
381 FdsCommandDict["macro"] = Options.Macros
382 FdsCommandDict["build_architecture_list"] = Options.archList
383 FdsCommandDict["platform_build_directory"] = Options.outputDir
384 FdsCommandDict["fd"] = [Options.uiFdName] if Options.uiFdName else []
385 FdsCommandDict["fv"] = [Options.uiFvName] if Options.uiFvName else []
386 FdsCommandDict["cap"] = [Options.uiCapName] if Options.uiCapName else []
387 return FdsCommandDict
388
389
390 gParamCheck = []
391 def SingleCheckCallback(option, opt_str, value, parser):
392 if option not in gParamCheck:
393 setattr(parser.values, option.dest, value)
394 gParamCheck.append(option)
395 else:
396 parser.error("Option %s only allows one instance in command line!" % option)
397
398 ## Parse command line options
399 #
400 # Using standard Python module optparse to parse command line option of this tool.
401 #
402 # @retval Opt A optparse.Values object containing the parsed options
403 #
404 def myOptionParser():
405 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
406 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))
407 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)
408 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")
409 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
410 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
411 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
412 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
413 action="callback", callback=SingleCheckCallback)
414 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",
415 action="callback", callback=SingleCheckCallback)
416 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",
417 action="callback", callback=SingleCheckCallback)
418 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
419 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
420 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
421 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
422 action="callback", callback=SingleCheckCallback)
423 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
424 action="callback", callback=SingleCheckCallback)
425 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
426 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")
427 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
428 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
429 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
430 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
431
432 Options, _ = Parser.parse_args()
433 return Options
434
435 ## The class implementing the EDK2 flash image generation process
436 #
437 # This process includes:
438 # 1. Collect workspace information, includes platform and module information
439 # 2. Call methods of Fd class to generate FD
440 # 3. Call methods of Fv class to generate FV that not belong to FD
441 #
442 class GenFds(object):
443 FdfParsef = None
444 OnlyGenerateThisFd = None
445 OnlyGenerateThisFv = None
446 OnlyGenerateThisCap = None
447
448 ## GenFd()
449 #
450 # @param OutputDir Output directory
451 # @param FdfParserObject FDF contents parser
452 # @param Workspace The directory of workspace
453 # @param ArchList The Arch list of platform
454 #
455 @staticmethod
456 def GenFd (OutputDir, FdfParserObject, WorkSpace, ArchList):
457 GenFdsGlobalVariable.SetDir ('', FdfParserObject, WorkSpace, ArchList)
458
459 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
460 if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict:
461 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[GenFds.OnlyGenerateThisCap.upper()]
462 if CapsuleObj is not None:
463 CapsuleObj.GenCapsule()
464 return
465
466 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
467 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
468 if FdObj is not None:
469 FdObj.GenFd()
470 return
471 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None:
472 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
473 FdObj.GenFd()
474
475 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")
476 if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict:
477 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[GenFds.OnlyGenerateThisFv.upper()]
478 if FvObj is not None:
479 Buffer = BytesIO()
480 FvObj.AddToBuffer(Buffer)
481 Buffer.close()
482 return
483 elif GenFds.OnlyGenerateThisFv is None:
484 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():
485 Buffer = BytesIO('')
486 FvObj.AddToBuffer(Buffer)
487 Buffer.close()
488
489 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None:
490 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:
491 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")
492 for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values():
493 CapsuleObj.GenCapsule()
494
495 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
496 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")
497 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():
498 OptRomObj.AddToBuffer(None)
499
500 @staticmethod
501 def GenFfsMakefile(OutputDir, FdfParserObject, WorkSpace, ArchList, GlobalData):
502 GenFdsGlobalVariable.SetEnv(FdfParserObject, WorkSpace, ArchList, GlobalData)
503 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
504 FdObj.GenFd(Flag=True)
505
506 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():
507 FvObj.AddToBuffer(Buffer=None, Flag=True)
508
509 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
510 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():
511 OptRomObj.AddToBuffer(Buffer=None, Flag=True)
512
513 return GenFdsGlobalVariable.FfsCmdDict
514
515 ## GetFvBlockSize()
516 #
517 # @param FvObj Whose block size to get
518 # @retval int Block size value
519 #
520 @staticmethod
521 def GetFvBlockSize(FvObj):
522 DefaultBlockSize = 0x1
523 FdObj = None
524 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
525 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
526 if FdObj is None:
527 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
528 for ElementRegion in ElementFd.RegionList:
529 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:
530 for ElementRegionData in ElementRegion.RegionDataList:
531 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
532 if FvObj.BlockSizeList != []:
533 return FvObj.BlockSizeList[0][0]
534 else:
535 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
536 if FvObj.BlockSizeList != []:
537 return FvObj.BlockSizeList[0][0]
538 return DefaultBlockSize
539 else:
540 for ElementRegion in FdObj.RegionList:
541 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:
542 for ElementRegionData in ElementRegion.RegionDataList:
543 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
544 if FvObj.BlockSizeList != []:
545 return FvObj.BlockSizeList[0][0]
546 else:
547 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
548 return DefaultBlockSize
549
550 ## DisplayFvSpaceInfo()
551 #
552 # @param FvObj Whose block size to get
553 # @retval None
554 #
555 @staticmethod
556 def DisplayFvSpaceInfo(FdfParserObject):
557
558 FvSpaceInfoList = []
559 MaxFvNameLength = 0
560 for FvName in FdfParserObject.Profile.FvDict:
561 if len(FvName) > MaxFvNameLength:
562 MaxFvNameLength = len(FvName)
563 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')
564 if os.path.exists(FvSpaceInfoFileName):
565 FileLinesList = getlines(FvSpaceInfoFileName)
566 TotalFound = False
567 Total = ''
568 UsedFound = False
569 Used = ''
570 FreeFound = False
571 Free = ''
572 for Line in FileLinesList:
573 NameValue = Line.split('=')
574 if len(NameValue) == 2:
575 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
576 TotalFound = True
577 Total = NameValue[1].strip()
578 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
579 UsedFound = True
580 Used = NameValue[1].strip()
581 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
582 FreeFound = True
583 Free = NameValue[1].strip()
584
585 if TotalFound and UsedFound and FreeFound:
586 FvSpaceInfoList.append((FvName, Total, Used, Free))
587
588 GenFdsGlobalVariable.InfLogger('\nFV Space Information')
589 for FvSpaceInfo in FvSpaceInfoList:
590 Name = FvSpaceInfo[0]
591 TotalSizeValue = long(FvSpaceInfo[1], 0)
592 UsedSizeValue = long(FvSpaceInfo[2], 0)
593 FreeSizeValue = long(FvSpaceInfo[3], 0)
594 if UsedSizeValue == TotalSizeValue:
595 Percentage = '100'
596 else:
597 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')
598
599 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')
600
601 ## PreprocessImage()
602 #
603 # @param BuildDb Database from build meta data files
604 # @param DscFile modules from dsc file will be preprocessed
605 # @retval None
606 #
607 @staticmethod
608 def PreprocessImage(BuildDb, DscFile):
609 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds
610 PcdValue = ''
611 for Key in PcdDict:
612 PcdObj = PcdDict[Key]
613 if PcdObj.TokenCName == 'PcdBsBaseAddress':
614 PcdValue = PcdObj.DefaultValue
615 break
616
617 if PcdValue == '':
618 return
619
620 Int64PcdValue = long(PcdValue, 0)
621 if Int64PcdValue == 0 or Int64PcdValue < -1:
622 return
623
624 TopAddress = 0
625 if Int64PcdValue > 0:
626 TopAddress = Int64PcdValue
627
628 ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules
629 for Key in ModuleDict:
630 ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
631 print(ModuleObj.BaseName + ' ' + ModuleObj.ModuleType)
632
633 @staticmethod
634 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):
635 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")
636 GuidXRefFile = BytesIO('')
637 PkgGuidDict = {}
638 GuidDict = {}
639 ModuleList = []
640 FileGuidList = []
641 for Arch in ArchList:
642 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
643 PkgList = GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag)
644 for P in PkgList:
645 PkgGuidDict.update(P.Guids)
646 for Name, Guid in PlatformDataBase.Pcds:
647 Pcd = PlatformDataBase.Pcds[Name, Guid]
648 if Pcd.Type in [TAB_PCDS_DYNAMIC_HII, TAB_PCDS_DYNAMIC_EX_HII]:
649 for SkuId in Pcd.SkuInfoList:
650 Sku = Pcd.SkuInfoList[SkuId]
651 if Sku.VariableGuid and Sku.VariableGuid in PkgGuidDict.keys():
652 GuidDict[Sku.VariableGuid] = PkgGuidDict[Sku.VariableGuid]
653 for ModuleFile in PlatformDataBase.Modules:
654 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
655 if Module in ModuleList:
656 continue
657 else:
658 ModuleList.append(Module)
659 if GlobalData.gGuidPattern.match(ModuleFile.BaseName):
660 GuidXRefFile.write("%s %s\n" % (ModuleFile.BaseName, Module.BaseName))
661 else:
662 GuidXRefFile.write("%s %s\n" % (Module.Guid, Module.BaseName))
663 GuidDict.update(Module.Protocols)
664 GuidDict.update(Module.Guids)
665 GuidDict.update(Module.Ppis)
666 for FvName in FdfParserObj.Profile.FvDict:
667 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:
668 if not isinstance(FfsObj, FileStatement):
669 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))
670 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
671 if FdfModule in ModuleList:
672 continue
673 else:
674 ModuleList.append(FdfModule)
675 GuidXRefFile.write("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))
676 GuidDict.update(FdfModule.Protocols)
677 GuidDict.update(FdfModule.Guids)
678 GuidDict.update(FdfModule.Ppis)
679 else:
680 FileStatementGuid = FfsObj.NameGuid
681 if FileStatementGuid in FileGuidList:
682 continue
683 else:
684 FileGuidList.append(FileStatementGuid)
685 Name = []
686 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
687 FfsPath = glob(os.path.join(FfsPath, FileStatementGuid) + TAB_STAR)
688 if not FfsPath:
689 continue
690 if not os.path.exists(FfsPath[0]):
691 continue
692 MatchDict = {}
693 ReFileEnds = compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
694 FileList = os.listdir(FfsPath[0])
695 for File in FileList:
696 Match = ReFileEnds.search(File)
697 if Match:
698 for Index in range(1, 8):
699 if Match.group(Index) and Match.group(Index) in MatchDict:
700 MatchDict[Match.group(Index)].append(File)
701 elif Match.group(Index):
702 MatchDict[Match.group(Index)] = [File]
703 if not MatchDict:
704 continue
705 if '.ui' in MatchDict:
706 for File in MatchDict['.ui']:
707 with open(os.path.join(FfsPath[0], File), 'rb') as F:
708 F.read()
709 length = F.tell()
710 F.seek(4)
711 TmpStr = unpack('%dh' % ((length - 4) / 2), F.read())
712 Name = ''.join(chr(c) for c in TmpStr[:-1])
713 else:
714 FileList = []
715 if 'fv.sec.txt' in MatchDict:
716 FileList = MatchDict['fv.sec.txt']
717 elif '.pe32.txt' in MatchDict:
718 FileList = MatchDict['.pe32.txt']
719 elif '.te.txt' in MatchDict:
720 FileList = MatchDict['.te.txt']
721 elif '.pic.txt' in MatchDict:
722 FileList = MatchDict['.pic.txt']
723 elif '.raw.txt' in MatchDict:
724 FileList = MatchDict['.raw.txt']
725 elif '.ffs.txt' in MatchDict:
726 FileList = MatchDict['.ffs.txt']
727 else:
728 pass
729 for File in FileList:
730 with open(os.path.join(FfsPath[0], File), 'r') as F:
731 Name.append((F.read().split()[-1]))
732 if not Name:
733 continue
734
735 Name = ' '.join(Name) if isinstance(Name, type([])) else Name
736 GuidXRefFile.write("%s %s\n" %(FileStatementGuid, Name))
737
738 # Append GUIDs, Protocols, and PPIs to the Xref file
739 GuidXRefFile.write("\n")
740 for key, item in GuidDict.items():
741 GuidXRefFile.write("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))
742
743 if GuidXRefFile.getvalue():
744 SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False)
745 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)
746 elif os.path.exists(GuidXRefFileName):
747 os.remove(GuidXRefFileName)
748 GuidXRefFile.close()
749
750
751 if __name__ == '__main__':
752 r = main()
753 ## 0-127 is a safe return range, and 1 is a standard default error
754 if r < 0 or r > 127:
755 r = 1
756 exit(r)
757