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