]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/GenFds.py
BaseTools: Improve build performance of structure PCD value generation
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / GenFds.py
1 ## @file
2 # generate flash image
3 #
4 # Copyright (c) 2007 - 2017, 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 optparse import OptionParser
19 import sys
20 import Common.LongFilePathOs as os
21 import linecache
22 import FdfParser
23 import Common.BuildToolError as BuildToolError
24 from GenFdsGlobalVariable import GenFdsGlobalVariable
25 from Workspace.WorkspaceDatabase import WorkspaceDatabase
26 from Workspace.BuildClassObject import PcdClassObject
27 from Workspace.BuildClassObject import ModuleBuildClassObject
28 import RuleComplexFile
29 from EfiSection import EfiSection
30 import StringIO
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.String 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.Misc import CheckPcdDatum
42 from Common.Misc import BuildOptionPcdValueFormat
43 from Common.BuildVersion import gBUILD_VERSION
44 from Common.MultipleWorkspace import MultipleWorkspace as mws
45 import FfsFileStatement
46 import glob
47 from struct import unpack
48
49 ## Version and Copyright
50 versionNumber = "1.0" + ' ' + gBUILD_VERSION
51 __version__ = "%prog Version " + versionNumber
52 __copyright__ = "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
53
54 ## Tool entrance method
55 #
56 # This method mainly dispatch specific methods per the command line options.
57 # If no error found, return zero value so the caller of this tool can know
58 # if it's executed successfully or not.
59 #
60 # @retval 0 Tool was successful
61 # @retval 1 Tool failed
62 #
63 def main():
64 global Options
65 Options = myOptionParser()
66
67 global Workspace
68 Workspace = ""
69 ArchList = None
70 ReturnCode = 0
71
72 EdkLogger.Initialize()
73 try:
74 if Options.verbose != None:
75 EdkLogger.SetLevel(EdkLogger.VERBOSE)
76 GenFdsGlobalVariable.VerboseMode = True
77
78 if Options.FixedAddress != None:
79 GenFdsGlobalVariable.FixedLoadAddress = True
80
81 if Options.quiet != None:
82 EdkLogger.SetLevel(EdkLogger.QUIET)
83 if Options.debug != None:
84 EdkLogger.SetLevel(Options.debug + 1)
85 GenFdsGlobalVariable.DebugLevel = Options.debug
86 else:
87 EdkLogger.SetLevel(EdkLogger.INFO)
88
89 if (Options.Workspace == None):
90 EdkLogger.error("GenFds", OPTION_MISSING, "WORKSPACE not defined",
91 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
92 elif not os.path.exists(Options.Workspace):
93 EdkLogger.error("GenFds", PARAMETER_INVALID, "WORKSPACE is invalid",
94 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
95 else:
96 Workspace = os.path.normcase(Options.Workspace)
97 GenFdsGlobalVariable.WorkSpaceDir = Workspace
98 if 'EDK_SOURCE' in os.environ.keys():
99 GenFdsGlobalVariable.EdkSourceDir = os.path.normcase(os.environ['EDK_SOURCE'])
100 if (Options.debug):
101 GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace)
102 if Options.GenfdsMultiThread:
103 GenFdsGlobalVariable.EnableGenfdsMultiThread = True
104 os.chdir(GenFdsGlobalVariable.WorkSpaceDir)
105
106 # set multiple workspace
107 PackagesPath = os.getenv("PACKAGES_PATH")
108 mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath)
109
110 if (Options.filename):
111 FdfFilename = Options.filename
112 FdfFilename = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdfFilename)
113
114 if FdfFilename[0:2] == '..':
115 FdfFilename = os.path.realpath(FdfFilename)
116 if not os.path.isabs(FdfFilename):
117 FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)
118 if not os.path.exists(FdfFilename):
119 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename)
120
121 GenFdsGlobalVariable.FdfFile = FdfFilename
122 GenFdsGlobalVariable.FdfFileTimeStamp = os.path.getmtime(FdfFilename)
123 else:
124 EdkLogger.error("GenFds", OPTION_MISSING, "Missing FDF filename")
125
126 if (Options.BuildTarget):
127 GenFdsGlobalVariable.TargetName = Options.BuildTarget
128
129 if (Options.ToolChain):
130 GenFdsGlobalVariable.ToolChainTag = Options.ToolChain
131
132 if (Options.activePlatform):
133 ActivePlatform = Options.activePlatform
134 ActivePlatform = GenFdsGlobalVariable.ReplaceWorkspaceMacro(ActivePlatform)
135
136 if ActivePlatform[0:2] == '..':
137 ActivePlatform = os.path.realpath(ActivePlatform)
138
139 if not os.path.isabs (ActivePlatform):
140 ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)
141
142 if not os.path.exists(ActivePlatform) :
143 EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!")
144 else:
145 EdkLogger.error("GenFds", OPTION_MISSING, "Missing active platform")
146
147 GenFdsGlobalVariable.ActivePlatform = PathClass(NormPath(ActivePlatform))
148
149 if (Options.ConfDirectory):
150 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
151 ConfDirectoryPath = os.path.normpath(Options.ConfDirectory)
152 if ConfDirectoryPath.startswith('"'):
153 ConfDirectoryPath = ConfDirectoryPath[1:]
154 if ConfDirectoryPath.endswith('"'):
155 ConfDirectoryPath = ConfDirectoryPath[:-1]
156 if not os.path.isabs(ConfDirectoryPath):
157 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
158 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
159 ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ConfDirectoryPath)
160 else:
161 if "CONF_PATH" in os.environ.keys():
162 ConfDirectoryPath = os.path.normcase(os.environ["CONF_PATH"])
163 else:
164 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
165 ConfDirectoryPath = mws.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf')
166 GenFdsGlobalVariable.ConfDir = ConfDirectoryPath
167 BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt"))
168 if os.path.isfile(BuildConfigurationFile) == True:
169 TargetTxt = TargetTxtClassObject.TargetTxtClassObject()
170 TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
171 # if no build target given in command line, get it from target.txt
172 if not GenFdsGlobalVariable.TargetName:
173 BuildTargetList = TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
174 if len(BuildTargetList) != 1:
175 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for Target.")
176 GenFdsGlobalVariable.TargetName = BuildTargetList[0]
177
178 # if no tool chain given in command line, get it from target.txt
179 if not GenFdsGlobalVariable.ToolChainTag:
180 ToolChainList = TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
181 if ToolChainList == None or len(ToolChainList) == 0:
182 EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.")
183 if len(ToolChainList) != 1:
184 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for ToolChain.")
185 GenFdsGlobalVariable.ToolChainTag = ToolChainList[0]
186 else:
187 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
188
189 #Set global flag for build mode
190 GlobalData.gIgnoreSource = Options.IgnoreSources
191
192 if Options.Macros:
193 for Pair in Options.Macros:
194 if Pair.startswith('"'):
195 Pair = Pair[1:]
196 if Pair.endswith('"'):
197 Pair = Pair[:-1]
198 List = Pair.split('=')
199 if len(List) == 2:
200 if not List[1].strip():
201 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="No Value given for Macro %s" %List[0])
202 if List[0].strip() == "EFI_SOURCE":
203 GlobalData.gEfiSource = List[1].strip()
204 GlobalData.gGlobalDefines["EFI_SOURCE"] = GlobalData.gEfiSource
205 continue
206 elif List[0].strip() == "EDK_SOURCE":
207 GlobalData.gEdkSource = List[1].strip()
208 GlobalData.gGlobalDefines["EDK_SOURCE"] = GlobalData.gEdkSource
209 continue
210 elif List[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
211 GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip()
212 else:
213 GlobalData.gCommandLineDefines[List[0].strip()] = List[1].strip()
214 else:
215 GlobalData.gCommandLineDefines[List[0].strip()] = "TRUE"
216 os.environ["WORKSPACE"] = Workspace
217
218 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
219 if "TARGET" not in GlobalData.gGlobalDefines.keys():
220 GlobalData.gGlobalDefines["TARGET"] = GenFdsGlobalVariable.TargetName
221 if "TOOLCHAIN" not in GlobalData.gGlobalDefines.keys():
222 GlobalData.gGlobalDefines["TOOLCHAIN"] = GenFdsGlobalVariable.ToolChainTag
223 if "TOOL_CHAIN_TAG" not in GlobalData.gGlobalDefines.keys():
224 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable.ToolChainTag
225
226 """call Workspace build create database"""
227 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))
228 BuildWorkSpace = WorkspaceDatabase(GlobalData.gDatabasePath)
229 BuildWorkSpace.InitDatabase()
230
231 #
232 # Get files real name in workspace dir
233 #
234 GlobalData.gAllFiles = DirCache(Workspace)
235 GlobalData.gWorkspace = Workspace
236
237 if (Options.archList) :
238 ArchList = Options.archList.split(',')
239 else:
240 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
241 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON', Options.BuildTarget, Options.ToolChain].SupArchList
242
243 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON', Options.BuildTarget, Options.ToolChain].SupArchList) & set(ArchList)
244 if len(TargetArchList) == 0:
245 EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON'].SupArchList)))
246
247 for Arch in ArchList:
248 GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Options.BuildTarget, Options.ToolChain].OutputDirectory)
249 GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Options.BuildTarget, Options.ToolChain].PlatformName
250
251 if (Options.outputDir):
252 OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(Options.outputDir)
253 if not os.path.isabs (OutputDirFromCommandLine):
254 OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine)
255 for Arch in ArchList:
256 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine
257 else:
258 for Arch in ArchList:
259 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)
260
261 for Key in GenFdsGlobalVariable.OutputDirDict:
262 OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]
263 if OutputDir[0:2] == '..':
264 OutputDir = os.path.realpath(OutputDir)
265
266 if OutputDir[1] != ':':
267 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)
268
269 if not os.path.exists(OutputDir):
270 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir)
271 GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir
272
273 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
274 FdfParserObj = FdfParser.FdfParser(FdfFilename)
275 FdfParserObj.ParseFile()
276
277 if FdfParserObj.CycleReferenceCheck():
278 EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")
279
280 if (Options.uiFdName) :
281 if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict.keys():
282 GenFds.OnlyGenerateThisFd = Options.uiFdName
283 else:
284 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
285 "No such an FD in FDF file: %s" % Options.uiFdName)
286
287 if (Options.uiFvName) :
288 if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict.keys():
289 GenFds.OnlyGenerateThisFv = Options.uiFvName
290 else:
291 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
292 "No such an FV in FDF file: %s" % Options.uiFvName)
293
294 if (Options.uiCapName) :
295 if Options.uiCapName.upper() in FdfParserObj.Profile.CapsuleDict.keys():
296 GenFds.OnlyGenerateThisCap = Options.uiCapName
297 else:
298 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
299 "No such a Capsule in FDF file: %s" % Options.uiCapName)
300
301 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace
302 if ArchList != None:
303 GenFdsGlobalVariable.ArchList = ArchList
304
305 # Dsc Build Data will handle Pcd Settings from CommandLine.
306
307 """Modify images from build output if the feature of loading driver at fixed address is on."""
308 if GenFdsGlobalVariable.FixedLoadAddress:
309 GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform)
310
311 # Record the FV Region info that may specific in the FD
312 if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict:
313 for Fv in FdfParserObj.Profile.FvDict:
314 FvObj = FdfParserObj.Profile.FvDict[Fv]
315 for Fd in FdfParserObj.Profile.FdDict:
316 FdObj = FdfParserObj.Profile.FdDict[Fd]
317 for RegionObj in FdObj.RegionList:
318 if RegionObj.RegionType != 'FV':
319 continue
320 for RegionData in RegionObj.RegionDataList:
321 if FvObj.UiFvName.upper() == RegionData.upper():
322 if FvObj.FvRegionInFD:
323 if FvObj.FvRegionInFD != RegionObj.Size:
324 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName)
325 else:
326 FvObj.FvRegionInFD = RegionObj.Size
327 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)
328
329 GlobalData.BuildOptionPcd = Options.OptionPcd if Options.OptionPcd else {}
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, 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, X:
343 if Options.debug != 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 def CheckBuildOptionPcd():
371 for Arch in GenFdsGlobalVariable.ArchList:
372 PkgList = GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag)
373 for i, pcd in enumerate(GlobalData.BuildOptionPcd):
374 if type(pcd) is tuple:
375 continue
376 (pcdname, pcdvalue) = pcd.split('=')
377 if not pcdvalue:
378 EdkLogger.error('GenFds', OPTION_MISSING, "No Value specified for the PCD %s." % (pcdname))
379 if '.' in pcdname:
380 (TokenSpaceGuidCName, TokenCName) = pcdname.split('.')
381 HasTokenSpace = True
382 else:
383 TokenCName = pcdname
384 TokenSpaceGuidCName = ''
385 HasTokenSpace = False
386 TokenSpaceGuidCNameList = []
387 FoundFlag = False
388 PcdDatumType = ''
389 NewValue = ''
390 for package in PkgList:
391 for key in package.Pcds:
392 PcdItem = package.Pcds[key]
393 if HasTokenSpace:
394 if (PcdItem.TokenCName, PcdItem.TokenSpaceGuidCName) == (TokenCName, TokenSpaceGuidCName):
395 PcdDatumType = PcdItem.DatumType
396 NewValue = BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, pcdvalue)
397 FoundFlag = True
398 else:
399 if PcdItem.TokenCName == TokenCName:
400 if not PcdItem.TokenSpaceGuidCName in TokenSpaceGuidCNameList:
401 if len (TokenSpaceGuidCNameList) < 1:
402 TokenSpaceGuidCNameList.append(PcdItem.TokenSpaceGuidCName)
403 PcdDatumType = PcdItem.DatumType
404 TokenSpaceGuidCName = PcdItem.TokenSpaceGuidCName
405 NewValue = BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, pcdvalue)
406 FoundFlag = True
407 else:
408 EdkLogger.error(
409 'GenFds',
410 PCD_VALIDATION_INFO_ERROR,
411 "The Pcd %s is found under multiple different TokenSpaceGuid: %s and %s." % (TokenCName, PcdItem.TokenSpaceGuidCName, TokenSpaceGuidCNameList[0])
412 )
413
414 GlobalData.BuildOptionPcd[i] = (TokenSpaceGuidCName, TokenCName, NewValue)
415
416
417 ## FindExtendTool()
418 #
419 # Find location of tools to process data
420 #
421 # @param KeyStringList Filter for inputs of section generation
422 # @param CurrentArchList Arch list
423 # @param NameGuid The Guid name
424 #
425 def FindExtendTool(KeyStringList, CurrentArchList, NameGuid):
426 ToolDb = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDatabase
427 # if user not specify filter, try to deduce it from global data.
428 if KeyStringList == None or KeyStringList == []:
429 Target = GenFdsGlobalVariable.TargetName
430 ToolChain = GenFdsGlobalVariable.ToolChainTag
431 if ToolChain not in ToolDb['TOOL_CHAIN_TAG']:
432 EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain)
433 KeyStringList = [Target + '_' + ToolChain + '_' + CurrentArchList[0]]
434 for Arch in CurrentArchList:
435 if Target + '_' + ToolChain + '_' + Arch not in KeyStringList:
436 KeyStringList.append(Target + '_' + ToolChain + '_' + Arch)
437
438 if GenFdsGlobalVariable.GuidToolDefinition:
439 if NameGuid in GenFdsGlobalVariable.GuidToolDefinition.keys():
440 return GenFdsGlobalVariable.GuidToolDefinition[NameGuid]
441
442 ToolDefinition = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDictionary
443 ToolPathTmp = None
444 ToolOption = None
445 ToolPathKey = None
446 ToolOptionKey = None
447 KeyList = None
448 for ToolDef in ToolDefinition.items():
449 if NameGuid == ToolDef[1]:
450 KeyList = ToolDef[0].split('_')
451 Key = KeyList[0] + \
452 '_' + \
453 KeyList[1] + \
454 '_' + \
455 KeyList[2]
456 if Key in KeyStringList and KeyList[4] == 'GUID':
457 ToolPathKey = Key + '_' + KeyList[3] + '_PATH'
458 ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
459 ToolPath = ToolDefinition.get(ToolPathKey)
460 ToolOption = ToolDefinition.get(ToolOptionKey)
461 if ToolPathTmp == None:
462 ToolPathTmp = ToolPath
463 else:
464 if ToolPathTmp != ToolPath:
465 EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath))
466
467 BuildOption = {}
468 for Arch in CurrentArchList:
469 Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
470 # key is (ToolChainFamily, ToolChain, CodeBase)
471 for item in Platform.BuildOptions:
472 if '_PATH' in item[1] or '_FLAGS' in item[1] or '_GUID' in item[1]:
473 if not item[0] or (item[0] and GenFdsGlobalVariable.ToolChainFamily== item[0]):
474 if item[1] not in BuildOption:
475 BuildOption[item[1]] = Platform.BuildOptions[item]
476 if BuildOption:
477 ToolList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH]
478 for Index in range(2, -1, -1):
479 for Key in dict(BuildOption):
480 List = Key.split('_')
481 if List[Index] == '*':
482 for String in ToolDb[ToolList[Index]]:
483 if String in [Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]:
484 List[Index] = String
485 NewKey = '%s_%s_%s_%s_%s' % tuple(List)
486 if NewKey not in BuildOption:
487 BuildOption[NewKey] = BuildOption[Key]
488 continue
489 del BuildOption[Key]
490 elif List[Index] not in ToolDb[ToolList[Index]]:
491 del BuildOption[Key]
492 if BuildOption:
493 if not KeyList:
494 for Op in BuildOption:
495 if NameGuid == BuildOption[Op]:
496 KeyList = Op.split('_')
497 Key = KeyList[0] + '_' + KeyList[1] +'_' + KeyList[2]
498 if Key in KeyStringList and KeyList[4] == 'GUID':
499 ToolPathKey = Key + '_' + KeyList[3] + '_PATH'
500 ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
501 if ToolPathKey in BuildOption.keys():
502 ToolPathTmp = BuildOption.get(ToolPathKey)
503 if ToolOptionKey in BuildOption.keys():
504 ToolOption = BuildOption.get(ToolOptionKey)
505
506 GenFdsGlobalVariable.GuidToolDefinition[NameGuid] = (ToolPathTmp, ToolOption)
507 return ToolPathTmp, ToolOption
508
509 ## Parse command line options
510 #
511 # Using standard Python module optparse to parse command line option of this tool.
512 #
513 # @retval Opt A optparse.Values object containing the parsed options
514 # @retval Args Target of build command
515 #
516 def myOptionParser():
517 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
518 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))
519 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)
520 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")
521 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
522 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
523 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
524 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
525 action="callback", callback=SingleCheckCallback)
526 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",
527 action="callback", callback=SingleCheckCallback)
528 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",
529 action="callback", callback=SingleCheckCallback)
530 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
531 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
532 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
533 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
534 action="callback", callback=SingleCheckCallback)
535 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
536 action="callback", callback=SingleCheckCallback)
537 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
538 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")
539 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
540 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
541 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
542 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
543
544 (Options, args) = Parser.parse_args()
545 return Options
546
547 ## The class implementing the EDK2 flash image generation process
548 #
549 # This process includes:
550 # 1. Collect workspace information, includes platform and module information
551 # 2. Call methods of Fd class to generate FD
552 # 3. Call methods of Fv class to generate FV that not belong to FD
553 #
554 class GenFds :
555 FdfParsef = None
556 # FvName, FdName, CapName in FDF, Image file name
557 ImageBinDict = {}
558 OnlyGenerateThisFd = None
559 OnlyGenerateThisFv = None
560 OnlyGenerateThisCap = None
561
562 ## GenFd()
563 #
564 # @param OutputDir Output directory
565 # @param FdfParser FDF contents parser
566 # @param Workspace The directory of workspace
567 # @param ArchList The Arch list of platform
568 #
569 def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):
570 GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)
571
572 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
573 if GenFds.OnlyGenerateThisCap != None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.keys():
574 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.get(GenFds.OnlyGenerateThisCap.upper())
575 if CapsuleObj != None:
576 CapsuleObj.GenCapsule()
577 return
578
579 if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
580 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(GenFds.OnlyGenerateThisFd.upper())
581 if FdObj != None:
582 FdObj.GenFd()
583 return
584 elif GenFds.OnlyGenerateThisFd == None and GenFds.OnlyGenerateThisFv == None:
585 for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
586 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
587 FdObj.GenFd()
588
589 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")
590 if GenFds.OnlyGenerateThisFv != None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
591 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(GenFds.OnlyGenerateThisFv.upper())
592 if FvObj != None:
593 Buffer = StringIO.StringIO()
594 FvObj.AddToBuffer(Buffer)
595 Buffer.close()
596 return
597 elif GenFds.OnlyGenerateThisFv == None:
598 for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
599 Buffer = StringIO.StringIO('')
600 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]
601 FvObj.AddToBuffer(Buffer)
602 Buffer.close()
603
604 if GenFds.OnlyGenerateThisFv == None and GenFds.OnlyGenerateThisFd == None and GenFds.OnlyGenerateThisCap == None:
605 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:
606 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")
607 for CapsuleName in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.keys():
608 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[CapsuleName]
609 CapsuleObj.GenCapsule()
610
611 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
612 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")
613 for DriverName in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.keys():
614 OptRomObj = GenFdsGlobalVariable.FdfParser.Profile.OptRomDict[DriverName]
615 OptRomObj.AddToBuffer(None)
616 @staticmethod
617 def GenFfsMakefile(OutputDir, FdfParser, WorkSpace, ArchList, GlobalData):
618 GenFdsGlobalVariable.SetEnv(FdfParser, WorkSpace, ArchList, GlobalData)
619 for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
620 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
621 FdObj.GenFd(Flag=True)
622
623 for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
624 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]
625 FvObj.AddToBuffer(Buffer=None, Flag=True)
626
627 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
628 for DriverName in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.keys():
629 OptRomObj = GenFdsGlobalVariable.FdfParser.Profile.OptRomDict[DriverName]
630 OptRomObj.AddToBuffer(Buffer=None, Flag=True)
631
632 return GenFdsGlobalVariable.FfsCmdDict
633
634 ## GetFvBlockSize()
635 #
636 # @param FvObj Whose block size to get
637 # @retval int Block size value
638 #
639 def GetFvBlockSize(FvObj):
640 DefaultBlockSize = 0x1
641 FdObj = None
642 if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
643 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
644 if FdObj == None:
645 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
646 for ElementRegion in ElementFd.RegionList:
647 if ElementRegion.RegionType == 'FV':
648 for ElementRegionData in ElementRegion.RegionDataList:
649 if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:
650 if FvObj.BlockSizeList != []:
651 return FvObj.BlockSizeList[0][0]
652 else:
653 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
654 if FvObj.BlockSizeList != []:
655 return FvObj.BlockSizeList[0][0]
656 return DefaultBlockSize
657 else:
658 for ElementRegion in FdObj.RegionList:
659 if ElementRegion.RegionType == 'FV':
660 for ElementRegionData in ElementRegion.RegionDataList:
661 if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:
662 if FvObj.BlockSizeList != []:
663 return FvObj.BlockSizeList[0][0]
664 else:
665 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
666 return DefaultBlockSize
667
668 ## DisplayFvSpaceInfo()
669 #
670 # @param FvObj Whose block size to get
671 # @retval None
672 #
673 def DisplayFvSpaceInfo(FdfParser):
674
675 FvSpaceInfoList = []
676 MaxFvNameLength = 0
677 for FvName in FdfParser.Profile.FvDict:
678 if len(FvName) > MaxFvNameLength:
679 MaxFvNameLength = len(FvName)
680 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')
681 if os.path.exists(FvSpaceInfoFileName):
682 FileLinesList = linecache.getlines(FvSpaceInfoFileName)
683 TotalFound = False
684 Total = ''
685 UsedFound = False
686 Used = ''
687 FreeFound = False
688 Free = ''
689 for Line in FileLinesList:
690 NameValue = Line.split('=')
691 if len(NameValue) == 2:
692 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
693 TotalFound = True
694 Total = NameValue[1].strip()
695 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
696 UsedFound = True
697 Used = NameValue[1].strip()
698 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
699 FreeFound = True
700 Free = NameValue[1].strip()
701
702 if TotalFound and UsedFound and FreeFound:
703 FvSpaceInfoList.append((FvName, Total, Used, Free))
704
705 GenFdsGlobalVariable.InfLogger('\nFV Space Information')
706 for FvSpaceInfo in FvSpaceInfoList:
707 Name = FvSpaceInfo[0]
708 TotalSizeValue = long(FvSpaceInfo[1], 0)
709 UsedSizeValue = long(FvSpaceInfo[2], 0)
710 FreeSizeValue = long(FvSpaceInfo[3], 0)
711 if UsedSizeValue == TotalSizeValue:
712 Percentage = '100'
713 else:
714 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')
715
716 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')
717
718 ## PreprocessImage()
719 #
720 # @param BuildDb Database from build meta data files
721 # @param DscFile modules from dsc file will be preprocessed
722 # @retval None
723 #
724 def PreprocessImage(BuildDb, DscFile):
725 PcdDict = BuildDb.BuildObject[DscFile, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds
726 PcdValue = ''
727 for Key in PcdDict:
728 PcdObj = PcdDict[Key]
729 if PcdObj.TokenCName == 'PcdBsBaseAddress':
730 PcdValue = PcdObj.DefaultValue
731 break
732
733 if PcdValue == '':
734 return
735
736 Int64PcdValue = long(PcdValue, 0)
737 if Int64PcdValue == 0 or Int64PcdValue < -1:
738 return
739
740 TopAddress = 0
741 if Int64PcdValue > 0:
742 TopAddress = Int64PcdValue
743
744 ModuleDict = BuildDb.BuildObject[DscFile, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules
745 for Key in ModuleDict:
746 ModuleObj = BuildDb.BuildObject[Key, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
747 print ModuleObj.BaseName + ' ' + ModuleObj.ModuleType
748
749 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):
750 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")
751 GuidXRefFile = StringIO.StringIO('')
752 GuidDict = {}
753 ModuleList = []
754 FileGuidList = []
755 for Arch in ArchList:
756 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
757 for ModuleFile in PlatformDataBase.Modules:
758 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
759 if Module in ModuleList:
760 continue
761 else:
762 ModuleList.append(Module)
763 GuidXRefFile.write("%s %s\n" % (Module.Guid, Module.BaseName))
764 for key, item in Module.Protocols.items():
765 GuidDict[key] = item
766 for key, item in Module.Guids.items():
767 GuidDict[key] = item
768 for key, item in Module.Ppis.items():
769 GuidDict[key] = item
770 for FvName in FdfParserObj.Profile.FvDict:
771 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:
772 if not isinstance(FfsObj, FfsFileStatement.FileStatement):
773 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))
774 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
775 if FdfModule in ModuleList:
776 continue
777 else:
778 ModuleList.append(FdfModule)
779 GuidXRefFile.write("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))
780 for key, item in FdfModule.Protocols.items():
781 GuidDict[key] = item
782 for key, item in FdfModule.Guids.items():
783 GuidDict[key] = item
784 for key, item in FdfModule.Ppis.items():
785 GuidDict[key] = item
786 else:
787 FileStatementGuid = FfsObj.NameGuid
788 if FileStatementGuid in FileGuidList:
789 continue
790 else:
791 FileGuidList.append(FileStatementGuid)
792 Name = []
793 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
794 FfsPath = glob.glob(os.path.join(FfsPath, FileStatementGuid) + '*')
795 if not FfsPath:
796 continue
797 if not os.path.exists(FfsPath[0]):
798 continue
799 MatchDict = {}
800 ReFileEnds = re.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
801 FileList = os.listdir(FfsPath[0])
802 for File in FileList:
803 Match = ReFileEnds.search(File)
804 if Match:
805 for Index in range(1, 8):
806 if Match.group(Index) and Match.group(Index) in MatchDict:
807 MatchDict[Match.group(Index)].append(File)
808 elif Match.group(Index):
809 MatchDict[Match.group(Index)] = [File]
810 if not MatchDict:
811 continue
812 if '.ui' in MatchDict:
813 for File in MatchDict['.ui']:
814 with open(os.path.join(FfsPath[0], File), 'rb') as F:
815 F.read()
816 length = F.tell()
817 F.seek(4)
818 TmpStr = unpack('%dh' % ((length - 4) / 2), F.read())
819 Name = ''.join([chr(c) for c in TmpStr[:-1]])
820 else:
821 FileList = []
822 if 'fv.sec.txt' in MatchDict:
823 FileList = MatchDict['fv.sec.txt']
824 elif '.pe32.txt' in MatchDict:
825 FileList = MatchDict['.pe32.txt']
826 elif '.te.txt' in MatchDict:
827 FileList = MatchDict['.te.txt']
828 elif '.pic.txt' in MatchDict:
829 FileList = MatchDict['.pic.txt']
830 elif '.raw.txt' in MatchDict:
831 FileList = MatchDict['.raw.txt']
832 elif '.ffs.txt' in MatchDict:
833 FileList = MatchDict['.ffs.txt']
834 else:
835 pass
836 for File in FileList:
837 with open(os.path.join(FfsPath[0], File), 'r') as F:
838 Name.append((F.read().split()[-1]))
839 if not Name:
840 continue
841
842 Name = ' '.join(Name) if type(Name) == type([]) else Name
843 GuidXRefFile.write("%s %s\n" %(FileStatementGuid, Name))
844
845 # Append GUIDs, Protocols, and PPIs to the Xref file
846 GuidXRefFile.write("\n")
847 for key, item in GuidDict.items():
848 GuidXRefFile.write("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))
849
850 if GuidXRefFile.getvalue():
851 SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False)
852 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)
853 elif os.path.exists(GuidXRefFileName):
854 os.remove(GuidXRefFileName)
855 GuidXRefFile.close()
856
857 ##Define GenFd as static function
858 GenFd = staticmethod(GenFd)
859 GetFvBlockSize = staticmethod(GetFvBlockSize)
860 DisplayFvSpaceInfo = staticmethod(DisplayFvSpaceInfo)
861 PreprocessImage = staticmethod(PreprocessImage)
862 GenerateGuidXRefFile = staticmethod(GenerateGuidXRefFile)
863
864 if __name__ == '__main__':
865 r = main()
866 ## 0-127 is a safe return range, and 1 is a standard default error
867 if r < 0 or r > 127: r = 1
868 sys.exit(r)
869