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