]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/GenFds/GenFds.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / GenFds.py
... / ...
CommitLineData
1## @file\r
2# generate flash image\r
3#\r
4# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>\r
5#\r
6# SPDX-License-Identifier: BSD-2-Clause-Patent\r
7#\r
8\r
9##\r
10# Import Modules\r
11#\r
12from __future__ import print_function\r
13from __future__ import absolute_import\r
14from re import compile\r
15from optparse import OptionParser\r
16from sys import exit\r
17from glob import glob\r
18from struct import unpack\r
19from linecache import getlines\r
20from io import BytesIO\r
21\r
22import Common.LongFilePathOs as os\r
23from Common.TargetTxtClassObject import TargetTxtDict,gDefaultTargetTxtFile\r
24from Common.DataType import *\r
25import Common.GlobalData as GlobalData\r
26from Common import EdkLogger\r
27from Common.StringUtils import NormPath\r
28from Common.Misc import DirCache, PathClass, GuidStructureStringToGuidString\r
29from Common.Misc import SaveFileOnChange, ClearDuplicatedInf\r
30from Common.BuildVersion import gBUILD_VERSION\r
31from Common.MultipleWorkspace import MultipleWorkspace as mws\r
32from Common.BuildToolError import FatalError, GENFDS_ERROR, CODE_ERROR, FORMAT_INVALID, RESOURCE_NOT_AVAILABLE, FILE_NOT_FOUND, OPTION_MISSING, FORMAT_NOT_SUPPORTED, OPTION_VALUE_INVALID, PARAMETER_INVALID\r
33from Workspace.WorkspaceDatabase import WorkspaceDatabase\r
34\r
35from .FdfParser import FdfParser, Warning\r
36from .GenFdsGlobalVariable import GenFdsGlobalVariable\r
37from .FfsFileStatement import FileStatement\r
38import Common.DataType as DataType\r
39from struct import Struct\r
40\r
41## Version and Copyright\r
42versionNumber = "1.0" + ' ' + gBUILD_VERSION\r
43__version__ = "%prog Version " + versionNumber\r
44__copyright__ = "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."\r
45\r
46## Tool entrance method\r
47#\r
48# This method mainly dispatch specific methods per the command line options.\r
49# If no error found, return zero value so the caller of this tool can know\r
50# if it's executed successfully or not.\r
51#\r
52# @retval 0 Tool was successful\r
53# @retval 1 Tool failed\r
54#\r
55def main():\r
56 global Options\r
57 Options = myOptionParser()\r
58 EdkLogger.Initialize()\r
59 return GenFdsApi(OptionsToCommandDict(Options))\r
60\r
61def resetFdsGlobalVariable():\r
62 GenFdsGlobalVariable.FvDir = ''\r
63 GenFdsGlobalVariable.OutputDirDict = {}\r
64 GenFdsGlobalVariable.BinDir = ''\r
65 # will be FvDir + os.sep + 'Ffs'\r
66 GenFdsGlobalVariable.FfsDir = ''\r
67 GenFdsGlobalVariable.FdfParser = None\r
68 GenFdsGlobalVariable.LibDir = ''\r
69 GenFdsGlobalVariable.WorkSpace = None\r
70 GenFdsGlobalVariable.WorkSpaceDir = ''\r
71 GenFdsGlobalVariable.ConfDir = ''\r
72 GenFdsGlobalVariable.OutputDirFromDscDict = {}\r
73 GenFdsGlobalVariable.TargetName = ''\r
74 GenFdsGlobalVariable.ToolChainTag = ''\r
75 GenFdsGlobalVariable.RuleDict = {}\r
76 GenFdsGlobalVariable.ArchList = None\r
77 GenFdsGlobalVariable.ActivePlatform = None\r
78 GenFdsGlobalVariable.FvAddressFileName = ''\r
79 GenFdsGlobalVariable.VerboseMode = False\r
80 GenFdsGlobalVariable.DebugLevel = -1\r
81 GenFdsGlobalVariable.SharpCounter = 0\r
82 GenFdsGlobalVariable.SharpNumberPerLine = 40\r
83 GenFdsGlobalVariable.FdfFile = ''\r
84 GenFdsGlobalVariable.FdfFileTimeStamp = 0\r
85 GenFdsGlobalVariable.FixedLoadAddress = False\r
86 GenFdsGlobalVariable.PlatformName = ''\r
87\r
88 GenFdsGlobalVariable.BuildRuleFamily = DataType.TAB_COMPILER_MSFT\r
89 GenFdsGlobalVariable.ToolChainFamily = DataType.TAB_COMPILER_MSFT\r
90 GenFdsGlobalVariable.__BuildRuleDatabase = None\r
91 GenFdsGlobalVariable.GuidToolDefinition = {}\r
92 GenFdsGlobalVariable.FfsCmdDict = {}\r
93 GenFdsGlobalVariable.SecCmdList = []\r
94 GenFdsGlobalVariable.CopyList = []\r
95 GenFdsGlobalVariable.ModuleFile = ''\r
96 GenFdsGlobalVariable.EnableGenfdsMultiThread = True\r
97\r
98 GenFdsGlobalVariable.LargeFileInFvFlags = []\r
99 GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID = '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'\r
100 GenFdsGlobalVariable.LARGE_FILE_SIZE = 0x1000000\r
101\r
102 GenFdsGlobalVariable.SectionHeader = Struct("3B 1B")\r
103\r
104 # FvName, FdName, CapName in FDF, Image file name\r
105 GenFdsGlobalVariable.ImageBinDict = {}\r
106\r
107def GenFdsApi(FdsCommandDict, WorkSpaceDataBase=None):\r
108 global Workspace\r
109 Workspace = ""\r
110 ArchList = None\r
111 ReturnCode = 0\r
112 resetFdsGlobalVariable()\r
113\r
114 try:\r
115 if FdsCommandDict.get("verbose"):\r
116 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
117 GenFdsGlobalVariable.VerboseMode = True\r
118\r
119 if FdsCommandDict.get("FixedAddress"):\r
120 GenFdsGlobalVariable.FixedLoadAddress = True\r
121\r
122 if FdsCommandDict.get("quiet"):\r
123 EdkLogger.SetLevel(EdkLogger.QUIET)\r
124 if FdsCommandDict.get("debug"):\r
125 EdkLogger.SetLevel(FdsCommandDict.get("debug") + 1)\r
126 GenFdsGlobalVariable.DebugLevel = FdsCommandDict.get("debug")\r
127 else:\r
128 EdkLogger.SetLevel(EdkLogger.INFO)\r
129\r
130 if not FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE')):\r
131 EdkLogger.error("GenFds", OPTION_MISSING, "WORKSPACE not defined",\r
132 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")\r
133 elif not os.path.exists(FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE'))):\r
134 EdkLogger.error("GenFds", PARAMETER_INVALID, "WORKSPACE is invalid",\r
135 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")\r
136 else:\r
137 Workspace = os.path.normcase(FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE')))\r
138 GenFdsGlobalVariable.WorkSpaceDir = Workspace\r
139 if FdsCommandDict.get("debug"):\r
140 GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace)\r
141 if FdsCommandDict.get("GenfdsMultiThread"):\r
142 GenFdsGlobalVariable.EnableGenfdsMultiThread = True\r
143 else:\r
144 GenFdsGlobalVariable.EnableGenfdsMultiThread = False\r
145 os.chdir(GenFdsGlobalVariable.WorkSpaceDir)\r
146\r
147 # set multiple workspace\r
148 PackagesPath = os.getenv("PACKAGES_PATH")\r
149 mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath)\r
150\r
151 if FdsCommandDict.get("fdf_file"):\r
152 FdfFilename = FdsCommandDict.get("fdf_file")[0].Path\r
153 FdfFilename = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdfFilename)\r
154\r
155 if FdfFilename[0:2] == '..':\r
156 FdfFilename = os.path.abspath(FdfFilename)\r
157 if not os.path.isabs(FdfFilename):\r
158 FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)\r
159 if not os.path.exists(FdfFilename):\r
160 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename)\r
161\r
162 GenFdsGlobalVariable.FdfFile = FdfFilename\r
163 GenFdsGlobalVariable.FdfFileTimeStamp = os.path.getmtime(FdfFilename)\r
164 else:\r
165 EdkLogger.error("GenFds", OPTION_MISSING, "Missing FDF filename")\r
166\r
167 if FdsCommandDict.get("build_target"):\r
168 GenFdsGlobalVariable.TargetName = FdsCommandDict.get("build_target")\r
169\r
170 if FdsCommandDict.get("toolchain_tag"):\r
171 GenFdsGlobalVariable.ToolChainTag = FdsCommandDict.get("toolchain_tag")\r
172\r
173 if FdsCommandDict.get("active_platform"):\r
174 ActivePlatform = FdsCommandDict.get("active_platform")\r
175 ActivePlatform = GenFdsGlobalVariable.ReplaceWorkspaceMacro(ActivePlatform)\r
176\r
177 if ActivePlatform[0:2] == '..':\r
178 ActivePlatform = os.path.abspath(ActivePlatform)\r
179\r
180 if not os.path.isabs (ActivePlatform):\r
181 ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)\r
182\r
183 if not os.path.exists(ActivePlatform):\r
184 EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!")\r
185 else:\r
186 EdkLogger.error("GenFds", OPTION_MISSING, "Missing active platform")\r
187\r
188 GenFdsGlobalVariable.ActivePlatform = PathClass(NormPath(ActivePlatform))\r
189\r
190 if FdsCommandDict.get("conf_directory"):\r
191 # Get alternate Conf location, if it is absolute, then just use the absolute directory name\r
192 ConfDirectoryPath = os.path.normpath(FdsCommandDict.get("conf_directory"))\r
193 if ConfDirectoryPath.startswith('"'):\r
194 ConfDirectoryPath = ConfDirectoryPath[1:]\r
195 if ConfDirectoryPath.endswith('"'):\r
196 ConfDirectoryPath = ConfDirectoryPath[:-1]\r
197 if not os.path.isabs(ConfDirectoryPath):\r
198 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE\r
199 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf\r
200 ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ConfDirectoryPath)\r
201 else:\r
202 if "CONF_PATH" in os.environ:\r
203 ConfDirectoryPath = os.path.normcase(os.environ["CONF_PATH"])\r
204 else:\r
205 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf\r
206 ConfDirectoryPath = mws.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf')\r
207 GenFdsGlobalVariable.ConfDir = ConfDirectoryPath\r
208 if not GlobalData.gConfDirectory:\r
209 GlobalData.gConfDirectory = GenFdsGlobalVariable.ConfDir\r
210 BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, gDefaultTargetTxtFile))\r
211 if os.path.isfile(BuildConfigurationFile) == True:\r
212 # if no build target given in command line, get it from target.txt\r
213 TargetObj = TargetTxtDict()\r
214 TargetTxt = TargetObj.Target\r
215 if not GenFdsGlobalVariable.TargetName:\r
216 BuildTargetList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]\r
217 if len(BuildTargetList) != 1:\r
218 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for Target.")\r
219 GenFdsGlobalVariable.TargetName = BuildTargetList[0]\r
220\r
221 # if no tool chain given in command line, get it from target.txt\r
222 if not GenFdsGlobalVariable.ToolChainTag:\r
223 ToolChainList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
224 if ToolChainList is None or len(ToolChainList) == 0:\r
225 EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.")\r
226 if len(ToolChainList) != 1:\r
227 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for ToolChain.")\r
228 GenFdsGlobalVariable.ToolChainTag = ToolChainList[0]\r
229 else:\r
230 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
231\r
232 #Set global flag for build mode\r
233 GlobalData.gIgnoreSource = FdsCommandDict.get("IgnoreSources")\r
234\r
235 if FdsCommandDict.get("macro"):\r
236 for Pair in FdsCommandDict.get("macro"):\r
237 if Pair.startswith('"'):\r
238 Pair = Pair[1:]\r
239 if Pair.endswith('"'):\r
240 Pair = Pair[:-1]\r
241 List = Pair.split('=')\r
242 if len(List) == 2:\r
243 if not List[1].strip():\r
244 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="No Value given for Macro %s" %List[0])\r
245 if List[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:\r
246 GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip()\r
247 else:\r
248 GlobalData.gCommandLineDefines[List[0].strip()] = List[1].strip()\r
249 else:\r
250 GlobalData.gCommandLineDefines[List[0].strip()] = "TRUE"\r
251 os.environ["WORKSPACE"] = Workspace\r
252\r
253 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined\r
254 if "TARGET" not in GlobalData.gGlobalDefines:\r
255 GlobalData.gGlobalDefines["TARGET"] = GenFdsGlobalVariable.TargetName\r
256 if "TOOLCHAIN" not in GlobalData.gGlobalDefines:\r
257 GlobalData.gGlobalDefines["TOOLCHAIN"] = GenFdsGlobalVariable.ToolChainTag\r
258 if "TOOL_CHAIN_TAG" not in GlobalData.gGlobalDefines:\r
259 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable.ToolChainTag\r
260\r
261 """call Workspace build create database"""\r
262 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))\r
263\r
264 if WorkSpaceDataBase:\r
265 BuildWorkSpace = WorkSpaceDataBase\r
266 else:\r
267 BuildWorkSpace = WorkspaceDatabase()\r
268 #\r
269 # Get files real name in workspace dir\r
270 #\r
271 GlobalData.gAllFiles = DirCache(Workspace)\r
272 GlobalData.gWorkspace = Workspace\r
273\r
274 if FdsCommandDict.get("build_architecture_list"):\r
275 ArchList = FdsCommandDict.get("build_architecture_list").split(',')\r
276 else:\r
277 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList\r
278\r
279 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList) & set(ArchList)\r
280 if len(TargetArchList) == 0:\r
281 EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON].SupArchList)))\r
282\r
283 for Arch in ArchList:\r
284 GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].OutputDirectory)\r
285\r
286 # assign platform name based on last entry in ArchList\r
287 GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, ArchList[-1], FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].PlatformName\r
288\r
289 if FdsCommandDict.get("platform_build_directory"):\r
290 OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdsCommandDict.get("platform_build_directory"))\r
291 if not os.path.isabs (OutputDirFromCommandLine):\r
292 OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine)\r
293 for Arch in ArchList:\r
294 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine\r
295 else:\r
296 for Arch in ArchList:\r
297 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)\r
298\r
299 for Key in GenFdsGlobalVariable.OutputDirDict:\r
300 OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]\r
301 if OutputDir[0:2] == '..':\r
302 OutputDir = os.path.abspath(OutputDir)\r
303\r
304 if OutputDir[1] != ':':\r
305 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)\r
306\r
307 if not os.path.exists(OutputDir):\r
308 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir)\r
309 GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir\r
310\r
311 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """\r
312 if WorkSpaceDataBase:\r
313 FdfParserObj = GlobalData.gFdfParser\r
314 else:\r
315 FdfParserObj = FdfParser(FdfFilename)\r
316 FdfParserObj.ParseFile()\r
317\r
318 if FdfParserObj.CycleReferenceCheck():\r
319 EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")\r
320\r
321 if FdsCommandDict.get("fd"):\r
322 if FdsCommandDict.get("fd")[0].upper() in FdfParserObj.Profile.FdDict:\r
323 GenFds.OnlyGenerateThisFd = FdsCommandDict.get("fd")[0]\r
324 else:\r
325 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,\r
326 "No such an FD in FDF file: %s" % FdsCommandDict.get("fd")[0])\r
327\r
328 if FdsCommandDict.get("fv"):\r
329 if FdsCommandDict.get("fv")[0].upper() in FdfParserObj.Profile.FvDict:\r
330 GenFds.OnlyGenerateThisFv = FdsCommandDict.get("fv")[0]\r
331 else:\r
332 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,\r
333 "No such an FV in FDF file: %s" % FdsCommandDict.get("fv")[0])\r
334\r
335 if FdsCommandDict.get("cap"):\r
336 if FdsCommandDict.get("cap")[0].upper() in FdfParserObj.Profile.CapsuleDict:\r
337 GenFds.OnlyGenerateThisCap = FdsCommandDict.get("cap")[0]\r
338 else:\r
339 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,\r
340 "No such a Capsule in FDF file: %s" % FdsCommandDict.get("cap")[0])\r
341\r
342 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace\r
343 if ArchList:\r
344 GenFdsGlobalVariable.ArchList = ArchList\r
345\r
346 # Dsc Build Data will handle Pcd Settings from CommandLine.\r
347\r
348 """Modify images from build output if the feature of loading driver at fixed address is on."""\r
349 if GenFdsGlobalVariable.FixedLoadAddress:\r
350 GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform)\r
351\r
352 # Record the FV Region info that may specific in the FD\r
353 if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict:\r
354 for FvObj in FdfParserObj.Profile.FvDict.values():\r
355 for FdObj in FdfParserObj.Profile.FdDict.values():\r
356 for RegionObj in FdObj.RegionList:\r
357 if RegionObj.RegionType != BINARY_FILE_TYPE_FV:\r
358 continue\r
359 for RegionData in RegionObj.RegionDataList:\r
360 if FvObj.UiFvName.upper() == RegionData.upper():\r
361 if not FvObj.BaseAddress:\r
362 FvObj.BaseAddress = '0x%x' % (int(FdObj.BaseAddress, 0) + RegionObj.Offset)\r
363 if FvObj.FvRegionInFD:\r
364 if FvObj.FvRegionInFD != RegionObj.Size:\r
365 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName)\r
366 else:\r
367 FvObj.FvRegionInFD = RegionObj.Size\r
368 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)\r
369\r
370 """Call GenFds"""\r
371 GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)\r
372\r
373 """Generate GUID cross reference file"""\r
374 GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj)\r
375\r
376 """Display FV space info."""\r
377 GenFds.DisplayFvSpaceInfo(FdfParserObj)\r
378\r
379 except Warning as X:\r
380 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
381 ReturnCode = FORMAT_INVALID\r
382 except FatalError as X:\r
383 if FdsCommandDict.get("debug") is not None:\r
384 import traceback\r
385 EdkLogger.quiet(traceback.format_exc())\r
386 ReturnCode = X.args[0]\r
387 except:\r
388 import traceback\r
389 EdkLogger.error(\r
390 "\nPython",\r
391 CODE_ERROR,\r
392 "Tools code failure",\r
393 ExtraData="Please send email to %s for help, attaching following call stack trace!\n" % MSG_EDKII_MAIL_ADDR,\r
394 RaiseError=False\r
395 )\r
396 EdkLogger.quiet(traceback.format_exc())\r
397 ReturnCode = CODE_ERROR\r
398 finally:\r
399 ClearDuplicatedInf()\r
400 return ReturnCode\r
401\r
402def OptionsToCommandDict(Options):\r
403 FdsCommandDict = {}\r
404 FdsCommandDict["verbose"] = Options.verbose\r
405 FdsCommandDict["FixedAddress"] = Options.FixedAddress\r
406 FdsCommandDict["quiet"] = Options.quiet\r
407 FdsCommandDict["debug"] = Options.debug\r
408 FdsCommandDict["Workspace"] = Options.Workspace\r
409 FdsCommandDict["GenfdsMultiThread"] = not Options.NoGenfdsMultiThread\r
410 FdsCommandDict["fdf_file"] = [PathClass(Options.filename)] if Options.filename else []\r
411 FdsCommandDict["build_target"] = Options.BuildTarget\r
412 FdsCommandDict["toolchain_tag"] = Options.ToolChain\r
413 FdsCommandDict["active_platform"] = Options.activePlatform\r
414 FdsCommandDict["OptionPcd"] = Options.OptionPcd\r
415 FdsCommandDict["conf_directory"] = Options.ConfDirectory\r
416 FdsCommandDict["IgnoreSources"] = Options.IgnoreSources\r
417 FdsCommandDict["macro"] = Options.Macros\r
418 FdsCommandDict["build_architecture_list"] = Options.archList\r
419 FdsCommandDict["platform_build_directory"] = Options.outputDir\r
420 FdsCommandDict["fd"] = [Options.uiFdName] if Options.uiFdName else []\r
421 FdsCommandDict["fv"] = [Options.uiFvName] if Options.uiFvName else []\r
422 FdsCommandDict["cap"] = [Options.uiCapName] if Options.uiCapName else []\r
423 return FdsCommandDict\r
424\r
425\r
426gParamCheck = []\r
427def SingleCheckCallback(option, opt_str, value, parser):\r
428 if option not in gParamCheck:\r
429 setattr(parser.values, option.dest, value)\r
430 gParamCheck.append(option)\r
431 else:\r
432 parser.error("Option %s only allows one instance in command line!" % option)\r
433\r
434## Parse command line options\r
435#\r
436# Using standard Python module optparse to parse command line option of this tool.\r
437#\r
438# @retval Opt A optparse.Values object containing the parsed options\r
439#\r
440def myOptionParser():\r
441 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""\r
442 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))\r
443 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)\r
444 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")\r
445 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
446 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")\r
447 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
448 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",\r
449 action="callback", callback=SingleCheckCallback)\r
450 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",\r
451 action="callback", callback=SingleCheckCallback)\r
452 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",\r
453 action="callback", callback=SingleCheckCallback)\r
454 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")\r
455 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")\r
456 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")\r
457 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",\r
458 action="callback", callback=SingleCheckCallback)\r
459 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",\r
460 action="callback", callback=SingleCheckCallback)\r
461 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
462 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")\r
463 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
464 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")\r
465 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")\r
466 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=True, help="Enable GenFds multi thread to generate ffs file.")\r
467 Parser.add_option("--no-genfds-multi-thread", action="store_true", dest="NoGenfdsMultiThread", default=False, help="Disable GenFds multi thread to generate ffs file.")\r
468\r
469 Options, _ = Parser.parse_args()\r
470 return Options\r
471\r
472## The class implementing the EDK2 flash image generation process\r
473#\r
474# This process includes:\r
475# 1. Collect workspace information, includes platform and module information\r
476# 2. Call methods of Fd class to generate FD\r
477# 3. Call methods of Fv class to generate FV that not belong to FD\r
478#\r
479class GenFds(object):\r
480 FdfParsef = None\r
481 OnlyGenerateThisFd = None\r
482 OnlyGenerateThisFv = None\r
483 OnlyGenerateThisCap = None\r
484\r
485 ## GenFd()\r
486 #\r
487 # @param OutputDir Output directory\r
488 # @param FdfParserObject FDF contents parser\r
489 # @param Workspace The directory of workspace\r
490 # @param ArchList The Arch list of platform\r
491 #\r
492 @staticmethod\r
493 def GenFd (OutputDir, FdfParserObject, WorkSpace, ArchList):\r
494 GenFdsGlobalVariable.SetDir ('', FdfParserObject, WorkSpace, ArchList)\r
495\r
496 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")\r
497 if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict:\r
498 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[GenFds.OnlyGenerateThisCap.upper()]\r
499 if CapsuleObj is not None:\r
500 CapsuleObj.GenCapsule()\r
501 return\r
502\r
503 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:\r
504 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]\r
505 if FdObj is not None:\r
506 FdObj.GenFd()\r
507 return\r
508 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None:\r
509 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
510 FdObj.GenFd()\r
511\r
512 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")\r
513 if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict:\r
514 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[GenFds.OnlyGenerateThisFv.upper()]\r
515 if FvObj is not None:\r
516 Buffer = BytesIO()\r
517 FvObj.AddToBuffer(Buffer)\r
518 Buffer.close()\r
519 return\r
520 elif GenFds.OnlyGenerateThisFv is None:\r
521 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():\r
522 Buffer = BytesIO()\r
523 FvObj.AddToBuffer(Buffer)\r
524 Buffer.close()\r
525\r
526 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None:\r
527 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:\r
528 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")\r
529 for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values():\r
530 CapsuleObj.GenCapsule()\r
531\r
532 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:\r
533 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")\r
534 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():\r
535 OptRomObj.AddToBuffer(None)\r
536\r
537 @staticmethod\r
538 def GenFfsMakefile(OutputDir, FdfParserObject, WorkSpace, ArchList, GlobalData):\r
539 GenFdsGlobalVariable.SetEnv(FdfParserObject, WorkSpace, ArchList, GlobalData)\r
540 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
541 FdObj.GenFd(Flag=True)\r
542\r
543 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():\r
544 FvObj.AddToBuffer(Buffer=None, Flag=True)\r
545\r
546 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:\r
547 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():\r
548 OptRomObj.AddToBuffer(Buffer=None, Flag=True)\r
549\r
550 return GenFdsGlobalVariable.FfsCmdDict\r
551\r
552 ## GetFvBlockSize()\r
553 #\r
554 # @param FvObj Whose block size to get\r
555 # @retval int Block size value\r
556 #\r
557 @staticmethod\r
558 def GetFvBlockSize(FvObj):\r
559 DefaultBlockSize = 0x1\r
560 FdObj = None\r
561 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:\r
562 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]\r
563 if FdObj is None:\r
564 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
565 for ElementRegion in ElementFd.RegionList:\r
566 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:\r
567 for ElementRegionData in ElementRegion.RegionDataList:\r
568 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:\r
569 if FvObj.BlockSizeList != []:\r
570 return FvObj.BlockSizeList[0][0]\r
571 else:\r
572 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
573 if FvObj.BlockSizeList != []:\r
574 return FvObj.BlockSizeList[0][0]\r
575 return DefaultBlockSize\r
576 else:\r
577 for ElementRegion in FdObj.RegionList:\r
578 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:\r
579 for ElementRegionData in ElementRegion.RegionDataList:\r
580 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:\r
581 if FvObj.BlockSizeList != []:\r
582 return FvObj.BlockSizeList[0][0]\r
583 else:\r
584 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
585 return DefaultBlockSize\r
586\r
587 ## DisplayFvSpaceInfo()\r
588 #\r
589 # @param FvObj Whose block size to get\r
590 # @retval None\r
591 #\r
592 @staticmethod\r
593 def DisplayFvSpaceInfo(FdfParserObject):\r
594\r
595 FvSpaceInfoList = []\r
596 MaxFvNameLength = 0\r
597 for FvName in FdfParserObject.Profile.FvDict:\r
598 if len(FvName) > MaxFvNameLength:\r
599 MaxFvNameLength = len(FvName)\r
600 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')\r
601 if os.path.exists(FvSpaceInfoFileName):\r
602 FileLinesList = getlines(FvSpaceInfoFileName)\r
603 TotalFound = False\r
604 Total = ''\r
605 UsedFound = False\r
606 Used = ''\r
607 FreeFound = False\r
608 Free = ''\r
609 for Line in FileLinesList:\r
610 NameValue = Line.split('=')\r
611 if len(NameValue) == 2:\r
612 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':\r
613 TotalFound = True\r
614 Total = NameValue[1].strip()\r
615 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':\r
616 UsedFound = True\r
617 Used = NameValue[1].strip()\r
618 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':\r
619 FreeFound = True\r
620 Free = NameValue[1].strip()\r
621\r
622 if TotalFound and UsedFound and FreeFound:\r
623 FvSpaceInfoList.append((FvName, Total, Used, Free))\r
624\r
625 GenFdsGlobalVariable.InfLogger('\nFV Space Information')\r
626 for FvSpaceInfo in FvSpaceInfoList:\r
627 Name = FvSpaceInfo[0]\r
628 TotalSizeValue = int(FvSpaceInfo[1], 0)\r
629 UsedSizeValue = int(FvSpaceInfo[2], 0)\r
630 FreeSizeValue = int(FvSpaceInfo[3], 0)\r
631 if UsedSizeValue == TotalSizeValue:\r
632 Percentage = '100'\r
633 else:\r
634 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')\r
635\r
636 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] '\\r
637 + str(TotalSizeValue) + ' (' + hex(TotalSizeValue) + ')' + ' total, '\\r
638 + str(UsedSizeValue) + ' (' + hex(UsedSizeValue) + ')' + ' used, '\\r
639 + str(FreeSizeValue) + ' (' + hex(FreeSizeValue) + ')' + ' free')\r
640\r
641 ## PreprocessImage()\r
642 #\r
643 # @param BuildDb Database from build meta data files\r
644 # @param DscFile modules from dsc file will be preprocessed\r
645 # @retval None\r
646 #\r
647 @staticmethod\r
648 def PreprocessImage(BuildDb, DscFile):\r
649 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds\r
650 PcdValue = ''\r
651 for Key in PcdDict:\r
652 PcdObj = PcdDict[Key]\r
653 if PcdObj.TokenCName == 'PcdBsBaseAddress':\r
654 PcdValue = PcdObj.DefaultValue\r
655 break\r
656\r
657 if PcdValue == '':\r
658 return\r
659\r
660 Int64PcdValue = int(PcdValue, 0)\r
661 if Int64PcdValue == 0 or Int64PcdValue < -1:\r
662 return\r
663\r
664 TopAddress = 0\r
665 if Int64PcdValue > 0:\r
666 TopAddress = Int64PcdValue\r
667\r
668 ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules\r
669 for Key in ModuleDict:\r
670 ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
671 print(ModuleObj.BaseName + ' ' + ModuleObj.ModuleType)\r
672\r
673 @staticmethod\r
674 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):\r
675 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")\r
676 GuidXRefFile = []\r
677 PkgGuidDict = {}\r
678 GuidDict = {}\r
679 ModuleList = []\r
680 FileGuidList = []\r
681 VariableGuidSet = set()\r
682 for Arch in ArchList:\r
683 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
684 PkgList = GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag)\r
685 for P in PkgList:\r
686 PkgGuidDict.update(P.Guids)\r
687 for Name, Guid in PlatformDataBase.Pcds:\r
688 Pcd = PlatformDataBase.Pcds[Name, Guid]\r
689 if Pcd.Type in [TAB_PCDS_DYNAMIC_HII, TAB_PCDS_DYNAMIC_EX_HII]:\r
690 for SkuId in Pcd.SkuInfoList:\r
691 Sku = Pcd.SkuInfoList[SkuId]\r
692 if Sku.VariableGuid in VariableGuidSet:continue\r
693 VariableGuidSet.add(Sku.VariableGuid)\r
694 if Sku.VariableGuid and Sku.VariableGuid in PkgGuidDict.keys():\r
695 GuidDict[Sku.VariableGuid] = PkgGuidDict[Sku.VariableGuid]\r
696 for ModuleFile in PlatformDataBase.Modules:\r
697 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
698 if Module in ModuleList:\r
699 continue\r
700 else:\r
701 ModuleList.append(Module)\r
702 if GlobalData.gGuidPattern.match(ModuleFile.BaseName):\r
703 GuidXRefFile.append("%s %s\n" % (ModuleFile.BaseName, Module.BaseName))\r
704 else:\r
705 GuidXRefFile.append("%s %s\n" % (Module.Guid, Module.BaseName))\r
706 GuidDict.update(Module.Protocols)\r
707 GuidDict.update(Module.Guids)\r
708 GuidDict.update(Module.Ppis)\r
709 for FvName in FdfParserObj.Profile.FvDict:\r
710 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:\r
711 if not isinstance(FfsObj, FileStatement):\r
712 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))\r
713 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
714 if FdfModule in ModuleList:\r
715 continue\r
716 else:\r
717 ModuleList.append(FdfModule)\r
718 GuidXRefFile.append("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))\r
719 GuidDict.update(FdfModule.Protocols)\r
720 GuidDict.update(FdfModule.Guids)\r
721 GuidDict.update(FdfModule.Ppis)\r
722 else:\r
723 FileStatementGuid = FfsObj.NameGuid\r
724 if FileStatementGuid in FileGuidList:\r
725 continue\r
726 else:\r
727 FileGuidList.append(FileStatementGuid)\r
728 Name = []\r
729 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')\r
730 FfsPath = glob(os.path.join(FfsPath, FileStatementGuid) + TAB_STAR)\r
731 if not FfsPath:\r
732 continue\r
733 if not os.path.exists(FfsPath[0]):\r
734 continue\r
735 MatchDict = {}\r
736 ReFileEnds = compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')\r
737 FileList = os.listdir(FfsPath[0])\r
738 for File in FileList:\r
739 Match = ReFileEnds.search(File)\r
740 if Match:\r
741 for Index in range(1, 8):\r
742 if Match.group(Index) and Match.group(Index) in MatchDict:\r
743 MatchDict[Match.group(Index)].append(File)\r
744 elif Match.group(Index):\r
745 MatchDict[Match.group(Index)] = [File]\r
746 if not MatchDict:\r
747 continue\r
748 if '.ui' in MatchDict:\r
749 for File in MatchDict['.ui']:\r
750 with open(os.path.join(FfsPath[0], File), 'rb') as F:\r
751 F.read()\r
752 length = F.tell()\r
753 F.seek(4)\r
754 TmpStr = unpack('%dh' % ((length - 4) // 2), F.read())\r
755 Name = ''.join(chr(c) for c in TmpStr[:-1])\r
756 else:\r
757 FileList = []\r
758 if 'fv.sec.txt' in MatchDict:\r
759 FileList = MatchDict['fv.sec.txt']\r
760 elif '.pe32.txt' in MatchDict:\r
761 FileList = MatchDict['.pe32.txt']\r
762 elif '.te.txt' in MatchDict:\r
763 FileList = MatchDict['.te.txt']\r
764 elif '.pic.txt' in MatchDict:\r
765 FileList = MatchDict['.pic.txt']\r
766 elif '.raw.txt' in MatchDict:\r
767 FileList = MatchDict['.raw.txt']\r
768 elif '.ffs.txt' in MatchDict:\r
769 FileList = MatchDict['.ffs.txt']\r
770 else:\r
771 pass\r
772 for File in FileList:\r
773 with open(os.path.join(FfsPath[0], File), 'r') as F:\r
774 Name.append((F.read().split()[-1]))\r
775 if not Name:\r
776 continue\r
777\r
778 Name = ' '.join(Name) if isinstance(Name, type([])) else Name\r
779 GuidXRefFile.append("%s %s\n" %(FileStatementGuid, Name))\r
780\r
781 # Append GUIDs, Protocols, and PPIs to the Xref file\r
782 GuidXRefFile.append("\n")\r
783 for key, item in GuidDict.items():\r
784 GuidXRefFile.append("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))\r
785\r
786 if GuidXRefFile:\r
787 GuidXRefFile = ''.join(GuidXRefFile)\r
788 SaveFileOnChange(GuidXRefFileName, GuidXRefFile, False)\r
789 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)\r
790 elif os.path.exists(GuidXRefFileName):\r
791 os.remove(GuidXRefFileName)\r
792\r
793\r
794if __name__ == '__main__':\r
795 r = main()\r
796 ## 0-127 is a safe return range, and 1 is a standard default error\r
797 if r < 0 or r > 127:\r
798 r = 1\r
799 exit(r)\r
800\r