X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=BaseTools%2FSource%2FPython%2Fbuild%2FBuildReport.py;h=75e8ec97ab8a74e224aebc4008627099c8c5384b;hp=f805aae5ca1b637cb7af007e70c298cb82bbe504;hb=65eff519e5ef56ddf51b11ed3524f55854e49dde;hpb=636f2be673b2f43518167d8fddae56b714f19314 diff --git a/BaseTools/Source/Python/build/BuildReport.py b/BaseTools/Source/Python/build/BuildReport.py index f805aae5ca..75e8ec97ab 100644 --- a/BaseTools/Source/Python/build/BuildReport.py +++ b/BaseTools/Source/Python/build/BuildReport.py @@ -4,8 +4,8 @@ # This module contains the functionality to generate build report after # build all target completes successfully. # -# Copyright (c) 2010, Intel Corporation -# All rights reserved. This program and the accompanying materials +# Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php @@ -16,21 +16,35 @@ ## Import Modules # -import os +import Common.LongFilePathOs as os import re import platform import textwrap import traceback import sys +import time +import struct +import hashlib +import subprocess +import threading from datetime import datetime +from StringIO import StringIO from Common import EdkLogger +from Common.Misc import SaveFileOnChange from Common.Misc import GuidStructureByteArrayToGuidString from Common.Misc import GuidStructureStringToGuidString from Common.InfClassObject import gComponentType2ModuleType -from Common.BuildToolError import FILE_OPEN_FAILURE from Common.BuildToolError import FILE_WRITE_FAILURE from Common.BuildToolError import CODE_ERROR - +from Common.BuildToolError import COMMAND_FAILURE +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws +import Common.GlobalData as GlobalData +from AutoGen.AutoGen import ModuleAutoGen +from Common.Misc import PathClass +from Common.String import NormPath +from Common.DataType import * +import collections ## Pattern to extract contents in EDK DXS files gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL) @@ -60,15 +74,22 @@ gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]") ## Pattern to find the entry point for EDK module using EDKII Glue library gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)") +## Tags for MaxLength of line in report +gLineMaxLength = 120 + +## Tags for end of line in report +gEndOfLine = "\r\n" + ## Tags for section start, end and separator -gSectionStart = ">" + "=" * 118 + "<" -gSectionEnd = "<" + "=" * 118 + ">" + "\n" -gSectionSep = "=" * 120 +gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<" +gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n" +gSectionSep = "=" * gLineMaxLength ## Tags for subsection start, end and separator -gSubSectionStart = ">" + "-" * 118 + "<" -gSubSectionEnd = "<" + "-" * 118 + ">" -gSubSectionSep = "-" * 120 +gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<" +gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">" +gSubSectionSep = "-" * gLineMaxLength + ## The look up table to map PCD type to pair of report display type and DEC type gPcdTypeMap = { @@ -78,9 +99,9 @@ gPcdTypeMap = { 'Dynamic' : ('DYN', 'Dynamic'), 'DynamicHii' : ('DYNHII', 'Dynamic'), 'DynamicVpd' : ('DYNVPD', 'Dynamic'), - 'DynamicEx' : ('DEX', 'Dynamic'), - 'DynamicExHii' : ('DEXHII', 'Dynamic'), - 'DynamicExVpd' : ('DEXVPD', 'Dynamic'), + 'DynamicEx' : ('DEX', 'DynamicEx'), + 'DynamicExHii' : ('DEXHII', 'DynamicEx'), + 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'), } ## The look up table to map module type to driver type @@ -97,8 +118,13 @@ gDriverTypeMap = { 'UEFI_APPLICATION' : '0x9 (APPLICATION)', 'SMM_CORE' : '0xD (SMM_CORE)', 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers + 'MM_STANDALONE' : '0xE (MM_STANDALONE)', + 'MM_CORE_STANDALONE' : '0xF (MM_CORE_STANDALONE)' } +## The look up table of the supported opcode in the dependency expression binaries +gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"] + ## # Writes a string to the file object. # @@ -112,7 +138,38 @@ gDriverTypeMap = { def FileWrite(File, String, Wrapper=False): if Wrapper: String = textwrap.fill(String, 120) - File.write(String + "\r\n") + File.write(String + gEndOfLine) + +def ByteArrayForamt(Value): + IsByteArray = False + SplitNum = 16 + ArrayList = [] + if Value.startswith('{') and Value.endswith('}'): + Value = Value[1:-1] + ValueList = Value.split(',') + if len(ValueList) >= SplitNum: + IsByteArray = True + if IsByteArray: + if ValueList: + Len = len(ValueList)/SplitNum + for i, element in enumerate(ValueList): + ValueList[i] = '0x%02X' % int(element.strip(), 16) + if Len: + Id = 0 + while (Id <= Len): + End = min(SplitNum*(Id+1), len(ValueList)) + Str = ','.join(ValueList[SplitNum*Id : End]) + if End == len(ValueList): + Str += '}' + ArrayList.append(Str) + break + else: + Str += ',' + ArrayList.append(Str) + Id += 1 + else: + ArrayList = [Value + '}'] + return IsByteArray, ArrayList ## # Find all the header file that the module source directly includes. @@ -160,6 +217,94 @@ def FindIncludeFiles(Source, IncludePathList, IncludeFiles): IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName break +## Split each lines in file +# +# This method is used to split the lines in file to make the length of each line +# less than MaxLength. +# +# @param Content The content of file +# @param MaxLength The Max Length of the line +# +def FileLinesSplit(Content=None, MaxLength=None): + ContentList = Content.split(TAB_LINE_BREAK) + NewContent = '' + NewContentList = [] + for Line in ContentList: + while len(Line.rstrip()) > MaxLength: + LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength) + LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength) + LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength) + if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0: + LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) + else: + LineBreakIndex = MaxLength + NewContentList.append(Line[:LineBreakIndex]) + Line = Line[LineBreakIndex:] + if Line: + NewContentList.append(Line) + for NewLine in NewContentList: + NewContent += NewLine + TAB_LINE_BREAK + + NewContent = NewContent.replace(TAB_LINE_BREAK, gEndOfLine).replace('\r\r\n', gEndOfLine) + return NewContent + + + +## +# Parse binary dependency expression section +# +# This utility class parses the dependency expression section and translate the readable +# GUID name and value. +# +class DepexParser(object): + ## + # Constructor function for class DepexParser + # + # This constructor function collect GUID values so that the readable + # GUID name can be translated. + # + # @param self The object pointer + # @param Wa Workspace context information + # + def __init__(self, Wa): + self._GuidDb = {} + for Pa in Wa.AutoGenObjectList: + for Package in Pa.PackageList: + for Protocol in Package.Protocols: + GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol]) + self._GuidDb[GuidValue.upper()] = Protocol + for Ppi in Package.Ppis: + GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi]) + self._GuidDb[GuidValue.upper()] = Ppi + for Guid in Package.Guids: + GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid]) + self._GuidDb[GuidValue.upper()] = Guid + + ## + # Parse the binary dependency expression files. + # + # This function parses the binary dependency expression file and translate it + # to the instruction list. + # + # @param self The object pointer + # @param DepexFileName The file name of binary dependency expression file. + # + def ParseDepexFile(self, DepexFileName): + DepexFile = open(DepexFileName, "rb") + DepexStatement = [] + OpCode = DepexFile.read(1) + while OpCode: + Statement = gOpCodeList[struct.unpack("B", OpCode)[0]] + if Statement in ["BEFORE", "AFTER", "PUSH"]: + GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \ + struct.unpack("=LHHBBBBBBBB", DepexFile.read(16)) + GuidString = self._GuidDb.get(GuidValue, GuidValue) + Statement = "%s %s" % (Statement, GuidString) + DepexStatement.append(Statement) + OpCode = DepexFile.read(1) + + return DepexStatement + ## # Reports library information # @@ -188,7 +333,11 @@ class LibraryReport(object): LibConstructorList = Lib.ConstructorList LibDesstructorList = Lib.DestructorList LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType] - self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList)) + for LibAutoGen in M.LibraryAutoGenList: + if LibInfPath == LibAutoGen.MetaFile.Path: + LibTime = LibAutoGen.BuildTime + break + self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime)) ## # Generate report for module library information @@ -201,9 +350,9 @@ class LibraryReport(object): # @param File The file object for report # def GenerateReport(self, File): - FileWrite(File, gSubSectionStart) - FileWrite(File, "Library") if len(self.LibraryList) > 0: + FileWrite(File, gSubSectionStart) + FileWrite(File, TAB_BRG_LIBRARY) FileWrite(File, gSubSectionSep) for LibraryItem in self.LibraryList: LibInfPath = LibraryItem[0] @@ -225,12 +374,14 @@ class LibraryReport(object): LibDepex = " ".join(LibraryItem[4]) if LibDepex: EdkIILibInfo += " Depex = " + LibDepex + if LibraryItem[5]: + EdkIILibInfo += " Time = " + LibraryItem[5] if EdkIILibInfo: FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo)) else: FileWrite(File, "{%s}" % LibClass) - FileWrite(File, gSubSectionEnd) + FileWrite(File, gSubSectionEnd) ## # Reports dependency expression information @@ -252,11 +403,12 @@ class DepexReport(object): # def __init__(self, M): self.Depex = "" + self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex") ModuleType = M.ModuleType if not ModuleType: ModuleType = gComponentType2ModuleType.get(M.ComponentType, "") - if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]: + if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "MM_CORE_STANDALONE", "UEFI_APPLICATION"]: return for Source in M.SourceFileList: @@ -287,14 +439,24 @@ class DepexReport(object): # # This function generates report for the module dependency expression. # - # @param self The object pointer - # @param File The file object for report + # @param self The object pointer + # @param File The file object for report + # @param GlobalDepexParser The platform global Dependency expression parser object # - def GenerateReport(self, File): + def GenerateReport(self, File, GlobalDepexParser): if not self.Depex: return - FileWrite(File, gSubSectionStart) + if os.path.isfile(self._DepexFileName): + try: + DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName) + FileWrite(File, "Final Dependency Expression (DEPEX) Instructions") + for DepexStatement in DepexStatements: + FileWrite(File, " %s" % DepexStatement) + FileWrite(File, gSubSectionSep) + except: + EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName) + FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source) if self.Source == "INF": @@ -404,6 +566,7 @@ class ModuleReport(object): self.FileGuid = M.Guid self.Size = 0 self.BuildTimeStamp = None + self.Hash = 0 self.DriverType = "" if not M.IsLibrary: ModuleType = M.ModuleType @@ -413,7 +576,7 @@ class ModuleReport(object): # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER" # if ModuleType == "DXE_SMM_DRIVER": - PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000") + PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000") if int(PiSpec, 0) >= 0x0001000A: ModuleType = "SMM_DRIVER" self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)") @@ -422,6 +585,7 @@ class ModuleReport(object): self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "") self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "") self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "") + self.BuildTime = M.BuildTime self._BuildDir = M.BuildDir self.ModulePcdSet = {} @@ -451,12 +615,14 @@ class ModuleReport(object): # This function generates report for separate module expression # in a platform build. # - # @param self The object pointer - # @param File The file object for report - # @param GlobalPcdReport The platform global PCD class object - # @param ReportType The kind of report items in the final report file + # @param self The object pointer + # @param File The file object for report + # @param GlobalPcdReport The platform global PCD report object + # @param GlobalPredictionReport The platform global Prediction report object + # @param GlobalDepexParser The platform global Dependency expression parser object + # @param ReportType The kind of report items in the final report file # - def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, ReportType): + def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType): FileWrite(File, gSectionStart) FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt") @@ -473,14 +639,50 @@ class ModuleReport(object): except IOError: EdkLogger.warn(None, "Fail to read report file", FwReportFileName) + if "HASH" in ReportType: + OutputDir = os.path.join(self._BuildDir, "OUTPUT") + DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi") + if os.path.isfile(DefaultEFIfile): + Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp") + # rebase the efi image since its base address may not zero + cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile] + try: + PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + except Exception, X: + EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0])) + EndOfProcedure = threading.Event() + EndOfProcedure.clear() + if PopenObject.stderr: + StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure)) + StdErrThread.setName("STDERR-Redirector") + StdErrThread.setDaemon(False) + StdErrThread.start() + # waiting for program exit + PopenObject.wait() + if PopenObject.stderr: + StdErrThread.join() + if PopenObject.returncode != 0: + EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile)) + if os.path.isfile(Tempfile): + self.Hash = hashlib.sha1() + buf = open(Tempfile, 'rb').read() + if self.Hash.update(buf): + self.Hash = self.Hash.update(buf) + self.Hash = self.Hash.hexdigest() + os.remove(Tempfile) + FileWrite(File, "Module Summary") FileWrite(File, "Module Name: %s" % self.ModuleName) FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath) FileWrite(File, "File GUID: %s" % self.FileGuid) if self.Size: FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0)) + if self.Hash: + FileWrite(File, "SHA1 HASH: %s *%s" % (self.Hash, self.ModuleName + ".efi")) if self.BuildTimeStamp: FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp) + if self.BuildTime: + FileWrite(File, "Module Build Time: %s" % self.BuildTime) if self.DriverType: FileWrite(File, "Driver Type: %s" % self.DriverType) if self.UefiSpecVersion: @@ -503,7 +705,7 @@ class ModuleReport(object): self.LibraryReport.GenerateReport(File) if "DEPEX" in ReportType: - self.DepexReport.GenerateReport(File) + self.DepexReport.GenerateReport(File, GlobalDepexParser) if "BUILD_FLAGS" in ReportType: self.BuildFlagsReport.GenerateReport(File) @@ -513,6 +715,18 @@ class ModuleReport(object): FileWrite(File, gSectionEnd) +def ReadMessage(From, To, ExitFlag): + while True: + # read one line a time + Line = From.readline() + # empty string means "end" + if Line != None and Line != "": + To(Line.rstrip()) + else: + break + if ExitFlag.isSet(): + break + ## # Reports platform and module PCD information # @@ -532,7 +746,10 @@ class PcdReport(object): # def __init__(self, Wa): self.AllPcds = {} + self.UnusedPcds = {} + self.ConditionalPcds = {} self.MaxLen = 0 + self.Arch = None if Wa.FdfProfile: self.FdfPcdSet = Wa.FdfProfile.PcdDict else: @@ -540,6 +757,7 @@ class PcdReport(object): self.ModulePcdOverride = {} for Pa in Wa.AutoGenObjectList: + self.Arch = Pa.Arch # # Collect all platform referenced PCDs and grouped them by PCD token space # GUID C Names @@ -550,6 +768,70 @@ class PcdReport(object): PcdList.append(Pcd) if len(Pcd.TokenCName) > self.MaxLen: self.MaxLen = len(Pcd.TokenCName) + # + # Collect the PCD defined in DSC/FDF file, but not used in module + # + UnusedPcdFullList = [] + for item in Pa.Platform.Pcds: + Pcd = Pa.Platform.Pcds[item] + if not Pcd.Type: + # check the Pcd in FDF file, whether it is used in module first + for T in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]: + PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, []) + if Pcd in PcdList: + Pcd.Type = T + break + if not Pcd.Type: + PcdTypeFlag = False + for package in Pa.PackageList: + for T in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]: + if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds: + Pcd.Type = T + PcdTypeFlag = True + if not Pcd.DatumType: + Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType + break + if PcdTypeFlag: + break + if not Pcd.DatumType: + PcdType = Pcd.Type + # Try to remove Hii and Vpd suffix + if PcdType.startswith("DynamicEx"): + PcdType = "DynamicEx" + elif PcdType.startswith("Dynamic"): + PcdType = "Dynamic" + for package in Pa.PackageList: + if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds: + Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType + break + + PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, []) + if Pcd not in PcdList and Pcd not in UnusedPcdFullList: + UnusedPcdFullList.append(Pcd) + if len(Pcd.TokenCName) > self.MaxLen: + self.MaxLen = len(Pcd.TokenCName) + + if GlobalData.gConditionalPcds: + for PcdItem in GlobalData.gConditionalPcds: + if '.' in PcdItem: + (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.') + if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds.keys(): + Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)] + PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, []) + if Pcd not in PcdList: + PcdList.append(Pcd) + + UnusedPcdList = [] + if UnusedPcdFullList: + for Pcd in UnusedPcdFullList: + if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds: + continue + UnusedPcdList.append(Pcd) + + for Pcd in UnusedPcdList: + PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, []) + if Pcd not in PcdList: + PcdList.append(Pcd) for Module in Pa.Platform.Modules.values(): # @@ -567,18 +849,27 @@ class PcdReport(object): # Collect PCD DEC default value. # self.DecPcdDefault = {} - for Package in Wa.BuildDatabase.WorkspaceDb.PackageList: - for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds: - DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue - self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue) + for Pa in Wa.AutoGenObjectList: + for Package in Pa.PackageList: + for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds: + DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue + self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue) # # Collect PCDs defined in DSC common section # self.DscPcdDefault = {} - for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList: - for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds: - DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue - self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue + for Pa in Wa.AutoGenObjectList: + for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds: + DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue + if DscDefaultValue: + self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue + + def GenerateReport(self, File, ModulePcdSet): + if self.ConditionalPcds: + self.GenerateReportDetail(File, ModulePcdSet, 1) + if self.UnusedPcds: + self.GenerateReportDetail(File, ModulePcdSet, 2) + self.GenerateReportDetail(File, ModulePcdSet) ## # Generate report for PCD information @@ -590,43 +881,67 @@ class PcdReport(object): # @param File The file object for report # @param ModulePcdSet Set of all PCDs referenced by module or None for # platform PCD report + # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional + # directives section report, 2 means Unused Pcds section report # @param DscOverridePcds Module DSC override PCDs set # - def GenerateReport(self, File, ModulePcdSet): + def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0): + PcdDict = self.AllPcds + if ReportSubType == 1: + PcdDict = self.ConditionalPcds + elif ReportSubType == 2: + PcdDict = self.UnusedPcds + if ModulePcdSet == None: - # - # For platform global PCD section - # FileWrite(File, gSectionStart) - FileWrite(File, "Platform Configuration Database Report") + if ReportSubType == 1: + FileWrite(File, "Conditional Directives used by the build system") + elif ReportSubType == 2: + FileWrite(File, "PCDs not used by modules or in conditional directives") + else: + FileWrite(File, "Platform Configuration Database Report") + + FileWrite(File, " *B - PCD override in the build option") FileWrite(File, " *P - Platform scoped PCD override in DSC file") FileWrite(File, " *F - Platform scoped PCD override in FDF file") - FileWrite(File, " *M - Module scoped PCD override in DSC file") + if not ReportSubType: + FileWrite(File, " *M - Module scoped PCD override") FileWrite(File, gSectionSep) else: - # - # For module PCD sub-section - # - FileWrite(File, gSubSectionStart) - FileWrite(File, "PCD") - FileWrite(File, gSubSectionSep) + if not ReportSubType and ModulePcdSet: + # + # For module PCD sub-section + # + FileWrite(File, gSubSectionStart) + FileWrite(File, TAB_BRG_PCD) + FileWrite(File, gSubSectionSep) - for Key in self.AllPcds: + for Key in PcdDict: # # Group PCD by their token space GUID C Name # First = True - for Type in self.AllPcds[Key]: + for Type in PcdDict[Key]: # # Group PCD by their usage type # TypeName, DecType = gPcdTypeMap.get(Type, ("", Type)) - for Pcd in self.AllPcds[Key][Type]: + for Pcd in PcdDict[Key][Type]: + PcdTokenCName = Pcd.TokenCName + MixedPcdFlag = False + if GlobalData.MixedPcd: + for PcdKey in GlobalData.MixedPcd: + if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]: + PcdTokenCName = PcdKey[0] + MixedPcdFlag = True + if MixedPcdFlag and not ModulePcdSet: + continue # # Get PCD default value and their override relationship # DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType)) DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName)) + DscDefaultValBak= DscDefaultValue DscDefaultValue = self.FdfPcdSet.get((Pcd.TokenCName, Key), DscDefaultValue) InfDefaultValue = None @@ -639,6 +954,15 @@ class PcdReport(object): InfDefault, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type] if InfDefault == "": InfDefault = None + + BuildOptionMatch = False + if GlobalData.BuildOptionPcd: + for pcd in GlobalData.BuildOptionPcd: + if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]): + PcdValue = pcd[2] + BuildOptionMatch = True + break + if First: if ModulePcdSet == None: FileWrite(File, "") @@ -681,55 +1005,240 @@ class PcdReport(object): else: DscMatch = (DscDefaultValue.strip() == PcdValue.strip()) + IsStructure = False + if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd.keys()) and ((Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.gStructurePcd[self.Arch]): + IsStructure = True + if TypeName in ('DYNVPD', 'DEXVPD'): + SkuInfoList = Pcd.SkuInfoList + Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)] + Pcd.DatumType = Pcd.StructName + if TypeName in ('DYNVPD', 'DEXVPD'): + Pcd.SkuInfoList = SkuInfoList + if Pcd.SkuOverrideValues: + DscMatch = True + DecMatch = False # # Report PCD item according to their override relationship # if DecMatch and InfMatch: - FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip())) + self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, ' ') + elif BuildOptionMatch: + self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B') else: if DscMatch: if (Pcd.TokenCName, Key) in self.FdfPcdSet: - FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip())) + self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F') else: - FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip())) + self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P') else: - FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip())) - - if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'): - for SkuInfo in Pcd.SkuInfoList.values(): - if TypeName in ('DYNHII', 'DEXHII'): - FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset)) - else: - FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset)) - - if not DscMatch and DscDefaultValue != None: - FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue.strip())) - - if not InfMatch and InfDefaultValue != None: - FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue.strip())) - - if not DecMatch and DecDefaultValue != None: - FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue.strip())) + self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M') if ModulePcdSet == None: - ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {}) - for ModulePath in ModuleOverride: - ModuleDefault = ModuleOverride[ModulePath] - if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'): - ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0) - Match = (ModulePcdDefaultValueNumber == PcdValueNumber) - else: - Match = (ModuleDefault.strip() == PcdValue.strip()) - if Match: - continue - FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip())) + if IsStructure: + continue + if not TypeName in ('PATCH', 'FLAG', 'FIXED'): + continue + if not BuildOptionMatch: + ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {}) + for ModulePath in ModuleOverride: + ModuleDefault = ModuleOverride[ModulePath] + if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'): + ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0) + Match = (ModulePcdDefaultValueNumber == PcdValueNumber) + else: + Match = (ModuleDefault.strip() == PcdValue.strip()) + if Match: + continue + IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip()) + if IsByteArray: + FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, '{')) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip())) if ModulePcdSet == None: FileWrite(File, gSectionEnd) else: - FileWrite(File, gSubSectionEnd) - + if not ReportSubType and ModulePcdSet: + FileWrite(File, gSubSectionEnd) + + + def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue): + if not DscMatch and DscDefaultValue != None: + Value = DscDefaultValue.strip() + IsByteArray, ArrayList = ByteArrayForamt(Value) + if IsByteArray: + FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{")) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value)) + if not InfMatch and InfDefaultValue != None: + Value = InfDefaultValue.strip() + IsByteArray, ArrayList = ByteArrayForamt(Value) + if IsByteArray: + FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{")) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value)) + + if not DecMatch and DecDefaultValue != None: + Value = DecDefaultValue.strip() + IsByteArray, ArrayList = ByteArrayForamt(Value) + if IsByteArray: + FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{")) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value)) + if IsStructure: + self.PrintStructureInfo(File, Pcd.DefaultValues) + + def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = ' '): + if not Pcd.SkuInfoList: + Value = Pcd.DefaultValue + IsByteArray, ArrayList = ByteArrayForamt(Value) + if IsByteArray: + FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{')) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value)) + if IsStructure: + OverrideValues = Pcd.SkuOverrideValues + if OverrideValues: + Keys = OverrideValues.keys() + Data = OverrideValues[Keys[0]] + Struct = Data.values()[0] + self.PrintStructureInfo(File, Struct) + self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue) + else: + FirstPrint = True + SkuList = sorted(Pcd.SkuInfoList.keys()) + for Sku in SkuList: + SkuInfo = Pcd.SkuInfoList[Sku] + if TypeName in ('DYNHII', 'DEXHII'): + if SkuInfo.DefaultStoreDict: + DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys()) + for DefaultStore in DefaultStoreList: + Value = SkuInfo.DefaultStoreDict[DefaultStore] + IsByteArray, ArrayList = ByteArrayForamt(Value) + if FirstPrint: + FirstPrint = False + if IsByteArray: + FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', '{')) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', Value)) + else: + if IsByteArray: + FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', '{')) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', Value)) + FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset)) + if IsStructure: + OverrideValues = Pcd.SkuOverrideValues[Sku] + Struct = OverrideValues[DefaultStore] + self.PrintStructureInfo(File, Struct) + self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue) + elif TypeName in ('DYNVPD', 'DEXVPD'): + Value = SkuInfo.DefaultValue + IsByteArray, ArrayList = ByteArrayForamt(Value) + if FirstPrint: + FirstPrint = False + if IsByteArray: + FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', "{")) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value)) + else: + if IsByteArray: + FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ' , TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', "{")) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ' , TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value)) + FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset)) + if IsStructure: + OverrideValues = Pcd.SkuOverrideValues[Sku] + if OverrideValues: + Keys = OverrideValues.keys() + Struct = OverrideValues[Keys[0]] + self.PrintStructureInfo(File, Struct) + self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue) + else: + Value = SkuInfo.DefaultValue + IsByteArray, ArrayList = ByteArrayForamt(Value) + if FirstPrint: + FirstPrint = False + if IsByteArray: + FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '{')) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value)) + else: + if IsByteArray: + FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '{')) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value)) + if IsStructure: + OverrideValues = Pcd.SkuOverrideValues[Sku] + if OverrideValues: + Keys = OverrideValues.keys() + Struct = OverrideValues[Keys[0]] + self.PrintStructureInfo(File, Struct) + self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue) + + def PrintStructureInfo(self, File, Struct): + NewInfo = collections.OrderedDict() + for Key, Value in Struct.items(): + if Key not in NewInfo: + NewInfo[Key] = Value[0] + else: + del NewInfo[Key] + NewInfo[Key] = Value[0] + if NewInfo: + for item in NewInfo: + FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + item, NewInfo[item])) + def StrtoHex(self, value): + try: + value = hex(int(value)) + return value + except: + if value.startswith("L\"") and value.endswith("\""): + valuelist = [] + for ch in value[2:-1]: + valuelist.append(hex(ord(ch))) + valuelist.append('0x00') + return valuelist + elif value.startswith("\"") and value.endswith("\""): + return hex(ord(value[1:-1])) + elif value.startswith("{") and value.endswith("}"): + valuelist = [] + if ',' not in value: + return value[1:-1] + for ch in value[1:-1].split(','): + ch = ch.strip() + if ch.startswith('0x') or ch.startswith('0X'): + valuelist.append(ch) + continue + try: + valuelist.append(hex(int(ch.strip()))) + except: + pass + return valuelist + else: + return value ## # Reports platform and module Prediction information @@ -765,6 +1274,13 @@ class PredictionReport(object): for Pa in Wa.AutoGenObjectList: for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList: # + # BASE typed modules are EFI agnostic, so we need not scan + # their source code to find PPI/Protocol produce or consume + # information. + # + if Module.ModuleType == "BASE": + continue + # # Add module referenced source files # self._SourceList.append(str(Module)) @@ -889,12 +1405,17 @@ class PredictionReport(object): try: from Eot.Eot import Eot + # - # Invoke EOT tool + # Invoke EOT tool and echo its runtime performance # + EotStartTime = time.time() Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList, FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True) - + EotEndTime = time.time() + EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime)))) + EdkLogger.quiet("EOT run time: %s\n" % EotDuration) + # # Parse the output of EOT tool # @@ -1035,18 +1556,20 @@ class FdRegionReport(object): # @param Wa Workspace context information # def _DiscoverNestedFvList(self, FvName, Wa): - for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList: - for Section in Ffs.SectionList: - try: - for FvSection in Section.SectionList: - if FvSection.FvName in self.FvList: - continue - self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName - self.FvList.append(FvSection.FvName) - self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0) - self._DiscoverNestedFvList(FvSection.FvName, Wa) - except AttributeError: - pass + FvDictKey=FvName.upper() + if FvDictKey in Wa.FdfProfile.FvDict: + for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList: + for Section in Ffs.SectionList: + try: + for FvSection in Section.SectionList: + if FvSection.FvName in self.FvList: + continue + self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName + self.FvList.append(FvSection.FvName) + self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0) + self._DiscoverNestedFvList(FvSection.FvName, Wa) + except AttributeError: + pass ## # Constructor function for class FdRegionReport @@ -1087,20 +1610,20 @@ class FdRegionReport(object): self._DiscoverNestedFvList(FvName, Wa) PlatformPcds = {} - # # Collect PCDs declared in DEC files. + # + for Pa in Wa.AutoGenObjectList: + for Package in Pa.PackageList: + for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds: + DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue + PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue # - for Package in Wa.BuildDatabase.WorkspaceDb.PackageList: - for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds: - DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue - PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue - # - # Collect PCDs defined in DSC common section + # Collect PCDs defined in DSC file # - for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList: - for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds: - DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue + for Pa in Wa.AutoGenObjectList: + for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds: + DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue # @@ -1116,34 +1639,36 @@ class FdRegionReport(object): for Pa in Wa.AutoGenObjectList: for ModuleKey in Pa.Platform.Modules: M = Pa.Platform.Modules[ModuleKey].M - InfPath = os.path.join(Wa.WorkspaceDir, M.MetaFile.File) + InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File) self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath) # # Collect the GUID map in the FV firmware volume # for FvName in self.FvList: - for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList: - try: - # - # collect GUID map for binary EFI file in FDF file. - # - Guid = Ffs.NameGuid.upper() - Match = gPcdGuidPattern.match(Ffs.NameGuid) - if Match: - PcdTokenspace = Match.group(1) - PcdToken = Match.group(2) - if (PcdToken, PcdTokenspace) in PlatformPcds: - GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)] - Guid = GuidStructureByteArrayToGuidString(GuidValue).upper() - for Section in Ffs.SectionList: - try: - ModuleSectFile = os.path.join(Wa.WorkspaceDir, Section.SectFileName) - self._GuidsDb[Guid] = ModuleSectFile - except AttributeError: - pass - except AttributeError: - pass + FvDictKey=FvName.upper() + if FvDictKey in Wa.FdfProfile.FvDict: + for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList: + try: + # + # collect GUID map for binary EFI file in FDF file. + # + Guid = Ffs.NameGuid.upper() + Match = gPcdGuidPattern.match(Ffs.NameGuid) + if Match: + PcdTokenspace = Match.group(1) + PcdToken = Match.group(2) + if (PcdToken, PcdTokenspace) in PlatformPcds: + GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)] + Guid = GuidStructureByteArrayToGuidString(GuidValue).upper() + for Section in Ffs.SectionList: + try: + ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName) + self._GuidsDb[Guid] = ModuleSectFile + except AttributeError: + pass + except AttributeError: + pass ## @@ -1169,7 +1694,7 @@ class FdRegionReport(object): FvTotalSize = 0 FvTakenSize = 0 FvFreeSize = 0 - FvReportFileName = os.path.join(self._FvDir, FvName + ".fv.txt") + FvReportFileName = os.path.join(self._FvDir, FvName + ".Fv.txt") try: # # Collect size info in the firmware volume. @@ -1246,6 +1771,35 @@ class FdReport(object): self.BaseAddress = Fd.BaseAddress self.Size = Fd.Size self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList] + self.FvPath = os.path.join(Wa.BuildDir, "FV") + self.VpdFilePath = os.path.join(self.FvPath, "%s.map" % Wa.Platform.VpdToolGuid) + self.VPDBaseAddress = 0 + self.VPDSize = 0 + self.VPDInfoList = [] + for index, FdRegion in enumerate(Fd.RegionList): + if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList): + self.VPDBaseAddress = self.FdRegionList[index].BaseAddress + self.VPDSize = self.FdRegionList[index].Size + break + + if os.path.isfile(self.VpdFilePath): + fd = open(self.VpdFilePath, "r") + Lines = fd.readlines() + for Line in Lines: + Line = Line.strip() + if len(Line) == 0 or Line.startswith("#"): + continue + try: + PcdName, SkuId, Offset, Size, Value = Line.split("#")[0].split("|") + PcdName, SkuId, Offset, Size, Value = PcdName.strip(), SkuId.strip(), Offset.strip(), Size.strip(), Value.strip() + if Offset.lower().startswith('0x'): + Offset = '0x%08X' % (int(Offset, 16) + self.VPDBaseAddress) + else: + Offset = '0x%08X' % (int(Offset, 10) + self.VPDBaseAddress) + self.VPDInfoList.append("%s | %s | %s | %s | %s" % (PcdName, SkuId, Offset, Size, Value)) + except: + EdkLogger.error("BuildReport", CODE_ERROR, "Fail to parse VPD information file %s" % self.VpdFilePath) + fd.close() ## # Generate report for the firmware device. @@ -1266,6 +1820,24 @@ class FdReport(object): for FdRegionItem in self.FdRegionList: FdRegionItem.GenerateReport(File) + if len(self.VPDInfoList) > 0: + FileWrite(File, gSubSectionStart) + FileWrite(File, "FD VPD Region") + FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress) + FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0)) + FileWrite(File, gSubSectionSep) + for item in self.VPDInfoList: + ValueList = item.split('|') + Value = ValueList[-1].strip() + IsByteArray, ArrayList = ByteArrayForamt(Value) + if IsByteArray: + ValueList[-1] = ' {' + FileWrite(File, '|'.join(ValueList)) + for Array in ArrayList: + FileWrite(File, '%s' % (Array)) + else: + FileWrite(File, item) + FileWrite(File, gSubSectionEnd) FileWrite(File, gSectionEnd) @@ -1310,6 +1882,10 @@ class PlatformReport(object): if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType: self.PredictionReport = PredictionReport(Wa) + self.DepexParser = None + if "DEPEX" in ReportType: + self.DepexParser = DepexParser(Wa) + self.ModuleReportList = [] if MaList != None: self._IsModuleBuild = True @@ -1318,8 +1894,21 @@ class PlatformReport(object): else: self._IsModuleBuild = False for Pa in Wa.AutoGenObjectList: + ModuleAutoGenList = [] for ModuleKey in Pa.Platform.Modules: - self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, ReportType)) + ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M) + if GlobalData.gFdfParser != None: + if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict: + INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch] + for InfName in INFList: + InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch) + Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile) + if Ma == None: + continue + if Ma not in ModuleAutoGenList: + ModuleAutoGenList.append(Ma) + for MGen in ModuleAutoGenList: + self.ModuleReportList.append(ModuleReport(MGen, ReportType)) @@ -1333,20 +1922,41 @@ class PlatformReport(object): # @param self The object pointer # @param File The file object for report # @param BuildDuration The total time to build the modules + # @param AutoGenTime The total time of AutoGen Phase + # @param MakeTime The total time of Make Phase + # @param GenFdsTime The total time of GenFds Phase # @param ReportType The kind of report items in the final report file # - def GenerateReport(self, File, BuildDuration, ReportType): + def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType): FileWrite(File, "Platform Summary") FileWrite(File, "Platform Name: %s" % self.PlatformName) FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath) FileWrite(File, "Architectures: %s" % self.Architectures) FileWrite(File, "Tool Chain: %s" % self.ToolChain) FileWrite(File, "Target: %s" % self.Target) + if GlobalData.gSkuids: + FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids)) + if GlobalData.gDefaultStores: + FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores)) FileWrite(File, "Output Path: %s" % self.OutputPath) FileWrite(File, "Build Environment: %s" % self.BuildEnvironment) FileWrite(File, "Build Duration: %s" % BuildDuration) + if AutoGenTime: + FileWrite(File, "AutoGen Duration: %s" % AutoGenTime) + if MakeTime: + FileWrite(File, "Make Duration: %s" % MakeTime) + if GenFdsTime: + FileWrite(File, "GenFds Duration: %s" % GenFdsTime) FileWrite(File, "Report Content: %s" % ", ".join(ReportType)) + if GlobalData.MixedPcd: + FileWrite(File, gSectionStart) + FileWrite(File, "The following PCDs use different access methods:") + FileWrite(File, gSectionSep) + for PcdItem in GlobalData.MixedPcd: + FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0]))) + FileWrite(File, gSectionEnd) + if not self._IsModuleBuild: if "PCD" in ReportType: self.PcdReport.GenerateReport(File, None) @@ -1356,7 +1966,7 @@ class PlatformReport(object): FdReportListItem.GenerateReport(File) for ModuleReportItem in self.ModuleReportList: - ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, ReportType) + ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType) if not self._IsModuleBuild: if "EXECUTION_ORDER" in ReportType: @@ -1389,7 +1999,7 @@ class BuildReport(object): if ReportTypeItem not in self.ReportType: self.ReportType.append(ReportTypeItem) else: - self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"] + self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"] ## # Adds platform report to the list # @@ -1411,17 +2021,19 @@ class BuildReport(object): # # @param self The object pointer # @param BuildDuration The total time to build the modules + # @param AutoGenTime The total time of AutoGen phase + # @param MakeTime The total time of Make phase + # @param GenFdsTime The total time of GenFds phase # - def GenerateReport(self, BuildDuration): + def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime): if self.ReportFile: try: - File = open(self.ReportFile, "w+") - except IOError: - EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=self.ReportFile) - try: + File = StringIO('') for (Wa, MaList) in self.ReportList: - PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, self.ReportType) - EdkLogger.quiet("Report successfully saved to %s" % os.path.abspath(self.ReportFile)) + PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType) + Content = FileLinesSplit(File.getvalue(), gLineMaxLength) + SaveFileOnChange(self.ReportFile, Content, True) + EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile)) except IOError: EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile) except: