summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei')
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c931
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf89
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni17
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni14
4 files changed, 1051 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c
new file mode 100644
index 00000000..ad29affa
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c
@@ -0,0 +1,931 @@
+/** @file
+ Initialize TPM device and measure FVs before handing off control to DXE.
+
+Copyright (c) 2005 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <IndustryStandard/Tpm12.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/FirmwareVolumeInfo2.h>
+#include <Ppi/LockPhysicalPresence.h>
+#include <Ppi/TpmInitialized.h>
+#include <Ppi/FirmwareVolume.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
+#include <Ppi/Tcg.h>
+
+#include <Guid/TcgEventHob.h>
+#include <Guid/MeasuredFvHob.h>
+#include <Guid/TpmInstance.h>
+#include <Guid/MigratedFvInfo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PerformanceLib.h>
+
+BOOLEAN mImageInMemory = FALSE;
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializedPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializationDonePpiGuid,
+ NULL
+};
+
+/**
+ Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
+ and build a GUIDed HOB recording the event which will be passed to the DXE phase and
+ added into the Event Log.
+
+ @param[in] This Indicates the calling context
+ @param[in] Flags Bitmap providing additional information.
+ @param[in] HashData Physical address of the start of the data buffer
+ to be hashed, extended, and logged.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+HashLogExtendEvent (
+ IN EDKII_TCG_PPI *This,
+ IN UINT64 Flags,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLen,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ );
+
+EDKII_TCG_PPI mEdkiiTcgPpi = {
+ HashLogExtendEvent
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTcgPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEdkiiTcgPpiGuid,
+ &mEdkiiTcgPpi
+};
+
+//
+// Number of firmware blobs to grow by each time we run out of room
+//
+#define FIRMWARE_BLOB_GROWTH_STEP 4
+
+EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
+UINT32 mMeasuredMaxBaseFvIndex = 0;
+UINT32 mMeasuredBaseFvIndex = 0;
+
+EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
+UINT32 mMeasuredMaxChildFvIndex = 0;
+UINT32 mMeasuredChildFvIndex = 0;
+
+EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;
+
+/**
+ Lock physical presence if needed.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PhysicalPresencePpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Measure and record the Firmware Volume Information once FvInfoPPI install.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
+ @return Others Fail to measure FV.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolumeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Record all measured Firmware Volume Information into a Guid Hob
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
+ @return Others Fail to measure FV.
+
+**/
+EFI_STATUS
+EFIAPI
+EndofPeiSignalNotifyCallBack (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gPeiLockPhysicalPresencePpiGuid,
+ PhysicalPresencePpiNotifyCallback
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gEfiPeiFirmwareVolumeInfoPpiGuid,
+ FirmwareVolumeInfoPpiNotifyCallback
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gEfiPeiFirmwareVolumeInfo2PpiGuid,
+ FirmwareVolumeInfoPpiNotifyCallback
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ EndofPeiSignalNotifyCallBack
+ }
+};
+
+/**
+ Record all measured Firmware Volume Information into a Guid Hob
+ Guid Hob payload layout is
+
+ UINT32 *************************** FIRMWARE_BLOB number
+ EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
+ @return Others Fail to measure FV.
+
+**/
+EFI_STATUS
+EFIAPI
+EndofPeiSignalNotifyCallBack (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ MEASURED_HOB_DATA *MeasuredHobData;
+
+ MeasuredHobData = NULL;
+
+ PERF_CALLBACK_BEGIN (&gEfiEndOfPeiSignalPpiGuid);
+
+ //
+ // Create a Guid hob to save all measured Fv
+ //
+ MeasuredHobData = BuildGuidHob(
+ &gMeasuredFvHobGuid,
+ sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
+ );
+
+ if (MeasuredHobData != NULL){
+ //
+ // Save measured FV info enty number
+ //
+ MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
+
+ //
+ // Save measured base Fv info
+ //
+ CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
+
+ //
+ // Save measured child Fv info
+ //
+ CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
+ }
+
+ PERF_CALLBACK_END (&gEfiEndOfPeiSignalPpiGuid);
+
+ return EFI_SUCCESS;
+}
+
+/**
+Single function calculates SHA1 digest value for all raw data. It
+combines Sha1Init(), Sha1Update() and Sha1Final().
+
+@param[in] Data Raw data to be digested.
+@param[in] DataLen Size of the raw data.
+@param[out] Digest Pointer to a buffer that stores the final digest.
+
+@retval EFI_SUCCESS Always successfully calculate the final digest.
+**/
+EFI_STATUS
+EFIAPI
+TpmCommHashAll (
+ IN CONST UINT8 *Data,
+ IN UINTN DataLen,
+ OUT TPM_DIGEST *Digest
+ )
+{
+ VOID *Sha1Ctx;
+ UINTN CtxSize;
+
+ CtxSize = Sha1GetContextSize ();
+ Sha1Ctx = AllocatePool (CtxSize);
+ ASSERT (Sha1Ctx != NULL);
+
+ Sha1Init (Sha1Ctx);
+ Sha1Update (Sha1Ctx, Data, DataLen);
+ Sha1Final (Sha1Ctx, (UINT8 *)Digest);
+
+ FreePool (Sha1Ctx);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
+ and build a GUIDed HOB recording the event which will be passed to the DXE phase and
+ added into the Event Log.
+
+ @param[in] This Indicates the calling context.
+ @param[in] Flags Bitmap providing additional information.
+ @param[in] HashData Physical address of the start of the data buffer
+ to be hashed, extended, and logged.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+HashLogExtendEvent (
+ IN EDKII_TCG_PPI *This,
+ IN UINT64 Flags,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLen,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ VOID *HobData;
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ HobData = NULL;
+ if (HashDataLen != 0) {
+ Status = TpmCommHashAll (
+ HashData,
+ HashDataLen,
+ &NewEventHdr->Digest
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ Status = Tpm12Extend (
+ &NewEventHdr->Digest,
+ NewEventHdr->PCRIndex,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ HobData = BuildGuidHob (
+ &gTcgEventEntryHobGuid,
+ sizeof (*NewEventHdr) + NewEventHdr->EventSize
+ );
+ if (HobData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
+ HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
+ CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
+
+Done:
+ if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
+ DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
+ BuildGuidHob (&gTpmErrorHobGuid,0);
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ Status = EFI_DEVICE_ERROR;
+ }
+ return Status;
+}
+
+/**
+ Measure CRTM version.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureCRTMVersion (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+
+ //
+ // Use FirmwareVersion string to represent CRTM version.
+ // OEMs should get real CRTM version string and measure it.
+ //
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_S_CRTM_VERSION;
+ TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
+
+ return HashLogExtendEvent (
+ &mEdkiiTcgPpi,
+ 0,
+ (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
+ TcgEventHdr.EventSize,
+ &TcgEventHdr,
+ (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
+ );
+}
+
+/**
+ Measure FV image.
+ Add it into the measured FV list after the FV is measured successfully.
+
+ @param[in] FvBase Base address of FV image.
+ @param[in] FvLength Length of FV image.
+
+ @retval EFI_SUCCESS Fv image is measured successfully
+ or it has been already measured.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureFvImage (
+ IN EFI_PHYSICAL_ADDRESS FvBase,
+ IN UINT64 FvLength
+ )
+{
+ UINT32 Index;
+ EFI_STATUS Status;
+ EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+ EFI_PHYSICAL_ADDRESS FvOrgBase;
+ EFI_PHYSICAL_ADDRESS FvDataBase;
+ EFI_PEI_HOB_POINTERS Hob;
+ EDKII_MIGRATED_FV_INFO *MigratedFvInfo;
+
+ //
+ // Check if it is in Excluded FV list
+ //
+ if (mMeasurementExcludedFvPpi != NULL) {
+ for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {
+ if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {
+ DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei starts at: 0x%x\n", FvBase));
+ DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei has the size: 0x%x\n", FvLength));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Check whether FV is in the measured FV list.
+ //
+ for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
+ if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Search the matched migration FV info
+ //
+ FvOrgBase = FvBase;
+ FvDataBase = FvBase;
+ Hob.Raw = GetFirstGuidHob (&gEdkiiMigratedFvInfoGuid);
+ while (Hob.Raw != NULL) {
+ MigratedFvInfo = GET_GUID_HOB_DATA (Hob);
+ if ((MigratedFvInfo->FvNewBase == (UINT32) FvBase) && (MigratedFvInfo->FvLength == (UINT32) FvLength)) {
+ //
+ // Found the migrated FV info
+ //
+ FvOrgBase = (EFI_PHYSICAL_ADDRESS) (UINTN) MigratedFvInfo->FvOrgBase;
+ FvDataBase = (EFI_PHYSICAL_ADDRESS) (UINTN) MigratedFvInfo->FvDataBase;
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw);
+ }
+
+ //
+ // Measure and record the FV to the TPM
+ //
+ FvBlob.BlobBase = FvOrgBase;
+ FvBlob.BlobLength = FvLength;
+
+ DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase));
+ DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength));
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
+ TcgEventHdr.EventSize = sizeof (FvBlob);
+
+ Status = HashLogExtendEvent (
+ &mEdkiiTcgPpi,
+ 0,
+ (UINT8*) (UINTN) FvDataBase,
+ (UINTN) FvBlob.BlobLength,
+ &TcgEventHdr,
+ (UINT8*) &FvBlob
+ );
+
+ //
+ // Add new FV into the measured FV list.
+ //
+ if (mMeasuredBaseFvIndex >= mMeasuredMaxBaseFvIndex) {
+ mMeasuredBaseFvInfo = ReallocatePool (
+ sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxBaseFvIndex,
+ sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP),
+ mMeasuredBaseFvInfo
+ );
+ ASSERT (mMeasuredBaseFvInfo != NULL);
+ mMeasuredMaxBaseFvIndex = mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP;
+ }
+
+ mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;
+ mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
+ mMeasuredBaseFvIndex++;
+
+ return Status;
+}
+
+/**
+ Measure main BIOS.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureMainBios (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FvInstances;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_FV_INFO VolumeInfo;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+
+ FvInstances = 0;
+ while (TRUE) {
+ //
+ // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
+ // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
+ // platform for special CRTM TPM measuring.
+ //
+ Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Measure and record the firmware volume that is dispatched by PeiCore
+ //
+ Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Locate the corresponding FV_PPI according to founded FV's format guid
+ //
+ Status = PeiServicesLocatePpi (
+ &VolumeInfo.FvFormat,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
+ }
+
+ FvInstances++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure and record the Firmware Volume Information once FvInfoPPI install.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
+ @return Others Fail to measure FV.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolumeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
+ EFI_STATUS Status;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ UINTN Index;
+
+ Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
+
+ //
+ // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
+ //
+ Status = PeiServicesLocatePpi (
+ &Fv->FvFormat,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This is an FV from an FFS file, and the parent FV must have already been measured,
+ // No need to measure twice, so just record the FV and return
+ //
+ if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
+
+ if (mMeasuredChildFvIndex >= mMeasuredMaxChildFvIndex) {
+ mMeasuredChildFvInfo = ReallocatePool (
+ sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxChildFvIndex,
+ sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP),
+ mMeasuredChildFvInfo
+ );
+ ASSERT (mMeasuredChildFvInfo != NULL);
+ mMeasuredMaxChildFvIndex = mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP;
+ }
+ //
+ // Check whether FV is in the measured child FV list.
+ //
+ for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
+ if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
+ return EFI_SUCCESS;
+ }
+ }
+ mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
+ mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
+ mMeasuredChildFvIndex++;
+ return EFI_SUCCESS;
+ }
+
+ return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
+}
+
+/**
+ Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by corresponding PCDs.
+ And lock physical presence if needed.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_ABORTED physicalPresenceCMDEnable is locked.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+PhysicalPresencePpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ TPM_PERMANENT_FLAGS TpmPermanentFlags;
+ PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi;
+ TPM_PHYSICAL_PRESENCE PhysicalPresenceValue;
+
+ Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 1. Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by PCDs.
+ //
+ if (PcdGetBool (PcdPhysicalPresenceLifetimeLock) && !TpmPermanentFlags.physicalPresenceLifetimeLock) {
+ //
+ // Lock TPM LifetimeLock is required, and LifetimeLock is not locked yet.
+ //
+ PhysicalPresenceValue = TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK;
+ TpmPermanentFlags.physicalPresenceLifetimeLock = TRUE;
+
+ if (PcdGetBool (PcdPhysicalPresenceCmdEnable)) {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_ENABLE;
+ TpmPermanentFlags.physicalPresenceCMDEnable = TRUE;
+ } else {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_DISABLE;
+ TpmPermanentFlags.physicalPresenceCMDEnable = FALSE;
+ }
+
+ if (PcdGetBool (PcdPhysicalPresenceHwEnable)) {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_ENABLE;
+ } else {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_DISABLE;
+ }
+
+ Status = Tpm12PhysicalPresence (
+ PhysicalPresenceValue
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // 2. Lock physical presence if it is required.
+ //
+ LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi;
+ if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!TpmPermanentFlags.physicalPresenceCMDEnable) {
+ if (TpmPermanentFlags.physicalPresenceLifetimeLock) {
+ //
+ // physicalPresenceCMDEnable is locked, can't change.
+ //
+ return EFI_ABORTED;
+ }
+
+ //
+ // Enable physical presence command
+ // It is necessary in order to lock physical presence
+ //
+ Status = Tpm12PhysicalPresence (
+ TPM_PHYSICAL_PRESENCE_CMD_ENABLE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Lock physical presence
+ //
+ Status = Tpm12PhysicalPresence (
+ TPM_PHYSICAL_PRESENCE_LOCK
+ );
+ return Status;
+}
+
+/**
+ Check if TPM chip is activated or not.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval TRUE TPM is activated.
+ @retval FALSE TPM is deactivated.
+
+**/
+BOOLEAN
+IsTpmUsable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TPM_PERMANENT_FLAGS TpmPermanentFlags;
+
+ Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ return (BOOLEAN)(!TpmPermanentFlags.deactivated);
+}
+
+/**
+ Do measurement after memory is ready.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimEntryMP (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
+ 0,
+ NULL,
+ (VOID**)&mMeasurementExcludedFvPpi
+ );
+ // Do not check status, because it is optional
+
+ Status = Tpm12RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (IsTpmUsable ()) {
+ if (PcdGet8 (PcdTpmScrtmPolicy) == 1) {
+ Status = MeasureCRTMVersion (PeiServices);
+ }
+
+ Status = MeasureMainBios (PeiServices);
+ }
+
+ //
+ // Post callbacks:
+ // 1). for the FvInfoPpi services to measure and record
+ // the additional Fvs to TPM
+ // 2). for the OperatorPresencePpi service to determine whether to
+ // lock the TPM
+ //
+ Status = PeiServicesNotifyPpi (&mNotifyList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // install Tcg Services
+ //
+ Status = PeiServicesInstallPpi (&mTcgPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Entry point of this module.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @return Status.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimEntryMA (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+ EFI_BOOT_MODE BootMode;
+
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ DEBUG ((EFI_D_ERROR, "TPM error!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Initialize TPM device
+ //
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // In S3 path, skip shadow logic. no measurement is required
+ //
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ Status = (**PeiServices).RegisterForShadow(FileHandle);
+ if (Status == EFI_ALREADY_STARTED) {
+ mImageInMemory = TRUE;
+ } else if (Status == EFI_NOT_FOUND) {
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ if (!mImageInMemory) {
+ Status = Tpm12RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));
+ goto Done;
+ }
+
+ if (PcdGet8 (PcdTpmInitializationPolicy) == 1) {
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ Status = Tpm12Startup (TPM_ST_STATE);
+ } else {
+ Status = Tpm12Startup (TPM_ST_CLEAR);
+ }
+ if (EFI_ERROR (Status) ) {
+ goto Done;
+ }
+ }
+
+ //
+ // TpmSelfTest is optional on S3 path, skip it to save S3 time
+ //
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ Status = Tpm12ContinueSelfTest ();
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Only install TpmInitializedPpi on success
+ //
+ Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (mImageInMemory) {
+ Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
+ return Status;
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM error! Build Hob\n"));
+ BuildGuidHob (&gTpmErrorHobGuid,0);
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+ //
+ // Always install TpmInitializationDonePpi no matter success or fail.
+ // Other driver can know TPM initialization state by TpmInitializedPpi.
+ //
+ Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
+ ASSERT_EFI_ERROR (Status2);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf
new file mode 100644
index 00000000..32c2c08c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf
@@ -0,0 +1,89 @@
+## @file
+# Initializes TPM device and measures FVs in PEI phase
+#
+# This module will initialize TPM device, measure reported FVs and BIOS version.
+# This module may also lock TPM physical presence and physicalPresenceLifetimeLock.
+#
+# Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgPei
+ MODULE_UNI_FILE = TcgPei.uni
+ FILE_GUID = 2BE1E4A6-6505-43b3-9FFC-A3C8330E0432
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeimEntryMA
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+#
+
+[Sources]
+ TcgPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ HobLib
+ PeimEntryPoint
+ PeiServicesLib
+ BaseMemoryLib
+ DebugLib
+ BaseCryptLib
+ Tpm12DeviceLib
+ TimerLib
+ PeiServicesTablePointerLib
+ BaseLib
+ PcdLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+ Tpm12CommandLib
+ PerformanceLib
+
+[Guids]
+ gTcgEventEntryHobGuid ## PRODUCES ## HOB
+ gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB
+ gMeasuredFvHobGuid ## PRODUCES ## HOB
+ gEfiTpmDeviceInstanceTpm12Guid ## PRODUCES ## GUID # TPM device identifier
+ gEdkiiMigratedFvInfoGuid ## SOMETIMES_CONSUMES ## HOB
+
+[Ppis]
+ gPeiLockPhysicalPresencePpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES
+ gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES
+ gPeiTpmInitializationDonePpiGuid ## PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEdkiiTcgPpiGuid ## PRODUCES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceLifetimeLock ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceCmdEnable ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceHwEnable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmScrtmPolicy ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND
+ gEfiTpmDeviceSelectedGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TcgPeiExtra.uni
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni
new file mode 100644
index 00000000..c7a9dbc9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Initializes TPM device and measures FVs in PEI phase
+//
+// This module will initialize TPM device, measure reported FVs and BIOS version.
+// This module may also lock TPM physical presence and physicalPresenceLifetimeLock.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initializes TPM device and measures FVs in PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will initialize TPM device, measure reported FVs and BIOS version. This module may also lock TPM physical presence and physicalPresenceLifetimeLock."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni
new file mode 100644
index 00000000..c602e1d6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// TcgPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG (Trusted Computing Group) PEI"
+
+