]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Pei / Tcg2Pei.c
index 4ecfbe3b844b1f63006e2307c59f445bc76fc05e..3758fc6a41fbdbb64416d37cc9428503409cb188 100644 (file)
@@ -1,7 +1,8 @@
 /** @file\r
   Initialize TPM2 device and measure FVs before handing off control to DXE.\r
 \r
-Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2017, Microsoft 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
@@ -17,11 +18,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <IndustryStandard/UefiTcgPlatform.h>\r
 #include <Ppi/FirmwareVolumeInfo.h>\r
 #include <Ppi/FirmwareVolumeInfo2.h>\r
-#include <Ppi/LockPhysicalPresence.h>\r
 #include <Ppi/TpmInitialized.h>\r
 #include <Ppi/FirmwareVolume.h>\r
 #include <Ppi/EndOfPeiPhase.h>\r
 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>\r
+#include <Ppi/FirmwareVolumeInfoPrehashedFV.h>\r
 \r
 #include <Guid/TcgEventHob.h>\r
 #include <Guid/MeasuredFvHob.h>\r
@@ -41,7 +42,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/PerformanceLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/ReportStatusCodeLib.h>\r
-#include <Library/Tcg2PhysicalPresenceLib.h>\r
+#include <Library/ResetSystemLib.h>\r
 \r
 #define PERF_ID_TCG2_PEI  0x3080\r
 \r
@@ -132,42 +133,6 @@ EFI_PEI_NOTIFY_DESCRIPTOR           mNotifyList[] = {
   }\r
 };\r
 \r
-EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;\r
-\r
-/**\r
-  This function get digest from digest list.\r
-\r
-  @param HashAlg    digest algorithm\r
-  @param DigestList digest list\r
-  @param Digest     digest\r
-\r
-  @retval EFI_SUCCESS   Sha1Digest is found and returned.\r
-  @retval EFI_NOT_FOUND Sha1Digest is not found.\r
-**/\r
-EFI_STATUS\r
-Tpm2GetDigestFromDigestList (\r
-  IN TPMI_ALG_HASH      HashAlg,\r
-  IN TPML_DIGEST_VALUES *DigestList,\r
-  IN VOID               *Digest\r
-  )\r
-{\r
-  UINTN  Index;\r
-  UINT16 DigestSize;\r
-\r
-  DigestSize = GetHashSizeFromAlgo (HashAlg);\r
-  for (Index = 0; Index < DigestList->count; Index++) {\r
-    if (DigestList->digests[Index].hashAlg == HashAlg) {\r
-      CopyMem (\r
-        Digest,\r
-        &DigestList->digests[Index].digest,\r
-        DigestSize\r
-        );\r
-      return EFI_SUCCESS;\r
-    }\r
-  }\r
-\r
-  return EFI_NOT_FOUND;\r
-}\r
 \r
 /**\r
   Record all measured Firmware Volum Information into a Guid Hob\r
@@ -225,193 +190,87 @@ EndofPeiSignalNotifyCallBack (
 }\r
 \r
 /**\r
-  Check if buffer is all zero.\r
-\r
-  @param[in] Buffer      Buffer to be checked.\r
-  @param[in] BufferSize  Size of buffer to be checked.\r
-\r
-  @retval TRUE  Buffer is all zero.\r
-  @retval FALSE Buffer is not all zero.\r
+  Make sure that the current PCR allocations, the TPM supported PCRs,\r
+  and the PcdTpm2HashMask are all in agreement.\r
 **/\r
-BOOLEAN\r
-IsZeroBuffer (\r
-  IN VOID  *Buffer,\r
-  IN UINTN BufferSize\r
+VOID\r
+SyncPcrAllocationsAndPcrMask (\r
+  VOID\r
   )\r
 {\r
-  UINT8 *BufferData;\r
-  UINTN Index;\r
-\r
-  BufferData = Buffer;\r
-  for (Index = 0; Index < BufferSize; Index++) {\r
-    if (BufferData[Index] != 0) {\r
-      return FALSE;\r
-    }\r
-  }\r
-  return TRUE;\r
-}\r
+  EFI_STATUS                        Status;\r
+  EFI_TCG2_EVENT_ALGORITHM_BITMAP   TpmHashAlgorithmBitmap;\r
+  UINT32                            TpmActivePcrBanks;\r
+  UINT32                            NewTpmActivePcrBanks;\r
+  UINT32                            Tpm2PcrMask;\r
+  UINT32                            NewTpm2PcrMask;\r
 \r
-/**\r
-  Get TPML_DIGEST_VALUES data size.\r
+  DEBUG ((EFI_D_ERROR, "SyncPcrAllocationsAndPcrMask!\n"));\r
 \r
-  @param[in]     DigestList    TPML_DIGEST_VALUES data.\r
+  //\r
+  // Determine the current TPM support and the Platform PCR mask.\r
+  //\r
+  Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &TpmActivePcrBanks);\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
-  @return TPML_DIGEST_VALUES data size.\r
-**/\r
-UINT32\r
-GetDigestListSize (\r
-  IN TPML_DIGEST_VALUES             *DigestList\r
-  )\r
-{\r
-  UINTN  Index;\r
-  UINT16 DigestSize;\r
-  UINT32 TotalSize;\r
-\r
-  TotalSize = sizeof(DigestList->count);\r
-  for (Index = 0; Index < DigestList->count; Index++) {\r
-    DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);\r
-    TotalSize += sizeof(DigestList->digests[Index].hashAlg) + DigestSize;\r
+  Tpm2PcrMask = PcdGet32 (PcdTpm2HashMask);\r
+  if (Tpm2PcrMask == 0) {\r
+    //\r
+    // if PcdTPm2HashMask is zero, use ActivePcr setting\r
+    //\r
+    PcdSet32S (PcdTpm2HashMask, TpmActivePcrBanks);\r
+    Tpm2PcrMask = TpmActivePcrBanks;\r
   }\r
 \r
-  return TotalSize;\r
-}\r
-\r
-/**\r
-  Return if hash alg is supported in TPM PCR bank.\r
-\r
-  @param HashAlg  Hash algorithm to be checked.\r
-\r
-  @retval TRUE  Hash algorithm is supported.\r
-  @retval FALSE Hash algorithm is not supported.\r
-**/\r
-BOOLEAN\r
-IsHashAlgSupportedInPcrBank (\r
-  IN TPMI_ALG_HASH  HashAlg\r
-  )\r
-{\r
-  UINT32  ActivePcrBanks;\r
+  //\r
+  // Find the intersection of Pcd support and TPM support.\r
+  // If banks are missing from the TPM support that are in the PCD, update the PCD.\r
+  // If banks are missing from the PCD that are active in the TPM, reallocate the banks and reboot.\r
+  //\r
 \r
-  ActivePcrBanks = PcdGet32 (PcdTpm2HashMask);\r
-  switch (HashAlg) {\r
-  case TPM_ALG_SHA1:\r
-    if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {\r
-      return TRUE;\r
-    }\r
-    break;\r
-  case TPM_ALG_SHA256:\r
-    if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {\r
-      return TRUE;\r
-    }\r
-    break;\r
-  case TPM_ALG_SHA384:\r
-    if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {\r
-      return TRUE;\r
-    }\r
-    break;\r
-  case TPM_ALG_SHA512:\r
-    if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {\r
-      return TRUE;\r
-    }\r
-    break;\r
-  case TPM_ALG_SM3_256:\r
-    if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {\r
-      return TRUE;\r
+  //\r
+  // If there are active PCR banks that are not supported by the Platform mask,\r
+  // update the TPM allocations and reboot the machine.\r
+  //\r
+  if ((TpmActivePcrBanks & Tpm2PcrMask) != TpmActivePcrBanks) {\r
+    NewTpmActivePcrBanks = TpmActivePcrBanks & Tpm2PcrMask;\r
+\r
+    DEBUG ((EFI_D_INFO, "%a - Reallocating PCR banks from 0x%X to 0x%X.\n", __FUNCTION__, TpmActivePcrBanks, NewTpmActivePcrBanks));\r
+    if (NewTpmActivePcrBanks == 0) {\r
+      DEBUG ((EFI_D_ERROR, "%a - No viable PCRs active! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));\r
+      ASSERT (FALSE);\r
+    } else {\r
+      Status = Tpm2PcrAllocateBanks (NULL, (UINT32)TpmHashAlgorithmBitmap, NewTpmActivePcrBanks);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // We can't do much here, but we hope that this doesn't happen.\r
+        //\r
+        DEBUG ((EFI_D_ERROR, "%a - Failed to reallocate PCRs!\n", __FUNCTION__));\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+      //\r
+      // Need reset system, since we just called Tpm2PcrAllocateBanks().\r
+      //\r
+      ResetCold();\r
     }\r
-    break;\r
   }\r
 \r
-  return FALSE;\r
-}\r
-\r
-/**\r
-  Copy TPML_DIGEST_VALUES into a buffer\r
-\r
-  @param[in,out] Buffer        Buffer to hold TPML_DIGEST_VALUES.\r
-  @param[in]     DigestList    TPML_DIGEST_VALUES to be copied.\r
+  //\r
+  // If there are any PCRs that claim support in the Platform mask that are\r
+  // not supported by the TPM, update the mask.\r
+  //\r
+  if ((Tpm2PcrMask & TpmHashAlgorithmBitmap) != Tpm2PcrMask) {\r
+    NewTpm2PcrMask = Tpm2PcrMask & TpmHashAlgorithmBitmap;\r
 \r
-  @return The end of buffer to hold TPML_DIGEST_VALUES.\r
-**/\r
-VOID *\r
-CopyDigestListToBuffer (\r
-  IN OUT VOID                       *Buffer,\r
-  IN TPML_DIGEST_VALUES             *DigestList\r
-  )\r
-{\r
-  UINTN  Index;\r
-  UINT16 DigestSize;\r
-\r
-  CopyMem (Buffer, &DigestList->count, sizeof(DigestList->count));\r
-  Buffer = (UINT8 *)Buffer + sizeof(DigestList->count);\r
-  for (Index = 0; Index < DigestList->count; Index++) {\r
-    if (!IsHashAlgSupportedInPcrBank (DigestList->digests[Index].hashAlg)) {\r
-      DEBUG ((EFI_D_ERROR, "WARNING: TPM2 Event log has HashAlg unsupported by PCR bank (0x%x)\n", DigestList->digests[Index].hashAlg));\r
-      continue;\r
+    DEBUG ((EFI_D_INFO, "%a - Updating PcdTpm2HashMask from 0x%X to 0x%X.\n", __FUNCTION__, Tpm2PcrMask, NewTpm2PcrMask));\r
+    if (NewTpm2PcrMask == 0) {\r
+      DEBUG ((EFI_D_ERROR, "%a - No viable PCRs supported! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));\r
+      ASSERT (FALSE);\r
     }\r
-    CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof(DigestList->digests[Index].hashAlg));\r
-    Buffer = (UINT8 *)Buffer + sizeof(DigestList->digests[Index].hashAlg);\r
-    DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);\r
-    CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize);\r
-    Buffer = (UINT8 *)Buffer + DigestSize;\r
-  }\r
-\r
-  return Buffer;\r
-}\r
-\r
-/**\r
-  Set Tpm2HashMask PCD value accroding to TPM2 PCR bank.\r
-**/\r
-VOID\r
-SetTpm2HashMask (\r
-  VOID\r
-  )\r
-{\r
-  EFI_STATUS           Status;\r
-  UINT32               ActivePcrBanks;\r
-  TPML_PCR_SELECTION   Pcrs;\r
-  UINTN                Index;\r
-\r
-  DEBUG ((EFI_D_ERROR, "SetTpm2HashMask!\n"));\r
 \r
-  Status = Tpm2GetCapabilityPcrs (&Pcrs);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n"));\r
-    ActivePcrBanks = EFI_TCG2_BOOT_HASH_ALG_SHA1;\r
-  } else {\r
-    DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count));\r
-    ActivePcrBanks = 0;\r
-    for (Index = 0; Index < Pcrs.count; Index++) {\r
-      DEBUG ((EFI_D_INFO, "hash - %x\n", Pcrs.pcrSelections[Index].hash));\r
-      switch (Pcrs.pcrSelections[Index].hash) {\r
-      case TPM_ALG_SHA1:\r
-        if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {\r
-          ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA1;\r
-        }        \r
-        break;\r
-      case TPM_ALG_SHA256:\r
-        if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {\r
-          ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA256;\r
-        }\r
-        break;\r
-      case TPM_ALG_SHA384:\r
-        if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {\r
-          ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA384;\r
-        }\r
-        break;\r
-      case TPM_ALG_SHA512:\r
-        if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {\r
-          ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA512;\r
-        }\r
-        break;\r
-      case TPM_ALG_SM3_256:\r
-        if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {\r
-          ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SM3_256;\r
-        }\r
-        break;\r
-      }\r
-    }\r
+    Status = PcdSet32S (PcdTpm2HashMask, NewTpm2PcrMask);\r
+    ASSERT_EFI_ERROR (Status);\r
   }\r
-  Status = PcdSet32S (PcdTpm2HashMask, ActivePcrBanks);\r
-  ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
 /**\r
@@ -447,7 +306,7 @@ LogHashEvent (
       DEBUG ((EFI_D_INFO, "  LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat));\r
       switch (mTcg2EventInfo[Index].LogFormat) {\r
       case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:\r
-        Status = Tpm2GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);\r
+        Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);\r
         if (!EFI_ERROR (Status)) {\r
           HobData = BuildGuidHob (\r
                      &gTcgEventEntryHobGuid,\r
@@ -464,6 +323,10 @@ LogHashEvent (
         }\r
         break;\r
       case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:\r
+        //\r
+        // Use GetDigestListSize (DigestList) in the GUID HOB DataLength calculation\r
+        // to reserve enough buffer to hold TPML_DIGEST_VALUES compact binary.\r
+        //\r
         HobData = BuildGuidHob (\r
                    &gTcgEvent2EntryHobGuid,\r
                    sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize\r
@@ -477,7 +340,7 @@ LogHashEvent (
         TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex;\r
         TcgPcrEvent2->EventType = NewEventHdr->EventType;\r
         DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest;\r
-        DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList);\r
+        DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList, PcdGet32 (PcdTpm2HashMask));\r
         CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize));\r
         DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);\r
         CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize);\r
@@ -598,59 +461,158 @@ MeasureFvImage (
   IN UINT64                         FvLength\r
   )\r
 {\r
-  UINT32                            Index;\r
-  EFI_STATUS                        Status;\r
-  EFI_PLATFORM_FIRMWARE_BLOB        FvBlob;\r
-  TCG_PCR_EVENT_HDR                 TcgEventHdr;\r
+  UINT32                                                Index;\r
+  EFI_STATUS                                            Status;\r
+  EFI_PLATFORM_FIRMWARE_BLOB                            FvBlob;\r
+  TCG_PCR_EVENT_HDR                                     TcgEventHdr;\r
+  UINT32                                                Instance;\r
+  UINT32                                                Tpm2HashMask;\r
+  TPML_DIGEST_VALUES                                    DigestList;\r
+  UINT32                                                DigestCount;\r
+  EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *MeasurementExcludedFvPpi;\r
+  EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI       *PrehashedFvPpi;\r
+  HASH_INFO                                             *PreHashInfo;\r
+  UINT32                                                HashAlgoMask;\r
 \r
   //\r
-  // Check if it is in Excluded FV list\r
+  // Check Excluded FV list\r
   //\r
-  if (mMeasurementExcludedFvPpi != NULL) {\r
-    for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {\r
-      if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {\r
-        DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));\r
-        DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));\r
-        return EFI_SUCCESS;\r
+  Instance = 0;\r
+  do {\r
+    Status = PeiServicesLocatePpi(\r
+                 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,\r
+                 Instance,\r
+                 NULL,\r
+                 (VOID**)&MeasurementExcludedFvPpi\r
+                 );\r
+    if (!EFI_ERROR(Status)) {\r
+      for (Index = 0; Index < MeasurementExcludedFvPpi->Count; Index ++) {\r
+        if (MeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase\r
+         && MeasurementExcludedFvPpi->Fv[Index].FvLength == FvLength) {\r
+          DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));\r
+          DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));\r
+          return EFI_SUCCESS;\r
+        }\r
       }\r
+\r
+      Instance++;\r
     }\r
-  }\r
+  } while (!EFI_ERROR(Status));\r
 \r
   //\r
-  // Check whether FV is in the measured FV list.\r
+  // Check measured FV list\r
   //\r
   for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {\r
-    if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {\r
+    if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase && mMeasuredBaseFvInfo[Index].BlobLength == FvLength) {\r
+      DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei starts at: 0x%x\n", FvBase));\r
+      DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei has the size: 0x%x\n", FvLength));\r
       return EFI_SUCCESS;\r
     }\r
   }\r
-  \r
+\r
   //\r
-  // Measure and record the FV to the TPM\r
+  // Check pre-hashed FV list\r
   //\r
-  FvBlob.BlobBase   = FvBase;\r
-  FvBlob.BlobLength = FvLength;\r
+  Instance     = 0;\r
+  Tpm2HashMask = PcdGet32 (PcdTpm2HashMask);\r
+  do {\r
+    Status = PeiServicesLocatePpi (\r
+               &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid,\r
+               Instance,\r
+               NULL,\r
+               (VOID**)&PrehashedFvPpi\r
+               );\r
+    if (!EFI_ERROR(Status) && PrehashedFvPpi->FvBase == FvBase && PrehashedFvPpi->FvLength == FvLength) {\r
+      ZeroMem (&DigestList, sizeof(TPML_DIGEST_VALUES));\r
+\r
+      //\r
+      // The FV is prehashed, check against TPM hash mask\r
+      //\r
+      PreHashInfo = (HASH_INFO *)(PrehashedFvPpi + 1);\r
+      for (Index = 0, DigestCount = 0; Index < PrehashedFvPpi->Count; Index++) {\r
+        DEBUG((DEBUG_INFO, "Hash Algo ID in PrehashedFvPpi=0x%x\n", PreHashInfo->HashAlgoId));\r
+        HashAlgoMask = GetHashMaskFromAlgo(PreHashInfo->HashAlgoId);\r
+        if ((Tpm2HashMask & HashAlgoMask) != 0 ) {\r
+          //\r
+          // Hash is required, copy it to DigestList\r
+          //\r
+          WriteUnaligned16(&(DigestList.digests[DigestCount].hashAlg), PreHashInfo->HashAlgoId);\r
+          CopyMem (\r
+            &DigestList.digests[DigestCount].digest,\r
+            PreHashInfo + 1,\r
+            PreHashInfo->HashSize\r
+            );\r
+          DigestCount++;\r
+          //\r
+          // Clean the corresponding Hash Algo mask bit\r
+          //\r
+          Tpm2HashMask &= ~HashAlgoMask;\r
+        }\r
+        PreHashInfo = (HASH_INFO *)((UINT8 *)(PreHashInfo + 1) + PreHashInfo->HashSize);\r
+      }\r
+\r
+      WriteUnaligned32(&DigestList.count, DigestCount);\r
 \r
-  DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));\r
-  DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));\r
+      break;\r
+    }\r
+    Instance++;\r
+  } while (!EFI_ERROR(Status));\r
 \r
-  TcgEventHdr.PCRIndex = 0;\r
+  //\r
+  // Init the log event for FV measurement\r
+  //\r
+  FvBlob.BlobBase       = FvBase;\r
+  FvBlob.BlobLength     = FvLength;\r
+  TcgEventHdr.PCRIndex  = 0;\r
   TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;\r
   TcgEventHdr.EventSize = sizeof (FvBlob);\r
 \r
-  Status = HashLogExtendEvent (\r
-             0,\r
-             (UINT8*) (UINTN) FvBlob.BlobBase,\r
-             (UINTN) FvBlob.BlobLength,\r
-             &TcgEventHdr,\r
-             (UINT8*) &FvBlob\r
-             );\r
+  if (Tpm2HashMask == 0) {\r
+    //\r
+    // FV pre-hash algos comply with current TPM hash requirement\r
+    // Skip hashing step in measure, only extend DigestList to PCR and log event\r
+    //\r
+    Status = Tpm2PcrExtend(\r
+               0,\r
+               &DigestList\r
+               );\r
+\r
+    if (!EFI_ERROR(Status)) {\r
+       Status = LogHashEvent (&DigestList, &TcgEventHdr, (UINT8*) &FvBlob);\r
+       DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));\r
+       DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));\r
+    } else if (Status == EFI_DEVICE_ERROR) {\r
+      BuildGuidHob (&gTpmErrorHobGuid,0);\r
+      REPORT_STATUS_CODE (\r
+        EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+        (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
+        );\r
+    }\r
+  } else {\r
+    //\r
+    // Hash the FV, extend digest to the TPM and log TCG event\r
+    //\r
+    Status = HashLogExtendEvent (\r
+               0,\r
+               (UINT8*) (UINTN) FvBlob.BlobBase,\r
+               (UINTN) FvBlob.BlobLength,\r
+               &TcgEventHdr,\r
+               (UINT8*) &FvBlob\r
+               );\r
+    DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));\r
+    DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));\r
+  }\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase));\r
+    return Status;\r
+  }\r
 \r
   //\r
   // Add new FV into the measured FV list.\r
   //\r
-  ASSERT (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));\r
-  if (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
+  ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));\r
+  if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
     mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase   = FvBase;\r
     mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;\r
     mMeasuredBaseFvIndex++;\r
@@ -673,47 +635,44 @@ MeasureMainBios (
   )\r
 {\r
   EFI_STATUS                        Status;\r
-  UINT32                            FvInstances;\r
   EFI_PEI_FV_HANDLE                 VolumeHandle;\r
   EFI_FV_INFO                       VolumeInfo;\r
   EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;\r
 \r
   PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);\r
-  FvInstances    = 0;\r
-  while (TRUE) {\r
-    //\r
-    // Traverse all firmware volume instances of Static Core Root of Trust for Measurement\r
-    // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special\r
-    // platform for special CRTM TPM measuring.\r
-    //\r
-    Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);\r
-    if (EFI_ERROR (Status)) {\r
-      break;\r
-    }\r
-  \r
-    //\r
-    // Measure and record the firmware volume that is dispatched by PeiCore\r
-    //\r
-    Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
-    ASSERT_EFI_ERROR (Status);\r
-    //\r
-    // Locate the corresponding FV_PPI according to founded FV's format guid\r
-    //\r
-    Status = PeiServicesLocatePpi (\r
-               &VolumeInfo.FvFormat, \r
-               0, \r
-               NULL,\r
-               (VOID**)&FvPpi\r
-               );\r
-    if (!EFI_ERROR (Status)) {\r
-      MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);\r
-    }\r
 \r
-    FvInstances++;\r
-  }\r
+  //\r
+  // Only measure BFV at the very beginning. Other parts of Static Core Root of\r
+  // Trust for Measurement(S-CRTM) will be measured later on FvInfoNotify.\r
+  // BFV is processed without installing FV Info Ppi. Other FVs either inside BFV or\r
+  // reported by platform will be installed with Fv Info Ppi\r
+  // This firmware volume measure policy can be modified/enhanced by special\r
+  // platform for special CRTM TPM measuring.\r
+  //\r
+  Status = PeiServicesFfsFindNextVolume (0, &VolumeHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Measure and record the firmware volume that is dispatched by PeiCore\r
+  //\r
+  Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Locate the corresponding FV_PPI according to founded FV's format guid\r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &VolumeInfo.FvFormat,\r
+             0,\r
+             NULL,\r
+             (VOID**)&FvPpi\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);\r
+\r
   PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -761,8 +720,8 @@ FirmwareVolmeInfoPpiNotifyCallback (
   //\r
   if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {\r
     \r
-    ASSERT (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));\r
-    if (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
+    ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));\r
+    if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
       //\r
       // Check whether FV is in the measured child FV list.\r
       //\r
@@ -798,14 +757,6 @@ PeimEntryMP (
 {\r
   EFI_STATUS                        Status;\r
 \r
-  Status = PeiServicesLocatePpi (\r
-               &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, \r
-               0, \r
-               NULL,\r
-               (VOID**)&mMeasurementExcludedFvPpi\r
-               );\r
-  // Do not check status, because it is optional\r
-\r
   mMeasuredBaseFvInfo  = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
   ASSERT (mMeasuredBaseFvInfo != NULL);\r
   mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
@@ -816,6 +767,9 @@ PeimEntryMP (
   }\r
 \r
   Status = MeasureMainBios ();\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
 \r
   //\r
   // Post callbacks:\r
@@ -828,6 +782,33 @@ PeimEntryMP (
   return Status;\r
 }\r
 \r
+/**\r
+  Measure and log Separator event with error, and extend the measurement result into a specific PCR.\r
+\r
+  @param[in] PCRIndex         PCR index.  \r
+\r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+MeasureSeparatorEventWithError (\r
+  IN      TPM_PCRINDEX              PCRIndex\r
+  )\r
+{\r
+  TCG_PCR_EVENT_HDR                 TcgEvent;\r
+  UINT32                            EventData;\r
+\r
+  //\r
+  // Use EventData 0x1 to indicate there is error.\r
+  //\r
+  EventData = 0x1;\r
+  TcgEvent.PCRIndex  = PCRIndex;\r
+  TcgEvent.EventType = EV_SEPARATOR;\r
+  TcgEvent.EventSize = (UINT32)sizeof (EventData);\r
+  return HashLogExtendEvent(0,(UINT8 *)&EventData, TcgEvent.EventSize, &TcgEvent,(UINT8 *)&EventData);\r
+}\r
+\r
 /**\r
   Entry point of this module.\r
 \r
@@ -847,10 +828,12 @@ PeimEntryMA (
   EFI_STATUS                        Status;\r
   EFI_STATUS                        Status2;\r
   EFI_BOOT_MODE                     BootMode;\r
+  TPM_PCRINDEX                      PcrIndex;\r
+  BOOLEAN                           S3ErrorReport;\r
 \r
   if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||\r
       CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){\r
-    DEBUG ((EFI_D_ERROR, "No TPM2 instance required!\n"));\r
+    DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n"));\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -885,11 +868,15 @@ PeimEntryMA (
       goto Done;\r
     }\r
 \r
+    S3ErrorReport = FALSE;\r
     if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {\r
       if (BootMode == BOOT_ON_S3_RESUME) {\r
         Status = Tpm2Startup (TPM_SU_STATE);\r
         if (EFI_ERROR (Status) ) {\r
           Status = Tpm2Startup (TPM_SU_CLEAR);\r
+          if (!EFI_ERROR(Status)) {\r
+            S3ErrorReport = TRUE;\r
+          }\r
         }\r
       } else {\r
         Status = Tpm2Startup (TPM_SU_CLEAR);\r
@@ -902,7 +889,24 @@ PeimEntryMA (
     //\r
     // Update Tpm2HashMask according to PCR bank.\r
     //\r
-    SetTpm2HashMask ();\r
+    SyncPcrAllocationsAndPcrMask ();\r
+\r
+    if (S3ErrorReport) {\r
+      //\r
+      // The system firmware that resumes from S3 MUST deal with a\r
+      // TPM2_Startup error appropriately.\r
+      // For example, issue a TPM2_Startup(TPM_SU_CLEAR) command and\r
+      // configuring the device securely by taking actions like extending a\r
+      // separator with an error digest (0x01) into PCRs 0 through 7.\r
+      //\r
+      for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {\r
+        Status = MeasureSeparatorEventWithError (PcrIndex);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Separator Event with Error not Measured. Error!\n"));\r
+        }\r
+      }\r
+    }\r
+\r
     //\r
     // TpmSelfTest is optional on S3 path, skip it to save S3 time\r
     //\r