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