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