From 0c18794ea4289f03fefc7117b56740414cc0536c Mon Sep 17 00:00:00 2001 From: gdong1 Date: Fri, 2 Sep 2011 07:49:32 +0000 Subject: Add security package to repository. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12261 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Tcg/TcgPei/TcgPei.c | 593 ++++++++++++++++++++++++++++++++++++++ SecurityPkg/Tcg/TcgPei/TcgPei.inf | 67 +++++ SecurityPkg/Tcg/TcgPei/TisPei.c | 160 ++++++++++ SecurityPkg/Tcg/TcgPei/TpmComm.c | 272 +++++++++++++++++ SecurityPkg/Tcg/TcgPei/TpmComm.h | 163 +++++++++++ 5 files changed, 1255 insertions(+) create mode 100644 SecurityPkg/Tcg/TcgPei/TcgPei.c create mode 100644 SecurityPkg/Tcg/TcgPei/TcgPei.inf create mode 100644 SecurityPkg/Tcg/TcgPei/TisPei.c create mode 100644 SecurityPkg/Tcg/TcgPei/TpmComm.c create mode 100644 SecurityPkg/Tcg/TcgPei/TpmComm.h (limited to 'SecurityPkg/Tcg/TcgPei') diff --git a/SecurityPkg/Tcg/TcgPei/TcgPei.c b/SecurityPkg/Tcg/TcgPei/TcgPei.c new file mode 100644 index 0000000000..63caddec8c --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TcgPei.c @@ -0,0 +1,593 @@ +/** @file + Initialize TPM device and measure FVs before handing off control to DXE. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TpmComm.h" + +BOOLEAN mImageInMemory = FALSE; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializedPpiGuid, + NULL +}; + +/** + 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 Volum 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 +FirmwareVolmeInfoPpiNotifyCallback ( + 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 | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiFirmwareVolumeInfoPpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + } +}; + +CHAR8 mSCrtmVersion[] = "{D20BC7C6-A1A5-415c-AE85-38290AB6BE04}"; + +EFI_PLATFORM_FIRMWARE_BLOB mMeasuredFvInfo[FixedPcdGet32 (PcdPeiCoreMaxFvSupported)]; +UINT32 mMeasuredFvIndex = 0; + +/** + 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] PeiServices Describes the list of possible PEI Services. + @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] TpmHandle TPM handle. + @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 +HashLogExtendEvent ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 *HashData, + IN UINTN HashDataLen, + IN TIS_TPM_HANDLE TpmHandle, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + VOID *HobData; + + HobData = NULL; + if (HashDataLen != 0) { + Status = TpmCommHashAll ( + HashData, + HashDataLen, + &NewEventHdr->Digest + ); + ASSERT_EFI_ERROR (Status); + } + + Status = TpmCommExtend ( + PeiServices, + TpmHandle, + &NewEventHdr->Digest, + NewEventHdr->PCRIndex, + NULL + ); + ASSERT_EFI_ERROR (Status); + + HobData = BuildGuidHob ( + &gTcgEventEntryHobGuid, + sizeof (*NewEventHdr) + NewEventHdr->EventSize + ); + if (HobData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr)); + HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr)); + CopyMem (HobData, NewEventData, NewEventHdr->EventSize); + return EFI_SUCCESS; +} + +/** + Measure CRTM version. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @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, + IN TIS_TPM_HANDLE TpmHandle + ) +{ + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Here, only a static GUID is measured instead of real CRTM version. + // OEMs should get real CRTM version string and measure it. + // + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_S_CRTM_VERSION; + TcgEventHdr.EventSize = sizeof (mSCrtmVersion); + return HashLogExtendEvent ( + PeiServices, + (UINT8*)&mSCrtmVersion, + TcgEventHdr.EventSize, + TpmHandle, + &TcgEventHdr, + (UINT8*)&mSCrtmVersion + ); +} + +/** + 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; + TIS_TPM_HANDLE TpmHandle; + + TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS; + + // + // Check whether FV is in the measured FV list. + // + for (Index = 0; Index < mMeasuredFvIndex; Index ++) { + if (mMeasuredFvInfo[Index].BlobBase == FvBase) { + return EFI_SUCCESS; + } + } + + // + // Measure and record the FV to the TPM + // + FvBlob.BlobBase = FvBase; + 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 ( + (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(), + (UINT8*) (UINTN) FvBlob.BlobBase, + (UINTN) FvBlob.BlobLength, + TpmHandle, + &TcgEventHdr, + (UINT8*) &FvBlob + ); + ASSERT_EFI_ERROR (Status); + + // + // Add new FV into the measured FV list. + // + ASSERT (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) { + mMeasuredFvInfo[mMeasuredFvIndex].BlobBase = FvBase; + mMeasuredFvInfo[mMeasuredFvIndex++].BlobLength = FvLength; + } + + return Status; +} + +/** + Measure main BIOS. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @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, + IN TIS_TPM_HANDLE TpmHandle + ) +{ + 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 Volum 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 +FirmwareVolmeInfoPpiNotifyCallback ( + 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; + + 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 returns + // + if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) { + return EFI_SUCCESS; + } + + return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize); +} + +/** + 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; + PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi; + BOOLEAN LifetimeLock; + BOOLEAN CmdEnable; + TIS_TPM_HANDLE TpmHandle; + + TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS; + LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi; + + if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) { + return EFI_SUCCESS; + } + + // + // Lock TPM physical presence. + // + + Status = TpmCommGetCapability (PeiServices, TpmHandle, NULL, &LifetimeLock, &CmdEnable); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!CmdEnable) { + if (LifetimeLock) { + // + // physicalPresenceCMDEnable is locked, can't change. + // + return EFI_ABORTED; + } + + // + // Enable physical presence command + // It is necessary in order to lock physical presence + // + Status = TpmCommPhysicalPresence ( + PeiServices, + TpmHandle, + TPM_PHYSICAL_PRESENCE_CMD_ENABLE + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Lock physical presence + // + Status = TpmCommPhysicalPresence ( + PeiServices, + TpmHandle, + TPM_PHYSICAL_PRESENCE_LOCK + ); + return Status; +} + +/** + Check if TPM chip is activeated or not. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @retval TRUE TPM is activated. + @retval FALSE TPM is deactivated. + +**/ +BOOLEAN +EFIAPI +IsTpmUsable ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle + ) +{ + EFI_STATUS Status; + BOOLEAN Deactivated; + + Status = TpmCommGetCapability (PeiServices, TpmHandle, &Deactivated, NULL, NULL); + if (EFI_ERROR (Status)) { + return FALSE; + } + return (BOOLEAN)(!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; + TIS_TPM_HANDLE TpmHandle; + + TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS; + Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsTpmUsable (PeiServices, TpmHandle)) { + Status = MeasureCRTMVersion (PeiServices, TpmHandle); + ASSERT_EFI_ERROR (Status); + + Status = MeasureMainBios (PeiServices, TpmHandle); + } + + // + // 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); + + 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_BOOT_MODE BootMode; + TIS_TPM_HANDLE TpmHandle; + + if (PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm)) { + return EFI_UNSUPPORTED; + } + + Status = (**PeiServices).RegisterForShadow(FileHandle); + if (Status == EFI_ALREADY_STARTED) { + mImageInMemory = TRUE; + } else if (Status == EFI_NOT_FOUND) { + ASSERT_EFI_ERROR (Status); + } + + if (!mImageInMemory) { + // + // Initialize TPM device + // + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS; + Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "TPM not detected!\n")); + return Status; + } + + Status = TpmCommStartup ((EFI_PEI_SERVICES**)PeiServices, TpmHandle, BootMode); + if (EFI_ERROR (Status) ) { + return Status; + } + Status = TpmCommContinueSelfTest ((EFI_PEI_SERVICES**)PeiServices, TpmHandle); + if (EFI_ERROR (Status)) { + return Status; + } + Status = PeiServicesInstallPpi (&mTpmInitializedPpiList); + ASSERT_EFI_ERROR (Status); + } + + if (mImageInMemory) { + Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return Status; +} diff --git a/SecurityPkg/Tcg/TcgPei/TcgPei.inf b/SecurityPkg/Tcg/TcgPei/TcgPei.inf new file mode 100644 index 0000000000..60a3bfa5f1 --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TcgPei.inf @@ -0,0 +1,67 @@ +## @file +# This module will initialize TPM device and measure FVs in PEI phase. +# +# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgPei + 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 IPF EBC +# + +[Sources] + TcgPei.c + TisPei.c + TpmComm.c + TpmComm.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + HobLib + PeimEntryPoint + PeiServicesLib + BaseMemoryLib + DebugLib + TpmCommLib + TimerLib + IoLib + PeiServicesTablePointerLib + +[Guids] + gTcgEventEntryHobGuid + +[Ppis] + gPeiLockPhysicalPresencePpiGuid + gEfiPeiFirmwareVolumeInfoPpiGuid + gPeiTpmInitializedPpiGuid + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm + +[FixedPcd] + gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport + gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid diff --git a/SecurityPkg/Tcg/TcgPei/TisPei.c b/SecurityPkg/Tcg/TcgPei/TisPei.c new file mode 100644 index 0000000000..97d9628bda --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TisPei.c @@ -0,0 +1,160 @@ +/** @file + TIS (TPM Interface Specification) functions used by TPM PEI driver. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +/** + Send a command to TPM for execution and return response data. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TisReg TPM register space base address. + @param[in] BufferIn Buffer for command data. + @param[in] SizeIn Size of command data. + @param[in, out] BufferOut Buffer for response data. + @param[in, out] SizeOut Size of response data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TisTpmCommand ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_PC_REGISTERS_PTR TisReg, + IN UINT8 *BufferIn, + IN UINT32 SizeIn, + IN OUT UINT8 *BufferOut, + IN OUT UINT32 *SizeOut + ) +{ + EFI_STATUS Status; + UINT16 BurstCount; + UINT32 Index; + UINT32 TpmOutSize; + UINT16 Data16; + UINT32 Data32; + + Status = TisPcPrepareCommand (TisReg); + if (EFI_ERROR (Status)){ + DEBUG ((DEBUG_ERROR, "Tpm is not ready for command!\n")); + return Status; + } + // + // Send the command data to Tpm + // + Index = 0; + while (Index < SizeIn) { + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + goto Exit; + } + for (; BurstCount > 0 && Index < SizeIn; BurstCount--) { + MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index)); + Index++; + } + } + // + // Check the Tpm status STS_EXPECT change from 1 to 0 + // + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) TIS_PC_VALID, + TIS_PC_STS_EXPECT, + TIS_TIMEOUT_C + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "The send buffer too small!\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Exit; + } + // + // Executed the TPM command and waiting for the response data ready + // + MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO); + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA), + 0, + TIS_TIMEOUT_B + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Wait for Tpm response data time out!!\n")); + Status = EFI_TIMEOUT; + goto Exit; + } + // + // Get response data header + // + Index = 0; + BurstCount = 0; + while (Index < sizeof (TPM_RSP_COMMAND_HDR)) { + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + goto Exit; + } + for (; BurstCount > 0; BurstCount--) { + *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo); + Index++; + if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break; + } + } + // + // Check the reponse data header (tag,parasize and returncode ) + // + CopyMem (&Data16, BufferOut, sizeof (UINT16)); + if (SwapBytes16 (Data16) != TPM_TAG_RSP_COMMAND ) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32)); + TpmOutSize = SwapBytes32 (Data32); + if (*SizeOut < TpmOutSize) { + Status = EFI_BUFFER_TOO_SMALL; + goto Exit; + } + *SizeOut = TpmOutSize; + // + // Continue reading the remaining data + // + while ( Index < TpmOutSize ) { + for (; BurstCount > 0; BurstCount--) { + *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo); + Index++; + if (Index == TpmOutSize) { + Status = EFI_SUCCESS; + goto Exit; + } + } + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + goto Exit; + } + } +Exit: + MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY); + return Status; +} + diff --git a/SecurityPkg/Tcg/TcgPei/TpmComm.c b/SecurityPkg/Tcg/TcgPei/TpmComm.c new file mode 100644 index 0000000000..fb5011ee9d --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TpmComm.c @@ -0,0 +1,272 @@ +/** @file + Utility functions used by TPM PEI driver. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TpmComm.h" + +/** + Send a command to TPM for execution and return response data. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TisReg TPM register space base address. + @param[in] BufferIn Buffer for command data. + @param[in] SizeIn Size of command data. + @param[in, out] BufferOut Buffer for response data. + @param[in, out] SizeOut size of response data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TisTpmCommand ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_PC_REGISTERS_PTR TisReg, + IN UINT8 *BufferIn, + IN UINT32 SizeIn, + IN OUT UINT8 *BufferOut, + IN OUT UINT32 *SizeOut + ); + +/** + Send TPM_Startup command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] BootMode Boot mode. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommStartup ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN EFI_BOOT_MODE BootMode + ) +{ + EFI_STATUS Status; + TPM_STARTUP_TYPE TpmSt; + UINT32 TpmRecvSize; + UINT32 TpmSendSize; + TPM_CMD_START_UP SendBuffer; + UINT8 RecvBuffer[20]; + + TpmSt = TPM_ST_CLEAR; + if (BootMode == BOOT_ON_S3_RESUME) { + TpmSt = TPM_ST_STATE; + } + // + // send Tpm command TPM_ORD_Startup + // + TpmRecvSize = 20; + TpmSendSize = sizeof (TPM_CMD_START_UP); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Startup); + SendBuffer.TpmSt = SwapBytes16 (TpmSt); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + return Status; +} + +/** + Send TPM_ContinueSelfTest command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommContinueSelfTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle + ) +{ + EFI_STATUS Status; + UINT32 TpmRecvSize; + UINT32 TpmSendSize; + TPM_CMD_SELF_TEST SendBuffer; + UINT8 RecvBuffer[20]; + + // + // send Tpm command TPM_ORD_ContinueSelfTest + // + TpmRecvSize = 20; + TpmSendSize = sizeof (TPM_CMD_SELF_TEST); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_ContinueSelfTest); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + return Status; +} + +/** + Get TPM capability flags. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[out] Deactivated Returns deactivated flag. + @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag. + @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommGetCapability ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + OUT BOOLEAN *Deactivated, OPTIONAL + OUT BOOLEAN *LifetimeLock, OPTIONAL + OUT BOOLEAN *CmdEnable OPTIONAL + ) +{ + EFI_STATUS Status; + UINT32 TpmRecvSize; + UINT32 TpmSendSize; + TPM_CMD_GET_CAPABILITY SendBuffer; + UINT8 RecvBuffer[40]; + TPM_PERMANENT_FLAGS *TpmPermanentFlags; + + // + // send Tpm command TPM_ORD_GetCapability + // + TpmRecvSize = 40; + TpmSendSize = sizeof (TPM_CMD_GET_CAPABILITY); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_GetCapability); + SendBuffer.Capability = SwapBytes32 (TPM_CAP_FLAG); + SendBuffer.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT)); + SendBuffer.CapabilityFlag = SwapBytes32 (TPM_CAP_FLAG_PERMANENT); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + if (EFI_ERROR (Status)) { + return Status; + } + TpmPermanentFlags = (TPM_PERMANENT_FLAGS *)&RecvBuffer[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)]; + if (Deactivated != NULL) { + *Deactivated = TpmPermanentFlags->deactivated; + } + + if (LifetimeLock != NULL) { + *LifetimeLock = TpmPermanentFlags->physicalPresenceLifetimeLock; + } + + if (CmdEnable != NULL) { + *CmdEnable = TpmPermanentFlags->physicalPresenceCMDEnable; + } + return Status; +} + +/** + Extend a TPM PCR. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] DigestToExtend The 160 bit value representing the event to be recorded. + @param[in] PcrIndex The PCR to be updated. + @param[out] NewPcrValue New PCR value after extend. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommExtend ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_DIGEST *DigestToExtend, + IN TPM_PCRINDEX PcrIndex, + OUT TPM_DIGEST *NewPcrValue + ) +{ + EFI_STATUS Status; + UINT32 TpmSendSize; + UINT32 TpmRecvSize; + TPM_CMD_EXTEND SendBuffer; + UINT8 RecvBuffer[10 + sizeof(TPM_DIGEST)]; + + // + // send Tpm command TPM_ORD_Extend + // + TpmRecvSize = sizeof (TPM_RSP_COMMAND_HDR) + sizeof (TPM_DIGEST); + TpmSendSize = sizeof (TPM_CMD_EXTEND); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Extend); + SendBuffer.PcrIndex = SwapBytes32 (PcrIndex); + CopyMem (&SendBuffer.TpmDigest, (UINT8 *)DigestToExtend, sizeof (TPM_DIGEST)); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + ASSERT_EFI_ERROR (Status); + + if(NewPcrValue != NULL) { + CopyMem ((UINT8*)NewPcrValue, &RecvBuffer[10], sizeof (TPM_DIGEST)); + } + + return Status; +} + + +/** + Send TSC_PhysicalPresence command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] PhysicalPresence The state to set the TPMs Physical Presence flags. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommPhysicalPresence ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_PHYSICAL_PRESENCE PhysicalPresence + ) +{ + EFI_STATUS Status; + UINT32 TpmSendSize; + UINT32 TpmRecvSize; + TPM_CMD_PHYSICAL_PRESENCE SendBuffer; + UINT8 RecvBuffer[10]; + + // + // send Tpm command TSC_ORD_PhysicalPresence + // + TpmRecvSize = 10; + TpmSendSize = sizeof (TPM_CMD_PHYSICAL_PRESENCE); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TSC_ORD_PhysicalPresence); + SendBuffer.PhysicalPresence = SwapBytes16 (PhysicalPresence); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + return Status; +} diff --git a/SecurityPkg/Tcg/TcgPei/TpmComm.h b/SecurityPkg/Tcg/TcgPei/TpmComm.h new file mode 100644 index 0000000000..52d7f2e20d --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TpmComm.h @@ -0,0 +1,163 @@ +/** @file + The header file for TPM PEI driver. + +Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TPM_COMM_H_ +#define _TPM_COMM_H_ + +#include +#include +#include +#include +#include +#include + +#pragma pack(1) + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_STARTUP_TYPE TpmSt; +} TPM_CMD_START_UP; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; +} TPM_CMD_SELF_TEST; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + UINT32 Capability; + UINT32 CapabilityFlagSize; + UINT32 CapabilityFlag; +} TPM_CMD_GET_CAPABILITY; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_PCRINDEX PcrIndex; + TPM_DIGEST TpmDigest; +} TPM_CMD_EXTEND; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_PHYSICAL_PRESENCE PhysicalPresence; +} TPM_CMD_PHYSICAL_PRESENCE; + +#pragma pack() + +/** + Send TPM_Startup command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] BootMode Boot mode. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommStartup ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN EFI_BOOT_MODE BootMode + ); + +/** + Send TPM_ContinueSelfTest command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommContinueSelfTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle + ); + +/** + Get TPM capability flags. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[out] Deactivated Returns deactivated flag. + @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag. + @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommGetCapability ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + OUT BOOLEAN *Deactivated, OPTIONAL + OUT BOOLEAN *LifetimeLock, OPTIONAL + OUT BOOLEAN *CmdEnable OPTIONAL + ); + +/** + Extend a TPM PCR. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] DigestToExtend The 160 bit value representing the event to be recorded. + @param[in] PcrIndex The PCR to be updated. + @param[out] NewPcrValue New PCR value after extend. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommExtend ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_DIGEST *DigestToExtend, + IN TPM_PCRINDEX PcrIndex, + OUT TPM_DIGEST *NewPcrValue + ); + + +/** + Send TSC_PhysicalPresence command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] PhysicalPresence The state to set the TPMs Physical Presence flags. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommPhysicalPresence ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_PHYSICAL_PRESENCE PhysicalPresence + ); + +#endif // _TPM_COMM_H_ -- cgit v1.2.3