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