c507b0148af0baccdd7e608e086a655d531d5310
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / GenFds.py
1 ## @file
2 # generate flash image
3 #
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 #
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
10 #
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 #
14
15 ##
16 # Import Modules
17 #
18 from 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 import RuleComplexFile
28 from EfiSection import EfiSection
29 import StringIO
30 import Common.TargetTxtClassObject as TargetTxtClassObject
31 import Common.ToolDefClassObject as ToolDefClassObject
32 from Common.DataType import *
33 import Common.GlobalData as GlobalData
34 from Common import EdkLogger
35 from Common.String import *
36 from Common.Misc import DirCache, PathClass
37 from Common.Misc import SaveFileOnChange
38 from Common.Misc import ClearDuplicatedInf
39 from Common.Misc import GuidStructureStringToGuidString
40 from Common.BuildVersion import gBUILD_VERSION
41 from Common.MultipleWorkspace import MultipleWorkspace as mws
42 import FfsFileStatement
43 import glob
44 from struct import unpack
45
46 ## Version and Copyright
47 versionNumber = "1.0" + ' ' + gBUILD_VERSION
48 __version__ = "%prog Version " + versionNumber
49 __copyright__ = "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
50
51 ## Tool entrance method
52 #
53 # This method mainly dispatch specific methods per the command line options.
54 # If no error found, return zero value so the caller of this tool can know
55 # if it's executed successfully or not.
56 #
57 # @retval 0 Tool was successful
58 # @retval 1 Tool failed
59 #
60 def main():
61 global Options
62 Options = myOptionParser()
63
64 global Workspace
65 Workspace = ""
66 ArchList = None
67 ReturnCode = 0
68
69 EdkLogger.Initialize()
70 try:
71 if Options.verbose is not None:
72 EdkLogger.SetLevel(EdkLogger.VERBOSE)
73 GenFdsGlobalVariable.VerboseMode = True
74
75 if Options.FixedAddress is not None:
76 GenFdsGlobalVariable.FixedLoadAddress = True
77
78 if Options.quiet is not None:
79 EdkLogger.SetLevel(EdkLogger.QUIET)
80 if Options.debug is not None:
81 EdkLogger.SetLevel(Options.debug + 1)
82 GenFdsGlobalVariable.DebugLevel = Options.debug
83 else:
84 EdkLogger.SetLevel(EdkLogger.INFO)
85
86 if (Options.Workspace is None):
87 EdkLogger.error("GenFds", OPTION_MISSING, "WORKSPACE not defined",
88 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
89 elif not os.path.exists(Options.Workspace):
90 EdkLogger.error("GenFds", PARAMETER_INVALID, "WORKSPACE is invalid",
91 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
92 else:
93 Workspace = os.path.normcase(Options.Workspace)
94 GenFdsGlobalVariable.WorkSpaceDir = Workspace
95 if 'EDK_SOURCE' in os.environ.keys():
96 GenFdsGlobalVariable.EdkSourceDir = os.path.normcase(os.environ['EDK_SOURCE'])
97 if (Options.debug):
98 GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace)
99 if Options.GenfdsMultiThread:
100 GenFdsGlobalVariable.EnableGenfdsMultiThread = True
101 os.chdir(GenFdsGlobalVariable.WorkSpaceDir)
102
103 # set multiple workspace
104 PackagesPath = os.getenv("PACKAGES_PATH")
105 mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath)
106
107 if (Options.filename):
108 FdfFilename = Options.filename
109 FdfFilename = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdfFilename)
110
111 if FdfFilename[0:2] == '..':
112 FdfFilename = os.path.realpath(FdfFilename)
113 if not os.path.isabs(FdfFilename):
114 FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)
115 if not os.path.exists(FdfFilename):
116 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename)
117
118 GenFdsGlobalVariable.FdfFile = FdfFilename
119 GenFdsGlobalVariable.FdfFileTimeStamp = os.path.getmtime(FdfFilename)
120 else:
121 EdkLogger.error("GenFds", OPTION_MISSING, "Missing FDF filename")
122
123 if (Options.BuildTarget):
124 GenFdsGlobalVariable.TargetName = Options.BuildTarget
125
126 if (Options.ToolChain):
127 GenFdsGlobalVariable.ToolChainTag = Options.ToolChain
128
129 if (Options.activePlatform):
130 ActivePlatform = Options.activePlatform
131 ActivePlatform = GenFdsGlobalVariable.ReplaceWorkspaceMacro(ActivePlatform)
132
133 if ActivePlatform[0:2] == '..':
134 ActivePlatform = os.path.realpath(ActivePlatform)
135
136 if not os.path.isabs (ActivePlatform):
137 ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)
138
139 if not os.path.exists(ActivePlatform) :
140 EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!")
141 else:
142 EdkLogger.error("GenFds", OPTION_MISSING, "Missing active platform")
143
144 GlobalData.BuildOptionPcd = Options.OptionPcd if Options.OptionPcd else {}
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 if not GlobalData.gConfDirectory:
166 GlobalData.gConfDirectory = GenFdsGlobalVariable.ConfDir
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 is 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, TAB_COMMON, Options.BuildTarget, Options.ToolChain].SupArchList
242
243 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_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, TAB_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 is not 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 is not 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 ## FindExtendTool()
370 #
371 # Find location of tools to process data
372 #
373 # @param KeyStringList Filter for inputs of section generation
374 # @param CurrentArchList Arch list
375 # @param NameGuid The Guid name
376 #
377 def FindExtendTool(KeyStringList, CurrentArchList, NameGuid):
378 ToolDb = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDatabase
379 # if user not specify filter, try to deduce it from global data.
380 if KeyStringList is None or KeyStringList == []:
381 Target = GenFdsGlobalVariable.TargetName
382 ToolChain = GenFdsGlobalVariable.ToolChainTag
383 if ToolChain not in ToolDb['TOOL_CHAIN_TAG']:
384 EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain)
385 KeyStringList = [Target + '_' + ToolChain + '_' + CurrentArchList[0]]
386 for Arch in CurrentArchList:
387 if Target + '_' + ToolChain + '_' + Arch not in KeyStringList:
388 KeyStringList.append(Target + '_' + ToolChain + '_' + Arch)
389
390 if GenFdsGlobalVariable.GuidToolDefinition:
391 if NameGuid in GenFdsGlobalVariable.GuidToolDefinition.keys():
392 return GenFdsGlobalVariable.GuidToolDefinition[NameGuid]
393
394 ToolDefinition = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDictionary
395 ToolPathTmp = None
396 ToolOption = None
397 ToolPathKey = None
398 ToolOptionKey = None
399 KeyList = None
400 for ToolDef in ToolDefinition.items():
401 if NameGuid.lower() == ToolDef[1].lower() :
402 KeyList = ToolDef[0].split('_')
403 Key = KeyList[0] + \
404 '_' + \
405 KeyList[1] + \
406 '_' + \
407 KeyList[2]
408 if Key in KeyStringList and KeyList[4] == 'GUID':
409 ToolPathKey = Key + '_' + KeyList[3] + '_PATH'
410 ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
411 ToolPath = ToolDefinition.get(ToolPathKey)
412 ToolOption = ToolDefinition.get(ToolOptionKey)
413 if ToolPathTmp is None:
414 ToolPathTmp = ToolPath
415 else:
416 if ToolPathTmp != ToolPath:
417 EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath))
418
419 BuildOption = {}
420 for Arch in CurrentArchList:
421 Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
422 # key is (ToolChainFamily, ToolChain, CodeBase)
423 for item in Platform.BuildOptions:
424 if '_PATH' in item[1] or '_FLAGS' in item[1] or '_GUID' in item[1]:
425 if not item[0] or (item[0] and GenFdsGlobalVariable.ToolChainFamily== item[0]):
426 if item[1] not in BuildOption:
427 BuildOption[item[1]] = Platform.BuildOptions[item]
428 if BuildOption:
429 ToolList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH]
430 for Index in range(2, -1, -1):
431 for Key in dict(BuildOption):
432 List = Key.split('_')
433 if List[Index] == '*':
434 for String in ToolDb[ToolList[Index]]:
435 if String in [Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]:
436 List[Index] = String
437 NewKey = '%s_%s_%s_%s_%s' % tuple(List)
438 if NewKey not in BuildOption:
439 BuildOption[NewKey] = BuildOption[Key]
440 continue
441 del BuildOption[Key]
442 elif List[Index] not in ToolDb[ToolList[Index]]:
443 del BuildOption[Key]
444 if BuildOption:
445 if not KeyList:
446 for Op in BuildOption:
447 if NameGuid == BuildOption[Op]:
448 KeyList = Op.split('_')
449 Key = KeyList[0] + '_' + KeyList[1] +'_' + KeyList[2]
450 if Key in KeyStringList and KeyList[4] == 'GUID':
451 ToolPathKey = Key + '_' + KeyList[3] + '_PATH'
452 ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
453 if ToolPathKey in BuildOption.keys():
454 ToolPathTmp = BuildOption.get(ToolPathKey)
455 if ToolOptionKey in BuildOption.keys():
456 ToolOption = BuildOption.get(ToolOptionKey)
457
458 GenFdsGlobalVariable.GuidToolDefinition[NameGuid] = (ToolPathTmp, ToolOption)
459 return ToolPathTmp, ToolOption
460
461 ## Parse command line options
462 #
463 # Using standard Python module optparse to parse command line option of this tool.
464 #
465 # @retval Opt A optparse.Values object containing the parsed options
466 # @retval Args Target of build command
467 #
468 def myOptionParser():
469 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
470 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))
471 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)
472 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")
473 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
474 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
475 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
476 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
477 action="callback", callback=SingleCheckCallback)
478 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",
479 action="callback", callback=SingleCheckCallback)
480 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",
481 action="callback", callback=SingleCheckCallback)
482 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
483 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
484 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
485 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
486 action="callback", callback=SingleCheckCallback)
487 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
488 action="callback", callback=SingleCheckCallback)
489 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
490 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")
491 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
492 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
493 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
494 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
495
496 (Options, args) = Parser.parse_args()
497 return Options
498
499 ## The class implementing the EDK2 flash image generation process
500 #
501 # This process includes:
502 # 1. Collect workspace information, includes platform and module information
503 # 2. Call methods of Fd class to generate FD
504 # 3. Call methods of Fv class to generate FV that not belong to FD
505 #
506 class GenFds :
507 FdfParsef = None
508 # FvName, FdName, CapName in FDF, Image file name
509 ImageBinDict = {}
510 OnlyGenerateThisFd = None
511 OnlyGenerateThisFv = None
512 OnlyGenerateThisCap = None
513
514 ## GenFd()
515 #
516 # @param OutputDir Output directory
517 # @param FdfParser FDF contents parser
518 # @param Workspace The directory of workspace
519 # @param ArchList The Arch list of platform
520 #
521 def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):
522 GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)
523
524 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
525 if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.keys():
526 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.get(GenFds.OnlyGenerateThisCap.upper())
527 if CapsuleObj is not None:
528 CapsuleObj.GenCapsule()
529 return
530
531 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
532 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(GenFds.OnlyGenerateThisFd.upper())
533 if FdObj is not None:
534 FdObj.GenFd()
535 return
536 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None:
537 for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
538 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
539 FdObj.GenFd()
540
541 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")
542 if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
543 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(GenFds.OnlyGenerateThisFv.upper())
544 if FvObj is not None:
545 Buffer = StringIO.StringIO()
546 FvObj.AddToBuffer(Buffer)
547 Buffer.close()
548 return
549 elif GenFds.OnlyGenerateThisFv is None:
550 for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
551 Buffer = StringIO.StringIO('')
552 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]
553 FvObj.AddToBuffer(Buffer)
554 Buffer.close()
555
556 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None:
557 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:
558 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")
559 for CapsuleName in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.keys():
560 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[CapsuleName]
561 CapsuleObj.GenCapsule()
562
563 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
564 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")
565 for DriverName in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.keys():
566 OptRomObj = GenFdsGlobalVariable.FdfParser.Profile.OptRomDict[DriverName]
567 OptRomObj.AddToBuffer(None)
568 @staticmethod
569 def GenFfsMakefile(OutputDir, FdfParser, WorkSpace, ArchList, GlobalData):
570 GenFdsGlobalVariable.SetEnv(FdfParser, WorkSpace, ArchList, GlobalData)
571 for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
572 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
573 FdObj.GenFd(Flag=True)
574
575 for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
576 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]
577 FvObj.AddToBuffer(Buffer=None, Flag=True)
578
579 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
580 for DriverName in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.keys():
581 OptRomObj = GenFdsGlobalVariable.FdfParser.Profile.OptRomDict[DriverName]
582 OptRomObj.AddToBuffer(Buffer=None, Flag=True)
583
584 return GenFdsGlobalVariable.FfsCmdDict
585
586 ## GetFvBlockSize()
587 #
588 # @param FvObj Whose block size to get
589 # @retval int Block size value
590 #
591 def GetFvBlockSize(FvObj):
592 DefaultBlockSize = 0x1
593 FdObj = None
594 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
595 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
596 if FdObj is None:
597 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
598 for ElementRegion in ElementFd.RegionList:
599 if ElementRegion.RegionType == 'FV':
600 for ElementRegionData in ElementRegion.RegionDataList:
601 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
602 if FvObj.BlockSizeList != []:
603 return FvObj.BlockSizeList[0][0]
604 else:
605 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
606 if FvObj.BlockSizeList != []:
607 return FvObj.BlockSizeList[0][0]
608 return DefaultBlockSize
609 else:
610 for ElementRegion in FdObj.RegionList:
611 if ElementRegion.RegionType == 'FV':
612 for ElementRegionData in ElementRegion.RegionDataList:
613 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
614 if FvObj.BlockSizeList != []:
615 return FvObj.BlockSizeList[0][0]
616 else:
617 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
618 return DefaultBlockSize
619
620 ## DisplayFvSpaceInfo()
621 #
622 # @param FvObj Whose block size to get
623 # @retval None
624 #
625 def DisplayFvSpaceInfo(FdfParser):
626
627 FvSpaceInfoList = []
628 MaxFvNameLength = 0
629 for FvName in FdfParser.Profile.FvDict:
630 if len(FvName) > MaxFvNameLength:
631 MaxFvNameLength = len(FvName)
632 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')
633 if os.path.exists(FvSpaceInfoFileName):
634 FileLinesList = linecache.getlines(FvSpaceInfoFileName)
635 TotalFound = False
636 Total = ''
637 UsedFound = False
638 Used = ''
639 FreeFound = False
640 Free = ''
641 for Line in FileLinesList:
642 NameValue = Line.split('=')
643 if len(NameValue) == 2:
644 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
645 TotalFound = True
646 Total = NameValue[1].strip()
647 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
648 UsedFound = True
649 Used = NameValue[1].strip()
650 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
651 FreeFound = True
652 Free = NameValue[1].strip()
653
654 if TotalFound and UsedFound and FreeFound:
655 FvSpaceInfoList.append((FvName, Total, Used, Free))
656
657 GenFdsGlobalVariable.InfLogger('\nFV Space Information')
658 for FvSpaceInfo in FvSpaceInfoList:
659 Name = FvSpaceInfo[0]
660 TotalSizeValue = long(FvSpaceInfo[1], 0)
661 UsedSizeValue = long(FvSpaceInfo[2], 0)
662 FreeSizeValue = long(FvSpaceInfo[3], 0)
663 if UsedSizeValue == TotalSizeValue:
664 Percentage = '100'
665 else:
666 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')
667
668 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')
669
670 ## PreprocessImage()
671 #
672 # @param BuildDb Database from build meta data files
673 # @param DscFile modules from dsc file will be preprocessed
674 # @retval None
675 #
676 def PreprocessImage(BuildDb, DscFile):
677 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds
678 PcdValue = ''
679 for Key in PcdDict:
680 PcdObj = PcdDict[Key]
681 if PcdObj.TokenCName == 'PcdBsBaseAddress':
682 PcdValue = PcdObj.DefaultValue
683 break
684
685 if PcdValue == '':
686 return
687
688 Int64PcdValue = long(PcdValue, 0)
689 if Int64PcdValue == 0 or Int64PcdValue < -1:
690 return
691
692 TopAddress = 0
693 if Int64PcdValue > 0:
694 TopAddress = Int64PcdValue
695
696 ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules
697 for Key in ModuleDict:
698 ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
699 print ModuleObj.BaseName + ' ' + ModuleObj.ModuleType
700
701 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):
702 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")
703 GuidXRefFile = StringIO.StringIO('')
704 GuidDict = {}
705 ModuleList = []
706 FileGuidList = []
707 for Arch in ArchList:
708 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
709 for ModuleFile in PlatformDataBase.Modules:
710 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
711 if Module in ModuleList:
712 continue
713 else:
714 ModuleList.append(Module)
715 GuidXRefFile.write("%s %s\n" % (Module.Guid, Module.BaseName))
716 for key, item in Module.Protocols.items():
717 GuidDict[key] = item
718 for key, item in Module.Guids.items():
719 GuidDict[key] = item
720 for key, item in Module.Ppis.items():
721 GuidDict[key] = item
722 for FvName in FdfParserObj.Profile.FvDict:
723 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:
724 if not isinstance(FfsObj, FfsFileStatement.FileStatement):
725 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))
726 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
727 if FdfModule in ModuleList:
728 continue
729 else:
730 ModuleList.append(FdfModule)
731 GuidXRefFile.write("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))
732 for key, item in FdfModule.Protocols.items():
733 GuidDict[key] = item
734 for key, item in FdfModule.Guids.items():
735 GuidDict[key] = item
736 for key, item in FdfModule.Ppis.items():
737 GuidDict[key] = item
738 else:
739 FileStatementGuid = FfsObj.NameGuid
740 if FileStatementGuid in FileGuidList:
741 continue
742 else:
743 FileGuidList.append(FileStatementGuid)
744 Name = []
745 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
746 FfsPath = glob.glob(os.path.join(FfsPath, FileStatementGuid) + '*')
747 if not FfsPath:
748 continue
749 if not os.path.exists(FfsPath[0]):
750 continue
751 MatchDict = {}
752 ReFileEnds = re.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
753 FileList = os.listdir(FfsPath[0])
754 for File in FileList:
755 Match = ReFileEnds.search(File)
756 if Match:
757 for Index in range(1, 8):
758 if Match.group(Index) and Match.group(Index) in MatchDict:
759 MatchDict[Match.group(Index)].append(File)
760 elif Match.group(Index):
761 MatchDict[Match.group(Index)] = [File]
762 if not MatchDict:
763 continue
764 if '.ui' in MatchDict:
765 for File in MatchDict['.ui']:
766 with open(os.path.join(FfsPath[0], File), 'rb') as F:
767 F.read()
768 length = F.tell()
769 F.seek(4)
770 TmpStr = unpack('%dh' % ((length - 4) / 2), F.read())
771 Name = ''.join([chr(c) for c in TmpStr[:-1]])
772 else:
773 FileList = []
774 if 'fv.sec.txt' in MatchDict:
775 FileList = MatchDict['fv.sec.txt']
776 elif '.pe32.txt' in MatchDict:
777 FileList = MatchDict['.pe32.txt']
778 elif '.te.txt' in MatchDict:
779 FileList = MatchDict['.te.txt']
780 elif '.pic.txt' in MatchDict:
781 FileList = MatchDict['.pic.txt']
782 elif '.raw.txt' in MatchDict:
783 FileList = MatchDict['.raw.txt']
784 elif '.ffs.txt' in MatchDict:
785 FileList = MatchDict['.ffs.txt']
786 else:
787 pass
788 for File in FileList:
789 with open(os.path.join(FfsPath[0], File), 'r') as F:
790 Name.append((F.read().split()[-1]))
791 if not Name:
792 continue
793
794 Name = ' '.join(Name) if type(Name) == type([]) else Name
795 GuidXRefFile.write("%s %s\n" %(FileStatementGuid, Name))
796
797 # Append GUIDs, Protocols, and PPIs to the Xref file
798 GuidXRefFile.write("\n")
799 for key, item in GuidDict.items():
800 GuidXRefFile.write("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))
801
802 if GuidXRefFile.getvalue():
803 SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False)
804 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)
805 elif os.path.exists(GuidXRefFileName):
806 os.remove(GuidXRefFileName)
807 GuidXRefFile.close()
808
809 ##Define GenFd as static function
810 GenFd = staticmethod(GenFd)
811 GetFvBlockSize = staticmethod(GetFvBlockSize)
812 DisplayFvSpaceInfo = staticmethod(DisplayFvSpaceInfo)
813 PreprocessImage = staticmethod(PreprocessImage)
814 GenerateGuidXRefFile = staticmethod(GenerateGuidXRefFile)
815
816 if __name__ == '__main__':
817 r = main()
818 ## 0-127 is a safe return range, and 1 is a standard default error
819 if r < 0 or r > 127: r = 1
820 sys.exit(r)
821