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