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