BaseTools: Replace StringIO.StringIO with io.BytesIO
[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 optparse import OptionParser
20 import sys
21 import Common.LongFilePathOs as os
22 import linecache
23 import FdfParser
24 import Common.BuildToolError as BuildToolError
25 from GenFdsGlobalVariable import GenFdsGlobalVariable
26 from Workspace.WorkspaceDatabase import WorkspaceDatabase
27 from Workspace.BuildClassObject import PcdClassObject
28 import RuleComplexFile
29 from EfiSection import EfiSection
30 from io import BytesIO
31 import Common.TargetTxtClassObject as TargetTxtClassObject
32 import Common.ToolDefClassObject as ToolDefClassObject
33 from Common.DataType import *
34 import Common.GlobalData as GlobalData
35 from Common import EdkLogger
36 from Common.StringUtils import *
37 from Common.Misc import DirCache, PathClass
38 from Common.Misc import SaveFileOnChange
39 from Common.Misc import ClearDuplicatedInf
40 from Common.Misc import GuidStructureStringToGuidString
41 from Common.BuildVersion import gBUILD_VERSION
42 from Common.MultipleWorkspace import MultipleWorkspace as mws
43 import FfsFileStatement
44 import glob
45 from struct import unpack
46
47 ## Version and Copyright
48 versionNumber = "1.0" + ' ' + gBUILD_VERSION
49 __version__ = "%prog Version " + versionNumber
50 __copyright__ = "Copyright (c) 2007 - 2017, 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
65 global Workspace
66 Workspace = ""
67 ArchList = None
68 ReturnCode = 0
69
70 EdkLogger.Initialize()
71 try:
72 if Options.verbose is not None:
73 EdkLogger.SetLevel(EdkLogger.VERBOSE)
74 GenFdsGlobalVariable.VerboseMode = True
75
76 if Options.FixedAddress is not None:
77 GenFdsGlobalVariable.FixedLoadAddress = True
78
79 if Options.quiet is not None:
80 EdkLogger.SetLevel(EdkLogger.QUIET)
81 if Options.debug is not None:
82 EdkLogger.SetLevel(Options.debug + 1)
83 GenFdsGlobalVariable.DebugLevel = Options.debug
84 else:
85 EdkLogger.SetLevel(EdkLogger.INFO)
86
87 if (Options.Workspace is None):
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(Options.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(Options.Workspace)
95 GenFdsGlobalVariable.WorkSpaceDir = Workspace
96 if 'EDK_SOURCE' in os.environ:
97 GenFdsGlobalVariable.EdkSourceDir = os.path.normcase(os.environ['EDK_SOURCE'])
98 if (Options.debug):
99 GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace)
100 if Options.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 (Options.filename):
109 FdfFilename = Options.filename
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 (Options.BuildTarget):
125 GenFdsGlobalVariable.TargetName = Options.BuildTarget
126
127 if (Options.ToolChain):
128 GenFdsGlobalVariable.ToolChainTag = Options.ToolChain
129
130 if (Options.activePlatform):
131 ActivePlatform = Options.activePlatform
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 = Options.OptionPcd if Options.OptionPcd else {}
146 GenFdsGlobalVariable.ActivePlatform = PathClass(NormPath(ActivePlatform))
147
148 if (Options.ConfDirectory):
149 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
150 ConfDirectoryPath = os.path.normpath(Options.ConfDirectory)
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.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[DataType.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[DataType.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 = Options.IgnoreSources
192
193 if Options.Macros:
194 for Pair in Options.Macros:
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 BuildWorkSpace = WorkspaceDatabase(GlobalData.gDatabasePath)
230 BuildWorkSpace.InitDatabase()
231
232 #
233 # Get files real name in workspace dir
234 #
235 GlobalData.gAllFiles = DirCache(Workspace)
236 GlobalData.gWorkspace = Workspace
237
238 if (Options.archList) :
239 ArchList = Options.archList.split(',')
240 else:
241 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
242 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, Options.BuildTarget, Options.ToolChain].SupArchList
243
244 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, Options.BuildTarget, Options.ToolChain].SupArchList) & set(ArchList)
245 if len(TargetArchList) == 0:
246 EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON].SupArchList)))
247
248 for Arch in ArchList:
249 GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Options.BuildTarget, Options.ToolChain].OutputDirectory)
250 GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Options.BuildTarget, Options.ToolChain].PlatformName
251
252 if (Options.outputDir):
253 OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(Options.outputDir)
254 if not os.path.isabs (OutputDirFromCommandLine):
255 OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine)
256 for Arch in ArchList:
257 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine
258 else:
259 for Arch in ArchList:
260 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)
261
262 for Key in GenFdsGlobalVariable.OutputDirDict:
263 OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]
264 if OutputDir[0:2] == '..':
265 OutputDir = os.path.realpath(OutputDir)
266
267 if OutputDir[1] != ':':
268 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)
269
270 if not os.path.exists(OutputDir):
271 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir)
272 GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir
273
274 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
275 FdfParserObj = FdfParser.FdfParser(FdfFilename)
276 FdfParserObj.ParseFile()
277
278 if FdfParserObj.CycleReferenceCheck():
279 EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")
280
281 if (Options.uiFdName) :
282 if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict:
283 GenFds.OnlyGenerateThisFd = Options.uiFdName
284 else:
285 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
286 "No such an FD in FDF file: %s" % Options.uiFdName)
287
288 if (Options.uiFvName) :
289 if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict:
290 GenFds.OnlyGenerateThisFv = Options.uiFvName
291 else:
292 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
293 "No such an FV in FDF file: %s" % Options.uiFvName)
294
295 if (Options.uiCapName) :
296 if Options.uiCapName.upper() in FdfParserObj.Profile.CapsuleDict:
297 GenFds.OnlyGenerateThisCap = Options.uiCapName
298 else:
299 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
300 "No such a Capsule in FDF file: %s" % Options.uiCapName)
301
302 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace
303 if ArchList is not None:
304 GenFdsGlobalVariable.ArchList = ArchList
305
306 # Dsc Build Data will handle Pcd Settings from CommandLine.
307
308 """Modify images from build output if the feature of loading driver at fixed address is on."""
309 if GenFdsGlobalVariable.FixedLoadAddress:
310 GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform)
311
312 # Record the FV Region info that may specific in the FD
313 if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict:
314 for Fv in FdfParserObj.Profile.FvDict:
315 FvObj = FdfParserObj.Profile.FvDict[Fv]
316 for Fd in FdfParserObj.Profile.FdDict:
317 FdObj = FdfParserObj.Profile.FdDict[Fd]
318 for RegionObj in FdObj.RegionList:
319 if RegionObj.RegionType != BINARY_FILE_TYPE_FV:
320 continue
321 for RegionData in RegionObj.RegionDataList:
322 if FvObj.UiFvName.upper() == RegionData.upper():
323 if FvObj.FvRegionInFD:
324 if FvObj.FvRegionInFD != RegionObj.Size:
325 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName)
326 else:
327 FvObj.FvRegionInFD = RegionObj.Size
328 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)
329
330 """Call GenFds"""
331 GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)
332
333 """Generate GUID cross reference file"""
334 GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj)
335
336 """Display FV space info."""
337 GenFds.DisplayFvSpaceInfo(FdfParserObj)
338
339 except FdfParser.Warning as X:
340 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
341 ReturnCode = FORMAT_INVALID
342 except FatalError as X:
343 if Options.debug is not None:
344 import traceback
345 EdkLogger.quiet(traceback.format_exc())
346 ReturnCode = X.args[0]
347 except:
348 import traceback
349 EdkLogger.error(
350 "\nPython",
351 CODE_ERROR,
352 "Tools code failure",
353 ExtraData="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
354 RaiseError=False
355 )
356 EdkLogger.quiet(traceback.format_exc())
357 ReturnCode = CODE_ERROR
358 finally:
359 ClearDuplicatedInf()
360 return ReturnCode
361
362 gParamCheck = []
363 def SingleCheckCallback(option, opt_str, value, parser):
364 if option not in gParamCheck:
365 setattr(parser.values, option.dest, value)
366 gParamCheck.append(option)
367 else:
368 parser.error("Option %s only allows one instance in command line!" % option)
369
370 ## FindExtendTool()
371 #
372 # Find location of tools to process data
373 #
374 # @param KeyStringList Filter for inputs of section generation
375 # @param CurrentArchList Arch list
376 # @param NameGuid The Guid name
377 #
378 def FindExtendTool(KeyStringList, CurrentArchList, NameGuid):
379 ToolDb = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDatabase
380 # if user not specify filter, try to deduce it from global data.
381 if KeyStringList is None or KeyStringList == []:
382 Target = GenFdsGlobalVariable.TargetName
383 ToolChain = GenFdsGlobalVariable.ToolChainTag
384 if ToolChain not in ToolDb['TOOL_CHAIN_TAG']:
385 EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain)
386 KeyStringList = [Target + '_' + ToolChain + '_' + CurrentArchList[0]]
387 for Arch in CurrentArchList:
388 if Target + '_' + ToolChain + '_' + Arch not in KeyStringList:
389 KeyStringList.append(Target + '_' + ToolChain + '_' + Arch)
390
391 if GenFdsGlobalVariable.GuidToolDefinition:
392 if NameGuid in GenFdsGlobalVariable.GuidToolDefinition:
393 return GenFdsGlobalVariable.GuidToolDefinition[NameGuid]
394
395 ToolDefinition = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDictionary
396 ToolPathTmp = None
397 ToolOption = None
398 ToolPathKey = None
399 ToolOptionKey = None
400 KeyList = None
401 for ToolDef in ToolDefinition.items():
402 if NameGuid.lower() == ToolDef[1].lower() :
403 KeyList = ToolDef[0].split('_')
404 Key = KeyList[0] + \
405 '_' + \
406 KeyList[1] + \
407 '_' + \
408 KeyList[2]
409 if Key in KeyStringList and KeyList[4] == TAB_GUID:
410 ToolPathKey = Key + '_' + KeyList[3] + '_PATH'
411 ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
412 ToolPath = ToolDefinition.get(ToolPathKey)
413 ToolOption = ToolDefinition.get(ToolOptionKey)
414 if ToolPathTmp is None:
415 ToolPathTmp = ToolPath
416 else:
417 if ToolPathTmp != ToolPath:
418 EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath))
419
420 BuildOption = {}
421 for Arch in CurrentArchList:
422 Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
423 # key is (ToolChainFamily, ToolChain, CodeBase)
424 for item in Platform.BuildOptions:
425 if '_PATH' in item[1] or '_FLAGS' in item[1] or '_GUID' in item[1]:
426 if not item[0] or (item[0] and GenFdsGlobalVariable.ToolChainFamily== item[0]):
427 if item[1] not in BuildOption:
428 BuildOption[item[1]] = Platform.BuildOptions[item]
429 if BuildOption:
430 ToolList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH]
431 for Index in range(2, -1, -1):
432 for Key in list(BuildOption.keys()):
433 List = Key.split('_')
434 if List[Index] == '*':
435 for String in ToolDb[ToolList[Index]]:
436 if String in [Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]:
437 List[Index] = String
438 NewKey = '%s_%s_%s_%s_%s' % tuple(List)
439 if NewKey not in BuildOption:
440 BuildOption[NewKey] = BuildOption[Key]
441 continue
442 del BuildOption[Key]
443 elif List[Index] not in ToolDb[ToolList[Index]]:
444 del BuildOption[Key]
445 if BuildOption:
446 if not KeyList:
447 for Op in BuildOption:
448 if NameGuid == BuildOption[Op]:
449 KeyList = Op.split('_')
450 Key = KeyList[0] + '_' + KeyList[1] +'_' + KeyList[2]
451 if Key in KeyStringList and KeyList[4] == TAB_GUID:
452 ToolPathKey = Key + '_' + KeyList[3] + '_PATH'
453 ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
454 if ToolPathKey in BuildOption:
455 ToolPathTmp = BuildOption[ToolPathKey]
456 if ToolOptionKey in BuildOption:
457 ToolOption = BuildOption[ToolOptionKey]
458
459 GenFdsGlobalVariable.GuidToolDefinition[NameGuid] = (ToolPathTmp, ToolOption)
460 return ToolPathTmp, ToolOption
461
462 ## Parse command line options
463 #
464 # Using standard Python module optparse to parse command line option of this tool.
465 #
466 # @retval Opt A optparse.Values object containing the parsed options
467 # @retval Args Target of build command
468 #
469 def myOptionParser():
470 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
471 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))
472 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)
473 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")
474 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
475 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
476 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
477 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
478 action="callback", callback=SingleCheckCallback)
479 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",
480 action="callback", callback=SingleCheckCallback)
481 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",
482 action="callback", callback=SingleCheckCallback)
483 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
484 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
485 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
486 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
487 action="callback", callback=SingleCheckCallback)
488 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
489 action="callback", callback=SingleCheckCallback)
490 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
491 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")
492 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
493 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
494 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
495 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
496
497 (Options, args) = Parser.parse_args()
498 return Options
499
500 ## The class implementing the EDK2 flash image generation process
501 #
502 # This process includes:
503 # 1. Collect workspace information, includes platform and module information
504 # 2. Call methods of Fd class to generate FD
505 # 3. Call methods of Fv class to generate FV that not belong to FD
506 #
507 class GenFds :
508 FdfParsef = None
509 # FvName, FdName, CapName in FDF, Image file name
510 ImageBinDict = {}
511 OnlyGenerateThisFd = None
512 OnlyGenerateThisFv = None
513 OnlyGenerateThisCap = None
514
515 ## GenFd()
516 #
517 # @param OutputDir Output directory
518 # @param FdfParser FDF contents parser
519 # @param Workspace The directory of workspace
520 # @param ArchList The Arch list of platform
521 #
522 def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):
523 GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)
524
525 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
526 if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict:
527 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[GenFds.OnlyGenerateThisCap.upper()]
528 if CapsuleObj is not None:
529 CapsuleObj.GenCapsule()
530 return
531
532 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
533 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
534 if FdObj is not None:
535 FdObj.GenFd()
536 return
537 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None:
538 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
539 FdObj.GenFd()
540
541 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")
542 if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict:
543 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[GenFds.OnlyGenerateThisFv.upper()]
544 if FvObj is not None:
545 Buffer = BytesIO()
546 FvObj.AddToBuffer(Buffer)
547 Buffer.close()
548 return
549 elif GenFds.OnlyGenerateThisFv is None:
550 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():
551 Buffer = BytesIO('')
552 FvObj.AddToBuffer(Buffer)
553 Buffer.close()
554
555 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None:
556 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:
557 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")
558 for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values():
559 CapsuleObj.GenCapsule()
560
561 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
562 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")
563 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():
564 OptRomObj.AddToBuffer(None)
565 @staticmethod
566 def GenFfsMakefile(OutputDir, FdfParser, WorkSpace, ArchList, GlobalData):
567 GenFdsGlobalVariable.SetEnv(FdfParser, WorkSpace, ArchList, GlobalData)
568 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
569 FdObj.GenFd(Flag=True)
570
571 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():
572 FvObj.AddToBuffer(Buffer=None, Flag=True)
573
574 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
575 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():
576 OptRomObj.AddToBuffer(Buffer=None, Flag=True)
577
578 return GenFdsGlobalVariable.FfsCmdDict
579
580 ## GetFvBlockSize()
581 #
582 # @param FvObj Whose block size to get
583 # @retval int Block size value
584 #
585 def GetFvBlockSize(FvObj):
586 DefaultBlockSize = 0x1
587 FdObj = None
588 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
589 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
590 if FdObj is None:
591 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
592 for ElementRegion in ElementFd.RegionList:
593 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:
594 for ElementRegionData in ElementRegion.RegionDataList:
595 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
596 if FvObj.BlockSizeList != []:
597 return FvObj.BlockSizeList[0][0]
598 else:
599 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
600 if FvObj.BlockSizeList != []:
601 return FvObj.BlockSizeList[0][0]
602 return DefaultBlockSize
603 else:
604 for ElementRegion in FdObj.RegionList:
605 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:
606 for ElementRegionData in ElementRegion.RegionDataList:
607 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
608 if FvObj.BlockSizeList != []:
609 return FvObj.BlockSizeList[0][0]
610 else:
611 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
612 return DefaultBlockSize
613
614 ## DisplayFvSpaceInfo()
615 #
616 # @param FvObj Whose block size to get
617 # @retval None
618 #
619 def DisplayFvSpaceInfo(FdfParser):
620
621 FvSpaceInfoList = []
622 MaxFvNameLength = 0
623 for FvName in FdfParser.Profile.FvDict:
624 if len(FvName) > MaxFvNameLength:
625 MaxFvNameLength = len(FvName)
626 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')
627 if os.path.exists(FvSpaceInfoFileName):
628 FileLinesList = linecache.getlines(FvSpaceInfoFileName)
629 TotalFound = False
630 Total = ''
631 UsedFound = False
632 Used = ''
633 FreeFound = False
634 Free = ''
635 for Line in FileLinesList:
636 NameValue = Line.split('=')
637 if len(NameValue) == 2:
638 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
639 TotalFound = True
640 Total = NameValue[1].strip()
641 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
642 UsedFound = True
643 Used = NameValue[1].strip()
644 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
645 FreeFound = True
646 Free = NameValue[1].strip()
647
648 if TotalFound and UsedFound and FreeFound:
649 FvSpaceInfoList.append((FvName, Total, Used, Free))
650
651 GenFdsGlobalVariable.InfLogger('\nFV Space Information')
652 for FvSpaceInfo in FvSpaceInfoList:
653 Name = FvSpaceInfo[0]
654 TotalSizeValue = long(FvSpaceInfo[1], 0)
655 UsedSizeValue = long(FvSpaceInfo[2], 0)
656 FreeSizeValue = long(FvSpaceInfo[3], 0)
657 if UsedSizeValue == TotalSizeValue:
658 Percentage = '100'
659 else:
660 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')
661
662 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')
663
664 ## PreprocessImage()
665 #
666 # @param BuildDb Database from build meta data files
667 # @param DscFile modules from dsc file will be preprocessed
668 # @retval None
669 #
670 def PreprocessImage(BuildDb, DscFile):
671 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds
672 PcdValue = ''
673 for Key in PcdDict:
674 PcdObj = PcdDict[Key]
675 if PcdObj.TokenCName == 'PcdBsBaseAddress':
676 PcdValue = PcdObj.DefaultValue
677 break
678
679 if PcdValue == '':
680 return
681
682 Int64PcdValue = long(PcdValue, 0)
683 if Int64PcdValue == 0 or Int64PcdValue < -1:
684 return
685
686 TopAddress = 0
687 if Int64PcdValue > 0:
688 TopAddress = Int64PcdValue
689
690 ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules
691 for Key in ModuleDict:
692 ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
693 print(ModuleObj.BaseName + ' ' + ModuleObj.ModuleType)
694
695 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):
696 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")
697 GuidXRefFile = BytesIO('')
698 GuidDict = {}
699 ModuleList = []
700 FileGuidList = []
701 for Arch in ArchList:
702 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
703 for ModuleFile in PlatformDataBase.Modules:
704 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
705 if Module in ModuleList:
706 continue
707 else:
708 ModuleList.append(Module)
709 GuidXRefFile.write("%s %s\n" % (Module.Guid, Module.BaseName))
710 for key, item in Module.Protocols.items():
711 GuidDict[key] = item
712 for key, item in Module.Guids.items():
713 GuidDict[key] = item
714 for key, item in Module.Ppis.items():
715 GuidDict[key] = item
716 for FvName in FdfParserObj.Profile.FvDict:
717 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:
718 if not isinstance(FfsObj, FfsFileStatement.FileStatement):
719 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))
720 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
721 if FdfModule in ModuleList:
722 continue
723 else:
724 ModuleList.append(FdfModule)
725 GuidXRefFile.write("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))
726 for key, item in FdfModule.Protocols.items():
727 GuidDict[key] = item
728 for key, item in FdfModule.Guids.items():
729 GuidDict[key] = item
730 for key, item in FdfModule.Ppis.items():
731 GuidDict[key] = item
732 else:
733 FileStatementGuid = FfsObj.NameGuid
734 if FileStatementGuid in FileGuidList:
735 continue
736 else:
737 FileGuidList.append(FileStatementGuid)
738 Name = []
739 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
740 FfsPath = glob.glob(os.path.join(FfsPath, FileStatementGuid) + '*')
741 if not FfsPath:
742 continue
743 if not os.path.exists(FfsPath[0]):
744 continue
745 MatchDict = {}
746 ReFileEnds = re.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
747 FileList = os.listdir(FfsPath[0])
748 for File in FileList:
749 Match = ReFileEnds.search(File)
750 if Match:
751 for Index in range(1, 8):
752 if Match.group(Index) and Match.group(Index) in MatchDict:
753 MatchDict[Match.group(Index)].append(File)
754 elif Match.group(Index):
755 MatchDict[Match.group(Index)] = [File]
756 if not MatchDict:
757 continue
758 if '.ui' in MatchDict:
759 for File in MatchDict['.ui']:
760 with open(os.path.join(FfsPath[0], File), 'rb') as F:
761 F.read()
762 length = F.tell()
763 F.seek(4)
764 TmpStr = unpack('%dh' % ((length - 4) / 2), F.read())
765 Name = ''.join(chr(c) for c in TmpStr[:-1])
766 else:
767 FileList = []
768 if 'fv.sec.txt' in MatchDict:
769 FileList = MatchDict['fv.sec.txt']
770 elif '.pe32.txt' in MatchDict:
771 FileList = MatchDict['.pe32.txt']
772 elif '.te.txt' in MatchDict:
773 FileList = MatchDict['.te.txt']
774 elif '.pic.txt' in MatchDict:
775 FileList = MatchDict['.pic.txt']
776 elif '.raw.txt' in MatchDict:
777 FileList = MatchDict['.raw.txt']
778 elif '.ffs.txt' in MatchDict:
779 FileList = MatchDict['.ffs.txt']
780 else:
781 pass
782 for File in FileList:
783 with open(os.path.join(FfsPath[0], File), 'r') as F:
784 Name.append((F.read().split()[-1]))
785 if not Name:
786 continue
787
788 Name = ' '.join(Name) if isinstance(Name, type([])) else Name
789 GuidXRefFile.write("%s %s\n" %(FileStatementGuid, Name))
790
791 # Append GUIDs, Protocols, and PPIs to the Xref file
792 GuidXRefFile.write("\n")
793 for key, item in GuidDict.items():
794 GuidXRefFile.write("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))
795
796 if GuidXRefFile.getvalue():
797 SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False)
798 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)
799 elif os.path.exists(GuidXRefFileName):
800 os.remove(GuidXRefFileName)
801 GuidXRefFile.close()
802
803 ##Define GenFd as static function
804 GenFd = staticmethod(GenFd)
805 GetFvBlockSize = staticmethod(GetFvBlockSize)
806 DisplayFvSpaceInfo = staticmethod(DisplayFvSpaceInfo)
807 PreprocessImage = staticmethod(PreprocessImage)
808 GenerateGuidXRefFile = staticmethod(GenerateGuidXRefFile)
809
810 if __name__ == '__main__':
811 r = main()
812 ## 0-127 is a safe return range, and 1 is a standard default error
813 if r < 0 or r > 127: r = 1
814 sys.exit(r)
815