]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/GenFds/GenFds.py
BaseTools/Tests: Update GNUmakefile to use python3 variable
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / GenFds.py
CommitLineData
f51461c8
LG
1## @file\r
2# generate flash image\r
3#\r
541a3f58 4# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
f51461c8
LG
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 optparse import OptionParser\r
19import sys\r
1be2ed90 20import Common.LongFilePathOs as os\r
f51461c8 21import linecache\r
bfa65b61 22from . import FdfParser\r
f51461c8 23import Common.BuildToolError as BuildToolError\r
bfa65b61 24from .GenFdsGlobalVariable import GenFdsGlobalVariable\r
f51461c8
LG
25from Workspace.WorkspaceDatabase import WorkspaceDatabase\r
26from Workspace.BuildClassObject import PcdClassObject\r
bfa65b61
GL
27from . import RuleComplexFile\r
28from .EfiSection import EfiSection\r
86379ac4 29from io import BytesIO\r
86e6cf98 30from io import StringIO\r
f51461c8
LG
31import Common.TargetTxtClassObject as TargetTxtClassObject\r
32import Common.ToolDefClassObject as ToolDefClassObject\r
95816356 33from Common.DataType import *\r
f51461c8
LG
34import Common.GlobalData as GlobalData\r
35from Common import EdkLogger\r
5a57246e 36from Common.StringUtils import *\r
47fea6af 37from Common.Misc import DirCache, PathClass\r
f51461c8 38from Common.Misc import SaveFileOnChange\r
97fa0ee9 39from Common.Misc import ClearDuplicatedInf\r
e4ac870f 40from Common.Misc import GuidStructureStringToGuidString\r
f51461c8 41from Common.BuildVersion import gBUILD_VERSION\r
05cc51ad 42from Common.MultipleWorkspace import MultipleWorkspace as mws\r
bfa65b61 43from . import FfsFileStatement\r
5e9256cd
YZ
44import glob\r
45from struct import unpack\r
cefc8d88 46from Common.GlobalData import gGuidPattern\r
f51461c8
LG
47\r
48## Version and Copyright\r
49versionNumber = "1.0" + ' ' + gBUILD_VERSION\r
50__version__ = "%prog Version " + versionNumber\r
f7496d71 51__copyright__ = "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."\r
f51461c8
LG
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
4231a819 73 if Options.verbose is not None:\r
f51461c8
LG
74 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
75 GenFdsGlobalVariable.VerboseMode = True\r
f7496d71 76\r
4231a819 77 if Options.FixedAddress is not None:\r
f51461c8 78 GenFdsGlobalVariable.FixedLoadAddress = True\r
f7496d71 79\r
4231a819 80 if Options.quiet is not None:\r
f51461c8 81 EdkLogger.SetLevel(EdkLogger.QUIET)\r
4231a819 82 if Options.debug is not None:\r
f51461c8
LG
83 EdkLogger.SetLevel(Options.debug + 1)\r
84 GenFdsGlobalVariable.DebugLevel = Options.debug\r
85 else:\r
86 EdkLogger.SetLevel(EdkLogger.INFO)\r
87\r
4231a819 88 if (Options.Workspace is None):\r
f51461c8
LG
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
9eb87141 97 if 'EDK_SOURCE' in os.environ:\r
f51461c8
LG
98 GenFdsGlobalVariable.EdkSourceDir = os.path.normcase(os.environ['EDK_SOURCE'])\r
99 if (Options.debug):\r
47fea6af 100 GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace)\r
37de70b7
YZ
101 if Options.GenfdsMultiThread:\r
102 GenFdsGlobalVariable.EnableGenfdsMultiThread = True\r
f51461c8 103 os.chdir(GenFdsGlobalVariable.WorkSpaceDir)\r
f7496d71 104\r
05cc51ad
LY
105 # set multiple workspace\r
106 PackagesPath = os.getenv("PACKAGES_PATH")\r
107 mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath)\r
f51461c8
LG
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
47fea6af 115 if not os.path.isabs(FdfFilename):\r
05cc51ad 116 FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)\r
f51461c8
LG
117 if not os.path.exists(FdfFilename):\r
118 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename)\r
f51461c8
LG
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
f51461c8
LG
127\r
128 if (Options.ToolChain):\r
129 GenFdsGlobalVariable.ToolChainTag = Options.ToolChain\r
f51461c8
LG
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
05cc51ad 139 ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)\r
f51461c8
LG
140\r
141 if not os.path.exists(ActivePlatform) :\r
142 EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!")\r
f51461c8
LG
143 else:\r
144 EdkLogger.error("GenFds", OPTION_MISSING, "Missing active platform")\r
145\r
705ed563 146 GlobalData.BuildOptionPcd = Options.OptionPcd if Options.OptionPcd else {}\r
e642ceb8 147 GenFdsGlobalVariable.ActivePlatform = PathClass(NormPath(ActivePlatform))\r
f51461c8 148\r
97fa0ee9
YL
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
9eb87141 161 if "CONF_PATH" in os.environ:\r
00bcb5c2
YZ
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
97fa0ee9 166 GenFdsGlobalVariable.ConfDir = ConfDirectoryPath\r
541a3f58
FY
167 if not GlobalData.gConfDirectory:\r
168 GlobalData.gConfDirectory = GenFdsGlobalVariable.ConfDir\r
97fa0ee9 169 BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt"))\r
f51461c8 170 if os.path.isfile(BuildConfigurationFile) == True:\r
e4979bee
YZ
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
4231a819 183 if ToolChainList is None or len(ToolChainList) == 0:\r
e4979bee
YZ
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
f51461c8
LG
188 else:\r
189 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
190\r
97fa0ee9
YL
191 #Set global flag for build mode\r
192 GlobalData.gIgnoreSource = Options.IgnoreSources\r
193\r
f51461c8
LG
194 if Options.Macros:\r
195 for Pair in Options.Macros:\r
97fa0ee9
YL
196 if Pair.startswith('"'):\r
197 Pair = Pair[1:]\r
198 if Pair.endswith('"'):\r
199 Pair = Pair[:-1]\r
f51461c8
LG
200 List = Pair.split('=')\r
201 if len(List) == 2:\r
e4979bee
YZ
202 if not List[1].strip():\r
203 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="No Value given for Macro %s" %List[0])\r
f51461c8
LG
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
e4979bee 220 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined\r
9eb87141 221 if "TARGET" not in GlobalData.gGlobalDefines:\r
e4979bee 222 GlobalData.gGlobalDefines["TARGET"] = GenFdsGlobalVariable.TargetName\r
9eb87141 223 if "TOOLCHAIN" not in GlobalData.gGlobalDefines:\r
e4979bee 224 GlobalData.gGlobalDefines["TOOLCHAIN"] = GenFdsGlobalVariable.ToolChainTag\r
9eb87141 225 if "TOOL_CHAIN_TAG" not in GlobalData.gGlobalDefines:\r
e4979bee
YZ
226 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable.ToolChainTag\r
227\r
f51461c8 228 """call Workspace build create database"""\r
97fa0ee9
YL
229 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))\r
230 BuildWorkSpace = WorkspaceDatabase(GlobalData.gDatabasePath)\r
f51461c8 231 BuildWorkSpace.InitDatabase()\r
f7496d71 232\r
f51461c8
LG
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
55c84777 243 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, Options.BuildTarget, Options.ToolChain].SupArchList\r
f51461c8 244\r
55c84777 245 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, Options.BuildTarget, Options.ToolChain].SupArchList) & set(ArchList)\r
f51461c8 246 if len(TargetArchList) == 0:\r
55c84777 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
f7496d71 248\r
f51461c8
LG
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
9eb87141 283 if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict:\r
f51461c8
LG
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
9eb87141 290 if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict:\r
f51461c8
LG
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
9eb87141 297 if Options.uiCapName.upper() in FdfParserObj.Profile.CapsuleDict:\r
f51461c8
LG
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
6b17c11b 303 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace\r
4231a819 304 if ArchList is not None:\r
6b17c11b
YZ
305 GenFdsGlobalVariable.ArchList = ArchList\r
306\r
6f49996c 307 # Dsc Build Data will handle Pcd Settings from CommandLine.\r
6b17c11b 308\r
f51461c8
LG
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
135ae8c8
YZ
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
91fa33ee 320 if RegionObj.RegionType != BINARY_FILE_TYPE_FV:\r
135ae8c8
YZ
321 continue\r
322 for RegionData in RegionObj.RegionDataList:\r
323 if FvObj.UiFvName.upper() == RegionData.upper():\r
8be15c61
YF
324 if not FvObj.BaseAddress:\r
325 FvObj.BaseAddress = '0x%x' % (int(FdObj.BaseAddress, 0) + RegionObj.Offset)\r
135ae8c8
YZ
326 if FvObj.FvRegionInFD:\r
327 if FvObj.FvRegionInFD != RegionObj.Size:\r
328 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName)\r
329 else:\r
330 FvObj.FvRegionInFD = RegionObj.Size\r
331 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)\r
332\r
f51461c8
LG
333 """Call GenFds"""\r
334 GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)\r
335\r
336 """Generate GUID cross reference file"""\r
5e9256cd 337 GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj)\r
f51461c8
LG
338\r
339 """Display FV space info."""\r
340 GenFds.DisplayFvSpaceInfo(FdfParserObj)\r
341\r
5b0671c1 342 except FdfParser.Warning as X:\r
47fea6af 343 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
f51461c8 344 ReturnCode = FORMAT_INVALID\r
5b0671c1 345 except FatalError as X:\r
4231a819 346 if Options.debug is not None:\r
f51461c8
LG
347 import traceback\r
348 EdkLogger.quiet(traceback.format_exc())\r
349 ReturnCode = X.args[0]\r
350 except:\r
351 import traceback\r
352 EdkLogger.error(\r
353 "\nPython",\r
354 CODE_ERROR,\r
355 "Tools code failure",\r
3a0f8bde 356 ExtraData="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",\r
f51461c8
LG
357 RaiseError=False\r
358 )\r
359 EdkLogger.quiet(traceback.format_exc())\r
360 ReturnCode = CODE_ERROR\r
97fa0ee9
YL
361 finally:\r
362 ClearDuplicatedInf()\r
f51461c8
LG
363 return ReturnCode\r
364\r
365gParamCheck = []\r
366def SingleCheckCallback(option, opt_str, value, parser):\r
367 if option not in gParamCheck:\r
368 setattr(parser.values, option.dest, value)\r
369 gParamCheck.append(option)\r
370 else:\r
371 parser.error("Option %s only allows one instance in command line!" % option)\r
6b17c11b 372\r
f51461c8
LG
373## Parse command line options\r
374#\r
375# Using standard Python module optparse to parse command line option of this tool.\r
376#\r
377# @retval Opt A optparse.Values object containing the parsed options\r
378# @retval Args Target of build command\r
379#\r
380def myOptionParser():\r
381 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""\r
47fea6af 382 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))\r
f51461c8
LG
383 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)\r
384 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
385 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
386 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")\r
387 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
388 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",\r
389 action="callback", callback=SingleCheckCallback)\r
390 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",\r
391 action="callback", callback=SingleCheckCallback)\r
392 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",\r
393 action="callback", callback=SingleCheckCallback)\r
394 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")\r
395 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")\r
396 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")\r
397 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",\r
398 action="callback", callback=SingleCheckCallback)\r
399 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",\r
400 action="callback", callback=SingleCheckCallback)\r
401 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
402 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")\r
97fa0ee9
YL
403 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
404 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")\r
6b17c11b 405 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")\r
37de70b7 406 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")\r
97fa0ee9 407\r
f51461c8
LG
408 (Options, args) = Parser.parse_args()\r
409 return Options\r
410\r
411## The class implementing the EDK2 flash image generation process\r
412#\r
413# This process includes:\r
414# 1. Collect workspace information, includes platform and module information\r
415# 2. Call methods of Fd class to generate FD\r
416# 3. Call methods of Fv class to generate FV that not belong to FD\r
417#\r
418class GenFds :\r
419 FdfParsef = None\r
f51461c8
LG
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
9eb87141
CJ
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
4231a819 437 if CapsuleObj is not None:\r
f51461c8
LG
438 CapsuleObj.GenCapsule()\r
439 return\r
440\r
9eb87141
CJ
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
4231a819 443 if FdObj is not None:\r
f51461c8
LG
444 FdObj.GenFd()\r
445 return\r
4231a819 446 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None:\r
9eb87141 447 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
f51461c8
LG
448 FdObj.GenFd()\r
449\r
450 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")\r
9eb87141
CJ
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
4231a819 453 if FvObj is not None:\r
86379ac4 454 Buffer = BytesIO()\r
f51461c8
LG
455 FvObj.AddToBuffer(Buffer)\r
456 Buffer.close()\r
457 return\r
4231a819 458 elif GenFds.OnlyGenerateThisFv is None:\r
9eb87141 459 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():\r
86e6cf98 460 Buffer = BytesIO()\r
f51461c8
LG
461 FvObj.AddToBuffer(Buffer)\r
462 Buffer.close()\r
f7496d71 463\r
4231a819 464 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None:\r
f51461c8
LG
465 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:\r
466 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")\r
9eb87141 467 for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values():\r
f51461c8
LG
468 CapsuleObj.GenCapsule()\r
469\r
470 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:\r
471 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")\r
9eb87141 472 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():\r
f51461c8 473 OptRomObj.AddToBuffer(None)\r
37de70b7
YZ
474 @staticmethod\r
475 def GenFfsMakefile(OutputDir, FdfParser, WorkSpace, ArchList, GlobalData):\r
476 GenFdsGlobalVariable.SetEnv(FdfParser, WorkSpace, ArchList, GlobalData)\r
9eb87141 477 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
37de70b7
YZ
478 FdObj.GenFd(Flag=True)\r
479\r
9eb87141 480 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():\r
37de70b7
YZ
481 FvObj.AddToBuffer(Buffer=None, Flag=True)\r
482\r
483 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:\r
9eb87141 484 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():\r
37de70b7
YZ
485 OptRomObj.AddToBuffer(Buffer=None, Flag=True)\r
486\r
487 return GenFdsGlobalVariable.FfsCmdDict\r
f51461c8
LG
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
9eb87141 497 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:\r
f51461c8 498 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]\r
4231a819 499 if FdObj is None:\r
f51461c8
LG
500 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
501 for ElementRegion in ElementFd.RegionList:\r
91fa33ee 502 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:\r
f51461c8 503 for ElementRegionData in ElementRegion.RegionDataList:\r
4231a819 504 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:\r
f51461c8
LG
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
91fa33ee 514 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV:\r
f51461c8 515 for ElementRegionData in ElementRegion.RegionDataList:\r
4231a819 516 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:\r
f51461c8
LG
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
f7496d71 529\r
f51461c8
LG
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
f7496d71 556\r
f51461c8
LG
557 if TotalFound and UsedFound and FreeFound:\r
558 FvSpaceInfoList.append((FvName, Total, Used, Free))\r
f7496d71 559\r
f51461c8
LG
560 GenFdsGlobalVariable.InfLogger('\nFV Space Information')\r
561 for FvSpaceInfo in FvSpaceInfoList:\r
562 Name = FvSpaceInfo[0]\r
8371d874
YF
563 TotalSizeValue = int(FvSpaceInfo[1], 0)\r
564 UsedSizeValue = int(FvSpaceInfo[2], 0)\r
565 FreeSizeValue = int(FvSpaceInfo[3], 0)\r
f51461c8
LG
566 if UsedSizeValue == TotalSizeValue:\r
567 Percentage = '100'\r
568 else:\r
47fea6af
YZ
569 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')\r
570\r
f51461c8
LG
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
55c84777 580 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds\r
f51461c8
LG
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
f7496d71 587\r
f51461c8
LG
588 if PcdValue == '':\r
589 return\r
f7496d71 590\r
8371d874 591 Int64PcdValue = int(PcdValue, 0)\r
f7496d71 592 if Int64PcdValue == 0 or Int64PcdValue < -1:\r
f51461c8 593 return\r
f7496d71 594\r
f51461c8
LG
595 TopAddress = 0\r
596 if Int64PcdValue > 0:\r
597 TopAddress = Int64PcdValue\r
f7496d71 598\r
55c84777 599 ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules\r
f51461c8 600 for Key in ModuleDict:\r
55c84777 601 ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
72443dd2 602 print(ModuleObj.BaseName + ' ' + ModuleObj.ModuleType)\r
f51461c8 603\r
5e9256cd 604 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):\r
f51461c8 605 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")\r
86e6cf98 606 GuidXRefFile = StringIO('')\r
0fece18d 607 PkgGuidDict = {}\r
e4ac870f 608 GuidDict = {}\r
5e9256cd
YZ
609 ModuleList = []\r
610 FileGuidList = []\r
cefc8d88 611 GuidPattern = gGuidPattern\r
8be15c61 612 VariableGuidSet = set()\r
f51461c8
LG
613 for Arch in ArchList:\r
614 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
0fece18d 615 PkgList = GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag)\r
616 for P in PkgList:\r
617 PkgGuidDict.update(P.Guids)\r
8be15c61 618 for Name, Guid in sorted(PlatformDataBase.Pcds):\r
0fece18d 619 Pcd = PlatformDataBase.Pcds[Name, Guid]\r
620 if Pcd.Type in [TAB_PCDS_DYNAMIC_HII, TAB_PCDS_DYNAMIC_EX_HII]:\r
621 for SkuId in Pcd.SkuInfoList:\r
622 Sku = Pcd.SkuInfoList[SkuId]\r
8be15c61
YF
623 if Sku.VariableGuid in VariableGuidSet:\r
624 continue\r
625 else:\r
626 VariableGuidSet.add(Sku.VariableGuid)\r
0fece18d 627 if Sku.VariableGuid and Sku.VariableGuid in PkgGuidDict.keys():\r
628 GuidDict[Sku.VariableGuid] = PkgGuidDict[Sku.VariableGuid]\r
f51461c8
LG
629 for ModuleFile in PlatformDataBase.Modules:\r
630 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
5e9256cd
YZ
631 if Module in ModuleList:\r
632 continue\r
633 else:\r
634 ModuleList.append(Module)\r
1d802e23
YF
635 GuidMatch = GuidPattern.match(ModuleFile.BaseName)\r
636 if GuidMatch is not None:\r
637 GuidXRefFile.write("%s %s\n" % (ModuleFile.BaseName, Module.BaseName))\r
638 else:\r
639 GuidXRefFile.write("%s %s\n" % (Module.Guid, Module.BaseName))\r
e4ac870f
LG
640 for key, item in Module.Protocols.items():\r
641 GuidDict[key] = item\r
642 for key, item in Module.Guids.items():\r
643 GuidDict[key] = item\r
644 for key, item in Module.Ppis.items():\r
645 GuidDict[key] = item\r
5e9256cd
YZ
646 for FvName in FdfParserObj.Profile.FvDict:\r
647 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:\r
648 if not isinstance(FfsObj, FfsFileStatement.FileStatement):\r
649 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))\r
650 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
651 if FdfModule in ModuleList:\r
652 continue\r
653 else:\r
654 ModuleList.append(FdfModule)\r
655 GuidXRefFile.write("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))\r
656 for key, item in FdfModule.Protocols.items():\r
657 GuidDict[key] = item\r
658 for key, item in FdfModule.Guids.items():\r
659 GuidDict[key] = item\r
660 for key, item in FdfModule.Ppis.items():\r
661 GuidDict[key] = item\r
662 else:\r
663 FileStatementGuid = FfsObj.NameGuid\r
664 if FileStatementGuid in FileGuidList:\r
665 continue\r
666 else:\r
667 FileGuidList.append(FileStatementGuid)\r
668 Name = []\r
669 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')\r
670 FfsPath = glob.glob(os.path.join(FfsPath, FileStatementGuid) + '*')\r
671 if not FfsPath:\r
672 continue\r
673 if not os.path.exists(FfsPath[0]):\r
674 continue\r
675 MatchDict = {}\r
676 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
677 FileList = os.listdir(FfsPath[0])\r
678 for File in FileList:\r
679 Match = ReFileEnds.search(File)\r
680 if Match:\r
681 for Index in range(1, 8):\r
682 if Match.group(Index) and Match.group(Index) in MatchDict:\r
683 MatchDict[Match.group(Index)].append(File)\r
684 elif Match.group(Index):\r
685 MatchDict[Match.group(Index)] = [File]\r
686 if not MatchDict:\r
687 continue\r
688 if '.ui' in MatchDict:\r
689 for File in MatchDict['.ui']:\r
690 with open(os.path.join(FfsPath[0], File), 'rb') as F:\r
691 F.read()\r
692 length = F.tell()\r
693 F.seek(4)\r
2e300969 694 TmpStr = unpack('%dh' % ((length - 4) // 2), F.read())\r
8252e6bf 695 Name = ''.join(chr(c) for c in TmpStr[:-1])\r
5e9256cd
YZ
696 else:\r
697 FileList = []\r
698 if 'fv.sec.txt' in MatchDict:\r
699 FileList = MatchDict['fv.sec.txt']\r
700 elif '.pe32.txt' in MatchDict:\r
701 FileList = MatchDict['.pe32.txt']\r
702 elif '.te.txt' in MatchDict:\r
703 FileList = MatchDict['.te.txt']\r
704 elif '.pic.txt' in MatchDict:\r
705 FileList = MatchDict['.pic.txt']\r
706 elif '.raw.txt' in MatchDict:\r
707 FileList = MatchDict['.raw.txt']\r
708 elif '.ffs.txt' in MatchDict:\r
709 FileList = MatchDict['.ffs.txt']\r
710 else:\r
711 pass\r
712 for File in FileList:\r
713 with open(os.path.join(FfsPath[0], File), 'r') as F:\r
714 Name.append((F.read().split()[-1]))\r
715 if not Name:\r
716 continue\r
717\r
0d1f5b2b 718 Name = ' '.join(Name) if isinstance(Name, type([])) else Name\r
5e9256cd
YZ
719 GuidXRefFile.write("%s %s\n" %(FileStatementGuid, Name))\r
720\r
e4ac870f
LG
721 # Append GUIDs, Protocols, and PPIs to the Xref file\r
722 GuidXRefFile.write("\n")\r
723 for key, item in GuidDict.items():\r
724 GuidXRefFile.write("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))\r
725\r
f51461c8
LG
726 if GuidXRefFile.getvalue():\r
727 SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False)\r
728 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)\r
729 elif os.path.exists(GuidXRefFileName):\r
730 os.remove(GuidXRefFileName)\r
731 GuidXRefFile.close()\r
732\r
733 ##Define GenFd as static function\r
734 GenFd = staticmethod(GenFd)\r
735 GetFvBlockSize = staticmethod(GetFvBlockSize)\r
736 DisplayFvSpaceInfo = staticmethod(DisplayFvSpaceInfo)\r
737 PreprocessImage = staticmethod(PreprocessImage)\r
738 GenerateGuidXRefFile = staticmethod(GenerateGuidXRefFile)\r
739\r
740if __name__ == '__main__':\r
741 r = main()\r
742 ## 0-127 is a safe return range, and 1 is a standard default error\r
743 if r < 0 or r > 127: r = 1\r
744 sys.exit(r)\r
745\r