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