]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/GenFds.py
BaseTools: Structure Pcd in CommandLine.
[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 """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 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
542
543 (Options, args) = Parser.parse_args()
544 return Options
545
546 ## The class implementing the EDK2 flash image generation process
547 #
548 # This process includes:
549 # 1. Collect workspace information, includes platform and module information
550 # 2. Call methods of Fd class to generate FD
551 # 3. Call methods of Fv class to generate FV that not belong to FD
552 #
553 class GenFds :
554 FdfParsef = None
555 # FvName, FdName, CapName in FDF, Image file name
556 ImageBinDict = {}
557 OnlyGenerateThisFd = None
558 OnlyGenerateThisFv = None
559 OnlyGenerateThisCap = None
560
561 ## GenFd()
562 #
563 # @param OutputDir Output directory
564 # @param FdfParser FDF contents parser
565 # @param Workspace The directory of workspace
566 # @param ArchList The Arch list of platform
567 #
568 def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):
569 GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)
570
571 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
572 if GenFds.OnlyGenerateThisCap != None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.keys():
573 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.get(GenFds.OnlyGenerateThisCap.upper())
574 if CapsuleObj != None:
575 CapsuleObj.GenCapsule()
576 return
577
578 if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
579 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(GenFds.OnlyGenerateThisFd.upper())
580 if FdObj != None:
581 FdObj.GenFd()
582 return
583 elif GenFds.OnlyGenerateThisFd == None and GenFds.OnlyGenerateThisFv == None:
584 for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
585 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
586 FdObj.GenFd()
587
588 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")
589 if GenFds.OnlyGenerateThisFv != None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
590 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(GenFds.OnlyGenerateThisFv.upper())
591 if FvObj != None:
592 Buffer = StringIO.StringIO()
593 FvObj.AddToBuffer(Buffer)
594 Buffer.close()
595 return
596 elif GenFds.OnlyGenerateThisFv == None:
597 for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
598 Buffer = StringIO.StringIO('')
599 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]
600 FvObj.AddToBuffer(Buffer)
601 Buffer.close()
602
603 if GenFds.OnlyGenerateThisFv == None and GenFds.OnlyGenerateThisFd == None and GenFds.OnlyGenerateThisCap == None:
604 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:
605 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")
606 for CapsuleName in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.keys():
607 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[CapsuleName]
608 CapsuleObj.GenCapsule()
609
610 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
611 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")
612 for DriverName in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.keys():
613 OptRomObj = GenFdsGlobalVariable.FdfParser.Profile.OptRomDict[DriverName]
614 OptRomObj.AddToBuffer(None)
615 @staticmethod
616 def GenFfsMakefile(OutputDir, FdfParser, WorkSpace, ArchList, GlobalData):
617 GenFdsGlobalVariable.SetEnv(FdfParser, WorkSpace, ArchList, GlobalData)
618 for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
619 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
620 FdObj.GenFd(Flag=True)
621
622 for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
623 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]
624 FvObj.AddToBuffer(Buffer=None, Flag=True)
625
626 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
627 for DriverName in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.keys():
628 OptRomObj = GenFdsGlobalVariable.FdfParser.Profile.OptRomDict[DriverName]
629 OptRomObj.AddToBuffer(Buffer=None, Flag=True)
630
631 return GenFdsGlobalVariable.FfsCmdDict
632
633 ## GetFvBlockSize()
634 #
635 # @param FvObj Whose block size to get
636 # @retval int Block size value
637 #
638 def GetFvBlockSize(FvObj):
639 DefaultBlockSize = 0x1
640 FdObj = None
641 if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
642 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
643 if FdObj == None:
644 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
645 for ElementRegion in ElementFd.RegionList:
646 if ElementRegion.RegionType == 'FV':
647 for ElementRegionData in ElementRegion.RegionDataList:
648 if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:
649 if FvObj.BlockSizeList != []:
650 return FvObj.BlockSizeList[0][0]
651 else:
652 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
653 if FvObj.BlockSizeList != []:
654 return FvObj.BlockSizeList[0][0]
655 return DefaultBlockSize
656 else:
657 for ElementRegion in FdObj.RegionList:
658 if ElementRegion.RegionType == 'FV':
659 for ElementRegionData in ElementRegion.RegionDataList:
660 if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:
661 if FvObj.BlockSizeList != []:
662 return FvObj.BlockSizeList[0][0]
663 else:
664 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
665 return DefaultBlockSize
666
667 ## DisplayFvSpaceInfo()
668 #
669 # @param FvObj Whose block size to get
670 # @retval None
671 #
672 def DisplayFvSpaceInfo(FdfParser):
673
674 FvSpaceInfoList = []
675 MaxFvNameLength = 0
676 for FvName in FdfParser.Profile.FvDict:
677 if len(FvName) > MaxFvNameLength:
678 MaxFvNameLength = len(FvName)
679 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')
680 if os.path.exists(FvSpaceInfoFileName):
681 FileLinesList = linecache.getlines(FvSpaceInfoFileName)
682 TotalFound = False
683 Total = ''
684 UsedFound = False
685 Used = ''
686 FreeFound = False
687 Free = ''
688 for Line in FileLinesList:
689 NameValue = Line.split('=')
690 if len(NameValue) == 2:
691 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
692 TotalFound = True
693 Total = NameValue[1].strip()
694 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
695 UsedFound = True
696 Used = NameValue[1].strip()
697 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
698 FreeFound = True
699 Free = NameValue[1].strip()
700
701 if TotalFound and UsedFound and FreeFound:
702 FvSpaceInfoList.append((FvName, Total, Used, Free))
703
704 GenFdsGlobalVariable.InfLogger('\nFV Space Information')
705 for FvSpaceInfo in FvSpaceInfoList:
706 Name = FvSpaceInfo[0]
707 TotalSizeValue = long(FvSpaceInfo[1], 0)
708 UsedSizeValue = long(FvSpaceInfo[2], 0)
709 FreeSizeValue = long(FvSpaceInfo[3], 0)
710 if UsedSizeValue == TotalSizeValue:
711 Percentage = '100'
712 else:
713 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')
714
715 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')
716
717 ## PreprocessImage()
718 #
719 # @param BuildDb Database from build meta data files
720 # @param DscFile modules from dsc file will be preprocessed
721 # @retval None
722 #
723 def PreprocessImage(BuildDb, DscFile):
724 PcdDict = BuildDb.BuildObject[DscFile, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds
725 PcdValue = ''
726 for Key in PcdDict:
727 PcdObj = PcdDict[Key]
728 if PcdObj.TokenCName == 'PcdBsBaseAddress':
729 PcdValue = PcdObj.DefaultValue
730 break
731
732 if PcdValue == '':
733 return
734
735 Int64PcdValue = long(PcdValue, 0)
736 if Int64PcdValue == 0 or Int64PcdValue < -1:
737 return
738
739 TopAddress = 0
740 if Int64PcdValue > 0:
741 TopAddress = Int64PcdValue
742
743 ModuleDict = BuildDb.BuildObject[DscFile, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules
744 for Key in ModuleDict:
745 ModuleObj = BuildDb.BuildObject[Key, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
746 print ModuleObj.BaseName + ' ' + ModuleObj.ModuleType
747
748 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):
749 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")
750 GuidXRefFile = StringIO.StringIO('')
751 GuidDict = {}
752 ModuleList = []
753 FileGuidList = []
754 for Arch in ArchList:
755 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
756 for ModuleFile in PlatformDataBase.Modules:
757 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
758 if Module in ModuleList:
759 continue
760 else:
761 ModuleList.append(Module)
762 GuidXRefFile.write("%s %s\n" % (Module.Guid, Module.BaseName))
763 for key, item in Module.Protocols.items():
764 GuidDict[key] = item
765 for key, item in Module.Guids.items():
766 GuidDict[key] = item
767 for key, item in Module.Ppis.items():
768 GuidDict[key] = item
769 for FvName in FdfParserObj.Profile.FvDict:
770 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:
771 if not isinstance(FfsObj, FfsFileStatement.FileStatement):
772 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))
773 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
774 if FdfModule in ModuleList:
775 continue
776 else:
777 ModuleList.append(FdfModule)
778 GuidXRefFile.write("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))
779 for key, item in FdfModule.Protocols.items():
780 GuidDict[key] = item
781 for key, item in FdfModule.Guids.items():
782 GuidDict[key] = item
783 for key, item in FdfModule.Ppis.items():
784 GuidDict[key] = item
785 else:
786 FileStatementGuid = FfsObj.NameGuid
787 if FileStatementGuid in FileGuidList:
788 continue
789 else:
790 FileGuidList.append(FileStatementGuid)
791 Name = []
792 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
793 FfsPath = glob.glob(os.path.join(FfsPath, FileStatementGuid) + '*')
794 if not FfsPath:
795 continue
796 if not os.path.exists(FfsPath[0]):
797 continue
798 MatchDict = {}
799 ReFileEnds = re.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
800 FileList = os.listdir(FfsPath[0])
801 for File in FileList:
802 Match = ReFileEnds.search(File)
803 if Match:
804 for Index in range(1, 8):
805 if Match.group(Index) and Match.group(Index) in MatchDict:
806 MatchDict[Match.group(Index)].append(File)
807 elif Match.group(Index):
808 MatchDict[Match.group(Index)] = [File]
809 if not MatchDict:
810 continue
811 if '.ui' in MatchDict:
812 for File in MatchDict['.ui']:
813 with open(os.path.join(FfsPath[0], File), 'rb') as F:
814 F.read()
815 length = F.tell()
816 F.seek(4)
817 TmpStr = unpack('%dh' % ((length - 4) / 2), F.read())
818 Name = ''.join([chr(c) for c in TmpStr[:-1]])
819 else:
820 FileList = []
821 if 'fv.sec.txt' in MatchDict:
822 FileList = MatchDict['fv.sec.txt']
823 elif '.pe32.txt' in MatchDict:
824 FileList = MatchDict['.pe32.txt']
825 elif '.te.txt' in MatchDict:
826 FileList = MatchDict['.te.txt']
827 elif '.pic.txt' in MatchDict:
828 FileList = MatchDict['.pic.txt']
829 elif '.raw.txt' in MatchDict:
830 FileList = MatchDict['.raw.txt']
831 elif '.ffs.txt' in MatchDict:
832 FileList = MatchDict['.ffs.txt']
833 else:
834 pass
835 for File in FileList:
836 with open(os.path.join(FfsPath[0], File), 'r') as F:
837 Name.append((F.read().split()[-1]))
838 if not Name:
839 continue
840
841 Name = ' '.join(Name) if type(Name) == type([]) else Name
842 GuidXRefFile.write("%s %s\n" %(FileStatementGuid, Name))
843
844 # Append GUIDs, Protocols, and PPIs to the Xref file
845 GuidXRefFile.write("\n")
846 for key, item in GuidDict.items():
847 GuidXRefFile.write("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))
848
849 if GuidXRefFile.getvalue():
850 SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False)
851 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)
852 elif os.path.exists(GuidXRefFileName):
853 os.remove(GuidXRefFileName)
854 GuidXRefFile.close()
855
856 ##Define GenFd as static function
857 GenFd = staticmethod(GenFd)
858 GetFvBlockSize = staticmethod(GetFvBlockSize)
859 DisplayFvSpaceInfo = staticmethod(DisplayFvSpaceInfo)
860 PreprocessImage = staticmethod(PreprocessImage)
861 GenerateGuidXRefFile = staticmethod(GenerateGuidXRefFile)
862
863 if __name__ == '__main__':
864 r = main()
865 ## 0-127 is a safe return range, and 1 is a standard default error
866 if r < 0 or r > 127: r = 1
867 sys.exit(r)
868