]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/BuildReport.py
Fill AtaDeviceHeader field in ATA command block
[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
40d841f6
LG
7# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
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
19import os\r
20import re\r
21import platform\r
22import textwrap\r
23import traceback\r
24import sys\r
40d841f6 25import time\r
52302d4d 26from datetime import datetime\r
40d841f6 27from StringIO import StringIO\r
52302d4d 28from Common import EdkLogger\r
40d841f6 29from Common.Misc import SaveFileOnChange\r
52302d4d
LG
30from Common.Misc import GuidStructureByteArrayToGuidString\r
31from Common.Misc import GuidStructureStringToGuidString\r
32from Common.InfClassObject import gComponentType2ModuleType\r
52302d4d
LG
33from Common.BuildToolError import FILE_WRITE_FAILURE\r
34from Common.BuildToolError import CODE_ERROR\r
35\r
36\r
37## Pattern to extract contents in EDK DXS files\r
38gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
39\r
40## Pattern to find total FV total size, occupied size in flash report intermediate file\r
41gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")\r
42gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")\r
43\r
44## Pattern to find module size and time stamp in module summary report intermediate file\r
45gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")\r
46gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")\r
47\r
48## Pattern to find GUID value in flash description files\r
49gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")\r
50\r
51## Pattern to collect offset, GUID value pair in the flash report intermediate file\r
52gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")\r
53\r
54## Pattern to find module base address and entry point in fixed flash map file\r
55gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"\r
56gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})\r
57\r
58## Pattern to find all module referenced header files in source files\r
59gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')\r
60gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")\r
61\r
62## Pattern to find the entry point for EDK module using EDKII Glue library\r
63gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")\r
64\r
65## Tags for section start, end and separator\r
66gSectionStart = ">" + "=" * 118 + "<"\r
67gSectionEnd = "<" + "=" * 118 + ">" + "\n"\r
68gSectionSep = "=" * 120\r
69\r
70## Tags for subsection start, end and separator\r
71gSubSectionStart = ">" + "-" * 118 + "<"\r
72gSubSectionEnd = "<" + "-" * 118 + ">"\r
73gSubSectionSep = "-" * 120\r
74\r
75## The look up table to map PCD type to pair of report display type and DEC type\r
76gPcdTypeMap = {\r
77 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),\r
78 'PatchableInModule': ('PATCH', 'PatchableInModule'),\r
79 'FeatureFlag' : ('FLAG', 'FeatureFlag'),\r
80 'Dynamic' : ('DYN', 'Dynamic'),\r
81 'DynamicHii' : ('DYNHII', 'Dynamic'),\r
82 'DynamicVpd' : ('DYNVPD', 'Dynamic'),\r
83 'DynamicEx' : ('DEX', 'Dynamic'),\r
84 'DynamicExHii' : ('DEXHII', 'Dynamic'),\r
85 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),\r
86 }\r
87\r
88## The look up table to map module type to driver type\r
89gDriverTypeMap = {\r
90 'SEC' : '0x3 (SECURITY_CORE)',\r
91 'PEI_CORE' : '0x4 (PEI_CORE)',\r
92 'PEIM' : '0x6 (PEIM)',\r
93 'DXE_CORE' : '0x5 (DXE_CORE)',\r
94 'DXE_DRIVER' : '0x7 (DRIVER)',\r
95 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',\r
96 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',\r
97 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',\r
98 'UEFI_DRIVER' : '0x7 (DRIVER)',\r
99 'UEFI_APPLICATION' : '0x9 (APPLICATION)',\r
100 'SMM_CORE' : '0xD (SMM_CORE)',\r
101 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers\r
102 }\r
103\r
104##\r
105# Writes a string to the file object.\r
106#\r
107# This function writes a string to the file object and a new line is appended\r
108# afterwards. It may optionally wraps the string for better readability.\r
109#\r
110# @File The file object to write\r
111# @String The string to be written to the file\r
112# @Wrapper Indicates whether to wrap the string\r
113#\r
114def FileWrite(File, String, Wrapper=False):\r
115 if Wrapper:\r
116 String = textwrap.fill(String, 120)\r
117 File.write(String + "\r\n")\r
118\r
119##\r
120# Find all the header file that the module source directly includes.\r
121#\r
122# This function scans source code to find all header files the module may\r
123# include. This is not accurate but very effective to find all the header\r
124# file the module might include with #include statement.\r
125#\r
126# @Source The source file name\r
127# @IncludePathList The list of include path to find the source file.\r
128# @IncludeFiles The dictionary of current found include files.\r
129#\r
130def FindIncludeFiles(Source, IncludePathList, IncludeFiles):\r
131 FileContents = open(Source).read()\r
132 #\r
133 # Find header files with pattern #include "XXX.h" or #include <XXX.h>\r
134 #\r
135 for Match in gIncludePattern.finditer(FileContents):\r
136 FileName = Match.group(1).strip()\r
137 for Dir in [os.path.dirname(Source)] + IncludePathList:\r
138 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
139 if os.path.exists(FullFileName):\r
140 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
141 break\r
142\r
143 #\r
144 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)\r
145 #\r
146 for Match in gIncludePattern2.finditer(FileContents):\r
147 Key = Match.group(2)\r
148 Type = Match.group(1)\r
149 if "ARCH_PROTOCOL" in Type:\r
150 FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
151 elif "PROTOCOL" in Type:\r
152 FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
153 elif "PPI" in Type:\r
154 FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
155 elif "GUID" in Type:\r
156 FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
157 else:\r
158 continue\r
159 for Dir in IncludePathList:\r
160 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
161 if os.path.exists(FullFileName):\r
162 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
163 break\r
164\r
165##\r
166# Reports library information\r
167#\r
168# This class reports the module library subsection in the build report file.\r
169#\r
170class LibraryReport(object):\r
171 ##\r
172 # Constructor function for class LibraryReport\r
173 #\r
174 # This constructor function generates LibraryReport object for\r
175 # a module.\r
176 #\r
177 # @param self The object pointer\r
178 # @param M Module context information\r
179 #\r
180 def __init__(self, M):\r
181 self.LibraryList = []\r
182 if int(str(M.AutoGenVersion), 0) >= 0x00010005:\r
183 self._EdkIIModule = True\r
184 else:\r
185 self._EdkIIModule = False\r
186\r
187 for Lib in M.DependentLibraryList:\r
188 LibInfPath = str(Lib)\r
189 LibClassList = Lib.LibraryClass[0].LibraryClass\r
190 LibConstructorList = Lib.ConstructorList\r
191 LibDesstructorList = Lib.DestructorList\r
192 LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]\r
193 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList))\r
194\r
195 ##\r
196 # Generate report for module library information\r
197 #\r
198 # This function generates report for the module library.\r
199 # If the module is EDKII style one, the additional library class, library\r
200 # constructor/destructor and dependency expression may also be reported.\r
201 #\r
202 # @param self The object pointer\r
203 # @param File The file object for report\r
204 #\r
205 def GenerateReport(self, File):\r
206 FileWrite(File, gSubSectionStart)\r
207 FileWrite(File, "Library")\r
208 if len(self.LibraryList) > 0:\r
209 FileWrite(File, gSubSectionSep)\r
210 for LibraryItem in self.LibraryList:\r
211 LibInfPath = LibraryItem[0]\r
212 FileWrite(File, LibInfPath)\r
213\r
214 #\r
215 # Report library class, library constructor and destructor for\r
216 # EDKII style module.\r
217 #\r
218 if self._EdkIIModule:\r
219 LibClass = LibraryItem[1]\r
220 EdkIILibInfo = ""\r
221 LibConstructor = " ".join(LibraryItem[2])\r
222 if LibConstructor:\r
223 EdkIILibInfo += " C = " + LibConstructor\r
224 LibDestructor = " ".join(LibraryItem[3])\r
225 if LibDestructor:\r
636f2be6 226 EdkIILibInfo += " D = " + LibDestructor\r
52302d4d
LG
227 LibDepex = " ".join(LibraryItem[4])\r
228 if LibDepex:\r
229 EdkIILibInfo += " Depex = " + LibDepex\r
230 if EdkIILibInfo:\r
231 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))\r
232 else:\r
233 FileWrite(File, "{%s}" % LibClass)\r
234\r
235 FileWrite(File, gSubSectionEnd)\r
236\r
237##\r
238# Reports dependency expression information\r
239#\r
240# This class reports the module dependency expression subsection in the build report file.\r
241#\r
242class DepexReport(object):\r
243 ##\r
244 # Constructor function for class DepexReport\r
245 #\r
246 # This constructor function generates DepexReport object for\r
247 # a module. If the module source contains the DXS file (usually EDK\r
248 # style module), it uses the dependency in DXS file; otherwise,\r
249 # it uses the dependency expression from its own INF [Depex] section\r
250 # and then merges with the ones from its dependent library INF.\r
251 #\r
252 # @param self The object pointer\r
253 # @param M Module context information\r
254 #\r
255 def __init__(self, M):\r
256 self.Depex = ""\r
257 ModuleType = M.ModuleType\r
258 if not ModuleType:\r
259 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
636f2be6
LG
260\r
261 if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:\r
52302d4d
LG
262 return\r
263 \r
264 for Source in M.SourceFileList:\r
265 if os.path.splitext(Source.Path)[1].lower() == ".dxs":\r
266 Match = gDxsDependencyPattern.search(open(Source.Path).read())\r
267 if Match:\r
268 self.Depex = Match.group(1).strip()\r
269 self.Source = "DXS"\r
270 break\r
271 else:\r
272 self.Depex = M.DepexExpressionList.get(M.ModuleType, "")\r
273 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])\r
274 if not self.ModuleDepex:\r
275 self.ModuleDepex = "(None)"\r
276\r
277 LibDepexList = []\r
278 for Lib in M.DependentLibraryList:\r
279 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()\r
280 if LibDepex != "":\r
281 LibDepexList.append("(" + LibDepex + ")")\r
282 self.LibraryDepex = " AND ".join(LibDepexList)\r
283 if not self.LibraryDepex:\r
284 self.LibraryDepex = "(None)"\r
285 self.Source = "INF"\r
286\r
287 ##\r
288 # Generate report for module dependency expression information\r
289 #\r
290 # This function generates report for the module dependency expression.\r
291 #\r
292 # @param self The object pointer\r
293 # @param File The file object for report\r
294 #\r
295 def GenerateReport(self, File):\r
296 if not self.Depex:\r
297 return\r
298 \r
299 FileWrite(File, gSubSectionStart)\r
300 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)\r
301\r
302 if self.Source == "INF":\r
303 FileWrite(File, "%s" % self.Depex, True)\r
304 FileWrite(File, gSubSectionSep)\r
305 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)\r
306 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)\r
307 else:\r
308 FileWrite(File, "%s" % self.Depex)\r
309 FileWrite(File, gSubSectionEnd)\r
310\r
311##\r
312# Reports dependency expression information\r
313#\r
314# This class reports the module build flags subsection in the build report file.\r
315#\r
316class BuildFlagsReport(object):\r
317 ##\r
318 # Constructor function for class BuildFlagsReport\r
319 #\r
320 # This constructor function generates BuildFlagsReport object for\r
321 # a module. It reports the build tool chain tag and all relevant\r
322 # build flags to build the module.\r
323 #\r
324 # @param self The object pointer\r
325 # @param M Module context information\r
326 #\r
327 def __init__(self, M):\r
328 BuildOptions = {}\r
329 #\r
330 # Add build flags according to source file extension so that\r
331 # irrelevant ones can be filtered out.\r
332 #\r
333 for Source in M.SourceFileList:\r
334 Ext = os.path.splitext(Source.File)[1].lower()\r
335 if Ext in [".c", ".cc", ".cpp"]:\r
336 BuildOptions["CC"] = 1\r
337 elif Ext in [".s", ".asm"]:\r
338 BuildOptions["PP"] = 1\r
339 BuildOptions["ASM"] = 1\r
340 elif Ext in [".vfr"]:\r
341 BuildOptions["VFRPP"] = 1\r
342 BuildOptions["VFR"] = 1\r
343 elif Ext in [".dxs"]:\r
344 BuildOptions["APP"] = 1\r
345 BuildOptions["CC"] = 1\r
346 elif Ext in [".asl"]:\r
347 BuildOptions["ASLPP"] = 1\r
348 BuildOptions["ASL"] = 1\r
349 elif Ext in [".aslc"]:\r
350 BuildOptions["ASLCC"] = 1\r
351 BuildOptions["ASLDLINK"] = 1\r
352 BuildOptions["CC"] = 1\r
353 elif Ext in [".asm16"]:\r
354 BuildOptions["ASMLINK"] = 1\r
355 BuildOptions["SLINK"] = 1\r
356 BuildOptions["DLINK"] = 1\r
357\r
358 #\r
359 # Save module build flags.\r
360 #\r
361 self.ToolChainTag = M.ToolChain\r
362 self.BuildFlags = {}\r
363 for Tool in BuildOptions:\r
364 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")\r
365\r
366 ##\r
367 # Generate report for module build flags information\r
368 #\r
369 # This function generates report for the module build flags expression.\r
370 #\r
371 # @param self The object pointer\r
372 # @param File The file object for report\r
373 #\r
374 def GenerateReport(self, File):\r
375 FileWrite(File, gSubSectionStart)\r
376 FileWrite(File, "Build Flags")\r
377 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)\r
378 for Tool in self.BuildFlags:\r
379 FileWrite(File, gSubSectionSep)\r
380 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)\r
381\r
382 FileWrite(File, gSubSectionEnd)\r
383\r
384\r
385##\r
386# Reports individual module information\r
387#\r
388# This class reports the module section in the build report file.\r
389# It comprises of module summary, module PCD, library, dependency expression,\r
390# build flags sections.\r
391#\r
392class ModuleReport(object):\r
393 ##\r
394 # Constructor function for class ModuleReport\r
395 #\r
396 # This constructor function generates ModuleReport object for\r
397 # a separate module in a platform build.\r
398 #\r
399 # @param self The object pointer\r
400 # @param M Module context information\r
401 # @param ReportType The kind of report items in the final report file\r
402 #\r
403 def __init__(self, M, ReportType):\r
404 self.ModuleName = M.Module.BaseName\r
405 self.ModuleInfPath = M.MetaFile.File\r
406 self.FileGuid = M.Guid\r
407 self.Size = 0\r
408 self.BuildTimeStamp = None\r
409 self.DriverType = ""\r
636f2be6
LG
410 if not M.IsLibrary:\r
411 ModuleType = M.ModuleType\r
412 if not ModuleType:\r
413 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
414 #\r
415 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"\r
416 #\r
417 if ModuleType == "DXE_SMM_DRIVER":\r
418 PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
419 if int(PiSpec, 0) >= 0x0001000A:\r
420 ModuleType = "SMM_DRIVER"\r
421 self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")\r
52302d4d
LG
422 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")\r
423 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")\r
424 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")\r
425 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")\r
426 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")\r
427\r
428 self._BuildDir = M.BuildDir\r
429 self.ModulePcdSet = {}\r
430 if "PCD" in ReportType:\r
431 #\r
432 # Collect all module used PCD set: module INF referenced directly or indirectly.\r
433 # It also saves module INF default values of them in case they exist.\r
434 #\r
435 for Pcd in M.ModulePcdList + M.LibraryPcdList:\r
436 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))\r
437\r
438 self.LibraryReport = None\r
439 if "LIBRARY" in ReportType:\r
440 self.LibraryReport = LibraryReport(M)\r
441\r
442 self.DepexReport = None\r
443 if "DEPEX" in ReportType:\r
444 self.DepexReport = DepexReport(M)\r
445\r
446 if "BUILD_FLAGS" in ReportType:\r
447 self.BuildFlagsReport = BuildFlagsReport(M)\r
448\r
449\r
450 ##\r
451 # Generate report for module information\r
452 #\r
453 # This function generates report for separate module expression\r
454 # in a platform build.\r
455 #\r
456 # @param self The object pointer\r
457 # @param File The file object for report\r
458 # @param GlobalPcdReport The platform global PCD class object\r
459 # @param ReportType The kind of report items in the final report file\r
460 #\r
461 def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, ReportType):\r
462 FileWrite(File, gSectionStart)\r
463\r
464 FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt")\r
465 if os.path.isfile(FwReportFileName):\r
466 try:\r
467 FileContents = open(FwReportFileName).read()\r
468 Match = gModuleSizePattern.search(FileContents)\r
469 if Match:\r
470 self.Size = int(Match.group(1))\r
471\r
472 Match = gTimeStampPattern.search(FileContents)\r
473 if Match:\r
474 self.BuildTimeStamp = datetime.fromtimestamp(int(Match.group(1)))\r
475 except IOError:\r
476 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)\r
477\r
478 FileWrite(File, "Module Summary")\r
479 FileWrite(File, "Module Name: %s" % self.ModuleName)\r
480 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)\r
481 FileWrite(File, "File GUID: %s" % self.FileGuid)\r
482 if self.Size:\r
483 FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))\r
484 if self.BuildTimeStamp:\r
485 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)\r
486 if self.DriverType:\r
487 FileWrite(File, "Driver Type: %s" % self.DriverType)\r
488 if self.UefiSpecVersion:\r
489 FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)\r
490 if self.PiSpecVersion:\r
491 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)\r
492 if self.PciDeviceId:\r
493 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)\r
494 if self.PciVendorId:\r
495 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)\r
496 if self.PciClassCode:\r
497 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)\r
498\r
499 FileWrite(File, gSectionSep)\r
500\r
501 if "PCD" in ReportType:\r
502 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet)\r
503\r
504 if "LIBRARY" in ReportType:\r
505 self.LibraryReport.GenerateReport(File)\r
506\r
507 if "DEPEX" in ReportType:\r
508 self.DepexReport.GenerateReport(File)\r
509\r
510 if "BUILD_FLAGS" in ReportType:\r
511 self.BuildFlagsReport.GenerateReport(File)\r
512\r
513 if "FIXED_ADDRESS" in ReportType and self.FileGuid:\r
514 GlobalPredictionReport.GenerateReport(File, self.FileGuid)\r
515\r
516 FileWrite(File, gSectionEnd)\r
517\r
518##\r
519# Reports platform and module PCD information\r
520#\r
521# This class reports the platform PCD section and module PCD subsection\r
522# in the build report file.\r
523#\r
524class PcdReport(object):\r
525 ##\r
526 # Constructor function for class PcdReport\r
527 #\r
528 # This constructor function generates PcdReport object a platform build.\r
529 # It collects the whole PCD database from platform DSC files, platform\r
530 # flash description file and package DEC files.\r
531 #\r
532 # @param self The object pointer\r
533 # @param Wa Workspace context information\r
534 #\r
535 def __init__(self, Wa):\r
536 self.AllPcds = {}\r
537 self.MaxLen = 0\r
538 if Wa.FdfProfile:\r
539 self.FdfPcdSet = Wa.FdfProfile.PcdDict\r
540 else:\r
541 self.FdfPcdSet = {}\r
542\r
543 self.ModulePcdOverride = {}\r
544 for Pa in Wa.AutoGenObjectList:\r
545 #\r
546 # Collect all platform referenced PCDs and grouped them by PCD token space\r
547 # GUID C Names\r
548 #\r
549 for Pcd in Pa.AllPcdList:\r
550 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
551 if Pcd not in PcdList:\r
552 PcdList.append(Pcd)\r
553 if len(Pcd.TokenCName) > self.MaxLen:\r
554 self.MaxLen = len(Pcd.TokenCName)\r
555\r
556 for Module in Pa.Platform.Modules.values():\r
557 #\r
558 # Collect module override PCDs\r
559 #\r
560 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:\r
561 TokenCName = ModulePcd.TokenCName\r
562 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName\r
563 ModuleDefault = ModulePcd.DefaultValue\r
564 ModulePath = os.path.basename(Module.M.MetaFile.File)\r
565 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault\r
566\r
567\r
568 #\r
569 # Collect PCD DEC default value.\r
570 #\r
571 self.DecPcdDefault = {}\r
572 for Package in Wa.BuildDatabase.WorkspaceDb.PackageList:\r
573 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
574 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
575 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
576 #\r
577 # Collect PCDs defined in DSC common section\r
578 #\r
579 self.DscPcdDefault = {}\r
580 for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:\r
581 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
582 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
40d841f6
LG
583 if DscDefaultValue:\r
584 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d
LG
585\r
586 ##\r
587 # Generate report for PCD information\r
588 #\r
589 # This function generates report for separate module expression\r
590 # in a platform build.\r
591 #\r
592 # @param self The object pointer\r
593 # @param File The file object for report\r
594 # @param ModulePcdSet Set of all PCDs referenced by module or None for\r
595 # platform PCD report\r
596 # @param DscOverridePcds Module DSC override PCDs set\r
597 #\r
598 def GenerateReport(self, File, ModulePcdSet):\r
599 if ModulePcdSet == None:\r
600 #\r
601 # For platform global PCD section\r
602 #\r
603 FileWrite(File, gSectionStart)\r
604 FileWrite(File, "Platform Configuration Database Report")\r
605 FileWrite(File, " *P - Platform scoped PCD override in DSC file")\r
606 FileWrite(File, " *F - Platform scoped PCD override in FDF file")\r
79714906 607 FileWrite(File, " *M - Module scoped PCD override")\r
52302d4d
LG
608 FileWrite(File, gSectionSep)\r
609 else:\r
610 #\r
611 # For module PCD sub-section\r
612 #\r
613 FileWrite(File, gSubSectionStart)\r
614 FileWrite(File, "PCD")\r
615 FileWrite(File, gSubSectionSep)\r
616\r
617 for Key in self.AllPcds:\r
618 #\r
619 # Group PCD by their token space GUID C Name\r
620 #\r
621 First = True\r
622 for Type in self.AllPcds[Key]:\r
623 #\r
624 # Group PCD by their usage type\r
625 #\r
626 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))\r
627 for Pcd in self.AllPcds[Key][Type]:\r
628 #\r
629 # Get PCD default value and their override relationship\r
630 #\r
631 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))\r
632 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))\r
633 DscDefaultValue = self.FdfPcdSet.get((Pcd.TokenCName, Key), DscDefaultValue)\r
634 InfDefaultValue = None\r
635 \r
636 PcdValue = DecDefaultValue\r
637 if DscDefaultValue:\r
638 PcdValue = DscDefaultValue\r
639 if ModulePcdSet != None:\r
640 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:\r
641 continue\r
642 InfDefault, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]\r
643 if InfDefault == "":\r
644 InfDefault = None\r
645 if First:\r
646 if ModulePcdSet == None:\r
647 FileWrite(File, "")\r
648 FileWrite(File, Key)\r
649 First = False\r
650\r
651\r
652 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
653 PcdValueNumber = int(PcdValue.strip(), 0)\r
654 if DecDefaultValue == None:\r
655 DecMatch = True\r
656 else:\r
657 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)\r
658 DecMatch = (DecDefaultValueNumber == PcdValueNumber)\r
659\r
660 if InfDefaultValue == None:\r
661 InfMatch = True\r
662 else:\r
663 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)\r
664 InfMatch = (InfDefaultValueNumber == PcdValueNumber)\r
665\r
666 if DscDefaultValue == None:\r
667 DscMatch = True\r
668 else:\r
669 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)\r
670 DscMatch = (DscDefaultValueNumber == PcdValueNumber)\r
671 else:\r
672 if DecDefaultValue == None:\r
673 DecMatch = True\r
674 else:\r
d5d56f1b 675 DecMatch = (DecDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
676\r
677 if InfDefaultValue == None:\r
678 InfMatch = True\r
679 else:\r
d5d56f1b 680 InfMatch = (InfDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
681\r
682 if DscDefaultValue == None:\r
683 DscMatch = True\r
684 else:\r
d5d56f1b 685 DscMatch = (DscDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
686\r
687 #\r
688 # Report PCD item according to their override relationship\r
689 #\r
690 if DecMatch and InfMatch:\r
d5d56f1b 691 FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
52302d4d
LG
692 else:\r
693 if DscMatch:\r
694 if (Pcd.TokenCName, Key) in self.FdfPcdSet:\r
d5d56f1b 695 FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
52302d4d 696 else:\r
d5d56f1b 697 FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
52302d4d 698 else:\r
d5d56f1b 699 FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
52302d4d
LG
700 \r
701 if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):\r
702 for SkuInfo in Pcd.SkuInfoList.values():\r
703 if TypeName in ('DYNHII', 'DEXHII'):\r
704 FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset)) \r
705 else:\r
706 FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
707 \r
708 if not DscMatch and DscDefaultValue != None:\r
d5d56f1b 709 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue.strip()))\r
52302d4d
LG
710\r
711 if not InfMatch and InfDefaultValue != None:\r
d5d56f1b 712 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue.strip()))\r
52302d4d
LG
713\r
714 if not DecMatch and DecDefaultValue != None:\r
d5d56f1b 715 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue.strip()))\r
52302d4d
LG
716\r
717 if ModulePcdSet == None:\r
718 ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
719 for ModulePath in ModuleOverride:\r
720 ModuleDefault = ModuleOverride[ModulePath]\r
721 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
722 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
723 Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
724 else:\r
d5d56f1b 725 Match = (ModuleDefault.strip() == PcdValue.strip())\r
52302d4d
LG
726 if Match:\r
727 continue\r
d5d56f1b 728 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip()))\r
52302d4d
LG
729\r
730 if ModulePcdSet == None:\r
731 FileWrite(File, gSectionEnd)\r
732 else:\r
733 FileWrite(File, gSubSectionEnd)\r
734\r
735\r
736\r
737##\r
738# Reports platform and module Prediction information\r
739#\r
740# This class reports the platform execution order prediction section and\r
741# module load fixed address prediction subsection in the build report file.\r
742#\r
743class PredictionReport(object):\r
744 ##\r
745 # Constructor function for class PredictionReport\r
746 #\r
747 # This constructor function generates PredictionReport object for the platform.\r
748 #\r
749 # @param self: The object pointer\r
750 # @param Wa Workspace context information\r
751 #\r
752 def __init__(self, Wa):\r
753 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")\r
754 self._MapFileParsed = False\r
755 self._EotToolInvoked = False\r
756 self._FvDir = Wa.FvDir\r
757 self._EotDir = Wa.BuildDir\r
758 self._FfsEntryPoint = {}\r
759 self._GuidMap = {}\r
760 self._SourceList = []\r
761 self.FixedMapDict = {}\r
762 self.ItemList = []\r
763 self.MaxLen = 0\r
764\r
765 #\r
766 # Collect all platform reference source files and GUID C Name\r
767 #\r
768 for Pa in Wa.AutoGenObjectList:\r
769 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:\r
770 #\r
40d841f6
LG
771 # BASE typed modules are EFI agnostic, so we need not scan\r
772 # their source code to find PPI/Protocol produce or consume\r
773 # information.\r
774 #\r
775 if Module.ModuleType == "BASE":\r
776 continue\r
777 #\r
52302d4d
LG
778 # Add module referenced source files\r
779 #\r
780 self._SourceList.append(str(Module))\r
781 IncludeList = {}\r
782 for Source in Module.SourceFileList:\r
783 if os.path.splitext(str(Source))[1].lower() == ".c":\r
784 self._SourceList.append(" " + str(Source))\r
785 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)\r
786 for IncludeFile in IncludeList.values():\r
787 self._SourceList.append(" " + IncludeFile)\r
788\r
789 for Guid in Module.PpiList:\r
790 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])\r
791 for Guid in Module.ProtocolList:\r
792 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])\r
793 for Guid in Module.GuidList:\r
794 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])\r
795\r
796 if Module.Guid and not Module.IsLibrary:\r
797 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)\r
798 if int(str(Module.AutoGenVersion), 0) >= 0x00010005:\r
799 RealEntryPoint = "_ModuleEntryPoint"\r
800 else:\r
801 RealEntryPoint = EntryPoint\r
802 if EntryPoint == "_ModuleEntryPoint":\r
803 CCFlags = Module.BuildOption.get("CC", {}).get("FLAGS", "")\r
804 Match = gGlueLibEntryPoint.search(CCFlags)\r
805 if Match:\r
806 EntryPoint = Match.group(1)\r
807\r
808 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)\r
809\r
810\r
811 #\r
812 # Collect platform firmware volume list as the input of EOT.\r
813 #\r
814 self._FvList = []\r
815 if Wa.FdfProfile:\r
816 for Fd in Wa.FdfProfile.FdDict:\r
817 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:\r
818 if FdRegion.RegionType != "FV":\r
819 continue\r
820 for FvName in FdRegion.RegionDataList:\r
821 if FvName in self._FvList:\r
822 continue\r
823 self._FvList.append(FvName)\r
824 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
825 for Section in Ffs.SectionList:\r
826 try:\r
827 for FvSection in Section.SectionList:\r
828 if FvSection.FvName in self._FvList:\r
829 continue\r
830 self._FvList.append(FvSection.FvName)\r
831 except AttributeError:\r
832 pass\r
833\r
834\r
835 ##\r
836 # Parse platform fixed address map files\r
837 #\r
838 # This function parses the platform final fixed address map file to get\r
839 # the database of predicted fixed address for module image base, entry point\r
840 # etc.\r
841 #\r
842 # @param self: The object pointer\r
843 #\r
844 def _ParseMapFile(self):\r
845 if self._MapFileParsed:\r
846 return\r
847 self._MapFileParsed = True\r
848 if os.path.isfile(self._MapFileName):\r
849 try:\r
850 FileContents = open(self._MapFileName).read()\r
851 for Match in gMapFileItemPattern.finditer(FileContents):\r
852 AddressType = Match.group(1)\r
853 BaseAddress = Match.group(2)\r
854 EntryPoint = Match.group(3)\r
855 Guid = Match.group(4).upper()\r
856 List = self.FixedMapDict.setdefault(Guid, [])\r
857 List.append((AddressType, BaseAddress, "*I"))\r
858 List.append((AddressType, EntryPoint, "*E"))\r
859 except:\r
860 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)\r
861\r
862 ##\r
863 # Invokes EOT tool to get the predicted the execution order.\r
864 #\r
865 # This function invokes EOT tool to calculate the predicted dispatch order\r
866 #\r
867 # @param self: The object pointer\r
868 #\r
869 def _InvokeEotTool(self):\r
870 if self._EotToolInvoked:\r
871 return\r
872\r
873 self._EotToolInvoked = True\r
874 FvFileList = []\r
875 for FvName in self._FvList:\r
876 FvFile = os.path.join(self._FvDir, FvName + ".Fv")\r
877 if os.path.isfile(FvFile):\r
878 FvFileList.append(FvFile)\r
879\r
880 if len(FvFileList) == 0:\r
881 return\r
882 #\r
883 # Write source file list and GUID file list to an intermediate file\r
884 # as the input for EOT tool and dispatch List as the output file\r
885 # from EOT tool.\r
886 #\r
887 SourceList = os.path.join(self._EotDir, "SourceFile.txt")\r
888 GuidList = os.path.join(self._EotDir, "GuidList.txt")\r
889 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")\r
890\r
891 TempFile = open(SourceList, "w+")\r
892 for Item in self._SourceList:\r
893 FileWrite(TempFile, Item)\r
894 TempFile.close()\r
895 TempFile = open(GuidList, "w+")\r
896 for Key in self._GuidMap:\r
897 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))\r
898 TempFile.close()\r
899\r
900 try:\r
901 from Eot.Eot import Eot\r
40d841f6 902\r
52302d4d 903 #\r
40d841f6 904 # Invoke EOT tool and echo its runtime performance\r
52302d4d 905 #\r
40d841f6 906 EotStartTime = time.time()\r
52302d4d
LG
907 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,\r
908 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)\r
40d841f6
LG
909 EotEndTime = time.time()\r
910 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))\r
911 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)\r
912 \r
52302d4d
LG
913 #\r
914 # Parse the output of EOT tool\r
915 #\r
916 for Line in open(DispatchList):\r
917 if len(Line.split()) < 4:\r
918 continue\r
919 (Guid, Phase, FfsName, FilePath) = Line.split()\r
920 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]\r
921 if len(Symbol) > self.MaxLen:\r
922 self.MaxLen = len(Symbol)\r
923 self.ItemList.append((Phase, Symbol, FilePath))\r
924 except:\r
925 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
926 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")\r
927\r
928\r
929 ##\r
930 # Generate platform execution order report\r
931 #\r
932 # This function generates the predicted module execution order.\r
933 #\r
934 # @param self The object pointer\r
935 # @param File The file object for report\r
936 #\r
937 def _GenerateExecutionOrderReport(self, File):\r
938 self._InvokeEotTool()\r
939 if len(self.ItemList) == 0:\r
940 return\r
941 FileWrite(File, gSectionStart)\r
942 FileWrite(File, "Execution Order Prediction")\r
943 FileWrite(File, "*P PEI phase")\r
944 FileWrite(File, "*D DXE phase")\r
945 FileWrite(File, "*E Module INF entry point name")\r
946 FileWrite(File, "*N Module notification function name")\r
947\r
948 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))\r
949 FileWrite(File, gSectionSep)\r
950 for Item in self.ItemList:\r
951 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))\r
952\r
953 FileWrite(File, gSectionStart)\r
954\r
955 ##\r
956 # Generate Fixed Address report.\r
957 #\r
958 # This function generate the predicted fixed address report for a module\r
959 # specified by Guid.\r
960 #\r
961 # @param self The object pointer\r
962 # @param File The file object for report\r
963 # @param Guid The module Guid value.\r
964 # @param NotifyList The list of all notify function in a module\r
965 #\r
966 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):\r
967 self._ParseMapFile()\r
968 FixedAddressList = self.FixedMapDict.get(Guid)\r
969 if not FixedAddressList:\r
970 return\r
971\r
972 FileWrite(File, gSubSectionStart)\r
973 FileWrite(File, "Fixed Address Prediction")\r
974 FileWrite(File, "*I Image Loading Address")\r
975 FileWrite(File, "*E Entry Point Address")\r
976 FileWrite(File, "*N Notification Function Address")\r
977 FileWrite(File, "*F Flash Address")\r
978 FileWrite(File, "*M Memory Address")\r
979 FileWrite(File, "*S SMM RAM Offset")\r
980 FileWrite(File, "TOM Top of Memory")\r
981\r
982 FileWrite(File, "Type Address Name")\r
983 FileWrite(File, gSubSectionSep)\r
984 for Item in FixedAddressList:\r
985 Type = Item[0]\r
986 Value = Item[1]\r
987 Symbol = Item[2]\r
988 if Symbol == "*I":\r
989 Name = "(Image Base)"\r
990 elif Symbol == "*E":\r
991 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]\r
992 elif Symbol in NotifyList:\r
993 Name = Symbol\r
994 Symbol = "*N"\r
995 else:\r
996 continue\r
997\r
998 if "Flash" in Type:\r
999 Symbol += "F"\r
1000 elif "Memory" in Type:\r
1001 Symbol += "M"\r
1002 else:\r
1003 Symbol += "S"\r
1004\r
1005 if Value[0] == "-":\r
1006 Value = "TOM" + Value\r
1007\r
1008 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))\r
1009\r
1010 ##\r
1011 # Generate report for the prediction part\r
1012 #\r
1013 # This function generate the predicted fixed address report for a module or\r
1014 # predicted module execution order for a platform.\r
1015 # If the input Guid is None, then, it generates the predicted module execution order;\r
1016 # otherwise it generated the module fixed loading address for the module specified by\r
1017 # Guid.\r
1018 #\r
1019 # @param self The object pointer\r
1020 # @param File The file object for report\r
1021 # @param Guid The module Guid value.\r
1022 #\r
1023 def GenerateReport(self, File, Guid):\r
1024 if Guid:\r
1025 self._GenerateFixedAddressReport(File, Guid.upper(), [])\r
1026 else:\r
1027 self._GenerateExecutionOrderReport(File)\r
1028\r
1029##\r
1030# Reports FD region information\r
1031#\r
1032# This class reports the FD subsection in the build report file.\r
1033# It collects region information of platform flash device.\r
1034# If the region is a firmware volume, it lists the set of modules\r
1035# and its space information; otherwise, it only lists its region name,\r
1036# base address and size in its sub-section header.\r
1037# If there are nesting FVs, the nested FVs will list immediate after\r
1038# this FD region subsection\r
1039#\r
1040class FdRegionReport(object):\r
1041 ##\r
1042 # Discover all the nested FV name list.\r
1043 #\r
1044 # This is an internal worker function to discover the all the nested FV information\r
1045 # in the parent firmware volume. It uses deep first search algorithm recursively to\r
1046 # find all the FV list name and append them to the list.\r
1047 #\r
1048 # @param self The object pointer\r
1049 # @param FvName The name of current firmware file system\r
1050 # @param Wa Workspace context information\r
1051 #\r
1052 def _DiscoverNestedFvList(self, FvName, Wa):\r
1053 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1054 for Section in Ffs.SectionList:\r
1055 try:\r
1056 for FvSection in Section.SectionList:\r
1057 if FvSection.FvName in self.FvList:\r
1058 continue\r
1059 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName\r
1060 self.FvList.append(FvSection.FvName)\r
1061 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)\r
1062 self._DiscoverNestedFvList(FvSection.FvName, Wa)\r
1063 except AttributeError:\r
1064 pass\r
1065\r
1066 ##\r
1067 # Constructor function for class FdRegionReport\r
1068 #\r
1069 # This constructor function generates FdRegionReport object for a specified FdRegion.\r
1070 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware\r
1071 # volume list. This function also collects GUID map in order to dump module identification\r
1072 # in the final report.\r
1073 #\r
1074 # @param self: The object pointer\r
1075 # @param FdRegion The current FdRegion object\r
1076 # @param Wa Workspace context information\r
1077 #\r
1078 def __init__(self, FdRegion, Wa):\r
1079 self.Type = FdRegion.RegionType\r
1080 self.BaseAddress = FdRegion.Offset\r
1081 self.Size = FdRegion.Size\r
1082 self.FvList = []\r
1083 self.FvInfo = {}\r
1084 self._GuidsDb = {}\r
1085 self._FvDir = Wa.FvDir\r
1086\r
1087 #\r
1088 # If the input FdRegion is not a firmware volume,\r
1089 # we are done.\r
1090 #\r
1091 if self.Type != "FV":\r
1092 return\r
1093\r
1094 #\r
1095 # Find all nested FVs in the FdRegion\r
1096 #\r
1097 for FvName in FdRegion.RegionDataList:\r
1098 if FvName in self.FvList:\r
1099 continue\r
1100 self.FvList.append(FvName)\r
1101 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)\r
1102 self._DiscoverNestedFvList(FvName, Wa)\r
1103\r
1104 PlatformPcds = {}\r
1105 \r
1106 #\r
1107 # Collect PCDs declared in DEC files.\r
1108 #\r
1109 for Package in Wa.BuildDatabase.WorkspaceDb.PackageList:\r
1110 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
1111 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
1112 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
1113 #\r
1114 # Collect PCDs defined in DSC common section\r
1115 #\r
1116 for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:\r
1117 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
1118 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
1119 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
1120\r
1121 #\r
1122 # Add PEI and DXE a priori files GUIDs defined in PI specification.\r
1123 #\r
1124 self._GuidsDb["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"\r
1125 self._GuidsDb["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"\r
1126 #\r
1127 # Add ACPI table storage file\r
1128 #\r
1129 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"\r
1130\r
1131 for Pa in Wa.AutoGenObjectList:\r
1132 for ModuleKey in Pa.Platform.Modules:\r
1133 M = Pa.Platform.Modules[ModuleKey].M\r
1134 InfPath = os.path.join(Wa.WorkspaceDir, M.MetaFile.File)\r
1135 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
1136\r
1137 #\r
1138 # Collect the GUID map in the FV firmware volume\r
1139 #\r
1140 for FvName in self.FvList:\r
1141 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1142 try:\r
1143 #\r
1144 # collect GUID map for binary EFI file in FDF file.\r
1145 #\r
1146 Guid = Ffs.NameGuid.upper()\r
1147 Match = gPcdGuidPattern.match(Ffs.NameGuid)\r
1148 if Match:\r
1149 PcdTokenspace = Match.group(1)\r
1150 PcdToken = Match.group(2)\r
1151 if (PcdToken, PcdTokenspace) in PlatformPcds:\r
1152 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]\r
1153 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
1154 for Section in Ffs.SectionList:\r
1155 try:\r
1156 ModuleSectFile = os.path.join(Wa.WorkspaceDir, Section.SectFileName)\r
1157 self._GuidsDb[Guid] = ModuleSectFile\r
1158 except AttributeError:\r
1159 pass\r
1160 except AttributeError:\r
1161 pass\r
1162\r
1163\r
1164 ##\r
1165 # Internal worker function to generate report for the FD region\r
1166 #\r
1167 # This internal worker function to generate report for the FD region.\r
1168 # It the type is firmware volume, it lists offset and module identification.\r
1169 #\r
1170 # @param self The object pointer\r
1171 # @param File The file object for report\r
1172 # @param Title The title for the FD subsection\r
1173 # @param BaseAddress The base address for the FD region\r
1174 # @param Size The size of the FD region\r
1175 # @param FvName The FV name if the FD region is a firmware volume\r
1176 #\r
1177 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):\r
1178 FileWrite(File, gSubSectionStart)\r
1179 FileWrite(File, Title)\r
1180 FileWrite(File, "Type: %s" % Type)\r
1181 FileWrite(File, "Base Address: 0x%X" % BaseAddress)\r
1182\r
1183 if self.Type == "FV":\r
1184 FvTotalSize = 0\r
1185 FvTakenSize = 0\r
1186 FvFreeSize = 0\r
1187 FvReportFileName = os.path.join(self._FvDir, FvName + ".fv.txt")\r
1188 try:\r
1189 #\r
1190 # Collect size info in the firmware volume.\r
1191 #\r
1192 FvReport = open(FvReportFileName).read()\r
1193 Match = gFvTotalSizePattern.search(FvReport)\r
1194 if Match:\r
1195 FvTotalSize = int(Match.group(1), 16)\r
1196 Match = gFvTakenSizePattern.search(FvReport)\r
1197 if Match:\r
1198 FvTakenSize = int(Match.group(1), 16)\r
1199 FvFreeSize = FvTotalSize - FvTakenSize\r
1200 #\r
1201 # Write size information to the report file.\r
1202 #\r
1203 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))\r
1204 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))\r
1205 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))\r
1206 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))\r
1207 FileWrite(File, "Offset Module")\r
1208 FileWrite(File, gSubSectionSep)\r
1209 #\r
1210 # Write module offset and module identification to the report file.\r
1211 #\r
1212 OffsetInfo = {}\r
1213 for Match in gOffsetGuidPattern.finditer(FvReport):\r
1214 Guid = Match.group(2).upper()\r
1215 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)\r
1216 OffsetList = OffsetInfo.keys()\r
1217 OffsetList.sort()\r
1218 for Offset in OffsetList:\r
1219 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))\r
1220 except IOError:\r
1221 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)\r
1222 else:\r
1223 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))\r
1224 FileWrite(File, gSubSectionEnd)\r
1225\r
1226 ##\r
1227 # Generate report for the FD region\r
1228 #\r
1229 # This function generates report for the FD region.\r
1230 #\r
1231 # @param self The object pointer\r
1232 # @param File The file object for report\r
1233 #\r
1234 def GenerateReport(self, File):\r
1235 if (len(self.FvList) > 0):\r
1236 for FvItem in self.FvList:\r
1237 Info = self.FvInfo[FvItem]\r
1238 self._GenerateReport(File, Info[0], "FV", Info[1], Info[2], FvItem)\r
1239 else:\r
1240 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)\r
1241\r
1242##\r
1243# Reports FD information\r
1244#\r
1245# This class reports the FD section in the build report file.\r
1246# It collects flash device information for a platform.\r
1247#\r
1248class FdReport(object):\r
1249 ##\r
1250 # Constructor function for class FdReport\r
1251 #\r
1252 # This constructor function generates FdReport object for a specified\r
1253 # firmware device.\r
1254 #\r
1255 # @param self The object pointer\r
1256 # @param Fd The current Firmware device object\r
1257 # @param Wa Workspace context information\r
1258 #\r
1259 def __init__(self, Fd, Wa):\r
1260 self.FdName = Fd.FdUiName\r
1261 self.BaseAddress = Fd.BaseAddress\r
1262 self.Size = Fd.Size\r
1263 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]\r
1264\r
1265 ##\r
1266 # Generate report for the firmware device.\r
1267 #\r
1268 # This function generates report for the firmware device.\r
1269 #\r
1270 # @param self The object pointer\r
1271 # @param File The file object for report\r
1272 #\r
1273 def GenerateReport(self, File):\r
1274 FileWrite(File, gSectionStart)\r
1275 FileWrite(File, "Firmware Device (FD)")\r
1276 FileWrite(File, "FD Name: %s" % self.FdName)\r
1277 FileWrite(File, "Base Address: %s" % self.BaseAddress)\r
1278 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))\r
1279 if len(self.FdRegionList) > 0:\r
1280 FileWrite(File, gSectionSep)\r
1281 for FdRegionItem in self.FdRegionList:\r
1282 FdRegionItem.GenerateReport(File)\r
1283\r
1284 FileWrite(File, gSectionEnd)\r
1285\r
1286\r
1287\r
1288##\r
1289# Reports platform information\r
1290#\r
1291# This class reports the whole platform information\r
1292#\r
1293class PlatformReport(object):\r
1294 ##\r
1295 # Constructor function for class PlatformReport\r
1296 #\r
1297 # This constructor function generates PlatformReport object a platform build.\r
1298 # It generates report for platform summary, flash, global PCDs and detailed\r
1299 # module information for modules involved in platform build.\r
1300 #\r
1301 # @param self The object pointer\r
1302 # @param Wa Workspace context information\r
d5d56f1b 1303 # @param MaList The list of modules in the platform build\r
52302d4d 1304 #\r
d5d56f1b 1305 def __init__(self, Wa, MaList, ReportType):\r
52302d4d
LG
1306 self._WorkspaceDir = Wa.WorkspaceDir\r
1307 self.PlatformName = Wa.Name\r
1308 self.PlatformDscPath = Wa.Platform\r
1309 self.Architectures = " ".join(Wa.ArchList)\r
1310 self.ToolChain = Wa.ToolChain\r
1311 self.Target = Wa.BuildTarget\r
1312 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)\r
1313 self.BuildEnvironment = platform.platform()\r
1314\r
1315 self.PcdReport = None\r
1316 if "PCD" in ReportType:\r
1317 self.PcdReport = PcdReport(Wa)\r
1318\r
1319 self.FdReportList = []\r
d5d56f1b 1320 if "FLASH" in ReportType and Wa.FdfProfile and MaList == None:\r
52302d4d
LG
1321 for Fd in Wa.FdfProfile.FdDict:\r
1322 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))\r
1323\r
1324 self.PredictionReport = None\r
1325 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:\r
1326 self.PredictionReport = PredictionReport(Wa)\r
1327\r
1328 self.ModuleReportList = []\r
d5d56f1b 1329 if MaList != None:\r
636f2be6 1330 self._IsModuleBuild = True\r
d5d56f1b
LG
1331 for Ma in MaList:\r
1332 self.ModuleReportList.append(ModuleReport(Ma, ReportType))\r
1333 else:\r
636f2be6 1334 self._IsModuleBuild = False\r
d5d56f1b
LG
1335 for Pa in Wa.AutoGenObjectList:\r
1336 for ModuleKey in Pa.Platform.Modules:\r
1337 self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, ReportType))\r
52302d4d
LG
1338\r
1339\r
1340\r
1341 ##\r
1342 # Generate report for the whole platform.\r
1343 #\r
1344 # This function generates report for platform information.\r
1345 # It comprises of platform summary, global PCD, flash and\r
1346 # module list sections.\r
1347 #\r
1348 # @param self The object pointer\r
1349 # @param File The file object for report\r
1350 # @param BuildDuration The total time to build the modules\r
1351 # @param ReportType The kind of report items in the final report file\r
1352 #\r
1353 def GenerateReport(self, File, BuildDuration, ReportType):\r
1354 FileWrite(File, "Platform Summary")\r
1355 FileWrite(File, "Platform Name: %s" % self.PlatformName)\r
1356 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)\r
1357 FileWrite(File, "Architectures: %s" % self.Architectures)\r
1358 FileWrite(File, "Tool Chain: %s" % self.ToolChain)\r
1359 FileWrite(File, "Target: %s" % self.Target)\r
1360 FileWrite(File, "Output Path: %s" % self.OutputPath)\r
1361 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)\r
1362 FileWrite(File, "Build Duration: %s" % BuildDuration)\r
1363 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))\r
1364\r
636f2be6
LG
1365 if not self._IsModuleBuild:\r
1366 if "PCD" in ReportType:\r
1367 self.PcdReport.GenerateReport(File, None)\r
1368 \r
1369 if "FLASH" in ReportType:\r
1370 for FdReportListItem in self.FdReportList:\r
1371 FdReportListItem.GenerateReport(File)\r
52302d4d
LG
1372\r
1373 for ModuleReportItem in self.ModuleReportList:\r
1374 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, ReportType)\r
1375\r
636f2be6
LG
1376 if not self._IsModuleBuild:\r
1377 if "EXECUTION_ORDER" in ReportType:\r
1378 self.PredictionReport.GenerateReport(File, None)\r
52302d4d
LG
1379\r
1380## BuildReport class\r
1381#\r
1382# This base class contain the routines to collect data and then\r
1383# applies certain format to the output report\r
1384#\r
1385class BuildReport(object):\r
1386 ##\r
1387 # Constructor function for class BuildReport\r
1388 #\r
1389 # This constructor function generates BuildReport object a platform build.\r
1390 # It generates report for platform summary, flash, global PCDs and detailed\r
1391 # module information for modules involved in platform build.\r
1392 #\r
1393 # @param self The object pointer\r
1394 # @param ReportFile The file name to save report file\r
1395 # @param ReportType The kind of report items in the final report file\r
1396 #\r
1397 def __init__(self, ReportFile, ReportType):\r
1398 self.ReportFile = ReportFile\r
1399 if ReportFile:\r
1400 self.ReportList = []\r
1401 self.ReportType = []\r
1402 if ReportType: \r
1403 for ReportTypeItem in ReportType:\r
1404 if ReportTypeItem not in self.ReportType:\r
1405 self.ReportType.append(ReportTypeItem)\r
1406 else:\r
1407 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]\r
1408 ##\r
1409 # Adds platform report to the list\r
1410 #\r
1411 # This function adds a platform report to the final report list.\r
1412 #\r
1413 # @param self The object pointer\r
1414 # @param Wa Workspace context information\r
d5d56f1b 1415 # @param MaList The list of modules in the platform build\r
52302d4d 1416 #\r
d5d56f1b 1417 def AddPlatformReport(self, Wa, MaList=None):\r
52302d4d 1418 if self.ReportFile:\r
d5d56f1b 1419 self.ReportList.append((Wa, MaList))\r
52302d4d
LG
1420\r
1421 ##\r
1422 # Generates the final report.\r
1423 #\r
1424 # This function generates platform build report. It invokes GenerateReport()\r
1425 # method for every platform report in the list.\r
1426 #\r
1427 # @param self The object pointer\r
1428 # @param BuildDuration The total time to build the modules\r
1429 #\r
1430 def GenerateReport(self, BuildDuration):\r
1431 if self.ReportFile:\r
1432 try:\r
40d841f6 1433 File = StringIO('')\r
d5d56f1b
LG
1434 for (Wa, MaList) in self.ReportList:\r
1435 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, self.ReportType)\r
40d841f6
LG
1436 SaveFileOnChange(self.ReportFile, File.getvalue(), False)\r
1437 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))\r
52302d4d
LG
1438 except IOError:\r
1439 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)\r
1440 except:\r
1441 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)\r
1442 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
1443 File.close()\r
636f2be6 1444 \r
52302d4d
LG
1445# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
1446if __name__ == '__main__':\r
1447 pass\r
1448\r