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