]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/build/BuildReport.py
BaseTools: Fixed the issue of Multiple Skus are always disables
[mirror_edk2.git] / BaseTools / Source / Python / build / BuildReport.py
index 329352204dc4267a2965ccd116095de99fd797ef..75e8ec97ab8a74e224aebc4008627099c8c5384b 100644 (file)
@@ -4,8 +4,8 @@
 # This module contains the functionality to generate build report after\r
 # build all target completes successfully.\r
 #\r
-# Copyright (c) 2010, Intel Corporation\r
-# All rights reserved. This program and the accompanying materials\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
 # http://opensource.org/licenses/bsd-license.php\r
 \r
 ## Import Modules\r
 #\r
-import os\r
+import Common.LongFilePathOs as os\r
 import re\r
 import platform\r
 import textwrap\r
 import traceback\r
 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
+from Common.Misc import SaveFileOnChange\r
 from Common.Misc import GuidStructureByteArrayToGuidString\r
 from Common.Misc import GuidStructureStringToGuidString\r
 from Common.InfClassObject import gComponentType2ModuleType\r
-from Common.BuildToolError import FILE_OPEN_FAILURE\r
 from Common.BuildToolError import FILE_WRITE_FAILURE\r
 from Common.BuildToolError import CODE_ERROR\r
-\r
+from Common.BuildToolError import COMMAND_FAILURE\r
+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
+from Common.DataType import *\r
+import collections\r
 \r
 ## Pattern to extract contents in EDK DXS files\r
 gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
@@ -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\r
 gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")\r
 \r
+## Tags for MaxLength of line in report\r
+gLineMaxLength = 120\r
+\r
+## Tags for end of line in report\r
+gEndOfLine = "\r\n"\r
+\r
 ## Tags for section start, end and separator\r
-gSectionStart = ">" + "=" * 118 + "<"\r
-gSectionEnd = "<" + "=" * 118 + ">" + "\n"\r
-gSectionSep = "=" * 120\r
+gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"\r
+gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"\r
+gSectionSep = "=" * gLineMaxLength\r
 \r
 ## Tags for subsection start, end and separator\r
-gSubSectionStart = ">" + "-" * 118 + "<"\r
-gSubSectionEnd = "<" + "-" * 118 + ">"\r
-gSubSectionSep = "-" * 120\r
+gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"\r
+gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"\r
+gSubSectionSep = "-" * gLineMaxLength\r
+\r
 \r
 ## The look up table to map PCD type to pair of report display type and DEC type\r
 gPcdTypeMap = {\r
@@ -78,9 +99,9 @@ gPcdTypeMap = {
   'Dynamic'          : ('DYN',    'Dynamic'),\r
   'DynamicHii'       : ('DYNHII', 'Dynamic'),\r
   'DynamicVpd'       : ('DYNVPD', 'Dynamic'),\r
-  'DynamicEx'        : ('DEX',    'Dynamic'),\r
-  'DynamicExHii'     : ('DEXHII', 'Dynamic'),\r
-  'DynamicExVpd'     : ('DEXVPD', 'Dynamic'),\r
+  'DynamicEx'        : ('DEX',    'DynamicEx'),\r
+  'DynamicExHii'     : ('DEXHII', 'DynamicEx'),\r
+  'DynamicExVpd'     : ('DEXVPD', 'DynamicEx'),\r
   }\r
 \r
 ## The look up table to map module type to driver type\r
@@ -97,8 +118,13 @@ 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
+gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]\r
+\r
 ##\r
 # Writes a string to the file object.\r
 #\r
@@ -112,7 +138,38 @@ gDriverTypeMap = {
 def FileWrite(File, String, Wrapper=False):\r
     if Wrapper:\r
         String = textwrap.fill(String, 120)\r
-    File.write(String + "\r\n")\r
+    File.write(String + gEndOfLine)\r
+\r
+def ByteArrayForamt(Value):\r
+    IsByteArray = False\r
+    SplitNum = 16\r
+    ArrayList = []\r
+    if Value.startswith('{') and Value.endswith('}'):\r
+        Value = Value[1:-1]\r
+        ValueList = Value.split(',')\r
+        if len(ValueList) >= SplitNum:\r
+            IsByteArray = True\r
+    if IsByteArray:\r
+        if ValueList:\r
+            Len = len(ValueList)/SplitNum\r
+            for i, element in enumerate(ValueList):\r
+                ValueList[i] = '0x%02X' % int(element.strip(), 16)\r
+        if Len:\r
+            Id = 0\r
+            while (Id <= Len):\r
+                End = min(SplitNum*(Id+1), len(ValueList))\r
+                Str = ','.join(ValueList[SplitNum*Id : End])\r
+                if End == len(ValueList):\r
+                    Str += '}'\r
+                    ArrayList.append(Str)\r
+                    break\r
+                else:\r
+                    Str += ','\r
+                    ArrayList.append(Str)\r
+                Id += 1\r
+        else:\r
+            ArrayList = [Value + '}']\r
+    return IsByteArray, ArrayList\r
 \r
 ##\r
 # Find all the header file that the module source directly includes.\r
@@ -160,6 +217,94 @@ def FindIncludeFiles(Source, IncludePathList, IncludeFiles):
                 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
                 break\r
 \r
+## Split each lines in file\r
+#\r
+#  This method is used to split the lines in file to make the length of each line \r
+#  less than MaxLength.\r
+#\r
+#  @param      Content           The content of file\r
+#  @param      MaxLength         The Max Length of the line\r
+#\r
+def FileLinesSplit(Content=None, MaxLength=None):\r
+    ContentList = Content.split(TAB_LINE_BREAK)\r
+    NewContent = ''\r
+    NewContentList = []\r
+    for Line in ContentList:\r
+        while len(Line.rstrip()) > MaxLength:\r
+            LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)\r
+            LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)\r
+            LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)\r
+            if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:\r
+                LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)\r
+            else:\r
+                LineBreakIndex = MaxLength\r
+            NewContentList.append(Line[:LineBreakIndex])\r
+            Line = Line[LineBreakIndex:]\r
+        if Line:\r
+            NewContentList.append(Line)\r
+    for NewLine in NewContentList:\r
+        NewContent += NewLine + TAB_LINE_BREAK\r
+    \r
+    NewContent = NewContent.replace(TAB_LINE_BREAK, gEndOfLine).replace('\r\r\n', gEndOfLine)\r
+    return NewContent\r
+    \r
+    \r
+    \r
+##\r
+# Parse binary dependency expression section\r
+#\r
+# This utility class parses the dependency expression section and translate the readable\r
+# GUID name and value.\r
+#\r
+class DepexParser(object):\r
+    ##\r
+    # Constructor function for class DepexParser\r
+    #\r
+    # This constructor function collect GUID values so that the readable\r
+    # GUID name can be translated.\r
+    #\r
+    # @param self            The object pointer\r
+    # @param Wa              Workspace context information\r
+    #\r
+    def __init__(self, Wa):\r
+        self._GuidDb = {}\r
+        for Pa in Wa.AutoGenObjectList:\r
+            for Package in Pa.PackageList:\r
+                for Protocol in Package.Protocols:\r
+                    GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])\r
+                    self._GuidDb[GuidValue.upper()] = Protocol\r
+                for Ppi in Package.Ppis:\r
+                    GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])\r
+                    self._GuidDb[GuidValue.upper()] = Ppi\r
+                for Guid in Package.Guids:\r
+                    GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])\r
+                    self._GuidDb[GuidValue.upper()] = Guid\r
+    \r
+    ##\r
+    # Parse the binary dependency expression files.\r
+    # \r
+    # This function parses the binary dependency expression file and translate it\r
+    # to the instruction list.\r
+    #\r
+    # @param self            The object pointer\r
+    # @param DepexFileName   The file name of binary dependency expression file.\r
+    #\r
+    def ParseDepexFile(self, DepexFileName):\r
+        DepexFile = open(DepexFileName, "rb")\r
+        DepexStatement = []\r
+        OpCode = DepexFile.read(1)\r
+        while OpCode:\r
+            Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]\r
+            if Statement in ["BEFORE", "AFTER", "PUSH"]:\r
+                GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \\r
+                            struct.unpack("=LHHBBBBBBBB", DepexFile.read(16))\r
+                GuidString = self._GuidDb.get(GuidValue, GuidValue)\r
+                Statement = "%s %s" % (Statement, GuidString)\r
+            DepexStatement.append(Statement)\r
+            OpCode = DepexFile.read(1)\r
+\r
+        return DepexStatement\r
+    \r
 ##\r
 # Reports library information\r
 #\r
@@ -188,7 +333,11 @@ class LibraryReport(object):
             LibConstructorList = Lib.ConstructorList\r
             LibDesstructorList = Lib.DestructorList\r
             LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]\r
-            self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList))\r
+            for LibAutoGen in M.LibraryAutoGenList:\r
+                if LibInfPath == LibAutoGen.MetaFile.Path:\r
+                    LibTime = LibAutoGen.BuildTime\r
+                    break\r
+            self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime))\r
 \r
     ##\r
     # Generate report for module library information\r
@@ -201,9 +350,9 @@ class LibraryReport(object):
     # @param File            The file object for report\r
     #\r
     def GenerateReport(self, File):\r
-        FileWrite(File, gSubSectionStart)\r
-        FileWrite(File, "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
@@ -225,12 +374,14 @@ class LibraryReport(object):
                     LibDepex = " ".join(LibraryItem[4])\r
                     if LibDepex:\r
                         EdkIILibInfo += " Depex = " + LibDepex\r
+                    if LibraryItem[5]:\r
+                        EdkIILibInfo += " Time = " + LibraryItem[5]\r
                     if EdkIILibInfo:\r
                         FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))\r
                     else:\r
                         FileWrite(File, "{%s}" % LibClass)\r
 \r
-        FileWrite(File, gSubSectionEnd)\r
+            FileWrite(File, gSubSectionEnd)\r
 \r
 ##\r
 # Reports dependency expression information\r
@@ -252,11 +403,12 @@ class DepexReport(object):
     #\r
     def __init__(self, M):\r
         self.Depex = ""\r
+        self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")\r
         ModuleType = M.ModuleType\r
         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
@@ -287,14 +439,24 @@ class DepexReport(object):
     #\r
     # This function generates report for the module dependency expression.\r
     #\r
-    # @param self            The object pointer\r
-    # @param File            The file object for report\r
+    # @param self              The object pointer\r
+    # @param File              The file object for report\r
+    # @param GlobalDepexParser The platform global Dependency expression parser object\r
     #\r
-    def GenerateReport(self, File):\r
+    def GenerateReport(self, File, GlobalDepexParser):\r
         if not self.Depex:\r
             return\r
-                \r
         FileWrite(File, gSubSectionStart)\r
+        if os.path.isfile(self._DepexFileName):\r
+            try:\r
+                DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)\r
+                FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")\r
+                for DepexStatement in DepexStatements:\r
+                    FileWrite(File, "  %s" % DepexStatement)\r
+                FileWrite(File, gSubSectionSep)\r
+            except:\r
+                EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)\r
+        \r
         FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)\r
 \r
         if self.Source == "INF":\r
@@ -404,6 +566,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
@@ -413,7 +576,7 @@ class ModuleReport(object):
             # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"\r
             #\r
             if ModuleType == "DXE_SMM_DRIVER":\r
-                PiSpec =  M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
+                PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
                 if int(PiSpec, 0) >= 0x0001000A:\r
                     ModuleType = "SMM_DRIVER"\r
             self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")\r
@@ -422,6 +585,7 @@ class ModuleReport(object):
         self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")\r
         self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")\r
         self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")\r
+        self.BuildTime = M.BuildTime\r
 \r
         self._BuildDir = M.BuildDir\r
         self.ModulePcdSet = {}\r
@@ -451,12 +615,14 @@ class ModuleReport(object):
     # This function generates report for separate module expression\r
     # in a platform build.\r
     #\r
-    # @param self            The object pointer\r
-    # @param File            The file object for report\r
-    # @param GlobalPcdReport The platform global PCD class object\r
-    # @param ReportType      The kind of report items in the final report file\r
+    # @param self                   The object pointer\r
+    # @param File                   The file object for report\r
+    # @param GlobalPcdReport        The platform global PCD report object\r
+    # @param GlobalPredictionReport The platform global Prediction report object\r
+    # @param GlobalDepexParser      The platform global Dependency expression parser object\r
+    # @param ReportType             The kind of report items in the final report file\r
     #\r
-    def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, ReportType):\r
+    def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):\r
         FileWrite(File, gSectionStart)\r
 \r
         FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt")\r
@@ -473,14 +639,50 @@ 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.BuildTime:\r
+            FileWrite(File, "Module Build Time:    %s" % self.BuildTime)\r
         if self.DriverType:\r
             FileWrite(File, "Driver Type:          %s" % self.DriverType)\r
         if self.UefiSpecVersion:\r
@@ -503,7 +705,7 @@ class ModuleReport(object):
             self.LibraryReport.GenerateReport(File)\r
 \r
         if "DEPEX" in ReportType:\r
-            self.DepexReport.GenerateReport(File)\r
+            self.DepexReport.GenerateReport(File, GlobalDepexParser)\r
 \r
         if "BUILD_FLAGS" in ReportType:\r
             self.BuildFlagsReport.GenerateReport(File)\r
@@ -513,6 +715,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
@@ -532,7 +746,10 @@ class PcdReport(object):
     #\r
     def __init__(self, Wa):\r
         self.AllPcds = {}\r
+        self.UnusedPcds = {}\r
+        self.ConditionalPcds = {}\r
         self.MaxLen = 0\r
+        self.Arch = None\r
         if Wa.FdfProfile:\r
             self.FdfPcdSet = Wa.FdfProfile.PcdDict\r
         else:\r
@@ -540,6 +757,7 @@ class PcdReport(object):
 \r
         self.ModulePcdOverride = {}\r
         for Pa in Wa.AutoGenObjectList:\r
+            self.Arch = Pa.Arch\r
             #\r
             # Collect all platform referenced PCDs and grouped them by PCD token space\r
             # GUID C Names\r
@@ -550,6 +768,70 @@ 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
+                    # check the Pcd in FDF file, whether it is used in module first\r
+                    for T in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:\r
+                        PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, [])\r
+                        if Pcd in PcdList:\r
+                            Pcd.Type = T\r
+                            break\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
@@ -567,18 +849,27 @@ class PcdReport(object):
         # Collect PCD DEC default value.\r
         #\r
         self.DecPcdDefault = {}\r
-        for Package in Wa.BuildDatabase.WorkspaceDb.PackageList:\r
-            for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
-                DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
-                self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
+        for Pa in Wa.AutoGenObjectList:\r
+            for Package in Pa.PackageList:\r
+                for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
+                    DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
+                    self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
         #\r
         # Collect PCDs defined in DSC common section\r
         #\r
         self.DscPcdDefault = {}\r
-        for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:\r
-            for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
-                DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
-                self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
+        for Pa in Wa.AutoGenObjectList:\r
+            for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:\r
+                DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
+                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
@@ -590,43 +881,67 @@ 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, "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
                     DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))\r
                     DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))\r
+                    DscDefaultValBak= DscDefaultValue\r
                     DscDefaultValue = self.FdfPcdSet.get((Pcd.TokenCName, Key), DscDefaultValue)\r
                     InfDefaultValue = None\r
                     \r
@@ -639,6 +954,15 @@ class PcdReport(object):
                         InfDefault, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]\r
                         if InfDefault == "":\r
                             InfDefault = None\r
+\r
+                    BuildOptionMatch = False\r
+                    if GlobalData.BuildOptionPcd:\r
+                        for pcd in GlobalData.BuildOptionPcd:\r
+                            if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):\r
+                                PcdValue = pcd[2]\r
+                                BuildOptionMatch = True\r
+                                break\r
+\r
                     if First:\r
                         if ModulePcdSet == None:\r
                             FileWrite(File, "")\r
@@ -681,55 +1005,240 @@ class PcdReport(object):
                         else:\r
                             DscMatch = (DscDefaultValue.strip() == PcdValue.strip())\r
 \r
+                    IsStructure = False\r
+                    if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd.keys()) and ((Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.gStructurePcd[self.Arch]):\r
+                        IsStructure = True\r
+                        if TypeName in ('DYNVPD', 'DEXVPD'):\r
+                            SkuInfoList = Pcd.SkuInfoList\r
+                        Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]\r
+                        Pcd.DatumType = Pcd.StructName\r
+                        if TypeName in ('DYNVPD', 'DEXVPD'):\r
+                            Pcd.SkuInfoList = SkuInfoList\r
+                        if Pcd.SkuOverrideValues:\r
+                            DscMatch = True\r
+                            DecMatch = False\r
                     #\r
                     # Report PCD item according to their override relationship\r
                     #\r
                     if DecMatch and InfMatch:\r
-                        FileWrite(File, '    %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
+                        self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '  ')\r
+                    elif BuildOptionMatch:\r
+                        self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B')\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
+                                self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F')\r
                             else:\r
-                                FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
+                                self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P')\r
                         else:\r
-                            FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
-                    \r
-                    if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):\r
-                        for SkuInfo in Pcd.SkuInfoList.values():\r
-                            if TypeName in ('DYNHII', 'DEXHII'):\r
-                                FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))        \r
-                            else:\r
-                                FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
-                               \r
-                    if not DscMatch and DscDefaultValue != None:\r
-                        FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue.strip()))\r
-\r
-                    if not InfMatch and InfDefaultValue != None:\r
-                        FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue.strip()))\r
-\r
-                    if not DecMatch and DecDefaultValue != None:\r
-                        FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue.strip()))\r
+                            self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')\r
 \r
                     if ModulePcdSet == None:\r
-                        ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
-                        for ModulePath in ModuleOverride:\r
-                            ModuleDefault = ModuleOverride[ModulePath]\r
-                            if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
-                                ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
-                                Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
-                            else:\r
-                                Match = (ModuleDefault.strip() == PcdValue.strip())\r
-                            if Match:\r
-                                continue\r
-                            FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip()))\r
+                        if IsStructure:\r
+                            continue\r
+                        if not TypeName in ('PATCH', 'FLAG', 'FIXED'):\r
+                            continue\r
+                        if not BuildOptionMatch:\r
+                            ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
+                            for ModulePath in ModuleOverride:\r
+                                ModuleDefault = ModuleOverride[ModulePath]\r
+                                if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
+                                    ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
+                                    Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
+                                else:\r
+                                    Match = (ModuleDefault.strip() == PcdValue.strip())\r
+                                if Match:\r
+                                    continue\r
+                                IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip())\r
+                                if IsByteArray:\r
+                                    FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, '{'))\r
+                                    for Array in ArrayList:\r
+                                        FileWrite(File, '%s' % (Array))\r
+                                else:\r
+                                    FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip()))\r
 \r
         if ModulePcdSet == None:\r
             FileWrite(File, gSectionEnd)\r
         else:\r
-            FileWrite(File, gSubSectionEnd)\r
-\r
+            if not ReportSubType and ModulePcdSet:\r
+                FileWrite(File, gSubSectionEnd)\r
+\r
+\r
+    def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue):\r
+        if not DscMatch and DscDefaultValue != None:\r
+            Value = DscDefaultValue.strip()\r
+            IsByteArray, ArrayList = ByteArrayForamt(Value)\r
+            if IsByteArray:\r
+                FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{"))\r
+                for Array in ArrayList:\r
+                    FileWrite(File, '%s' % (Array))\r
+            else:\r
+                FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value))\r
+        if not InfMatch and InfDefaultValue != None:\r
+            Value = InfDefaultValue.strip()\r
+            IsByteArray, ArrayList = ByteArrayForamt(Value)\r
+            if IsByteArray:\r
+                FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{"))\r
+                for Array in ArrayList:\r
+                    FileWrite(File, '%s' % (Array))\r
+            else:\r
+                FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value))\r
+\r
+        if not DecMatch and DecDefaultValue != None:\r
+            Value = DecDefaultValue.strip()\r
+            IsByteArray, ArrayList = ByteArrayForamt(Value)\r
+            if IsByteArray:\r
+                FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{"))\r
+                for Array in ArrayList:\r
+                    FileWrite(File, '%s' % (Array))\r
+            else:\r
+                FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value))\r
+            if IsStructure:\r
+                self.PrintStructureInfo(File, Pcd.DefaultValues)\r
+\r
+    def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = '  '):\r
+        if not Pcd.SkuInfoList:\r
+            Value = Pcd.DefaultValue\r
+            IsByteArray, ArrayList = ByteArrayForamt(Value)\r
+            if IsByteArray:\r
+                FileWrite(File, ' %-*s   : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))\r
+                for Array in ArrayList:\r
+                    FileWrite(File, '%s' % (Array))\r
+            else:\r
+                FileWrite(File, ' %-*s   : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))\r
+            if IsStructure:\r
+                OverrideValues = Pcd.SkuOverrideValues\r
+                if OverrideValues:\r
+                    Keys = OverrideValues.keys()\r
+                    Data = OverrideValues[Keys[0]]\r
+                    Struct = Data.values()[0]\r
+                    self.PrintStructureInfo(File, Struct)\r
+            self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
+        else:\r
+            FirstPrint = True\r
+            SkuList = sorted(Pcd.SkuInfoList.keys())\r
+            for Sku in SkuList:\r
+                SkuInfo = Pcd.SkuInfoList[Sku]\r
+                if TypeName in ('DYNHII', 'DEXHII'):\r
+                    if SkuInfo.DefaultStoreDict:\r
+                        DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())\r
+                        for DefaultStore in DefaultStoreList:\r
+                            Value = SkuInfo.DefaultStoreDict[DefaultStore]\r
+                            IsByteArray, ArrayList = ByteArrayForamt(Value)\r
+                            if FirstPrint:\r
+                                FirstPrint = False\r
+                                if IsByteArray:\r
+                                    FileWrite(File, ' %-*s   : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', '{'))\r
+                                    for Array in ArrayList:\r
+                                        FileWrite(File, '%s' % (Array))\r
+                                else:\r
+                                    FileWrite(File, ' %-*s   : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', Value))\r
+                            else:\r
+                                if IsByteArray:\r
+                                    FileWrite(File, ' %-*s   : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', '{'))\r
+                                    for Array in ArrayList:\r
+                                        FileWrite(File, '%s' % (Array))\r
+                                else:\r
+                                    FileWrite(File, ' %-*s   : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '(' + DefaultStore + ')', Value))\r
+                            FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))\r
+                            if IsStructure:\r
+                                OverrideValues = Pcd.SkuOverrideValues[Sku]\r
+                                Struct = OverrideValues[DefaultStore]\r
+                                self.PrintStructureInfo(File, Struct)\r
+                            self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
+                elif TypeName in ('DYNVPD', 'DEXVPD'):\r
+                    Value = SkuInfo.DefaultValue\r
+                    IsByteArray, ArrayList = ByteArrayForamt(Value)\r
+                    if FirstPrint:\r
+                        FirstPrint = False\r
+                        if IsByteArray:\r
+                            FileWrite(File, ' %-*s   : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', "{"))\r
+                            for Array in ArrayList:\r
+                                FileWrite(File, '%s' % (Array))\r
+                        else:\r
+                            FileWrite(File, ' %-*s   : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value))\r
+                    else:\r
+                        if IsByteArray:\r
+                            FileWrite(File, ' %-*s   : %6s %10s %10s = %s' % (self.MaxLen, ' ' , TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', "{"))\r
+                            for Array in ArrayList:\r
+                                FileWrite(File, '%s' % (Array))\r
+                        else:\r
+                            FileWrite(File, ' %-*s   : %6s %10s %10s = %s' % (self.MaxLen, ' ' , TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value))\r
+                    FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
+                    if IsStructure:\r
+                        OverrideValues = Pcd.SkuOverrideValues[Sku]\r
+                        if OverrideValues:\r
+                            Keys = OverrideValues.keys()\r
+                            Struct = OverrideValues[Keys[0]]\r
+                            self.PrintStructureInfo(File, Struct)\r
+                    self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
+                else:\r
+                    Value = SkuInfo.DefaultValue\r
+                    IsByteArray, ArrayList = ByteArrayForamt(Value)\r
+                    if FirstPrint:\r
+                        FirstPrint = False\r
+                        if IsByteArray:\r
+                            FileWrite(File, ' %-*s   : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '{'))\r
+                            for Array in ArrayList:\r
+                                FileWrite(File, '%s' % (Array))\r
+                        else:\r
+                            FileWrite(File, ' %-*s   : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value))\r
+                    else:\r
+                        if IsByteArray:\r
+                            FileWrite(File, ' %-*s   : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', '{'))\r
+                            for Array in ArrayList:\r
+                                FileWrite(File, '%s' % (Array))\r
+                        else:\r
+                            FileWrite(File, ' %-*s   : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuInfo.SkuIdName + ')', Value))\r
+                    if IsStructure:\r
+                        OverrideValues = Pcd.SkuOverrideValues[Sku]\r
+                        if OverrideValues:\r
+                            Keys = OverrideValues.keys()\r
+                            Struct = OverrideValues[Keys[0]]\r
+                            self.PrintStructureInfo(File, Struct)\r
+                    self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
+\r
+    def PrintStructureInfo(self, File, Struct):\r
+        NewInfo = collections.OrderedDict()\r
+        for Key, Value in Struct.items():\r
+            if Key not in NewInfo:\r
+                NewInfo[Key] = Value[0]\r
+            else:\r
+                del NewInfo[Key]\r
+                NewInfo[Key] = Value[0]\r
+        if NewInfo:\r
+            for item in NewInfo:\r
+                FileWrite(File, '        %-*s = %s' % (self.MaxLen + 4, '.' + item, NewInfo[item]))\r
 \r
+    def StrtoHex(self, value):\r
+        try:\r
+            value = hex(int(value))\r
+            return value\r
+        except:\r
+            if value.startswith("L\"") and value.endswith("\""):\r
+                valuelist = []\r
+                for ch in value[2:-1]:\r
+                    valuelist.append(hex(ord(ch)))\r
+                    valuelist.append('0x00')\r
+                return valuelist\r
+            elif value.startswith("\"") and value.endswith("\""):\r
+                return hex(ord(value[1:-1]))\r
+            elif value.startswith("{") and value.endswith("}"):\r
+                valuelist = []\r
+                if ',' not in value:\r
+                    return value[1:-1]\r
+                for ch in value[1:-1].split(','):\r
+                    ch = ch.strip()\r
+                    if ch.startswith('0x') or ch.startswith('0X'):\r
+                        valuelist.append(ch)\r
+                        continue\r
+                    try:\r
+                        valuelist.append(hex(int(ch.strip())))\r
+                    except:\r
+                        pass\r
+                return valuelist\r
+            else:\r
+                return value\r
 \r
 ##\r
 # Reports platform and module Prediction information\r
@@ -765,6 +1274,13 @@ class PredictionReport(object):
         for Pa in Wa.AutoGenObjectList:\r
             for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:\r
                 #\r
+                # BASE typed modules are EFI agnostic, so we need not scan\r
+                # their source code to find PPI/Protocol produce or consume\r
+                # information.\r
+                #\r
+                if Module.ModuleType == "BASE":\r
+                    continue\r
+                #\r
                 # Add module referenced source files\r
                 #\r
                 self._SourceList.append(str(Module))\r
@@ -889,12 +1405,17 @@ class PredictionReport(object):
 \r
         try:\r
             from Eot.Eot import Eot\r
+\r
             #\r
-            # Invoke EOT tool\r
+            # Invoke EOT tool and echo its runtime performance\r
             #\r
+            EotStartTime = time.time()\r
             Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,\r
                 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)\r
-\r
+            EotEndTime = time.time()\r
+            EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))\r
+            EdkLogger.quiet("EOT run time: %s\n" % EotDuration)\r
+            \r
             #\r
             # Parse the output of EOT tool\r
             #\r
@@ -1035,18 +1556,20 @@ class FdRegionReport(object):
     # @param Wa              Workspace context information\r
     #\r
     def _DiscoverNestedFvList(self, FvName, Wa):\r
-        for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
-            for Section in Ffs.SectionList:\r
-                try:\r
-                    for FvSection in Section.SectionList:\r
-                        if FvSection.FvName in self.FvList:\r
-                            continue\r
-                        self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName\r
-                        self.FvList.append(FvSection.FvName)\r
-                        self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)\r
-                        self._DiscoverNestedFvList(FvSection.FvName, Wa)\r
-                except AttributeError:\r
-                    pass\r
+        FvDictKey=FvName.upper()\r
+        if FvDictKey in Wa.FdfProfile.FvDict:\r
+            for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
+                for Section in Ffs.SectionList:\r
+                    try:\r
+                        for FvSection in Section.SectionList:\r
+                            if FvSection.FvName in self.FvList:\r
+                                continue\r
+                            self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName\r
+                            self.FvList.append(FvSection.FvName)\r
+                            self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)\r
+                            self._DiscoverNestedFvList(FvSection.FvName, Wa)\r
+                    except AttributeError:\r
+                        pass\r
 \r
     ##\r
     # Constructor function for class FdRegionReport\r
@@ -1087,20 +1610,20 @@ class FdRegionReport(object):
             self._DiscoverNestedFvList(FvName, Wa)\r
 \r
         PlatformPcds = {}\r
-        \r
         #\r
         # Collect PCDs declared in DEC files.\r
+        #        \r
+        for Pa in Wa.AutoGenObjectList:\r
+            for Package in Pa.PackageList:\r
+                for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
+                    DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
+                    PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
         #\r
-        for Package in Wa.BuildDatabase.WorkspaceDb.PackageList:\r
-            for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
-                DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
-                PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
-        #\r
-        # Collect PCDs defined in DSC common section\r
+        # Collect PCDs defined in DSC file\r
         #\r
-        for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:\r
-            for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
-                DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
+        for Pa in Wa.AutoGenObjectList:\r
+            for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:\r
+                DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
                 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
 \r
         #\r
@@ -1116,34 +1639,36 @@ class FdRegionReport(object):
         for Pa in Wa.AutoGenObjectList:\r
             for ModuleKey in Pa.Platform.Modules:\r
                 M = Pa.Platform.Modules[ModuleKey].M\r
-                InfPath = os.path.join(Wa.WorkspaceDir, M.MetaFile.File)\r
+                InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)\r
                 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
 \r
         #\r
         # Collect the GUID map in the FV firmware volume\r
         #\r
         for FvName in self.FvList:\r
-            for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
-                try:\r
-                    #\r
-                    # collect GUID map for binary EFI file in FDF file.\r
-                    #\r
-                    Guid = Ffs.NameGuid.upper()\r
-                    Match = gPcdGuidPattern.match(Ffs.NameGuid)\r
-                    if Match:\r
-                        PcdTokenspace = Match.group(1)\r
-                        PcdToken = Match.group(2)\r
-                        if (PcdToken, PcdTokenspace) in PlatformPcds:\r
-                            GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]\r
-                            Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
-                    for Section in Ffs.SectionList:\r
-                        try:\r
-                            ModuleSectFile = os.path.join(Wa.WorkspaceDir, Section.SectFileName)\r
-                            self._GuidsDb[Guid] = ModuleSectFile\r
-                        except AttributeError:\r
-                            pass\r
-                except AttributeError:\r
-                    pass\r
+            FvDictKey=FvName.upper()\r
+            if FvDictKey in Wa.FdfProfile.FvDict:\r
+                for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
+                    try:\r
+                        #\r
+                        # collect GUID map for binary EFI file in FDF file.\r
+                        #\r
+                        Guid = Ffs.NameGuid.upper()\r
+                        Match = gPcdGuidPattern.match(Ffs.NameGuid)\r
+                        if Match:\r
+                            PcdTokenspace = Match.group(1)\r
+                            PcdToken = Match.group(2)\r
+                            if (PcdToken, PcdTokenspace) in PlatformPcds:\r
+                                GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]\r
+                                Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
+                        for Section in Ffs.SectionList:\r
+                            try:\r
+                                ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)\r
+                                self._GuidsDb[Guid] = ModuleSectFile\r
+                            except AttributeError:\r
+                                pass\r
+                    except AttributeError:\r
+                        pass\r
 \r
 \r
     ##\r
@@ -1169,7 +1694,7 @@ class FdRegionReport(object):
             FvTotalSize = 0\r
             FvTakenSize = 0\r
             FvFreeSize  = 0\r
-            FvReportFileName = os.path.join(self._FvDir, FvName + ".fv.txt")\r
+            FvReportFileName = os.path.join(self._FvDir, FvName + ".Fv.txt")\r
             try:\r
                 #\r
                 # Collect size info in the firmware volume.\r
@@ -1246,6 +1771,35 @@ class FdReport(object):
         self.BaseAddress = Fd.BaseAddress\r
         self.Size = Fd.Size\r
         self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]\r
+        self.FvPath = os.path.join(Wa.BuildDir, "FV")\r
+        self.VpdFilePath = os.path.join(self.FvPath, "%s.map" % Wa.Platform.VpdToolGuid)\r
+        self.VPDBaseAddress = 0\r
+        self.VPDSize = 0\r
+        self.VPDInfoList = []\r
+        for index, FdRegion in enumerate(Fd.RegionList):\r
+            if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):\r
+                self.VPDBaseAddress = self.FdRegionList[index].BaseAddress\r
+                self.VPDSize = self.FdRegionList[index].Size\r
+                break\r
+\r
+        if os.path.isfile(self.VpdFilePath):\r
+            fd = open(self.VpdFilePath, "r")\r
+            Lines = fd.readlines()\r
+            for Line in Lines:\r
+                Line = Line.strip()\r
+                if len(Line) == 0 or Line.startswith("#"):\r
+                    continue\r
+                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
+                    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
+            fd.close()\r
 \r
     ##\r
     # Generate report for the firmware device.\r
@@ -1266,6 +1820,24 @@ class FdReport(object):
             for FdRegionItem in self.FdRegionList:\r
                 FdRegionItem.GenerateReport(File)\r
 \r
+        if len(self.VPDInfoList) > 0:\r
+            FileWrite(File, gSubSectionStart)\r
+            FileWrite(File, "FD VPD Region")\r
+            FileWrite(File, "Base Address:       0x%X" % self.VPDBaseAddress)\r
+            FileWrite(File, "Size:               0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))\r
+            FileWrite(File, gSubSectionSep)\r
+            for item in self.VPDInfoList:\r
+                ValueList = item.split('|')\r
+                Value = ValueList[-1].strip()\r
+                IsByteArray, ArrayList = ByteArrayForamt(Value)\r
+                if IsByteArray:\r
+                    ValueList[-1] = ' {'\r
+                    FileWrite(File, '|'.join(ValueList))\r
+                    for Array in ArrayList:\r
+                        FileWrite(File, '%s' % (Array))\r
+                else:\r
+                    FileWrite(File, item)\r
+            FileWrite(File, gSubSectionEnd)\r
         FileWrite(File, gSectionEnd)\r
 \r
 \r
@@ -1310,6 +1882,10 @@ class PlatformReport(object):
         if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:\r
             self.PredictionReport = PredictionReport(Wa)\r
 \r
+        self.DepexParser = None\r
+        if "DEPEX" in ReportType:\r
+            self.DepexParser = DepexParser(Wa)\r
+            \r
         self.ModuleReportList = []\r
         if MaList != None:\r
             self._IsModuleBuild = True\r
@@ -1318,8 +1894,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
@@ -1333,20 +1922,41 @@ class PlatformReport(object):
     # @param self            The object pointer\r
     # @param File            The file object for report\r
     # @param BuildDuration   The total time to build the modules\r
+    # @param AutoGenTime     The total time of AutoGen Phase\r
+    # @param MakeTime        The total time of Make Phase\r
+    # @param GenFdsTime      The total time of GenFds Phase\r
     # @param ReportType      The kind of report items in the final report file\r
     #\r
-    def GenerateReport(self, File, BuildDuration, ReportType):\r
+    def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):\r
         FileWrite(File, "Platform Summary")\r
         FileWrite(File, "Platform Name:        %s" % self.PlatformName)\r
         FileWrite(File, "Platform DSC Path:    %s" % self.PlatformDscPath)\r
         FileWrite(File, "Architectures:        %s" % self.Architectures)\r
         FileWrite(File, "Tool Chain:           %s" % self.ToolChain)\r
         FileWrite(File, "Target:               %s" % self.Target)\r
+        if GlobalData.gSkuids:\r
+            FileWrite(File, "SKUID:                %s" % " ".join(GlobalData.gSkuids))\r
+        if GlobalData.gDefaultStores:\r
+            FileWrite(File, "DefaultStore:         %s" % " ".join(GlobalData.gDefaultStores))\r
         FileWrite(File, "Output Path:          %s" % self.OutputPath)\r
         FileWrite(File, "Build Environment:    %s" % self.BuildEnvironment)\r
         FileWrite(File, "Build Duration:       %s" % BuildDuration)\r
+        if AutoGenTime:\r
+            FileWrite(File, "AutoGen Duration:     %s" % AutoGenTime)\r
+        if MakeTime:\r
+            FileWrite(File, "Make Duration:        %s" % MakeTime)\r
+        if GenFdsTime:\r
+            FileWrite(File, "GenFds Duration:      %s" % GenFdsTime)\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
@@ -1356,7 +1966,7 @@ class PlatformReport(object):
                     FdReportListItem.GenerateReport(File)\r
 \r
         for ModuleReportItem in self.ModuleReportList:\r
-            ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, ReportType)\r
+            ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)\r
 \r
         if not self._IsModuleBuild:\r
             if "EXECUTION_ORDER" in ReportType:\r
@@ -1389,7 +1999,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
@@ -1411,17 +2021,19 @@ class BuildReport(object):
     #\r
     # @param self            The object pointer\r
     # @param BuildDuration   The total time to build the modules\r
+    # @param AutoGenTime     The total time of AutoGen phase\r
+    # @param MakeTime        The total time of Make phase\r
+    # @param GenFdsTime      The total time of GenFds phase\r
     #\r
-    def GenerateReport(self, BuildDuration):\r
+    def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):\r
         if self.ReportFile:\r
             try:\r
-                File = open(self.ReportFile, "w+")\r
-            except IOError:\r
-                EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=self.ReportFile)\r
-            try:\r
+                File = StringIO('')\r
                 for (Wa, MaList) in self.ReportList:\r
-                    PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, self.ReportType)\r
-                EdkLogger.quiet("Report successfully saved to %s" % os.path.abspath(self.ReportFile))\r
+                    PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)\r
+                Content = FileLinesSplit(File.getvalue(), gLineMaxLength)\r
+                SaveFileOnChange(self.ReportFile, Content, True)\r
+                EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))\r
             except IOError:\r
                 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)\r
             except:\r