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