]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/build/BuildReport.py
BaseTools/build: register MM module types with build tools.
[mirror_edk2.git] / BaseTools / Source / Python / build / BuildReport.py
index 2dc02c2c4e056ecf792e3c0dbd0573440aa40c32..a1ee43aa26ed41d31b4f3613965876e4b4fe3db6 100644 (file)
@@ -4,7 +4,7 @@
 # This module contains the functionality to generate build report after\r
 # build all target completes successfully.\r
 #\r
-# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
 # This program and the accompanying materials\r
 # are licensed and made available under the terms and conditions of the BSD License\r
 # which accompanies this distribution.  The full text of the license may be found at\r
@@ -24,6 +24,9 @@ import traceback
 import sys\r
 import time\r
 import struct\r
+import hashlib\r
+import subprocess\r
+import threading\r
 from datetime import datetime\r
 from StringIO import StringIO\r
 from Common import EdkLogger\r
@@ -33,6 +36,7 @@ from Common.Misc import GuidStructureStringToGuidString
 from Common.InfClassObject import gComponentType2ModuleType\r
 from Common.BuildToolError import FILE_WRITE_FAILURE\r
 from Common.BuildToolError import CODE_ERROR\r
+from Common.BuildToolError import COMMAND_FAILURE\r
 from Common.DataType import TAB_LINE_BREAK\r
 from Common.DataType import TAB_DEPEX\r
 from Common.DataType import TAB_SLASH\r
@@ -43,6 +47,9 @@ from Common.DataType import TAB_BACK_SLASH
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
 from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 import Common.GlobalData as GlobalData\r
+from AutoGen.AutoGen import ModuleAutoGen\r
+from Common.Misc import PathClass\r
+from Common.String import NormPath\r
 \r
 ## Pattern to extract contents in EDK DXS files\r
 gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
@@ -116,6 +123,8 @@ gDriverTypeMap = {
   'UEFI_APPLICATION'  : '0x9 (APPLICATION)',\r
   'SMM_CORE'          : '0xD (SMM_CORE)',\r
   'SMM_DRIVER'        : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers\r
+  'MM_STANDALONE'     : '0xE (MM_STANDALONE)',\r
+  'MM_CORE_STANDALONE' : '0xF (MM_CORE_STANDALONE)'\r
   }\r
 \r
 ## The look up table of the supported opcode in the dependency expression binaries\r
@@ -311,9 +320,9 @@ class LibraryReport(object):
     # @param File            The file object for report\r
     #\r
     def GenerateReport(self, File):\r
-        FileWrite(File, gSubSectionStart)\r
-        FileWrite(File, TAB_BRG_LIBRARY)\r
         if len(self.LibraryList) > 0:\r
+            FileWrite(File, gSubSectionStart)\r
+            FileWrite(File, TAB_BRG_LIBRARY)\r
             FileWrite(File, gSubSectionSep)\r
             for LibraryItem in self.LibraryList:\r
                 LibInfPath = LibraryItem[0]\r
@@ -340,7 +349,7 @@ class LibraryReport(object):
                     else:\r
                         FileWrite(File, "{%s}" % LibClass)\r
 \r
-        FileWrite(File, gSubSectionEnd)\r
+            FileWrite(File, gSubSectionEnd)\r
 \r
 ##\r
 # Reports dependency expression information\r
@@ -367,7 +376,7 @@ class DepexReport(object):
         if not ModuleType:\r
             ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
 \r
-        if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:\r
+        if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "MM_CORE_STANDALONE", "UEFI_APPLICATION"]:\r
             return\r
       \r
         for Source in M.SourceFileList:\r
@@ -404,9 +413,6 @@ class DepexReport(object):
     #\r
     def GenerateReport(self, File, GlobalDepexParser):\r
         if not self.Depex:\r
-            FileWrite(File, gSubSectionStart)\r
-            FileWrite(File, TAB_DEPEX)\r
-            FileWrite(File, gSubSectionEnd)\r
             return\r
         FileWrite(File, gSubSectionStart)\r
         if os.path.isfile(self._DepexFileName):\r
@@ -528,6 +534,7 @@ class ModuleReport(object):
         self.FileGuid = M.Guid\r
         self.Size = 0\r
         self.BuildTimeStamp = None\r
+        self.Hash = 0\r
         self.DriverType = ""\r
         if not M.IsLibrary:\r
             ModuleType = M.ModuleType\r
@@ -599,12 +606,46 @@ class ModuleReport(object):
             except IOError:\r
                 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)\r
 \r
+        if "HASH" in ReportType:\r
+            OutputDir = os.path.join(self._BuildDir, "OUTPUT")\r
+            DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi")\r
+            if os.path.isfile(DefaultEFIfile):\r
+                Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp")\r
+                # rebase the efi image since its base address may not zero\r
+                cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile]\r
+                try:\r
+                    PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
+                except Exception, X:\r
+                    EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))\r
+                EndOfProcedure = threading.Event()\r
+                EndOfProcedure.clear()\r
+                if PopenObject.stderr:\r
+                    StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure))\r
+                    StdErrThread.setName("STDERR-Redirector")\r
+                    StdErrThread.setDaemon(False)\r
+                    StdErrThread.start()\r
+                # waiting for program exit\r
+                PopenObject.wait()\r
+                if PopenObject.stderr:\r
+                    StdErrThread.join()\r
+                if PopenObject.returncode != 0:\r
+                    EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile))\r
+                if os.path.isfile(Tempfile):\r
+                    self.Hash = hashlib.sha1()\r
+                    buf = open(Tempfile, 'rb').read()\r
+                    if self.Hash.update(buf):\r
+                        self.Hash = self.Hash.update(buf)\r
+                    self.Hash = self.Hash.hexdigest()\r
+                    os.remove(Tempfile)\r
+\r
         FileWrite(File, "Module Summary")\r
         FileWrite(File, "Module Name:          %s" % self.ModuleName)\r
         FileWrite(File, "Module INF Path:      %s" % self.ModuleInfPath)\r
         FileWrite(File, "File GUID:            %s" % self.FileGuid)\r
         if self.Size:\r
             FileWrite(File, "Size:                 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))\r
+        if self.Hash:\r
+            FileWrite(File, "SHA1 HASH:            %s *%s" % (self.Hash, self.ModuleName + ".efi"))\r
         if self.BuildTimeStamp:\r
             FileWrite(File, "Build Time Stamp:     %s" % self.BuildTimeStamp)\r
         if self.DriverType:\r
@@ -639,6 +680,18 @@ class ModuleReport(object):
 \r
         FileWrite(File, gSectionEnd)\r
 \r
+def ReadMessage(From, To, ExitFlag):\r
+    while True:\r
+        # read one line a time\r
+        Line = From.readline()\r
+        # empty string means "end"\r
+        if Line != None and Line != "":\r
+            To(Line.rstrip())\r
+        else:\r
+            break\r
+        if ExitFlag.isSet():\r
+            break\r
+\r
 ##\r
 # Reports platform and module PCD information\r
 #\r
@@ -658,6 +711,8 @@ class PcdReport(object):
     #\r
     def __init__(self, Wa):\r
         self.AllPcds = {}\r
+        self.UnusedPcds = {}\r
+        self.ConditionalPcds = {}\r
         self.MaxLen = 0\r
         if Wa.FdfProfile:\r
             self.FdfPcdSet = Wa.FdfProfile.PcdDict\r
@@ -676,6 +731,63 @@ class PcdReport(object):
                     PcdList.append(Pcd)\r
                 if len(Pcd.TokenCName) > self.MaxLen:\r
                     self.MaxLen = len(Pcd.TokenCName)\r
+            #\r
+            # Collect the PCD defined in DSC/FDF file, but not used in module\r
+            #\r
+            UnusedPcdFullList = []\r
+            for item in Pa.Platform.Pcds:\r
+                Pcd = Pa.Platform.Pcds[item]\r
+                if not Pcd.Type:\r
+                    PcdTypeFlag = False\r
+                    for package in Pa.PackageList:\r
+                        for T in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:\r
+                            if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds:\r
+                                Pcd.Type = T\r
+                                PcdTypeFlag = True\r
+                                if not Pcd.DatumType:\r
+                                    Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType\r
+                                break\r
+                        if PcdTypeFlag:\r
+                            break\r
+                if not Pcd.DatumType:\r
+                    PcdType = Pcd.Type\r
+                    # Try to remove Hii and Vpd suffix\r
+                    if PcdType.startswith("DynamicEx"):\r
+                        PcdType = "DynamicEx"\r
+                    elif PcdType.startswith("Dynamic"):\r
+                        PcdType = "Dynamic"\r
+                    for package in Pa.PackageList:\r
+                        if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds:\r
+                            Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType\r
+                            break\r
+\r
+                PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
+                if Pcd not in PcdList and Pcd not in UnusedPcdFullList:\r
+                    UnusedPcdFullList.append(Pcd)\r
+                if len(Pcd.TokenCName) > self.MaxLen:\r
+                    self.MaxLen = len(Pcd.TokenCName)\r
+\r
+            if GlobalData.gConditionalPcds:\r
+                for PcdItem in GlobalData.gConditionalPcds:\r
+                    if '.' in PcdItem:\r
+                        (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.')\r
+                        if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds.keys():\r
+                            Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)]\r
+                            PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
+                            if Pcd not in PcdList:\r
+                                PcdList.append(Pcd)\r
+\r
+            UnusedPcdList = []\r
+            if UnusedPcdFullList:\r
+                for Pcd in UnusedPcdFullList:\r
+                    if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds:\r
+                        continue\r
+                    UnusedPcdList.append(Pcd)\r
+\r
+            for Pcd in UnusedPcdList:\r
+                PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
+                if Pcd not in PcdList:\r
+                    PcdList.append(Pcd)\r
 \r
             for Module in Pa.Platform.Modules.values():\r
                 #\r
@@ -709,6 +821,13 @@ class PcdReport(object):
                 if DscDefaultValue:\r
                     self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
 \r
+    def GenerateReport(self, File, ModulePcdSet):\r
+        if self.ConditionalPcds:\r
+            self.GenerateReportDetail(File, ModulePcdSet, 1)\r
+        if self.UnusedPcds:\r
+            self.GenerateReportDetail(File, ModulePcdSet, 2)\r
+        self.GenerateReportDetail(File, ModulePcdSet)\r
+\r
     ##\r
     # Generate report for PCD information\r
     #\r
@@ -719,39 +838,61 @@ class PcdReport(object):
     # @param File            The file object for report\r
     # @param ModulePcdSet    Set of all PCDs referenced by module or None for\r
     #                        platform PCD report\r
+    # @param ReportySubType  0 means platform/module PCD report, 1 means Conditional\r
+    #                        directives section report, 2 means Unused Pcds section report\r
     # @param DscOverridePcds Module DSC override PCDs set\r
     #\r
-    def GenerateReport(self, File, ModulePcdSet):\r
+    def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0):\r
+        PcdDict = self.AllPcds\r
+        if ReportSubType == 1:\r
+            PcdDict = self.ConditionalPcds\r
+        elif ReportSubType == 2:\r
+            PcdDict = self.UnusedPcds\r
+\r
         if ModulePcdSet == None:\r
-            #\r
-            # For platform global PCD section\r
-            #\r
             FileWrite(File, gSectionStart)\r
-            FileWrite(File, "Platform Configuration Database Report")\r
+            if ReportSubType == 1:\r
+                FileWrite(File, "Conditional Directives used by the build system")\r
+            elif ReportSubType == 2:\r
+                FileWrite(File, "PCDs not used by modules or in conditional directives")\r
+            else:\r
+                FileWrite(File, "Platform Configuration Database Report")\r
+\r
             FileWrite(File, "  *B  - PCD override in the build option")\r
             FileWrite(File, "  *P  - Platform scoped PCD override in DSC file")\r
             FileWrite(File, "  *F  - Platform scoped PCD override in FDF file")\r
-            FileWrite(File, "  *M  - Module scoped PCD override")\r
+            if not ReportSubType:\r
+                FileWrite(File, "  *M  - Module scoped PCD override")\r
             FileWrite(File, gSectionSep)\r
         else:\r
-            #\r
-            # For module PCD sub-section\r
-            #\r
-            FileWrite(File, gSubSectionStart)\r
-            FileWrite(File, TAB_BRG_PCD)\r
-            FileWrite(File, gSubSectionSep)\r
+            if not ReportSubType and ModulePcdSet:\r
+                #\r
+                # For module PCD sub-section\r
+                #\r
+                FileWrite(File, gSubSectionStart)\r
+                FileWrite(File, TAB_BRG_PCD)\r
+                FileWrite(File, gSubSectionSep)\r
 \r
-        for Key in self.AllPcds:\r
+        for Key in PcdDict:\r
             #\r
             # Group PCD by their token space GUID C Name\r
             #\r
             First = True\r
-            for Type in self.AllPcds[Key]:\r
+            for Type in PcdDict[Key]:\r
                 #\r
                 # Group PCD by their usage type\r
                 #\r
                 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))\r
-                for Pcd in self.AllPcds[Key][Type]:\r
+                for Pcd in PcdDict[Key][Type]:\r
+                    PcdTokenCName = Pcd.TokenCName\r
+                    MixedPcdFlag = False\r
+                    if GlobalData.MixedPcd:\r
+                        for PcdKey in GlobalData.MixedPcd:\r
+                            if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]:\r
+                                PcdTokenCName = PcdKey[0]\r
+                                MixedPcdFlag = True\r
+                        if MixedPcdFlag and not ModulePcdSet:\r
+                            continue\r
                     #\r
                     # Get PCD default value and their override relationship\r
                     #\r
@@ -824,17 +965,17 @@ class PcdReport(object):
                     # Report PCD item according to their override relationship\r
                     #\r
                     if BuildOptionMatch:\r
-                        FileWrite(File, ' *B %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
+                        FileWrite(File, ' *B %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
                     elif DecMatch and InfMatch:\r
-                        FileWrite(File, '    %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
+                        FileWrite(File, '    %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
                     else:\r
                         if DscMatch:\r
                             if (Pcd.TokenCName, Key) in self.FdfPcdSet:\r
-                                FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
+                                FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
                             else:\r
-                                FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
+                                FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
                         else:\r
-                            FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
+                            FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
 \r
                     if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):\r
                         for SkuInfo in Pcd.SkuInfoList.values():\r
@@ -869,7 +1010,8 @@ class PcdReport(object):
         if ModulePcdSet == None:\r
             FileWrite(File, gSectionEnd)\r
         else:\r
-            FileWrite(File, gSubSectionEnd)\r
+            if not ReportSubType and ModulePcdSet:\r
+                FileWrite(File, gSubSectionEnd)\r
 \r
 \r
 \r
@@ -1426,7 +1568,10 @@ class FdReport(object):
                 try:\r
                     PcdName, SkuId, Offset, Size, Value = Line.split("#")[0].split("|")\r
                     PcdName, SkuId, Offset, Size, Value = PcdName.strip(), SkuId.strip(), Offset.strip(), Size.strip(), Value.strip()\r
-                    Offset = '0x%08X' % (int(Offset, 16) + self.VPDBaseAddress)\r
+                    if Offset.lower().startswith('0x'):\r
+                        Offset = '0x%08X' % (int(Offset, 16) + self.VPDBaseAddress)\r
+                    else:\r
+                        Offset = '0x%08X' % (int(Offset, 10) + self.VPDBaseAddress)\r
                     self.VPDInfoList.append("%s | %s | %s | %s | %s" % (PcdName, SkuId, Offset, Size, Value))\r
                 except:\r
                     EdkLogger.error("BuildReport", CODE_ERROR, "Fail to parse VPD information file %s" % self.VpdFilePath)\r
@@ -1516,8 +1661,21 @@ class PlatformReport(object):
         else:\r
             self._IsModuleBuild = False\r
             for Pa in Wa.AutoGenObjectList:\r
+                ModuleAutoGenList = []\r
                 for ModuleKey in Pa.Platform.Modules:\r
-                    self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, ReportType))\r
+                    ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)\r
+                if GlobalData.gFdfParser != None:\r
+                    if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:\r
+                        INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]\r
+                        for InfName in INFList:\r
+                            InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)\r
+                            Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile)\r
+                            if Ma == None:\r
+                                continue\r
+                            if Ma not in ModuleAutoGenList:\r
+                                ModuleAutoGenList.append(Ma)\r
+                for MGen in ModuleAutoGenList:\r
+                    self.ModuleReportList.append(ModuleReport(MGen, ReportType))\r
 \r
 \r
 \r
@@ -1545,6 +1703,14 @@ class PlatformReport(object):
         FileWrite(File, "Build Duration:       %s" % BuildDuration)\r
         FileWrite(File, "Report Content:       %s" % ", ".join(ReportType))\r
 \r
+        if GlobalData.MixedPcd:\r
+            FileWrite(File, gSectionStart)\r
+            FileWrite(File, "The following PCDs use different access methods:")\r
+            FileWrite(File, gSectionSep)\r
+            for PcdItem in GlobalData.MixedPcd:\r
+                FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))\r
+            FileWrite(File, gSectionEnd)\r
+\r
         if not self._IsModuleBuild:\r
             if "PCD" in ReportType:\r
                 self.PcdReport.GenerateReport(File, None)\r
@@ -1587,7 +1753,7 @@ class BuildReport(object):
                     if ReportTypeItem not in self.ReportType:\r
                         self.ReportType.append(ReportTypeItem)\r
             else:\r
-                self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]\r
+                self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]\r
     ##\r
     # Adds platform report to the list\r
     #\r