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