]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/GenFds/GenFds.py
BaseTools: Enable --genfds-multi-thread to default build
[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 TargetTxt\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.realpath(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.realpath(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, "target.txt"))\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 if not GenFdsGlobalVariable.TargetName:\r
214 BuildTargetList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]\r
215 if len(BuildTargetList) != 1:\r
216 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for Target.")\r
217 GenFdsGlobalVariable.TargetName = BuildTargetList[0]\r
218\r
219 # if no tool chain given in command line, get it from target.txt\r
220 if not GenFdsGlobalVariable.ToolChainTag:\r
221 ToolChainList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
222 if ToolChainList is None or len(ToolChainList) == 0:\r
223 EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.")\r
224 if len(ToolChainList) != 1:\r
225 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for ToolChain.")\r
226 GenFdsGlobalVariable.ToolChainTag = ToolChainList[0]\r
227 else:\r
228 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
229\r
230 #Set global flag for build mode\r
231 GlobalData.gIgnoreSource = FdsCommandDict.get("IgnoreSources")\r
232\r
233 if FdsCommandDict.get("macro"):\r
234 for Pair in FdsCommandDict.get("macro"):\r
235 if Pair.startswith('"'):\r
236 Pair = Pair[1:]\r
237 if Pair.endswith('"'):\r
238 Pair = Pair[:-1]\r
239 List = Pair.split('=')\r
240 if len(List) == 2:\r
241 if not List[1].strip():\r
242 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="No Value given for Macro %s" %List[0])\r
243 if List[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:\r
244 GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip()\r
245 else:\r
246 GlobalData.gCommandLineDefines[List[0].strip()] = List[1].strip()\r
247 else:\r
248 GlobalData.gCommandLineDefines[List[0].strip()] = "TRUE"\r
249 os.environ["WORKSPACE"] = Workspace\r
250\r
251 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined\r
252 if "TARGET" not in GlobalData.gGlobalDefines:\r
253 GlobalData.gGlobalDefines["TARGET"] = GenFdsGlobalVariable.TargetName\r
254 if "TOOLCHAIN" not in GlobalData.gGlobalDefines:\r
255 GlobalData.gGlobalDefines["TOOLCHAIN"] = GenFdsGlobalVariable.ToolChainTag\r
256 if "TOOL_CHAIN_TAG" not in GlobalData.gGlobalDefines:\r
257 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable.ToolChainTag\r
258\r
259 """call Workspace build create database"""\r
260 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))\r
261\r
262 if WorkSpaceDataBase:\r
263 BuildWorkSpace = WorkSpaceDataBase\r
264 else:\r
265 BuildWorkSpace = WorkspaceDatabase()\r
266 #\r
267 # Get files real name in workspace dir\r
268 #\r
269 GlobalData.gAllFiles = DirCache(Workspace)\r
270 GlobalData.gWorkspace = Workspace\r
271\r
272 if FdsCommandDict.get("build_architecture_list"):\r
273 ArchList = FdsCommandDict.get("build_architecture_list").split(',')\r
274 else:\r
275 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList\r
276\r
277 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList) & set(ArchList)\r
278 if len(TargetArchList) == 0:\r
279 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
280\r
281 for Arch in ArchList:\r
282 GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].OutputDirectory)\r
283\r
284 # assign platform name based on last entry in ArchList\r
285 GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, ArchList[-1], FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].PlatformName\r
286\r
287 if FdsCommandDict.get("platform_build_directory"):\r
288 OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdsCommandDict.get("platform_build_directory"))\r
289 if not os.path.isabs (OutputDirFromCommandLine):\r
290 OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine)\r
291 for Arch in ArchList:\r
292 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine\r
293 else:\r
294 for Arch in ArchList:\r
295 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)\r
296\r
297 for Key in GenFdsGlobalVariable.OutputDirDict:\r
298 OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]\r
299 if OutputDir[0:2] == '..':\r
300 OutputDir = os.path.realpath(OutputDir)\r
301\r
302 if OutputDir[1] != ':':\r
303 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)\r
304\r
305 if not os.path.exists(OutputDir):\r
306 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir)\r
307 GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir\r
308\r
309 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """\r
310 if WorkSpaceDataBase:\r
311 FdfParserObj = GlobalData.gFdfParser\r
312 else:\r
313 FdfParserObj = FdfParser(FdfFilename)\r
314 FdfParserObj.ParseFile()\r
315\r
316 if FdfParserObj.CycleReferenceCheck():\r
317 EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")\r
318\r
319 if FdsCommandDict.get("fd"):\r
320 if FdsCommandDict.get("fd")[0].upper() in FdfParserObj.Profile.FdDict:\r
321 GenFds.OnlyGenerateThisFd = FdsCommandDict.get("fd")[0]\r
322 else:\r
323 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,\r
324 "No such an FD in FDF file: %s" % FdsCommandDict.get("fd")[0])\r
325\r
326 if FdsCommandDict.get("fv"):\r
327 if FdsCommandDict.get("fv")[0].upper() in FdfParserObj.Profile.FvDict:\r
328 GenFds.OnlyGenerateThisFv = FdsCommandDict.get("fv")[0]\r
329 else:\r
330 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,\r
331 "No such an FV in FDF file: %s" % FdsCommandDict.get("fv")[0])\r
332\r
333 if FdsCommandDict.get("cap"):\r
334 if FdsCommandDict.get("cap")[0].upper() in FdfParserObj.Profile.CapsuleDict:\r
335 GenFds.OnlyGenerateThisCap = FdsCommandDict.get("cap")[0]\r
336 else:\r
337 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,\r
338 "No such a Capsule in FDF file: %s" % FdsCommandDict.get("cap")[0])\r
339\r
340 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace\r
341 if ArchList:\r
342 GenFdsGlobalVariable.ArchList = ArchList\r
343\r
344 # Dsc Build Data will handle Pcd Settings from CommandLine.\r
345\r
346 """Modify images from build output if the feature of loading driver at fixed address is on."""\r
347 if GenFdsGlobalVariable.FixedLoadAddress:\r
348 GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform)\r
349\r
350 # Record the FV Region info that may specific in the FD\r
351 if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict:\r
352 for FvObj in FdfParserObj.Profile.FvDict.values():\r
353 for FdObj in FdfParserObj.Profile.FdDict.values():\r
354 for RegionObj in FdObj.RegionList:\r
355 if RegionObj.RegionType != BINARY_FILE_TYPE_FV:\r
356 continue\r
357 for RegionData in RegionObj.RegionDataList:\r
358 if FvObj.UiFvName.upper() == RegionData.upper():\r
359 if not FvObj.BaseAddress:\r
360 FvObj.BaseAddress = '0x%x' % (int(FdObj.BaseAddress, 0) + RegionObj.Offset)\r
361 if FvObj.FvRegionInFD:\r
362 if FvObj.FvRegionInFD != RegionObj.Size:\r
363 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName)\r
364 else:\r
365 FvObj.FvRegionInFD = RegionObj.Size\r
366 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)\r
367\r
368 """Call GenFds"""\r
369 GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)\r
370\r
371 """Generate GUID cross reference file"""\r
372 GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj)\r
373\r
374 """Display FV space info."""\r
375 GenFds.DisplayFvSpaceInfo(FdfParserObj)\r
376\r
377 except Warning as X:\r
378 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
379 ReturnCode = FORMAT_INVALID\r
380 except FatalError as X:\r
381 if FdsCommandDict.get("debug") is not None:\r
382 import traceback\r
383 EdkLogger.quiet(traceback.format_exc())\r
384 ReturnCode = X.args[0]\r
385 except:\r
386 import traceback\r
387 EdkLogger.error(\r
388 "\nPython",\r
389 CODE_ERROR,\r
390 "Tools code failure",\r
391 ExtraData="Please send email to %s for help, attaching following call stack trace!\n" % MSG_EDKII_MAIL_ADDR,\r
392 RaiseError=False\r
393 )\r
394 EdkLogger.quiet(traceback.format_exc())\r
395 ReturnCode = CODE_ERROR\r
396 finally:\r
397 ClearDuplicatedInf()\r
398 return ReturnCode\r
399\r
400def OptionsToCommandDict(Options):\r
401 FdsCommandDict = {}\r
402 FdsCommandDict["verbose"] = Options.verbose\r
403 FdsCommandDict["FixedAddress"] = Options.FixedAddress\r
404 FdsCommandDict["quiet"] = Options.quiet\r
405 FdsCommandDict["debug"] = Options.debug\r
406 FdsCommandDict["Workspace"] = Options.Workspace\r
407 FdsCommandDict["GenfdsMultiThread"] = not Options.NoGenfdsMultiThread\r
408 FdsCommandDict["fdf_file"] = [PathClass(Options.filename)] if Options.filename else []\r
409 FdsCommandDict["build_target"] = Options.BuildTarget\r
410 FdsCommandDict["toolchain_tag"] = Options.ToolChain\r
411 FdsCommandDict["active_platform"] = Options.activePlatform\r
412 FdsCommandDict["OptionPcd"] = Options.OptionPcd\r
413 FdsCommandDict["conf_directory"] = Options.ConfDirectory\r
414 FdsCommandDict["IgnoreSources"] = Options.IgnoreSources\r
415 FdsCommandDict["macro"] = Options.Macros\r
416 FdsCommandDict["build_architecture_list"] = Options.archList\r
417 FdsCommandDict["platform_build_directory"] = Options.outputDir\r
418 FdsCommandDict["fd"] = [Options.uiFdName] if Options.uiFdName else []\r
419 FdsCommandDict["fv"] = [Options.uiFvName] if Options.uiFvName else []\r
420 FdsCommandDict["cap"] = [Options.uiCapName] if Options.uiCapName else []\r
421 return FdsCommandDict\r
422\r
423\r
424gParamCheck = []\r
425def SingleCheckCallback(option, opt_str, value, parser):\r
426 if option not in gParamCheck:\r
427 setattr(parser.values, option.dest, value)\r
428 gParamCheck.append(option)\r
429 else:\r
430 parser.error("Option %s only allows one instance in command line!" % option)\r
431\r
432## Parse command line options\r
433#\r
434# Using standard Python module optparse to parse command line option of this tool.\r
435#\r
436# @retval Opt A optparse.Values object containing the parsed options\r
437#\r
438def myOptionParser():\r
439 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""\r
440 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))\r
441 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)\r
442 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
443 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
444 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")\r
445 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
446 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",\r
447 action="callback", callback=SingleCheckCallback)\r
448 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",\r
449 action="callback", callback=SingleCheckCallback)\r
450 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",\r
451 action="callback", callback=SingleCheckCallback)\r
452 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")\r
453 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")\r
454 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")\r
455 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",\r
456 action="callback", callback=SingleCheckCallback)\r
457 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",\r
458 action="callback", callback=SingleCheckCallback)\r
459 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
460 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")\r
461 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
462 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")\r
463 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")\r
464 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=True, help="Enable GenFds multi thread to generate ffs file.")\r
465 Parser.add_option("--no-genfds-multi-thread", action="store_true", dest="NoGenfdsMultiThread", default=False, help="Disable GenFds multi thread to generate ffs file.")\r
466\r
467 Options, _ = Parser.parse_args()\r
468 return Options\r
469\r
470## The class implementing the EDK2 flash image generation process\r
471#\r
472# This process includes:\r
473# 1. Collect workspace information, includes platform and module information\r
474# 2. Call methods of Fd class to generate FD\r
475# 3. Call methods of Fv class to generate FV that not belong to FD\r
476#\r
477class GenFds(object):\r
478 FdfParsef = None\r
479 OnlyGenerateThisFd = None\r
480 OnlyGenerateThisFv = None\r
481 OnlyGenerateThisCap = None\r
482\r
483 ## GenFd()\r
484 #\r
485 # @param OutputDir Output directory\r
486 # @param FdfParserObject FDF contents parser\r
487 # @param Workspace The directory of workspace\r
488 # @param ArchList The Arch list of platform\r
489 #\r
490 @staticmethod\r
491 def GenFd (OutputDir, FdfParserObject, WorkSpace, ArchList):\r
492 GenFdsGlobalVariable.SetDir ('', FdfParserObject, WorkSpace, ArchList)\r
493\r
494 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")\r
495 if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict:\r
496 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[GenFds.OnlyGenerateThisCap.upper()]\r
497 if CapsuleObj is not None:\r
498 CapsuleObj.GenCapsule()\r
499 return\r
500\r
501 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:\r
502 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]\r
503 if FdObj is not None:\r
504 FdObj.GenFd()\r
505 return\r
506 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None:\r
507 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
508 FdObj.GenFd()\r
509\r
510 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")\r
511 if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict:\r
512 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[GenFds.OnlyGenerateThisFv.upper()]\r
513 if FvObj is not None:\r
514 Buffer = BytesIO()\r
515 FvObj.AddToBuffer(Buffer)\r
516 Buffer.close()\r
517 return\r
518 elif GenFds.OnlyGenerateThisFv is None:\r
519 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():\r
520 Buffer = BytesIO()\r
521 FvObj.AddToBuffer(Buffer)\r
522 Buffer.close()\r
523\r
524 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None:\r
525 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:\r
526 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")\r
527 for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values():\r
528 CapsuleObj.GenCapsule()\r
529\r
530 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:\r
531 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")\r
532 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():\r
533 OptRomObj.AddToBuffer(None)\r
534\r
535 @staticmethod\r
536 def GenFfsMakefile(OutputDir, FdfParserObject, WorkSpace, ArchList, GlobalData):\r
537 GenFdsGlobalVariable.SetEnv(FdfParserObject, WorkSpace, ArchList, GlobalData)\r
538 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
539 FdObj.GenFd(Flag=True)\r
540\r
541 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():\r
542 FvObj.AddToBuffer(Buffer=None, Flag=True)\r
543\r
544 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:\r
545 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():\r
546 OptRomObj.AddToBuffer(Buffer=None, Flag=True)\r
547\r
548 return GenFdsGlobalVariable.FfsCmdDict\r
549\r
550 ## GetFvBlockSize()\r
551 #\r
552 # @param FvObj Whose block size to get\r
553 # @retval int Block size value\r
554 #\r
555 @staticmethod\r
556 def GetFvBlockSize(FvObj):\r
557 DefaultBlockSize = 0x1\r
558 FdObj = None\r
559 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:\r
560 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]\r
561 if FdObj is None:\r
562 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
563 for ElementRegion in ElementFd.RegionList:\r
564 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:\r
565 for ElementRegionData in ElementRegion.RegionDataList:\r
566 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:\r
567 if FvObj.BlockSizeList != []:\r
568 return FvObj.BlockSizeList[0][0]\r
569 else:\r
570 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
571 if FvObj.BlockSizeList != []:\r
572 return FvObj.BlockSizeList[0][0]\r
573 return DefaultBlockSize\r
574 else:\r
575 for ElementRegion in FdObj.RegionList:\r
576 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:\r
577 for ElementRegionData in ElementRegion.RegionDataList:\r
578 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:\r
579 if FvObj.BlockSizeList != []:\r
580 return FvObj.BlockSizeList[0][0]\r
581 else:\r
582 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
583 return DefaultBlockSize\r
584\r
585 ## DisplayFvSpaceInfo()\r
586 #\r
587 # @param FvObj Whose block size to get\r
588 # @retval None\r
589 #\r
590 @staticmethod\r
591 def DisplayFvSpaceInfo(FdfParserObject):\r
592\r
593 FvSpaceInfoList = []\r
594 MaxFvNameLength = 0\r
595 for FvName in FdfParserObject.Profile.FvDict:\r
596 if len(FvName) > MaxFvNameLength:\r
597 MaxFvNameLength = len(FvName)\r
598 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')\r
599 if os.path.exists(FvSpaceInfoFileName):\r
600 FileLinesList = getlines(FvSpaceInfoFileName)\r
601 TotalFound = False\r
602 Total = ''\r
603 UsedFound = False\r
604 Used = ''\r
605 FreeFound = False\r
606 Free = ''\r
607 for Line in FileLinesList:\r
608 NameValue = Line.split('=')\r
609 if len(NameValue) == 2:\r
610 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':\r
611 TotalFound = True\r
612 Total = NameValue[1].strip()\r
613 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':\r
614 UsedFound = True\r
615 Used = NameValue[1].strip()\r
616 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':\r
617 FreeFound = True\r
618 Free = NameValue[1].strip()\r
619\r
620 if TotalFound and UsedFound and FreeFound:\r
621 FvSpaceInfoList.append((FvName, Total, Used, Free))\r
622\r
623 GenFdsGlobalVariable.InfLogger('\nFV Space Information')\r
624 for FvSpaceInfo in FvSpaceInfoList:\r
625 Name = FvSpaceInfo[0]\r
626 TotalSizeValue = int(FvSpaceInfo[1], 0)\r
627 UsedSizeValue = int(FvSpaceInfo[2], 0)\r
628 FreeSizeValue = int(FvSpaceInfo[3], 0)\r
629 if UsedSizeValue == TotalSizeValue:\r
630 Percentage = '100'\r
631 else:\r
632 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')\r
633\r
634 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')\r
635\r
636 ## PreprocessImage()\r
637 #\r
638 # @param BuildDb Database from build meta data files\r
639 # @param DscFile modules from dsc file will be preprocessed\r
640 # @retval None\r
641 #\r
642 @staticmethod\r
643 def PreprocessImage(BuildDb, DscFile):\r
644 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds\r
645 PcdValue = ''\r
646 for Key in PcdDict:\r
647 PcdObj = PcdDict[Key]\r
648 if PcdObj.TokenCName == 'PcdBsBaseAddress':\r
649 PcdValue = PcdObj.DefaultValue\r
650 break\r
651\r
652 if PcdValue == '':\r
653 return\r
654\r
655 Int64PcdValue = int(PcdValue, 0)\r
656 if Int64PcdValue == 0 or Int64PcdValue < -1:\r
657 return\r
658\r
659 TopAddress = 0\r
660 if Int64PcdValue > 0:\r
661 TopAddress = Int64PcdValue\r
662\r
663 ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules\r
664 for Key in ModuleDict:\r
665 ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
666 print(ModuleObj.BaseName + ' ' + ModuleObj.ModuleType)\r
667\r
668 @staticmethod\r
669 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):\r
670 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")\r
671 GuidXRefFile = []\r
672 PkgGuidDict = {}\r
673 GuidDict = {}\r
674 ModuleList = []\r
675 FileGuidList = []\r
676 VariableGuidSet = set()\r
677 for Arch in ArchList:\r
678 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
679 PkgList = GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag)\r
680 for P in PkgList:\r
681 PkgGuidDict.update(P.Guids)\r
682 for Name, Guid in PlatformDataBase.Pcds:\r
683 Pcd = PlatformDataBase.Pcds[Name, Guid]\r
684 if Pcd.Type in [TAB_PCDS_DYNAMIC_HII, TAB_PCDS_DYNAMIC_EX_HII]:\r
685 for SkuId in Pcd.SkuInfoList:\r
686 Sku = Pcd.SkuInfoList[SkuId]\r
687 if Sku.VariableGuid in VariableGuidSet:continue\r
688 VariableGuidSet.add(Sku.VariableGuid)\r
689 if Sku.VariableGuid and Sku.VariableGuid in PkgGuidDict.keys():\r
690 GuidDict[Sku.VariableGuid] = PkgGuidDict[Sku.VariableGuid]\r
691 for ModuleFile in PlatformDataBase.Modules:\r
692 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
693 if Module in ModuleList:\r
694 continue\r
695 else:\r
696 ModuleList.append(Module)\r
697 if GlobalData.gGuidPattern.match(ModuleFile.BaseName):\r
698 GuidXRefFile.append("%s %s\n" % (ModuleFile.BaseName, Module.BaseName))\r
699 else:\r
700 GuidXRefFile.append("%s %s\n" % (Module.Guid, Module.BaseName))\r
701 GuidDict.update(Module.Protocols)\r
702 GuidDict.update(Module.Guids)\r
703 GuidDict.update(Module.Ppis)\r
704 for FvName in FdfParserObj.Profile.FvDict:\r
705 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:\r
706 if not isinstance(FfsObj, FileStatement):\r
707 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))\r
708 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
709 if FdfModule in ModuleList:\r
710 continue\r
711 else:\r
712 ModuleList.append(FdfModule)\r
713 GuidXRefFile.append("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))\r
714 GuidDict.update(FdfModule.Protocols)\r
715 GuidDict.update(FdfModule.Guids)\r
716 GuidDict.update(FdfModule.Ppis)\r
717 else:\r
718 FileStatementGuid = FfsObj.NameGuid\r
719 if FileStatementGuid in FileGuidList:\r
720 continue\r
721 else:\r
722 FileGuidList.append(FileStatementGuid)\r
723 Name = []\r
724 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')\r
725 FfsPath = glob(os.path.join(FfsPath, FileStatementGuid) + TAB_STAR)\r
726 if not FfsPath:\r
727 continue\r
728 if not os.path.exists(FfsPath[0]):\r
729 continue\r
730 MatchDict = {}\r
731 ReFileEnds = compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')\r
732 FileList = os.listdir(FfsPath[0])\r
733 for File in FileList:\r
734 Match = ReFileEnds.search(File)\r
735 if Match:\r
736 for Index in range(1, 8):\r
737 if Match.group(Index) and Match.group(Index) in MatchDict:\r
738 MatchDict[Match.group(Index)].append(File)\r
739 elif Match.group(Index):\r
740 MatchDict[Match.group(Index)] = [File]\r
741 if not MatchDict:\r
742 continue\r
743 if '.ui' in MatchDict:\r
744 for File in MatchDict['.ui']:\r
745 with open(os.path.join(FfsPath[0], File), 'rb') as F:\r
746 F.read()\r
747 length = F.tell()\r
748 F.seek(4)\r
749 TmpStr = unpack('%dh' % ((length - 4) // 2), F.read())\r
750 Name = ''.join(chr(c) for c in TmpStr[:-1])\r
751 else:\r
752 FileList = []\r
753 if 'fv.sec.txt' in MatchDict:\r
754 FileList = MatchDict['fv.sec.txt']\r
755 elif '.pe32.txt' in MatchDict:\r
756 FileList = MatchDict['.pe32.txt']\r
757 elif '.te.txt' in MatchDict:\r
758 FileList = MatchDict['.te.txt']\r
759 elif '.pic.txt' in MatchDict:\r
760 FileList = MatchDict['.pic.txt']\r
761 elif '.raw.txt' in MatchDict:\r
762 FileList = MatchDict['.raw.txt']\r
763 elif '.ffs.txt' in MatchDict:\r
764 FileList = MatchDict['.ffs.txt']\r
765 else:\r
766 pass\r
767 for File in FileList:\r
768 with open(os.path.join(FfsPath[0], File), 'r') as F:\r
769 Name.append((F.read().split()[-1]))\r
770 if not Name:\r
771 continue\r
772\r
773 Name = ' '.join(Name) if isinstance(Name, type([])) else Name\r
774 GuidXRefFile.append("%s %s\n" %(FileStatementGuid, Name))\r
775\r
776 # Append GUIDs, Protocols, and PPIs to the Xref file\r
777 GuidXRefFile.append("\n")\r
778 for key, item in GuidDict.items():\r
779 GuidXRefFile.append("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))\r
780\r
781 if GuidXRefFile:\r
782 GuidXRefFile = ''.join(GuidXRefFile)\r
783 SaveFileOnChange(GuidXRefFileName, GuidXRefFile, False)\r
784 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)\r
785 elif os.path.exists(GuidXRefFileName):\r
786 os.remove(GuidXRefFileName)\r
787\r
788\r
789if __name__ == '__main__':\r
790 r = main()\r
791 ## 0-127 is a safe return range, and 1 is a standard default error\r
792 if r < 0 or r > 127:\r
793 r = 1\r
794 exit(r)\r
795\r