]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/BuildReport.py
BaseTools: Optimize VPD PCD value for the different SKUs
[mirror_edk2.git] / BaseTools / Source / Python / build / BuildReport.py
CommitLineData
52302d4d
LG
1## @file\r
2# Routines for generating build report.\r
3#\r
4# This module contains the functionality to generate build report after\r
5# build all target completes successfully.\r
6#\r
7cb63c87 7# Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
40d841f6 8# This program and the accompanying materials\r
52302d4d
LG
9# are licensed and made available under the terms and conditions of the BSD License\r
10# which accompanies this distribution. The full text of the license may be found at\r
11# http://opensource.org/licenses/bsd-license.php\r
12#\r
13# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15#\r
16\r
17## Import Modules\r
18#\r
1be2ed90 19import Common.LongFilePathOs as os\r
52302d4d
LG
20import re\r
21import platform\r
22import textwrap\r
23import traceback\r
24import sys\r
40d841f6 25import time\r
e56468c0 26import struct\r
eca5be7a
YZ
27import hashlib\r
28import subprocess\r
29import threading\r
52302d4d 30from datetime import datetime\r
40d841f6 31from StringIO import StringIO\r
52302d4d 32from Common import EdkLogger\r
40d841f6 33from Common.Misc import SaveFileOnChange\r
52302d4d
LG
34from Common.Misc import GuidStructureByteArrayToGuidString\r
35from Common.Misc import GuidStructureStringToGuidString\r
36from Common.InfClassObject import gComponentType2ModuleType\r
52302d4d
LG
37from Common.BuildToolError import FILE_WRITE_FAILURE\r
38from Common.BuildToolError import CODE_ERROR\r
eca5be7a 39from Common.BuildToolError import COMMAND_FAILURE\r
1be2ed90 40from Common.LongFilePathSupport import OpenLongFilePath as open\r
05cc51ad 41from Common.MultipleWorkspace import MultipleWorkspace as mws\r
763e8edf 42import Common.GlobalData as GlobalData\r
25193a33
YZ
43from AutoGen.AutoGen import ModuleAutoGen\r
44from Common.Misc import PathClass\r
45from Common.String import NormPath\r
e651d06c
LG
46from Common.DataType import *\r
47import collections\r
52302d4d
LG
48\r
49## Pattern to extract contents in EDK DXS files\r
50gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
51\r
52## Pattern to find total FV total size, occupied size in flash report intermediate file\r
53gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")\r
54gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")\r
55\r
56## Pattern to find module size and time stamp in module summary report intermediate file\r
57gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")\r
58gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")\r
59\r
60## Pattern to find GUID value in flash description files\r
61gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")\r
62\r
63## Pattern to collect offset, GUID value pair in the flash report intermediate file\r
64gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")\r
65\r
66## Pattern to find module base address and entry point in fixed flash map file\r
67gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"\r
68gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})\r
69\r
70## Pattern to find all module referenced header files in source files\r
71gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')\r
72gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")\r
73\r
74## Pattern to find the entry point for EDK module using EDKII Glue library\r
75gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")\r
76\r
64b2609f
LG
77## Tags for MaxLength of line in report\r
78gLineMaxLength = 120\r
79\r
4afd3d04
LG
80## Tags for end of line in report\r
81gEndOfLine = "\r\n"\r
82\r
52302d4d 83## Tags for section start, end and separator\r
47fea6af
YZ
84gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"\r
85gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"\r
64b2609f 86gSectionSep = "=" * gLineMaxLength\r
52302d4d
LG
87\r
88## Tags for subsection start, end and separator\r
47fea6af
YZ
89gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"\r
90gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"\r
64b2609f
LG
91gSubSectionSep = "-" * gLineMaxLength\r
92\r
52302d4d
LG
93\r
94## The look up table to map PCD type to pair of report display type and DEC type\r
95gPcdTypeMap = {\r
96 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),\r
97 'PatchableInModule': ('PATCH', 'PatchableInModule'),\r
98 'FeatureFlag' : ('FLAG', 'FeatureFlag'),\r
99 'Dynamic' : ('DYN', 'Dynamic'),\r
100 'DynamicHii' : ('DYNHII', 'Dynamic'),\r
101 'DynamicVpd' : ('DYNVPD', 'Dynamic'),\r
4afd3d04
LG
102 'DynamicEx' : ('DEX', 'DynamicEx'),\r
103 'DynamicExHii' : ('DEXHII', 'DynamicEx'),\r
104 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'),\r
52302d4d
LG
105 }\r
106\r
107## The look up table to map module type to driver type\r
108gDriverTypeMap = {\r
109 'SEC' : '0x3 (SECURITY_CORE)',\r
110 'PEI_CORE' : '0x4 (PEI_CORE)',\r
111 'PEIM' : '0x6 (PEIM)',\r
112 'DXE_CORE' : '0x5 (DXE_CORE)',\r
113 'DXE_DRIVER' : '0x7 (DRIVER)',\r
114 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',\r
115 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',\r
116 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',\r
117 'UEFI_DRIVER' : '0x7 (DRIVER)',\r
118 'UEFI_APPLICATION' : '0x9 (APPLICATION)',\r
119 'SMM_CORE' : '0xD (SMM_CORE)',\r
120 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers\r
e574123c
SV
121 'MM_STANDALONE' : '0xE (MM_STANDALONE)',\r
122 'MM_CORE_STANDALONE' : '0xF (MM_CORE_STANDALONE)'\r
52302d4d
LG
123 }\r
124\r
e56468c0 125## The look up table of the supported opcode in the dependency expression binaries\r
126gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]\r
127\r
52302d4d
LG
128##\r
129# Writes a string to the file object.\r
130#\r
131# This function writes a string to the file object and a new line is appended\r
132# afterwards. It may optionally wraps the string for better readability.\r
133#\r
134# @File The file object to write\r
135# @String The string to be written to the file\r
136# @Wrapper Indicates whether to wrap the string\r
137#\r
138def FileWrite(File, String, Wrapper=False):\r
139 if Wrapper:\r
140 String = textwrap.fill(String, 120)\r
4afd3d04 141 File.write(String + gEndOfLine)\r
52302d4d 142\r
e651d06c
LG
143def ByteArrayForamt(Value):\r
144 IsByteArray = False\r
145 SplitNum = 16\r
146 ArrayList = []\r
147 if Value.startswith('{') and Value.endswith('}'):\r
148 Value = Value[1:-1]\r
149 ValueList = Value.split(',')\r
150 if len(ValueList) >= SplitNum:\r
151 IsByteArray = True\r
152 if IsByteArray:\r
153 if ValueList:\r
154 Len = len(ValueList)/SplitNum\r
155 for i, element in enumerate(ValueList):\r
156 ValueList[i] = '0x%02X' % int(element.strip(), 16)\r
157 if Len:\r
158 Id = 0\r
159 while (Id <= Len):\r
160 End = min(SplitNum*(Id+1), len(ValueList))\r
161 Str = ','.join(ValueList[SplitNum*Id : End])\r
162 if End == len(ValueList):\r
163 Str += '}'\r
164 ArrayList.append(Str)\r
165 break\r
166 else:\r
167 Str += ','\r
168 ArrayList.append(Str)\r
169 Id += 1\r
170 else:\r
171 ArrayList = [Value + '}']\r
172 return IsByteArray, ArrayList\r
173\r
52302d4d
LG
174##\r
175# Find all the header file that the module source directly includes.\r
176#\r
177# This function scans source code to find all header files the module may\r
178# include. This is not accurate but very effective to find all the header\r
179# file the module might include with #include statement.\r
180#\r
181# @Source The source file name\r
182# @IncludePathList The list of include path to find the source file.\r
183# @IncludeFiles The dictionary of current found include files.\r
184#\r
185def FindIncludeFiles(Source, IncludePathList, IncludeFiles):\r
186 FileContents = open(Source).read()\r
187 #\r
188 # Find header files with pattern #include "XXX.h" or #include <XXX.h>\r
189 #\r
190 for Match in gIncludePattern.finditer(FileContents):\r
191 FileName = Match.group(1).strip()\r
192 for Dir in [os.path.dirname(Source)] + IncludePathList:\r
193 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
194 if os.path.exists(FullFileName):\r
195 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
196 break\r
197\r
198 #\r
199 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)\r
200 #\r
201 for Match in gIncludePattern2.finditer(FileContents):\r
202 Key = Match.group(2)\r
203 Type = Match.group(1)\r
204 if "ARCH_PROTOCOL" in Type:\r
205 FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
206 elif "PROTOCOL" in Type:\r
207 FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
208 elif "PPI" in Type:\r
209 FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
210 elif "GUID" in Type:\r
211 FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
212 else:\r
213 continue\r
214 for Dir in IncludePathList:\r
215 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
216 if os.path.exists(FullFileName):\r
217 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
218 break\r
219\r
64b2609f
LG
220## Split each lines in file\r
221#\r
222# This method is used to split the lines in file to make the length of each line \r
223# less than MaxLength.\r
224#\r
225# @param Content The content of file\r
226# @param MaxLength The Max Length of the line\r
227#\r
228def FileLinesSplit(Content=None, MaxLength=None):\r
229 ContentList = Content.split(TAB_LINE_BREAK)\r
230 NewContent = ''\r
231 NewContentList = []\r
232 for Line in ContentList:\r
233 while len(Line.rstrip()) > MaxLength:\r
234 LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)\r
235 LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)\r
25918452
LG
236 LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)\r
237 if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:\r
238 LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)\r
239 else:\r
240 LineBreakIndex = MaxLength\r
64b2609f
LG
241 NewContentList.append(Line[:LineBreakIndex])\r
242 Line = Line[LineBreakIndex:]\r
243 if Line:\r
244 NewContentList.append(Line)\r
245 for NewLine in NewContentList:\r
246 NewContent += NewLine + TAB_LINE_BREAK\r
4afd3d04
LG
247 \r
248 NewContent = NewContent.replace(TAB_LINE_BREAK, gEndOfLine).replace('\r\r\n', gEndOfLine)\r
64b2609f
LG
249 return NewContent\r
250 \r
251 \r
252 \r
e56468c0 253##\r
254# Parse binary dependency expression section\r
255#\r
256# This utility class parses the dependency expression section and translate the readable\r
257# GUID name and value.\r
258#\r
259class DepexParser(object):\r
260 ##\r
261 # Constructor function for class DepexParser\r
262 #\r
263 # This constructor function collect GUID values so that the readable\r
264 # GUID name can be translated.\r
265 #\r
266 # @param self The object pointer\r
267 # @param Wa Workspace context information\r
268 #\r
269 def __init__(self, Wa):\r
270 self._GuidDb = {}\r
0d2711a6 271 for Pa in Wa.AutoGenObjectList:\r
47fea6af 272 for Package in Pa.PackageList:\r
0d2711a6
LG
273 for Protocol in Package.Protocols:\r
274 GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])\r
275 self._GuidDb[GuidValue.upper()] = Protocol\r
276 for Ppi in Package.Ppis:\r
277 GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])\r
278 self._GuidDb[GuidValue.upper()] = Ppi\r
279 for Guid in Package.Guids:\r
280 GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])\r
281 self._GuidDb[GuidValue.upper()] = Guid\r
e56468c0 282 \r
283 ##\r
284 # Parse the binary dependency expression files.\r
285 # \r
286 # This function parses the binary dependency expression file and translate it\r
287 # to the instruction list.\r
288 #\r
289 # @param self The object pointer\r
290 # @param DepexFileName The file name of binary dependency expression file.\r
291 #\r
292 def ParseDepexFile(self, DepexFileName):\r
293 DepexFile = open(DepexFileName, "rb")\r
294 DepexStatement = []\r
295 OpCode = DepexFile.read(1)\r
296 while OpCode:\r
297 Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]\r
298 if Statement in ["BEFORE", "AFTER", "PUSH"]:\r
299 GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \\r
2bc3256c 300 struct.unpack("=LHHBBBBBBBB", DepexFile.read(16))\r
e56468c0 301 GuidString = self._GuidDb.get(GuidValue, GuidValue)\r
302 Statement = "%s %s" % (Statement, GuidString)\r
303 DepexStatement.append(Statement)\r
47fea6af
YZ
304 OpCode = DepexFile.read(1)\r
305\r
e56468c0 306 return DepexStatement\r
307 \r
52302d4d
LG
308##\r
309# Reports library information\r
310#\r
311# This class reports the module library subsection in the build report file.\r
312#\r
313class LibraryReport(object):\r
314 ##\r
315 # Constructor function for class LibraryReport\r
316 #\r
317 # This constructor function generates LibraryReport object for\r
318 # a module.\r
319 #\r
320 # @param self The object pointer\r
321 # @param M Module context information\r
322 #\r
323 def __init__(self, M):\r
324 self.LibraryList = []\r
325 if int(str(M.AutoGenVersion), 0) >= 0x00010005:\r
326 self._EdkIIModule = True\r
327 else:\r
328 self._EdkIIModule = False\r
329\r
330 for Lib in M.DependentLibraryList:\r
331 LibInfPath = str(Lib)\r
332 LibClassList = Lib.LibraryClass[0].LibraryClass\r
333 LibConstructorList = Lib.ConstructorList\r
334 LibDesstructorList = Lib.DestructorList\r
335 LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]\r
1b8eca8b
YZ
336 for LibAutoGen in M.LibraryAutoGenList:\r
337 if LibInfPath == LibAutoGen.MetaFile.Path:\r
338 LibTime = LibAutoGen.BuildTime\r
339 break\r
340 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime))\r
52302d4d
LG
341\r
342 ##\r
343 # Generate report for module library information\r
344 #\r
345 # This function generates report for the module library.\r
346 # If the module is EDKII style one, the additional library class, library\r
347 # constructor/destructor and dependency expression may also be reported.\r
348 #\r
349 # @param self The object pointer\r
350 # @param File The file object for report\r
351 #\r
352 def GenerateReport(self, File):\r
52302d4d 353 if len(self.LibraryList) > 0:\r
c2d0a1f6
YZ
354 FileWrite(File, gSubSectionStart)\r
355 FileWrite(File, TAB_BRG_LIBRARY)\r
52302d4d
LG
356 FileWrite(File, gSubSectionSep)\r
357 for LibraryItem in self.LibraryList:\r
358 LibInfPath = LibraryItem[0]\r
359 FileWrite(File, LibInfPath)\r
360\r
361 #\r
362 # Report library class, library constructor and destructor for\r
363 # EDKII style module.\r
364 #\r
365 if self._EdkIIModule:\r
366 LibClass = LibraryItem[1]\r
367 EdkIILibInfo = ""\r
368 LibConstructor = " ".join(LibraryItem[2])\r
369 if LibConstructor:\r
370 EdkIILibInfo += " C = " + LibConstructor\r
371 LibDestructor = " ".join(LibraryItem[3])\r
372 if LibDestructor:\r
636f2be6 373 EdkIILibInfo += " D = " + LibDestructor\r
52302d4d
LG
374 LibDepex = " ".join(LibraryItem[4])\r
375 if LibDepex:\r
376 EdkIILibInfo += " Depex = " + LibDepex\r
1b8eca8b
YZ
377 if LibraryItem[5]:\r
378 EdkIILibInfo += " Time = " + LibraryItem[5]\r
52302d4d
LG
379 if EdkIILibInfo:\r
380 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))\r
381 else:\r
382 FileWrite(File, "{%s}" % LibClass)\r
383\r
c2d0a1f6 384 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
385\r
386##\r
387# Reports dependency expression information\r
388#\r
389# This class reports the module dependency expression subsection in the build report file.\r
390#\r
391class DepexReport(object):\r
392 ##\r
393 # Constructor function for class DepexReport\r
394 #\r
395 # This constructor function generates DepexReport object for\r
396 # a module. If the module source contains the DXS file (usually EDK\r
397 # style module), it uses the dependency in DXS file; otherwise,\r
398 # it uses the dependency expression from its own INF [Depex] section\r
399 # and then merges with the ones from its dependent library INF.\r
400 #\r
401 # @param self The object pointer\r
402 # @param M Module context information\r
403 #\r
404 def __init__(self, M):\r
405 self.Depex = ""\r
47fea6af 406 self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")\r
52302d4d
LG
407 ModuleType = M.ModuleType\r
408 if not ModuleType:\r
409 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
636f2be6 410\r
e574123c 411 if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "MM_CORE_STANDALONE", "UEFI_APPLICATION"]:\r
52302d4d
LG
412 return\r
413 \r
414 for Source in M.SourceFileList:\r
415 if os.path.splitext(Source.Path)[1].lower() == ".dxs":\r
416 Match = gDxsDependencyPattern.search(open(Source.Path).read())\r
417 if Match:\r
418 self.Depex = Match.group(1).strip()\r
419 self.Source = "DXS"\r
420 break\r
421 else:\r
422 self.Depex = M.DepexExpressionList.get(M.ModuleType, "")\r
423 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])\r
424 if not self.ModuleDepex:\r
425 self.ModuleDepex = "(None)"\r
426\r
427 LibDepexList = []\r
428 for Lib in M.DependentLibraryList:\r
429 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()\r
430 if LibDepex != "":\r
431 LibDepexList.append("(" + LibDepex + ")")\r
432 self.LibraryDepex = " AND ".join(LibDepexList)\r
433 if not self.LibraryDepex:\r
434 self.LibraryDepex = "(None)"\r
435 self.Source = "INF"\r
436\r
437 ##\r
438 # Generate report for module dependency expression information\r
439 #\r
440 # This function generates report for the module dependency expression.\r
441 #\r
e56468c0 442 # @param self The object pointer\r
443 # @param File The file object for report\r
444 # @param GlobalDepexParser The platform global Dependency expression parser object\r
52302d4d 445 #\r
e56468c0 446 def GenerateReport(self, File, GlobalDepexParser):\r
52302d4d
LG
447 if not self.Depex:\r
448 return\r
52302d4d 449 FileWrite(File, gSubSectionStart)\r
e56468c0 450 if os.path.isfile(self._DepexFileName):\r
451 try:\r
452 DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)\r
453 FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")\r
454 for DepexStatement in DepexStatements:\r
455 FileWrite(File, " %s" % DepexStatement)\r
456 FileWrite(File, gSubSectionSep)\r
457 except:\r
458 EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)\r
459 \r
52302d4d
LG
460 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)\r
461\r
462 if self.Source == "INF":\r
463 FileWrite(File, "%s" % self.Depex, True)\r
464 FileWrite(File, gSubSectionSep)\r
465 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)\r
466 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)\r
467 else:\r
468 FileWrite(File, "%s" % self.Depex)\r
469 FileWrite(File, gSubSectionEnd)\r
470\r
471##\r
472# Reports dependency expression information\r
473#\r
474# This class reports the module build flags subsection in the build report file.\r
475#\r
476class BuildFlagsReport(object):\r
477 ##\r
478 # Constructor function for class BuildFlagsReport\r
479 #\r
480 # This constructor function generates BuildFlagsReport object for\r
481 # a module. It reports the build tool chain tag and all relevant\r
482 # build flags to build the module.\r
483 #\r
484 # @param self The object pointer\r
485 # @param M Module context information\r
486 #\r
487 def __init__(self, M):\r
488 BuildOptions = {}\r
489 #\r
490 # Add build flags according to source file extension so that\r
491 # irrelevant ones can be filtered out.\r
492 #\r
493 for Source in M.SourceFileList:\r
494 Ext = os.path.splitext(Source.File)[1].lower()\r
495 if Ext in [".c", ".cc", ".cpp"]:\r
496 BuildOptions["CC"] = 1\r
497 elif Ext in [".s", ".asm"]:\r
498 BuildOptions["PP"] = 1\r
499 BuildOptions["ASM"] = 1\r
500 elif Ext in [".vfr"]:\r
501 BuildOptions["VFRPP"] = 1\r
502 BuildOptions["VFR"] = 1\r
503 elif Ext in [".dxs"]:\r
504 BuildOptions["APP"] = 1\r
505 BuildOptions["CC"] = 1\r
506 elif Ext in [".asl"]:\r
507 BuildOptions["ASLPP"] = 1\r
508 BuildOptions["ASL"] = 1\r
509 elif Ext in [".aslc"]:\r
510 BuildOptions["ASLCC"] = 1\r
511 BuildOptions["ASLDLINK"] = 1\r
512 BuildOptions["CC"] = 1\r
513 elif Ext in [".asm16"]:\r
514 BuildOptions["ASMLINK"] = 1\r
515 BuildOptions["SLINK"] = 1\r
516 BuildOptions["DLINK"] = 1\r
517\r
518 #\r
519 # Save module build flags.\r
520 #\r
521 self.ToolChainTag = M.ToolChain\r
522 self.BuildFlags = {}\r
523 for Tool in BuildOptions:\r
524 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")\r
525\r
526 ##\r
527 # Generate report for module build flags information\r
528 #\r
529 # This function generates report for the module build flags expression.\r
530 #\r
531 # @param self The object pointer\r
532 # @param File The file object for report\r
533 #\r
534 def GenerateReport(self, File):\r
535 FileWrite(File, gSubSectionStart)\r
536 FileWrite(File, "Build Flags")\r
537 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)\r
538 for Tool in self.BuildFlags:\r
539 FileWrite(File, gSubSectionSep)\r
540 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)\r
541\r
542 FileWrite(File, gSubSectionEnd)\r
543\r
544\r
545##\r
546# Reports individual module information\r
547#\r
548# This class reports the module section in the build report file.\r
549# It comprises of module summary, module PCD, library, dependency expression,\r
550# build flags sections.\r
551#\r
552class ModuleReport(object):\r
553 ##\r
554 # Constructor function for class ModuleReport\r
555 #\r
556 # This constructor function generates ModuleReport object for\r
557 # a separate module in a platform build.\r
558 #\r
559 # @param self The object pointer\r
560 # @param M Module context information\r
561 # @param ReportType The kind of report items in the final report file\r
562 #\r
563 def __init__(self, M, ReportType):\r
564 self.ModuleName = M.Module.BaseName\r
565 self.ModuleInfPath = M.MetaFile.File\r
566 self.FileGuid = M.Guid\r
567 self.Size = 0\r
568 self.BuildTimeStamp = None\r
eca5be7a 569 self.Hash = 0\r
52302d4d 570 self.DriverType = ""\r
636f2be6
LG
571 if not M.IsLibrary:\r
572 ModuleType = M.ModuleType\r
573 if not ModuleType:\r
574 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
575 #\r
576 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"\r
577 #\r
578 if ModuleType == "DXE_SMM_DRIVER":\r
47fea6af 579 PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
0d2711a6 580 if int(PiSpec, 0) >= 0x0001000A:\r
636f2be6
LG
581 ModuleType = "SMM_DRIVER"\r
582 self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")\r
52302d4d
LG
583 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")\r
584 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")\r
585 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")\r
586 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")\r
587 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")\r
1b8eca8b 588 self.BuildTime = M.BuildTime\r
52302d4d
LG
589\r
590 self._BuildDir = M.BuildDir\r
591 self.ModulePcdSet = {}\r
592 if "PCD" in ReportType:\r
593 #\r
594 # Collect all module used PCD set: module INF referenced directly or indirectly.\r
595 # It also saves module INF default values of them in case they exist.\r
596 #\r
597 for Pcd in M.ModulePcdList + M.LibraryPcdList:\r
598 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))\r
599\r
600 self.LibraryReport = None\r
601 if "LIBRARY" in ReportType:\r
602 self.LibraryReport = LibraryReport(M)\r
603\r
604 self.DepexReport = None\r
605 if "DEPEX" in ReportType:\r
606 self.DepexReport = DepexReport(M)\r
607\r
608 if "BUILD_FLAGS" in ReportType:\r
609 self.BuildFlagsReport = BuildFlagsReport(M)\r
610\r
611\r
612 ##\r
613 # Generate report for module information\r
614 #\r
615 # This function generates report for separate module expression\r
616 # in a platform build.\r
617 #\r
e56468c0 618 # @param self The object pointer\r
619 # @param File The file object for report\r
620 # @param GlobalPcdReport The platform global PCD report object\r
621 # @param GlobalPredictionReport The platform global Prediction report object\r
622 # @param GlobalDepexParser The platform global Dependency expression parser object\r
623 # @param ReportType The kind of report items in the final report file\r
52302d4d 624 #\r
e56468c0 625 def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):\r
52302d4d
LG
626 FileWrite(File, gSectionStart)\r
627\r
628 FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt")\r
629 if os.path.isfile(FwReportFileName):\r
630 try:\r
631 FileContents = open(FwReportFileName).read()\r
632 Match = gModuleSizePattern.search(FileContents)\r
633 if Match:\r
634 self.Size = int(Match.group(1))\r
635\r
636 Match = gTimeStampPattern.search(FileContents)\r
637 if Match:\r
638 self.BuildTimeStamp = datetime.fromtimestamp(int(Match.group(1)))\r
639 except IOError:\r
640 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)\r
641\r
eca5be7a
YZ
642 if "HASH" in ReportType:\r
643 OutputDir = os.path.join(self._BuildDir, "OUTPUT")\r
644 DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi")\r
645 if os.path.isfile(DefaultEFIfile):\r
646 Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp")\r
647 # rebase the efi image since its base address may not zero\r
648 cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile]\r
649 try:\r
650 PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
651 except Exception, X:\r
652 EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))\r
653 EndOfProcedure = threading.Event()\r
654 EndOfProcedure.clear()\r
655 if PopenObject.stderr:\r
656 StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure))\r
657 StdErrThread.setName("STDERR-Redirector")\r
658 StdErrThread.setDaemon(False)\r
659 StdErrThread.start()\r
660 # waiting for program exit\r
661 PopenObject.wait()\r
662 if PopenObject.stderr:\r
663 StdErrThread.join()\r
664 if PopenObject.returncode != 0:\r
665 EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile))\r
666 if os.path.isfile(Tempfile):\r
667 self.Hash = hashlib.sha1()\r
668 buf = open(Tempfile, 'rb').read()\r
669 if self.Hash.update(buf):\r
670 self.Hash = self.Hash.update(buf)\r
671 self.Hash = self.Hash.hexdigest()\r
672 os.remove(Tempfile)\r
673\r
52302d4d
LG
674 FileWrite(File, "Module Summary")\r
675 FileWrite(File, "Module Name: %s" % self.ModuleName)\r
676 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)\r
677 FileWrite(File, "File GUID: %s" % self.FileGuid)\r
678 if self.Size:\r
679 FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))\r
eca5be7a
YZ
680 if self.Hash:\r
681 FileWrite(File, "SHA1 HASH: %s *%s" % (self.Hash, self.ModuleName + ".efi"))\r
52302d4d
LG
682 if self.BuildTimeStamp:\r
683 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)\r
1b8eca8b
YZ
684 if self.BuildTime:\r
685 FileWrite(File, "Module Build Time: %s" % self.BuildTime)\r
52302d4d
LG
686 if self.DriverType:\r
687 FileWrite(File, "Driver Type: %s" % self.DriverType)\r
688 if self.UefiSpecVersion:\r
689 FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)\r
690 if self.PiSpecVersion:\r
691 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)\r
692 if self.PciDeviceId:\r
693 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)\r
694 if self.PciVendorId:\r
695 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)\r
696 if self.PciClassCode:\r
697 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)\r
698\r
699 FileWrite(File, gSectionSep)\r
700\r
701 if "PCD" in ReportType:\r
702 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet)\r
703\r
704 if "LIBRARY" in ReportType:\r
705 self.LibraryReport.GenerateReport(File)\r
706\r
707 if "DEPEX" in ReportType:\r
e56468c0 708 self.DepexReport.GenerateReport(File, GlobalDepexParser)\r
52302d4d
LG
709\r
710 if "BUILD_FLAGS" in ReportType:\r
711 self.BuildFlagsReport.GenerateReport(File)\r
712\r
713 if "FIXED_ADDRESS" in ReportType and self.FileGuid:\r
714 GlobalPredictionReport.GenerateReport(File, self.FileGuid)\r
715\r
716 FileWrite(File, gSectionEnd)\r
717\r
eca5be7a
YZ
718def ReadMessage(From, To, ExitFlag):\r
719 while True:\r
720 # read one line a time\r
721 Line = From.readline()\r
722 # empty string means "end"\r
723 if Line != None and Line != "":\r
724 To(Line.rstrip())\r
725 else:\r
726 break\r
727 if ExitFlag.isSet():\r
728 break\r
729\r
52302d4d
LG
730##\r
731# Reports platform and module PCD information\r
732#\r
733# This class reports the platform PCD section and module PCD subsection\r
734# in the build report file.\r
735#\r
736class PcdReport(object):\r
737 ##\r
738 # Constructor function for class PcdReport\r
739 #\r
740 # This constructor function generates PcdReport object a platform build.\r
741 # It collects the whole PCD database from platform DSC files, platform\r
742 # flash description file and package DEC files.\r
743 #\r
744 # @param self The object pointer\r
745 # @param Wa Workspace context information\r
746 #\r
747 def __init__(self, Wa):\r
748 self.AllPcds = {}\r
c8d07c5e
YZ
749 self.UnusedPcds = {}\r
750 self.ConditionalPcds = {}\r
52302d4d 751 self.MaxLen = 0\r
e651d06c 752 self.Arch = None\r
52302d4d
LG
753 if Wa.FdfProfile:\r
754 self.FdfPcdSet = Wa.FdfProfile.PcdDict\r
755 else:\r
756 self.FdfPcdSet = {}\r
757\r
758 self.ModulePcdOverride = {}\r
759 for Pa in Wa.AutoGenObjectList:\r
e651d06c 760 self.Arch = Pa.Arch\r
52302d4d
LG
761 #\r
762 # Collect all platform referenced PCDs and grouped them by PCD token space\r
763 # GUID C Names\r
764 #\r
765 for Pcd in Pa.AllPcdList:\r
766 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
767 if Pcd not in PcdList:\r
768 PcdList.append(Pcd)\r
769 if len(Pcd.TokenCName) > self.MaxLen:\r
770 self.MaxLen = len(Pcd.TokenCName)\r
c8d07c5e
YZ
771 #\r
772 # Collect the PCD defined in DSC/FDF file, but not used in module\r
773 #\r
774 UnusedPcdFullList = []\r
775 for item in Pa.Platform.Pcds:\r
776 Pcd = Pa.Platform.Pcds[item]\r
c65df5d9
YZ
777 if not Pcd.Type:\r
778 # check the Pcd in FDF file, whether it is used in module first\r
779 for T in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:\r
780 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, [])\r
781 if Pcd in PcdList:\r
782 Pcd.Type = T\r
783 break\r
c8d07c5e
YZ
784 if not Pcd.Type:\r
785 PcdTypeFlag = False\r
786 for package in Pa.PackageList:\r
787 for T in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:\r
788 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds:\r
789 Pcd.Type = T\r
790 PcdTypeFlag = True\r
791 if not Pcd.DatumType:\r
792 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType\r
793 break\r
794 if PcdTypeFlag:\r
795 break\r
796 if not Pcd.DatumType:\r
797 PcdType = Pcd.Type\r
798 # Try to remove Hii and Vpd suffix\r
799 if PcdType.startswith("DynamicEx"):\r
800 PcdType = "DynamicEx"\r
801 elif PcdType.startswith("Dynamic"):\r
802 PcdType = "Dynamic"\r
803 for package in Pa.PackageList:\r
804 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds:\r
805 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType\r
806 break\r
807\r
808 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
809 if Pcd not in PcdList and Pcd not in UnusedPcdFullList:\r
810 UnusedPcdFullList.append(Pcd)\r
811 if len(Pcd.TokenCName) > self.MaxLen:\r
812 self.MaxLen = len(Pcd.TokenCName)\r
813\r
814 if GlobalData.gConditionalPcds:\r
815 for PcdItem in GlobalData.gConditionalPcds:\r
816 if '.' in PcdItem:\r
817 (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.')\r
818 if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds.keys():\r
819 Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)]\r
820 PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
821 if Pcd not in PcdList:\r
822 PcdList.append(Pcd)\r
823\r
824 UnusedPcdList = []\r
825 if UnusedPcdFullList:\r
826 for Pcd in UnusedPcdFullList:\r
827 if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds:\r
828 continue\r
829 UnusedPcdList.append(Pcd)\r
830\r
831 for Pcd in UnusedPcdList:\r
832 PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
833 if Pcd not in PcdList:\r
834 PcdList.append(Pcd)\r
52302d4d
LG
835\r
836 for Module in Pa.Platform.Modules.values():\r
837 #\r
838 # Collect module override PCDs\r
839 #\r
840 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:\r
841 TokenCName = ModulePcd.TokenCName\r
842 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName\r
843 ModuleDefault = ModulePcd.DefaultValue\r
844 ModulePath = os.path.basename(Module.M.MetaFile.File)\r
845 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault\r
846\r
847\r
848 #\r
849 # Collect PCD DEC default value.\r
850 #\r
851 self.DecPcdDefault = {}\r
0d2711a6
LG
852 for Pa in Wa.AutoGenObjectList:\r
853 for Package in Pa.PackageList:\r
854 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
855 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
856 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
52302d4d
LG
857 #\r
858 # Collect PCDs defined in DSC common section\r
859 #\r
860 self.DscPcdDefault = {}\r
e651d06c
LG
861 for Pa in Wa.AutoGenObjectList:\r
862 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:\r
863 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
40d841f6
LG
864 if DscDefaultValue:\r
865 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d 866\r
c8d07c5e
YZ
867 def GenerateReport(self, File, ModulePcdSet):\r
868 if self.ConditionalPcds:\r
869 self.GenerateReportDetail(File, ModulePcdSet, 1)\r
870 if self.UnusedPcds:\r
871 self.GenerateReportDetail(File, ModulePcdSet, 2)\r
872 self.GenerateReportDetail(File, ModulePcdSet)\r
873\r
52302d4d
LG
874 ##\r
875 # Generate report for PCD information\r
876 #\r
877 # This function generates report for separate module expression\r
878 # in a platform build.\r
879 #\r
880 # @param self The object pointer\r
881 # @param File The file object for report\r
882 # @param ModulePcdSet Set of all PCDs referenced by module or None for\r
883 # platform PCD report\r
c8d07c5e
YZ
884 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional\r
885 # directives section report, 2 means Unused Pcds section report\r
52302d4d
LG
886 # @param DscOverridePcds Module DSC override PCDs set\r
887 #\r
c8d07c5e
YZ
888 def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0):\r
889 PcdDict = self.AllPcds\r
890 if ReportSubType == 1:\r
891 PcdDict = self.ConditionalPcds\r
892 elif ReportSubType == 2:\r
893 PcdDict = self.UnusedPcds\r
894\r
52302d4d 895 if ModulePcdSet == None:\r
52302d4d 896 FileWrite(File, gSectionStart)\r
c8d07c5e
YZ
897 if ReportSubType == 1:\r
898 FileWrite(File, "Conditional Directives used by the build system")\r
899 elif ReportSubType == 2:\r
900 FileWrite(File, "PCDs not used by modules or in conditional directives")\r
901 else:\r
902 FileWrite(File, "Platform Configuration Database Report")\r
903\r
763e8edf 904 FileWrite(File, " *B - PCD override in the build option")\r
52302d4d
LG
905 FileWrite(File, " *P - Platform scoped PCD override in DSC file")\r
906 FileWrite(File, " *F - Platform scoped PCD override in FDF file")\r
c8d07c5e
YZ
907 if not ReportSubType:\r
908 FileWrite(File, " *M - Module scoped PCD override")\r
52302d4d
LG
909 FileWrite(File, gSectionSep)\r
910 else:\r
c2d0a1f6 911 if not ReportSubType and ModulePcdSet:\r
c8d07c5e
YZ
912 #\r
913 # For module PCD sub-section\r
914 #\r
915 FileWrite(File, gSubSectionStart)\r
916 FileWrite(File, TAB_BRG_PCD)\r
917 FileWrite(File, gSubSectionSep)\r
52302d4d 918\r
c8d07c5e 919 for Key in PcdDict:\r
52302d4d
LG
920 #\r
921 # Group PCD by their token space GUID C Name\r
922 #\r
923 First = True\r
c8d07c5e 924 for Type in PcdDict[Key]:\r
52302d4d
LG
925 #\r
926 # Group PCD by their usage type\r
927 #\r
928 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))\r
c8d07c5e 929 for Pcd in PcdDict[Key][Type]:\r
7cb63c87
YZ
930 PcdTokenCName = Pcd.TokenCName\r
931 MixedPcdFlag = False\r
932 if GlobalData.MixedPcd:\r
933 for PcdKey in GlobalData.MixedPcd:\r
934 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]:\r
935 PcdTokenCName = PcdKey[0]\r
936 MixedPcdFlag = True\r
937 if MixedPcdFlag and not ModulePcdSet:\r
938 continue\r
52302d4d
LG
939 #\r
940 # Get PCD default value and their override relationship\r
941 #\r
942 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))\r
943 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))\r
cc71d8b7 944 DscDefaultValBak= DscDefaultValue\r
52302d4d
LG
945 DscDefaultValue = self.FdfPcdSet.get((Pcd.TokenCName, Key), DscDefaultValue)\r
946 InfDefaultValue = None\r
947 \r
948 PcdValue = DecDefaultValue\r
949 if DscDefaultValue:\r
950 PcdValue = DscDefaultValue\r
951 if ModulePcdSet != None:\r
952 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:\r
953 continue\r
954 InfDefault, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]\r
955 if InfDefault == "":\r
956 InfDefault = None\r
763e8edf
YZ
957\r
958 BuildOptionMatch = False\r
959 if GlobalData.BuildOptionPcd:\r
960 for pcd in GlobalData.BuildOptionPcd:\r
961 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):\r
962 PcdValue = pcd[2]\r
963 BuildOptionMatch = True\r
964 break\r
965\r
52302d4d
LG
966 if First:\r
967 if ModulePcdSet == None:\r
968 FileWrite(File, "")\r
969 FileWrite(File, Key)\r
970 First = False\r
971\r
972\r
973 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
974 PcdValueNumber = int(PcdValue.strip(), 0)\r
975 if DecDefaultValue == None:\r
976 DecMatch = True\r
977 else:\r
978 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)\r
979 DecMatch = (DecDefaultValueNumber == PcdValueNumber)\r
980\r
981 if InfDefaultValue == None:\r
982 InfMatch = True\r
983 else:\r
984 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)\r
985 InfMatch = (InfDefaultValueNumber == PcdValueNumber)\r
986\r
987 if DscDefaultValue == None:\r
988 DscMatch = True\r
989 else:\r
990 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)\r
991 DscMatch = (DscDefaultValueNumber == PcdValueNumber)\r
992 else:\r
993 if DecDefaultValue == None:\r
994 DecMatch = True\r
995 else:\r
d5d56f1b 996 DecMatch = (DecDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
997\r
998 if InfDefaultValue == None:\r
999 InfMatch = True\r
1000 else:\r
d5d56f1b 1001 InfMatch = (InfDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
1002\r
1003 if DscDefaultValue == None:\r
1004 DscMatch = True\r
1005 else:\r
d5d56f1b 1006 DscMatch = (DscDefaultValue.strip() == PcdValue.strip())\r
52302d4d 1007\r
e651d06c
LG
1008 IsStructure = False\r
1009 if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd.keys()) and ((Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.gStructurePcd[self.Arch]):\r
1010 IsStructure = True\r
1011 if TypeName in ('DYNVPD', 'DEXVPD'):\r
1012 SkuInfoList = Pcd.SkuInfoList\r
1013 Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]\r
1014 Pcd.DatumType = Pcd.StructName\r
1015 if TypeName in ('DYNVPD', 'DEXVPD'):\r
1016 Pcd.SkuInfoList = SkuInfoList\r
1017 if Pcd.OverrideValues:\r
1018 DscMatch = True\r
1019 DecMatch = False\r
52302d4d
LG
1020 #\r
1021 # Report PCD item according to their override relationship\r
1022 #\r
0e6be43f 1023 if DecMatch and InfMatch:\r
e651d06c 1024 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, ' ')\r
0e6be43f 1025 elif BuildOptionMatch:\r
e651d06c 1026 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B')\r
52302d4d
LG
1027 else:\r
1028 if DscMatch:\r
1029 if (Pcd.TokenCName, Key) in self.FdfPcdSet:\r
e651d06c 1030 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F')\r
52302d4d 1031 else:\r
e651d06c 1032 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P')\r
52302d4d 1033 else:\r
e651d06c 1034 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')\r
52302d4d
LG
1035\r
1036 if ModulePcdSet == None:\r
e651d06c
LG
1037 if IsStructure:\r
1038 continue\r
1039 if not TypeName in ('PATCH', 'FLAG', 'FIXED'):\r
1040 continue\r
763e8edf
YZ
1041 if not BuildOptionMatch:\r
1042 ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
1043 for ModulePath in ModuleOverride:\r
1044 ModuleDefault = ModuleOverride[ModulePath]\r
1045 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
1046 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
1047 Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
1048 else:\r
1049 Match = (ModuleDefault.strip() == PcdValue.strip())\r
1050 if Match:\r
1051 continue\r
e651d06c
LG
1052 IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip())\r
1053 if IsByteArray:\r
1054 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, '{'))\r
1055 for Array in ArrayList:\r
1056 FileWrite(File, '%s' % (Array))\r
1057 else:\r
1058 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip()))\r
52302d4d
LG
1059\r
1060 if ModulePcdSet == None:\r
1061 FileWrite(File, gSectionEnd)\r
1062 else:\r
c2d0a1f6 1063 if not ReportSubType and ModulePcdSet:\r
c8d07c5e 1064 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
1065\r
1066\r
e651d06c
LG
1067 def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue):\r
1068 if not DscMatch and DscDefaultValue != None:\r
1069 Value = DscDefaultValue.strip()\r
1070 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1071 if IsByteArray:\r
1072 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{"))\r
1073 for Array in ArrayList:\r
1074 FileWrite(File, '%s' % (Array))\r
1075 else:\r
1076 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value))\r
1077 if not InfMatch and InfDefaultValue != None:\r
1078 Value = InfDefaultValue.strip()\r
1079 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1080 if IsByteArray:\r
1081 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{"))\r
1082 for Array in ArrayList:\r
1083 FileWrite(File, '%s' % (Array))\r
1084 else:\r
1085 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value))\r
1086\r
1087 if not DecMatch and DecDefaultValue != None:\r
1088 Value = DecDefaultValue.strip()\r
1089 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1090 if IsByteArray:\r
1091 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{"))\r
1092 for Array in ArrayList:\r
1093 FileWrite(File, '%s' % (Array))\r
1094 else:\r
1095 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value))\r
1096 if IsStructure:\r
1097 self.PrintStructureInfo(File, Pcd.DefaultValues)\r
1098\r
1099 def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = ' '):\r
1100 if not Pcd.SkuInfoList:\r
1101 Value = Pcd.DefaultValue\r
1102 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1103 if IsByteArray:\r
1104 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))\r
1105 for Array in ArrayList:\r
1106 FileWrite(File, '%s' % (Array))\r
1107 else:\r
1108 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))\r
1109 if IsStructure:\r
1110 OverrideValues = Pcd.OverrideValues\r
1111 if OverrideValues:\r
1112 Keys = OverrideValues.keys()\r
1113 Data = OverrideValues[Keys[0]]\r
1114 Struct = Data.values()[0]\r
1115 self.PrintStructureInfo(File, Struct)\r
1116 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
1117 else:\r
1118 FirstPrint = True\r
1119 SkuList = sorted(Pcd.SkuInfoList.keys())\r
1120 for Sku in SkuList:\r
1121 SkuInfo = Pcd.SkuInfoList[Sku]\r
1122 if TypeName in ('DYNHII', 'DEXHII'):\r
1123 if SkuInfo.DefaultStoreDict:\r
1124 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())\r
1125 for DefaultStore in DefaultStoreList:\r
1126 Value = SkuInfo.DefaultStoreDict[DefaultStore]\r
1127 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1128 if FirstPrint:\r
1129 FirstPrint = False\r
1130 if IsByteArray:\r
1131 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', '{'))\r
1132 for Array in ArrayList:\r
1133 FileWrite(File, '%s' % (Array))\r
1134 else:\r
1135 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', Value))\r
1136 else:\r
1137 if IsByteArray:\r
1138 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', '{'))\r
1139 for Array in ArrayList:\r
1140 FileWrite(File, '%s' % (Array))\r
1141 else:\r
1142 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', Value))\r
1143 FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))\r
1144 if IsStructure:\r
1145 OverrideValues = Pcd.OverrideValues[Sku]\r
1146 Struct = OverrideValues[DefaultStore]\r
1147 self.PrintStructureInfo(File, Struct)\r
1148 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
1149 elif TypeName in ('DYNVPD', 'DEXVPD'):\r
1150 Value = SkuInfo.DefaultValue\r
1151 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1152 if FirstPrint:\r
1153 FirstPrint = False\r
1154 if IsByteArray:\r
1155 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', "{"))\r
1156 for Array in ArrayList:\r
1157 FileWrite(File, '%s' % (Array))\r
1158 else:\r
1159 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value))\r
1160 else:\r
1161 if IsByteArray:\r
1162 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ' , TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', "{"))\r
1163 for Array in ArrayList:\r
1164 FileWrite(File, '%s' % (Array))\r
1165 else:\r
1166 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ' , TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value))\r
1167 FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
1168 if IsStructure:\r
1169 OverrideValues = Pcd.OverrideValues[Sku]\r
1170 if OverrideValues:\r
1171 Keys = OverrideValues.keys()\r
1172 Struct = OverrideValues[Keys[0]]\r
1173 self.PrintStructureInfo(File, Struct)\r
1174 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
1175 else:\r
1176 Value = SkuInfo.DefaultValue\r
1177 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1178 if FirstPrint:\r
1179 FirstPrint = False\r
1180 if IsByteArray:\r
1181 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '{'))\r
1182 for Array in ArrayList:\r
1183 FileWrite(File, '%s' % (Array))\r
1184 else:\r
1185 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value))\r
1186 else:\r
1187 if IsByteArray:\r
1188 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '{'))\r
1189 for Array in ArrayList:\r
1190 FileWrite(File, '%s' % (Array))\r
1191 else:\r
1192 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value))\r
1193 if IsStructure:\r
1194 OverrideValues = Pcd.OverrideValues[Sku]\r
1195 if OverrideValues:\r
1196 Keys = OverrideValues.keys()\r
1197 Struct = OverrideValues[Keys[0]]\r
1198 self.PrintStructureInfo(File, Struct)\r
1199 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
1200\r
1201 def PrintStructureInfo(self, File, Struct):\r
1202 NewInfo = collections.OrderedDict()\r
1203 for Key, Value in Struct.items():\r
1204 if Key not in NewInfo:\r
1205 NewInfo[Key] = Value[0]\r
1206 else:\r
1207 del NewInfo[Key]\r
1208 NewInfo[Key] = Value[0]\r
1209 if NewInfo:\r
1210 for item in NewInfo:\r
1211 FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + item, NewInfo[item]))\r
1212\r
1213 def StrtoHex(self, value):\r
1214 try:\r
1215 value = hex(int(value))\r
1216 return value\r
1217 except:\r
1218 if value.startswith("L\"") and value.endswith("\""):\r
1219 valuelist = []\r
1220 for ch in value[2:-1]:\r
1221 valuelist.append(hex(ord(ch)))\r
1222 valuelist.append('0x00')\r
1223 return valuelist\r
1224 elif value.startswith("\"") and value.endswith("\""):\r
1225 return hex(ord(value[1:-1]))\r
1226 elif value.startswith("{") and value.endswith("}"):\r
1227 valuelist = []\r
1228 if ',' not in value:\r
1229 return value[1:-1]\r
1230 for ch in value[1:-1].split(','):\r
1231 ch = ch.strip()\r
1232 if ch.startswith('0x') or ch.startswith('0X'):\r
1233 valuelist.append(ch)\r
1234 continue\r
1235 try:\r
1236 valuelist.append(hex(int(ch.strip())))\r
1237 except:\r
1238 pass\r
1239 return valuelist\r
1240 else:\r
1241 return value\r
52302d4d
LG
1242\r
1243##\r
1244# Reports platform and module Prediction information\r
1245#\r
1246# This class reports the platform execution order prediction section and\r
1247# module load fixed address prediction subsection in the build report file.\r
1248#\r
1249class PredictionReport(object):\r
1250 ##\r
1251 # Constructor function for class PredictionReport\r
1252 #\r
1253 # This constructor function generates PredictionReport object for the platform.\r
1254 #\r
1255 # @param self: The object pointer\r
1256 # @param Wa Workspace context information\r
1257 #\r
1258 def __init__(self, Wa):\r
1259 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")\r
1260 self._MapFileParsed = False\r
1261 self._EotToolInvoked = False\r
1262 self._FvDir = Wa.FvDir\r
1263 self._EotDir = Wa.BuildDir\r
1264 self._FfsEntryPoint = {}\r
1265 self._GuidMap = {}\r
1266 self._SourceList = []\r
1267 self.FixedMapDict = {}\r
1268 self.ItemList = []\r
1269 self.MaxLen = 0\r
1270\r
1271 #\r
1272 # Collect all platform reference source files and GUID C Name\r
1273 #\r
1274 for Pa in Wa.AutoGenObjectList:\r
1275 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:\r
1276 #\r
40d841f6
LG
1277 # BASE typed modules are EFI agnostic, so we need not scan\r
1278 # their source code to find PPI/Protocol produce or consume\r
1279 # information.\r
1280 #\r
1281 if Module.ModuleType == "BASE":\r
1282 continue\r
1283 #\r
52302d4d
LG
1284 # Add module referenced source files\r
1285 #\r
1286 self._SourceList.append(str(Module))\r
1287 IncludeList = {}\r
1288 for Source in Module.SourceFileList:\r
1289 if os.path.splitext(str(Source))[1].lower() == ".c":\r
1290 self._SourceList.append(" " + str(Source))\r
1291 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)\r
1292 for IncludeFile in IncludeList.values():\r
1293 self._SourceList.append(" " + IncludeFile)\r
1294\r
1295 for Guid in Module.PpiList:\r
1296 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])\r
1297 for Guid in Module.ProtocolList:\r
1298 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])\r
1299 for Guid in Module.GuidList:\r
1300 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])\r
1301\r
1302 if Module.Guid and not Module.IsLibrary:\r
1303 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)\r
1304 if int(str(Module.AutoGenVersion), 0) >= 0x00010005:\r
1305 RealEntryPoint = "_ModuleEntryPoint"\r
1306 else:\r
1307 RealEntryPoint = EntryPoint\r
1308 if EntryPoint == "_ModuleEntryPoint":\r
1309 CCFlags = Module.BuildOption.get("CC", {}).get("FLAGS", "")\r
1310 Match = gGlueLibEntryPoint.search(CCFlags)\r
1311 if Match:\r
1312 EntryPoint = Match.group(1)\r
1313\r
1314 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)\r
1315\r
1316\r
1317 #\r
1318 # Collect platform firmware volume list as the input of EOT.\r
1319 #\r
1320 self._FvList = []\r
1321 if Wa.FdfProfile:\r
1322 for Fd in Wa.FdfProfile.FdDict:\r
1323 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:\r
1324 if FdRegion.RegionType != "FV":\r
1325 continue\r
1326 for FvName in FdRegion.RegionDataList:\r
1327 if FvName in self._FvList:\r
1328 continue\r
1329 self._FvList.append(FvName)\r
1330 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1331 for Section in Ffs.SectionList:\r
1332 try:\r
1333 for FvSection in Section.SectionList:\r
1334 if FvSection.FvName in self._FvList:\r
1335 continue\r
1336 self._FvList.append(FvSection.FvName)\r
1337 except AttributeError:\r
1338 pass\r
1339\r
1340\r
1341 ##\r
1342 # Parse platform fixed address map files\r
1343 #\r
1344 # This function parses the platform final fixed address map file to get\r
1345 # the database of predicted fixed address for module image base, entry point\r
1346 # etc.\r
1347 #\r
1348 # @param self: The object pointer\r
1349 #\r
1350 def _ParseMapFile(self):\r
1351 if self._MapFileParsed:\r
1352 return\r
1353 self._MapFileParsed = True\r
1354 if os.path.isfile(self._MapFileName):\r
1355 try:\r
1356 FileContents = open(self._MapFileName).read()\r
1357 for Match in gMapFileItemPattern.finditer(FileContents):\r
1358 AddressType = Match.group(1)\r
1359 BaseAddress = Match.group(2)\r
1360 EntryPoint = Match.group(3)\r
1361 Guid = Match.group(4).upper()\r
1362 List = self.FixedMapDict.setdefault(Guid, [])\r
1363 List.append((AddressType, BaseAddress, "*I"))\r
1364 List.append((AddressType, EntryPoint, "*E"))\r
1365 except:\r
1366 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)\r
1367\r
1368 ##\r
1369 # Invokes EOT tool to get the predicted the execution order.\r
1370 #\r
1371 # This function invokes EOT tool to calculate the predicted dispatch order\r
1372 #\r
1373 # @param self: The object pointer\r
1374 #\r
1375 def _InvokeEotTool(self):\r
1376 if self._EotToolInvoked:\r
1377 return\r
1378\r
1379 self._EotToolInvoked = True\r
1380 FvFileList = []\r
1381 for FvName in self._FvList:\r
1382 FvFile = os.path.join(self._FvDir, FvName + ".Fv")\r
1383 if os.path.isfile(FvFile):\r
1384 FvFileList.append(FvFile)\r
1385\r
1386 if len(FvFileList) == 0:\r
1387 return\r
1388 #\r
1389 # Write source file list and GUID file list to an intermediate file\r
1390 # as the input for EOT tool and dispatch List as the output file\r
1391 # from EOT tool.\r
1392 #\r
1393 SourceList = os.path.join(self._EotDir, "SourceFile.txt")\r
1394 GuidList = os.path.join(self._EotDir, "GuidList.txt")\r
1395 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")\r
1396\r
1397 TempFile = open(SourceList, "w+")\r
1398 for Item in self._SourceList:\r
1399 FileWrite(TempFile, Item)\r
1400 TempFile.close()\r
1401 TempFile = open(GuidList, "w+")\r
1402 for Key in self._GuidMap:\r
1403 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))\r
1404 TempFile.close()\r
1405\r
1406 try:\r
1407 from Eot.Eot import Eot\r
40d841f6 1408\r
52302d4d 1409 #\r
40d841f6 1410 # Invoke EOT tool and echo its runtime performance\r
52302d4d 1411 #\r
40d841f6 1412 EotStartTime = time.time()\r
52302d4d
LG
1413 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,\r
1414 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)\r
40d841f6
LG
1415 EotEndTime = time.time()\r
1416 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))\r
1417 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)\r
1418 \r
52302d4d
LG
1419 #\r
1420 # Parse the output of EOT tool\r
1421 #\r
1422 for Line in open(DispatchList):\r
1423 if len(Line.split()) < 4:\r
1424 continue\r
1425 (Guid, Phase, FfsName, FilePath) = Line.split()\r
1426 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]\r
1427 if len(Symbol) > self.MaxLen:\r
1428 self.MaxLen = len(Symbol)\r
1429 self.ItemList.append((Phase, Symbol, FilePath))\r
1430 except:\r
1431 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
1432 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")\r
1433\r
1434\r
1435 ##\r
1436 # Generate platform execution order report\r
1437 #\r
1438 # This function generates the predicted module execution order.\r
1439 #\r
1440 # @param self The object pointer\r
1441 # @param File The file object for report\r
1442 #\r
1443 def _GenerateExecutionOrderReport(self, File):\r
1444 self._InvokeEotTool()\r
1445 if len(self.ItemList) == 0:\r
1446 return\r
1447 FileWrite(File, gSectionStart)\r
1448 FileWrite(File, "Execution Order Prediction")\r
1449 FileWrite(File, "*P PEI phase")\r
1450 FileWrite(File, "*D DXE phase")\r
1451 FileWrite(File, "*E Module INF entry point name")\r
1452 FileWrite(File, "*N Module notification function name")\r
1453\r
1454 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))\r
1455 FileWrite(File, gSectionSep)\r
1456 for Item in self.ItemList:\r
1457 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))\r
1458\r
1459 FileWrite(File, gSectionStart)\r
1460\r
1461 ##\r
1462 # Generate Fixed Address report.\r
1463 #\r
1464 # This function generate the predicted fixed address report for a module\r
1465 # specified by Guid.\r
1466 #\r
1467 # @param self The object pointer\r
1468 # @param File The file object for report\r
1469 # @param Guid The module Guid value.\r
1470 # @param NotifyList The list of all notify function in a module\r
1471 #\r
1472 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):\r
1473 self._ParseMapFile()\r
1474 FixedAddressList = self.FixedMapDict.get(Guid)\r
1475 if not FixedAddressList:\r
1476 return\r
1477\r
1478 FileWrite(File, gSubSectionStart)\r
1479 FileWrite(File, "Fixed Address Prediction")\r
1480 FileWrite(File, "*I Image Loading Address")\r
1481 FileWrite(File, "*E Entry Point Address")\r
1482 FileWrite(File, "*N Notification Function Address")\r
1483 FileWrite(File, "*F Flash Address")\r
1484 FileWrite(File, "*M Memory Address")\r
1485 FileWrite(File, "*S SMM RAM Offset")\r
1486 FileWrite(File, "TOM Top of Memory")\r
1487\r
1488 FileWrite(File, "Type Address Name")\r
1489 FileWrite(File, gSubSectionSep)\r
1490 for Item in FixedAddressList:\r
1491 Type = Item[0]\r
1492 Value = Item[1]\r
1493 Symbol = Item[2]\r
1494 if Symbol == "*I":\r
1495 Name = "(Image Base)"\r
1496 elif Symbol == "*E":\r
1497 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]\r
1498 elif Symbol in NotifyList:\r
1499 Name = Symbol\r
1500 Symbol = "*N"\r
1501 else:\r
1502 continue\r
1503\r
1504 if "Flash" in Type:\r
1505 Symbol += "F"\r
1506 elif "Memory" in Type:\r
1507 Symbol += "M"\r
1508 else:\r
1509 Symbol += "S"\r
1510\r
1511 if Value[0] == "-":\r
1512 Value = "TOM" + Value\r
1513\r
1514 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))\r
1515\r
1516 ##\r
1517 # Generate report for the prediction part\r
1518 #\r
1519 # This function generate the predicted fixed address report for a module or\r
1520 # predicted module execution order for a platform.\r
1521 # If the input Guid is None, then, it generates the predicted module execution order;\r
1522 # otherwise it generated the module fixed loading address for the module specified by\r
1523 # Guid.\r
1524 #\r
1525 # @param self The object pointer\r
1526 # @param File The file object for report\r
1527 # @param Guid The module Guid value.\r
1528 #\r
1529 def GenerateReport(self, File, Guid):\r
1530 if Guid:\r
1531 self._GenerateFixedAddressReport(File, Guid.upper(), [])\r
1532 else:\r
1533 self._GenerateExecutionOrderReport(File)\r
1534\r
1535##\r
1536# Reports FD region information\r
1537#\r
1538# This class reports the FD subsection in the build report file.\r
1539# It collects region information of platform flash device.\r
1540# If the region is a firmware volume, it lists the set of modules\r
1541# and its space information; otherwise, it only lists its region name,\r
1542# base address and size in its sub-section header.\r
1543# If there are nesting FVs, the nested FVs will list immediate after\r
1544# this FD region subsection\r
1545#\r
1546class FdRegionReport(object):\r
1547 ##\r
1548 # Discover all the nested FV name list.\r
1549 #\r
1550 # This is an internal worker function to discover the all the nested FV information\r
1551 # in the parent firmware volume. It uses deep first search algorithm recursively to\r
1552 # find all the FV list name and append them to the list.\r
1553 #\r
1554 # @param self The object pointer\r
1555 # @param FvName The name of current firmware file system\r
1556 # @param Wa Workspace context information\r
1557 #\r
1558 def _DiscoverNestedFvList(self, FvName, Wa):\r
a2432972
EC
1559 FvDictKey=FvName.upper()\r
1560 if FvDictKey in Wa.FdfProfile.FvDict:\r
1561 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1562 for Section in Ffs.SectionList:\r
1563 try:\r
1564 for FvSection in Section.SectionList:\r
1565 if FvSection.FvName in self.FvList:\r
1566 continue\r
1567 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName\r
1568 self.FvList.append(FvSection.FvName)\r
1569 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)\r
1570 self._DiscoverNestedFvList(FvSection.FvName, Wa)\r
1571 except AttributeError:\r
1572 pass\r
52302d4d
LG
1573\r
1574 ##\r
1575 # Constructor function for class FdRegionReport\r
1576 #\r
1577 # This constructor function generates FdRegionReport object for a specified FdRegion.\r
1578 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware\r
1579 # volume list. This function also collects GUID map in order to dump module identification\r
1580 # in the final report.\r
1581 #\r
1582 # @param self: The object pointer\r
1583 # @param FdRegion The current FdRegion object\r
1584 # @param Wa Workspace context information\r
1585 #\r
1586 def __init__(self, FdRegion, Wa):\r
1587 self.Type = FdRegion.RegionType\r
1588 self.BaseAddress = FdRegion.Offset\r
1589 self.Size = FdRegion.Size\r
1590 self.FvList = []\r
1591 self.FvInfo = {}\r
1592 self._GuidsDb = {}\r
1593 self._FvDir = Wa.FvDir\r
1594\r
1595 #\r
1596 # If the input FdRegion is not a firmware volume,\r
1597 # we are done.\r
1598 #\r
1599 if self.Type != "FV":\r
1600 return\r
1601\r
1602 #\r
1603 # Find all nested FVs in the FdRegion\r
1604 #\r
1605 for FvName in FdRegion.RegionDataList:\r
1606 if FvName in self.FvList:\r
1607 continue\r
1608 self.FvList.append(FvName)\r
1609 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)\r
1610 self._DiscoverNestedFvList(FvName, Wa)\r
1611\r
1612 PlatformPcds = {}\r
52302d4d
LG
1613 #\r
1614 # Collect PCDs declared in DEC files.\r
0d2711a6
LG
1615 # \r
1616 for Pa in Wa.AutoGenObjectList:\r
1617 for Package in Pa.PackageList:\r
1618 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
1619 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
1620 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
52302d4d 1621 #\r
af9785a9 1622 # Collect PCDs defined in DSC file\r
52302d4d 1623 #\r
e651d06c
LG
1624 for Pa in Wa.AutoGenObjectList:\r
1625 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:\r
1626 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
af9785a9 1627 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d
LG
1628\r
1629 #\r
1630 # Add PEI and DXE a priori files GUIDs defined in PI specification.\r
1631 #\r
1632 self._GuidsDb["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"\r
1633 self._GuidsDb["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"\r
1634 #\r
1635 # Add ACPI table storage file\r
1636 #\r
1637 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"\r
1638\r
1639 for Pa in Wa.AutoGenObjectList:\r
1640 for ModuleKey in Pa.Platform.Modules:\r
1641 M = Pa.Platform.Modules[ModuleKey].M\r
05cc51ad 1642 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)\r
52302d4d
LG
1643 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
1644\r
1645 #\r
1646 # Collect the GUID map in the FV firmware volume\r
1647 #\r
1648 for FvName in self.FvList:\r
a2432972
EC
1649 FvDictKey=FvName.upper()\r
1650 if FvDictKey in Wa.FdfProfile.FvDict:\r
1651 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1652 try:\r
1653 #\r
1654 # collect GUID map for binary EFI file in FDF file.\r
1655 #\r
1656 Guid = Ffs.NameGuid.upper()\r
1657 Match = gPcdGuidPattern.match(Ffs.NameGuid)\r
1658 if Match:\r
1659 PcdTokenspace = Match.group(1)\r
1660 PcdToken = Match.group(2)\r
1661 if (PcdToken, PcdTokenspace) in PlatformPcds:\r
1662 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]\r
1663 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
1664 for Section in Ffs.SectionList:\r
1665 try:\r
1666 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)\r
1667 self._GuidsDb[Guid] = ModuleSectFile\r
1668 except AttributeError:\r
1669 pass\r
1670 except AttributeError:\r
1671 pass\r
52302d4d
LG
1672\r
1673\r
1674 ##\r
1675 # Internal worker function to generate report for the FD region\r
1676 #\r
1677 # This internal worker function to generate report for the FD region.\r
1678 # It the type is firmware volume, it lists offset and module identification.\r
1679 #\r
1680 # @param self The object pointer\r
1681 # @param File The file object for report\r
1682 # @param Title The title for the FD subsection\r
1683 # @param BaseAddress The base address for the FD region\r
1684 # @param Size The size of the FD region\r
1685 # @param FvName The FV name if the FD region is a firmware volume\r
1686 #\r
1687 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):\r
1688 FileWrite(File, gSubSectionStart)\r
1689 FileWrite(File, Title)\r
1690 FileWrite(File, "Type: %s" % Type)\r
1691 FileWrite(File, "Base Address: 0x%X" % BaseAddress)\r
1692\r
1693 if self.Type == "FV":\r
1694 FvTotalSize = 0\r
1695 FvTakenSize = 0\r
1696 FvFreeSize = 0\r
b36d134f 1697 FvReportFileName = os.path.join(self._FvDir, FvName + ".Fv.txt")\r
52302d4d
LG
1698 try:\r
1699 #\r
1700 # Collect size info in the firmware volume.\r
1701 #\r
1702 FvReport = open(FvReportFileName).read()\r
1703 Match = gFvTotalSizePattern.search(FvReport)\r
1704 if Match:\r
1705 FvTotalSize = int(Match.group(1), 16)\r
1706 Match = gFvTakenSizePattern.search(FvReport)\r
1707 if Match:\r
1708 FvTakenSize = int(Match.group(1), 16)\r
1709 FvFreeSize = FvTotalSize - FvTakenSize\r
1710 #\r
1711 # Write size information to the report file.\r
1712 #\r
1713 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))\r
1714 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))\r
1715 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))\r
1716 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))\r
1717 FileWrite(File, "Offset Module")\r
1718 FileWrite(File, gSubSectionSep)\r
1719 #\r
1720 # Write module offset and module identification to the report file.\r
1721 #\r
1722 OffsetInfo = {}\r
1723 for Match in gOffsetGuidPattern.finditer(FvReport):\r
1724 Guid = Match.group(2).upper()\r
1725 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)\r
1726 OffsetList = OffsetInfo.keys()\r
1727 OffsetList.sort()\r
1728 for Offset in OffsetList:\r
1729 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))\r
1730 except IOError:\r
1731 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)\r
1732 else:\r
1733 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))\r
1734 FileWrite(File, gSubSectionEnd)\r
1735\r
1736 ##\r
1737 # Generate report for the FD region\r
1738 #\r
1739 # This function generates report for the FD region.\r
1740 #\r
1741 # @param self The object pointer\r
1742 # @param File The file object for report\r
1743 #\r
1744 def GenerateReport(self, File):\r
1745 if (len(self.FvList) > 0):\r
1746 for FvItem in self.FvList:\r
1747 Info = self.FvInfo[FvItem]\r
1748 self._GenerateReport(File, Info[0], "FV", Info[1], Info[2], FvItem)\r
1749 else:\r
1750 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)\r
1751\r
1752##\r
1753# Reports FD information\r
1754#\r
1755# This class reports the FD section in the build report file.\r
1756# It collects flash device information for a platform.\r
1757#\r
1758class FdReport(object):\r
1759 ##\r
1760 # Constructor function for class FdReport\r
1761 #\r
1762 # This constructor function generates FdReport object for a specified\r
1763 # firmware device.\r
1764 #\r
1765 # @param self The object pointer\r
1766 # @param Fd The current Firmware device object\r
1767 # @param Wa Workspace context information\r
1768 #\r
1769 def __init__(self, Fd, Wa):\r
1770 self.FdName = Fd.FdUiName\r
1771 self.BaseAddress = Fd.BaseAddress\r
1772 self.Size = Fd.Size\r
1773 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]\r
fb3d2279
YZ
1774 self.FvPath = os.path.join(Wa.BuildDir, "FV")\r
1775 self.VpdFilePath = os.path.join(self.FvPath, "%s.map" % Wa.Platform.VpdToolGuid)\r
043928da
YZ
1776 self.VPDBaseAddress = 0\r
1777 self.VPDSize = 0\r
fb3d2279
YZ
1778 self.VPDInfoList = []\r
1779 for index, FdRegion in enumerate(Fd.RegionList):\r
043928da 1780 if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):\r
fb3d2279
YZ
1781 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress\r
1782 self.VPDSize = self.FdRegionList[index].Size\r
1783 break\r
1784\r
1785 if os.path.isfile(self.VpdFilePath):\r
1786 fd = open(self.VpdFilePath, "r")\r
1787 Lines = fd.readlines()\r
1788 for Line in Lines:\r
1789 Line = Line.strip()\r
1790 if len(Line) == 0 or Line.startswith("#"):\r
1791 continue\r
1792 try:\r
1793 PcdName, SkuId, Offset, Size, Value = Line.split("#")[0].split("|")\r
1794 PcdName, SkuId, Offset, Size, Value = PcdName.strip(), SkuId.strip(), Offset.strip(), Size.strip(), Value.strip()\r
8401d398
YZ
1795 if Offset.lower().startswith('0x'):\r
1796 Offset = '0x%08X' % (int(Offset, 16) + self.VPDBaseAddress)\r
1797 else:\r
1798 Offset = '0x%08X' % (int(Offset, 10) + self.VPDBaseAddress)\r
fb3d2279
YZ
1799 self.VPDInfoList.append("%s | %s | %s | %s | %s" % (PcdName, SkuId, Offset, Size, Value))\r
1800 except:\r
1801 EdkLogger.error("BuildReport", CODE_ERROR, "Fail to parse VPD information file %s" % self.VpdFilePath)\r
1802 fd.close()\r
52302d4d
LG
1803\r
1804 ##\r
1805 # Generate report for the firmware device.\r
1806 #\r
1807 # This function generates report for the firmware device.\r
1808 #\r
1809 # @param self The object pointer\r
1810 # @param File The file object for report\r
1811 #\r
1812 def GenerateReport(self, File):\r
1813 FileWrite(File, gSectionStart)\r
1814 FileWrite(File, "Firmware Device (FD)")\r
1815 FileWrite(File, "FD Name: %s" % self.FdName)\r
1816 FileWrite(File, "Base Address: %s" % self.BaseAddress)\r
1817 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))\r
1818 if len(self.FdRegionList) > 0:\r
1819 FileWrite(File, gSectionSep)\r
1820 for FdRegionItem in self.FdRegionList:\r
1821 FdRegionItem.GenerateReport(File)\r
1822\r
fb3d2279
YZ
1823 if len(self.VPDInfoList) > 0:\r
1824 FileWrite(File, gSubSectionStart)\r
1825 FileWrite(File, "FD VPD Region")\r
1826 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)\r
1827 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))\r
1828 FileWrite(File, gSubSectionSep)\r
1829 for item in self.VPDInfoList:\r
e651d06c
LG
1830 ValueList = item.split('|')\r
1831 Value = ValueList[-1].strip()\r
1832 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1833 if IsByteArray:\r
1834 ValueList[-1] = ' {'\r
1835 FileWrite(File, '|'.join(ValueList))\r
1836 for Array in ArrayList:\r
1837 FileWrite(File, '%s' % (Array))\r
1838 else:\r
1839 FileWrite(File, item)\r
fb3d2279 1840 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
1841 FileWrite(File, gSectionEnd)\r
1842\r
1843\r
1844\r
1845##\r
1846# Reports platform information\r
1847#\r
1848# This class reports the whole platform information\r
1849#\r
1850class PlatformReport(object):\r
1851 ##\r
1852 # Constructor function for class PlatformReport\r
1853 #\r
1854 # This constructor function generates PlatformReport object a platform build.\r
1855 # It generates report for platform summary, flash, global PCDs and detailed\r
1856 # module information for modules involved in platform build.\r
1857 #\r
1858 # @param self The object pointer\r
1859 # @param Wa Workspace context information\r
d5d56f1b 1860 # @param MaList The list of modules in the platform build\r
52302d4d 1861 #\r
d5d56f1b 1862 def __init__(self, Wa, MaList, ReportType):\r
52302d4d
LG
1863 self._WorkspaceDir = Wa.WorkspaceDir\r
1864 self.PlatformName = Wa.Name\r
1865 self.PlatformDscPath = Wa.Platform\r
1866 self.Architectures = " ".join(Wa.ArchList)\r
1867 self.ToolChain = Wa.ToolChain\r
1868 self.Target = Wa.BuildTarget\r
1869 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)\r
1870 self.BuildEnvironment = platform.platform()\r
1871\r
1872 self.PcdReport = None\r
1873 if "PCD" in ReportType:\r
1874 self.PcdReport = PcdReport(Wa)\r
1875\r
1876 self.FdReportList = []\r
d5d56f1b 1877 if "FLASH" in ReportType and Wa.FdfProfile and MaList == None:\r
52302d4d
LG
1878 for Fd in Wa.FdfProfile.FdDict:\r
1879 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))\r
1880\r
1881 self.PredictionReport = None\r
1882 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:\r
1883 self.PredictionReport = PredictionReport(Wa)\r
1884\r
e56468c0 1885 self.DepexParser = None\r
1886 if "DEPEX" in ReportType:\r
1887 self.DepexParser = DepexParser(Wa)\r
1888 \r
52302d4d 1889 self.ModuleReportList = []\r
d5d56f1b 1890 if MaList != None:\r
636f2be6 1891 self._IsModuleBuild = True\r
d5d56f1b
LG
1892 for Ma in MaList:\r
1893 self.ModuleReportList.append(ModuleReport(Ma, ReportType))\r
1894 else:\r
636f2be6 1895 self._IsModuleBuild = False\r
d5d56f1b 1896 for Pa in Wa.AutoGenObjectList:\r
25193a33 1897 ModuleAutoGenList = []\r
d5d56f1b 1898 for ModuleKey in Pa.Platform.Modules:\r
25193a33
YZ
1899 ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)\r
1900 if GlobalData.gFdfParser != None:\r
1901 if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:\r
1902 INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]\r
1903 for InfName in INFList:\r
1904 InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)\r
1905 Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile)\r
1906 if Ma == None:\r
1907 continue\r
1908 if Ma not in ModuleAutoGenList:\r
1909 ModuleAutoGenList.append(Ma)\r
1910 for MGen in ModuleAutoGenList:\r
1911 self.ModuleReportList.append(ModuleReport(MGen, ReportType))\r
52302d4d
LG
1912\r
1913\r
1914\r
1915 ##\r
1916 # Generate report for the whole platform.\r
1917 #\r
1918 # This function generates report for platform information.\r
1919 # It comprises of platform summary, global PCD, flash and\r
1920 # module list sections.\r
1921 #\r
1922 # @param self The object pointer\r
1923 # @param File The file object for report\r
1924 # @param BuildDuration The total time to build the modules\r
1b8eca8b
YZ
1925 # @param AutoGenTime The total time of AutoGen Phase\r
1926 # @param MakeTime The total time of Make Phase\r
1927 # @param GenFdsTime The total time of GenFds Phase\r
52302d4d
LG
1928 # @param ReportType The kind of report items in the final report file\r
1929 #\r
1b8eca8b 1930 def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):\r
52302d4d
LG
1931 FileWrite(File, "Platform Summary")\r
1932 FileWrite(File, "Platform Name: %s" % self.PlatformName)\r
1933 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)\r
1934 FileWrite(File, "Architectures: %s" % self.Architectures)\r
1935 FileWrite(File, "Tool Chain: %s" % self.ToolChain)\r
1936 FileWrite(File, "Target: %s" % self.Target)\r
e651d06c
LG
1937 if GlobalData.gSkuids:\r
1938 FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))\r
1939 if GlobalData.gDefaultStores:\r
1940 FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))\r
52302d4d
LG
1941 FileWrite(File, "Output Path: %s" % self.OutputPath)\r
1942 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)\r
1943 FileWrite(File, "Build Duration: %s" % BuildDuration)\r
1b8eca8b
YZ
1944 if AutoGenTime:\r
1945 FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)\r
1946 if MakeTime:\r
1947 FileWrite(File, "Make Duration: %s" % MakeTime)\r
1948 if GenFdsTime:\r
1949 FileWrite(File, "GenFds Duration: %s" % GenFdsTime)\r
52302d4d
LG
1950 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))\r
1951\r
2a29017e
YZ
1952 if GlobalData.MixedPcd:\r
1953 FileWrite(File, gSectionStart)\r
1954 FileWrite(File, "The following PCDs use different access methods:")\r
1955 FileWrite(File, gSectionSep)\r
1956 for PcdItem in GlobalData.MixedPcd:\r
1957 FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))\r
1958 FileWrite(File, gSectionEnd)\r
1959\r
636f2be6
LG
1960 if not self._IsModuleBuild:\r
1961 if "PCD" in ReportType:\r
1962 self.PcdReport.GenerateReport(File, None)\r
1963 \r
1964 if "FLASH" in ReportType:\r
1965 for FdReportListItem in self.FdReportList:\r
1966 FdReportListItem.GenerateReport(File)\r
52302d4d
LG
1967\r
1968 for ModuleReportItem in self.ModuleReportList:\r
e56468c0 1969 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)\r
52302d4d 1970\r
636f2be6
LG
1971 if not self._IsModuleBuild:\r
1972 if "EXECUTION_ORDER" in ReportType:\r
1973 self.PredictionReport.GenerateReport(File, None)\r
52302d4d
LG
1974\r
1975## BuildReport class\r
1976#\r
1977# This base class contain the routines to collect data and then\r
1978# applies certain format to the output report\r
1979#\r
1980class BuildReport(object):\r
1981 ##\r
1982 # Constructor function for class BuildReport\r
1983 #\r
1984 # This constructor function generates BuildReport object a platform build.\r
1985 # It generates report for platform summary, flash, global PCDs and detailed\r
1986 # module information for modules involved in platform build.\r
1987 #\r
1988 # @param self The object pointer\r
1989 # @param ReportFile The file name to save report file\r
1990 # @param ReportType The kind of report items in the final report file\r
1991 #\r
1992 def __init__(self, ReportFile, ReportType):\r
1993 self.ReportFile = ReportFile\r
1994 if ReportFile:\r
1995 self.ReportList = []\r
1996 self.ReportType = []\r
1997 if ReportType: \r
1998 for ReportTypeItem in ReportType:\r
1999 if ReportTypeItem not in self.ReportType:\r
2000 self.ReportType.append(ReportTypeItem)\r
2001 else:\r
eca5be7a 2002 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]\r
52302d4d
LG
2003 ##\r
2004 # Adds platform report to the list\r
2005 #\r
2006 # This function adds a platform report to the final report list.\r
2007 #\r
2008 # @param self The object pointer\r
2009 # @param Wa Workspace context information\r
d5d56f1b 2010 # @param MaList The list of modules in the platform build\r
52302d4d 2011 #\r
d5d56f1b 2012 def AddPlatformReport(self, Wa, MaList=None):\r
52302d4d 2013 if self.ReportFile:\r
d5d56f1b 2014 self.ReportList.append((Wa, MaList))\r
52302d4d
LG
2015\r
2016 ##\r
2017 # Generates the final report.\r
2018 #\r
2019 # This function generates platform build report. It invokes GenerateReport()\r
2020 # method for every platform report in the list.\r
2021 #\r
2022 # @param self The object pointer\r
2023 # @param BuildDuration The total time to build the modules\r
1b8eca8b
YZ
2024 # @param AutoGenTime The total time of AutoGen phase\r
2025 # @param MakeTime The total time of Make phase\r
2026 # @param GenFdsTime The total time of GenFds phase\r
52302d4d 2027 #\r
1b8eca8b 2028 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):\r
52302d4d
LG
2029 if self.ReportFile:\r
2030 try:\r
40d841f6 2031 File = StringIO('')\r
d5d56f1b 2032 for (Wa, MaList) in self.ReportList:\r
1b8eca8b 2033 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)\r
64b2609f
LG
2034 Content = FileLinesSplit(File.getvalue(), gLineMaxLength)\r
2035 SaveFileOnChange(self.ReportFile, Content, True)\r
40d841f6 2036 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))\r
52302d4d
LG
2037 except IOError:\r
2038 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)\r
2039 except:\r
2040 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)\r
2041 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
2042 File.close()\r
636f2be6 2043 \r
52302d4d
LG
2044# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
2045if __name__ == '__main__':\r
2046 pass\r
2047\r