Home | History | Annotate | Download | only in TcgPei
      1 /** @file
      2   Initialize TPM device and measure FVs before handing off control to DXE.
      3 
      4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <PiPei.h>
     16 
     17 #include <IndustryStandard/Tpm12.h>
     18 #include <IndustryStandard/UefiTcgPlatform.h>
     19 #include <Ppi/FirmwareVolumeInfo.h>
     20 #include <Ppi/FirmwareVolumeInfo2.h>
     21 #include <Ppi/LockPhysicalPresence.h>
     22 #include <Ppi/TpmInitialized.h>
     23 #include <Ppi/FirmwareVolume.h>
     24 #include <Ppi/EndOfPeiPhase.h>
     25 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
     26 
     27 #include <Guid/TcgEventHob.h>
     28 #include <Guid/MeasuredFvHob.h>
     29 #include <Guid/TpmInstance.h>
     30 
     31 #include <Library/DebugLib.h>
     32 #include <Library/BaseMemoryLib.h>
     33 #include <Library/PeiServicesLib.h>
     34 #include <Library/PeimEntryPoint.h>
     35 #include <Library/TpmCommLib.h>
     36 #include <Library/HobLib.h>
     37 #include <Library/PcdLib.h>
     38 #include <Library/PeiServicesTablePointerLib.h>
     39 #include <Library/BaseLib.h>
     40 #include <Library/MemoryAllocationLib.h>
     41 #include <Library/ReportStatusCodeLib.h>
     42 
     43 #include "TpmComm.h"
     44 
     45 BOOLEAN                 mImageInMemory  = FALSE;
     46 
     47 EFI_PEI_PPI_DESCRIPTOR  mTpmInitializedPpiList = {
     48   EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
     49   &gPeiTpmInitializedPpiGuid,
     50   NULL
     51 };
     52 
     53 EFI_PEI_PPI_DESCRIPTOR  mTpmInitializationDonePpiList = {
     54   EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
     55   &gPeiTpmInitializationDonePpiGuid,
     56   NULL
     57 };
     58 
     59 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
     60 UINT32 mMeasuredBaseFvIndex = 0;
     61 
     62 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
     63 UINT32 mMeasuredChildFvIndex = 0;
     64 
     65 EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;
     66 
     67 /**
     68   Lock physical presence if needed.
     69 
     70   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
     71   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
     72   @param[in] Ppi               Address of the PPI that was installed.
     73 
     74   @retval EFI_SUCCESS          Operation completed successfully.
     75 
     76 **/
     77 EFI_STATUS
     78 EFIAPI
     79 PhysicalPresencePpiNotifyCallback (
     80   IN EFI_PEI_SERVICES              **PeiServices,
     81   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
     82   IN VOID                          *Ppi
     83   );
     84 
     85 /**
     86   Measure and record the Firmware Volum Information once FvInfoPPI install.
     87 
     88   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
     89   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
     90   @param[in] Ppi               Address of the PPI that was installed.
     91 
     92   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.
     93   @return Others               Fail to measure FV.
     94 
     95 **/
     96 EFI_STATUS
     97 EFIAPI
     98 FirmwareVolmeInfoPpiNotifyCallback (
     99   IN EFI_PEI_SERVICES              **PeiServices,
    100   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
    101   IN VOID                          *Ppi
    102   );
    103 
    104 /**
    105   Record all measured Firmware Volum Information into a Guid Hob
    106 
    107   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
    108   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
    109   @param[in] Ppi               Address of the PPI that was installed.
    110 
    111   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.
    112   @return Others               Fail to measure FV.
    113 
    114 **/
    115 EFI_STATUS
    116 EFIAPI
    117 EndofPeiSignalNotifyCallBack (
    118   IN EFI_PEI_SERVICES              **PeiServices,
    119   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
    120   IN VOID                          *Ppi
    121   );
    122 
    123 EFI_PEI_NOTIFY_DESCRIPTOR           mNotifyList[] = {
    124   {
    125     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    126     &gPeiLockPhysicalPresencePpiGuid,
    127     PhysicalPresencePpiNotifyCallback
    128   },
    129   {
    130     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    131     &gEfiPeiFirmwareVolumeInfoPpiGuid,
    132     FirmwareVolmeInfoPpiNotifyCallback
    133   },
    134   {
    135     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    136     &gEfiPeiFirmwareVolumeInfo2PpiGuid,
    137     FirmwareVolmeInfoPpiNotifyCallback
    138   },
    139   {
    140     (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
    141     &gEfiEndOfPeiSignalPpiGuid,
    142     EndofPeiSignalNotifyCallBack
    143   }
    144 };
    145 
    146 /**
    147   Record all measured Firmware Volum Information into a Guid Hob
    148   Guid Hob payload layout is
    149 
    150      UINT32 *************************** FIRMWARE_BLOB number
    151      EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
    152 
    153   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
    154   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
    155   @param[in] Ppi               Address of the PPI that was installed.
    156 
    157   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.
    158   @return Others               Fail to measure FV.
    159 
    160 **/
    161 EFI_STATUS
    162 EFIAPI
    163 EndofPeiSignalNotifyCallBack (
    164   IN EFI_PEI_SERVICES              **PeiServices,
    165   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
    166   IN VOID                          *Ppi
    167   )
    168 {
    169   MEASURED_HOB_DATA *MeasuredHobData;
    170 
    171   MeasuredHobData = NULL;
    172 
    173   //
    174   // Create a Guid hob to save all measured Fv
    175   //
    176   MeasuredHobData = BuildGuidHob(
    177                       &gMeasuredFvHobGuid,
    178                       sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
    179                       );
    180 
    181   if (MeasuredHobData != NULL){
    182     //
    183     // Save measured FV info enty number
    184     //
    185     MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
    186 
    187     //
    188     // Save measured base Fv info
    189     //
    190     CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
    191 
    192     //
    193     // Save measured child Fv info
    194     //
    195     CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
    196   }
    197 
    198   return EFI_SUCCESS;
    199 }
    200 
    201 /**
    202   Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
    203   and build a GUIDed HOB recording the event which will be passed to the DXE phase and
    204   added into the Event Log.
    205 
    206   @param[in]      PeiServices   Describes the list of possible PEI Services.
    207   @param[in]      HashData      Physical address of the start of the data buffer
    208                                 to be hashed, extended, and logged.
    209   @param[in]      HashDataLen   The length, in bytes, of the buffer referenced by HashData.
    210   @param[in]      TpmHandle     TPM handle.
    211   @param[in]      NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.
    212   @param[in]      NewEventData  Pointer to the new event data.
    213 
    214   @retval EFI_SUCCESS           Operation completed successfully.
    215   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
    216   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
    217 
    218 **/
    219 EFI_STATUS
    220 HashLogExtendEvent (
    221   IN      EFI_PEI_SERVICES          **PeiServices,
    222   IN      UINT8                     *HashData,
    223   IN      UINTN                     HashDataLen,
    224   IN      TIS_TPM_HANDLE            TpmHandle,
    225   IN      TCG_PCR_EVENT_HDR         *NewEventHdr,
    226   IN      UINT8                     *NewEventData
    227   )
    228 {
    229   EFI_STATUS                        Status;
    230   VOID                              *HobData;
    231 
    232   if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
    233     return EFI_DEVICE_ERROR;
    234   }
    235 
    236   HobData = NULL;
    237   if (HashDataLen != 0) {
    238     Status = TpmCommHashAll (
    239                HashData,
    240                HashDataLen,
    241                &NewEventHdr->Digest
    242                );
    243     if (EFI_ERROR (Status)) {
    244       goto Done;
    245     }
    246   }
    247 
    248   Status = TpmCommExtend (
    249              PeiServices,
    250              TpmHandle,
    251              &NewEventHdr->Digest,
    252              NewEventHdr->PCRIndex,
    253              NULL
    254              );
    255   if (EFI_ERROR (Status)) {
    256     goto Done;
    257   }
    258 
    259   HobData = BuildGuidHob (
    260              &gTcgEventEntryHobGuid,
    261              sizeof (*NewEventHdr) + NewEventHdr->EventSize
    262              );
    263   if (HobData == NULL) {
    264     Status = EFI_OUT_OF_RESOURCES;
    265     goto Done;
    266   }
    267 
    268   CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
    269   HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
    270   CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
    271 
    272 Done:
    273   if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
    274     DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
    275     BuildGuidHob (&gTpmErrorHobGuid,0);
    276     REPORT_STATUS_CODE (
    277       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    278       (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
    279       );
    280     Status = EFI_DEVICE_ERROR;
    281   }
    282   return Status;
    283 }
    284 
    285 /**
    286   Measure CRTM version.
    287 
    288   @param[in]      PeiServices   Describes the list of possible PEI Services.
    289   @param[in]      TpmHandle     TPM handle.
    290 
    291   @retval EFI_SUCCESS           Operation completed successfully.
    292   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
    293   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
    294 
    295 **/
    296 EFI_STATUS
    297 EFIAPI
    298 MeasureCRTMVersion (
    299   IN      EFI_PEI_SERVICES          **PeiServices,
    300   IN      TIS_TPM_HANDLE            TpmHandle
    301   )
    302 {
    303   TCG_PCR_EVENT_HDR                 TcgEventHdr;
    304 
    305   //
    306   // Use FirmwareVersion string to represent CRTM version.
    307   // OEMs should get real CRTM version string and measure it.
    308   //
    309 
    310   TcgEventHdr.PCRIndex  = 0;
    311   TcgEventHdr.EventType = EV_S_CRTM_VERSION;
    312   TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
    313 
    314   return HashLogExtendEvent (
    315            PeiServices,
    316            (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
    317            TcgEventHdr.EventSize,
    318            TpmHandle,
    319            &TcgEventHdr,
    320            (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
    321            );
    322 }
    323 
    324 /**
    325   Measure FV image.
    326   Add it into the measured FV list after the FV is measured successfully.
    327 
    328   @param[in]  FvBase            Base address of FV image.
    329   @param[in]  FvLength          Length of FV image.
    330 
    331   @retval EFI_SUCCESS           Fv image is measured successfully
    332                                 or it has been already measured.
    333   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
    334   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
    335 
    336 **/
    337 EFI_STATUS
    338 EFIAPI
    339 MeasureFvImage (
    340   IN EFI_PHYSICAL_ADDRESS           FvBase,
    341   IN UINT64                         FvLength
    342   )
    343 {
    344   UINT32                            Index;
    345   EFI_STATUS                        Status;
    346   EFI_PLATFORM_FIRMWARE_BLOB        FvBlob;
    347   TCG_PCR_EVENT_HDR                 TcgEventHdr;
    348   TIS_TPM_HANDLE                    TpmHandle;
    349 
    350   TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;
    351 
    352   //
    353   // Check if it is in Excluded FV list
    354   //
    355   if (mMeasurementExcludedFvPpi != NULL) {
    356     for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {
    357       if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {
    358         DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei starts at: 0x%x\n", FvBase));
    359         DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei has the size: 0x%x\n", FvLength));
    360         return EFI_SUCCESS;
    361       }
    362     }
    363   }
    364 
    365   //
    366   // Check whether FV is in the measured FV list.
    367   //
    368   for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
    369     if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {
    370       return EFI_SUCCESS;
    371     }
    372   }
    373 
    374   //
    375   // Measure and record the FV to the TPM
    376   //
    377   FvBlob.BlobBase   = FvBase;
    378   FvBlob.BlobLength = FvLength;
    379 
    380   DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase));
    381   DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength));
    382 
    383   TcgEventHdr.PCRIndex = 0;
    384   TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
    385   TcgEventHdr.EventSize = sizeof (FvBlob);
    386 
    387   Status = HashLogExtendEvent (
    388              (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),
    389              (UINT8*) (UINTN) FvBlob.BlobBase,
    390              (UINTN) FvBlob.BlobLength,
    391              TpmHandle,
    392              &TcgEventHdr,
    393              (UINT8*) &FvBlob
    394              );
    395 
    396   //
    397   // Add new FV into the measured FV list.
    398   //
    399   ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
    400   if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
    401     mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase   = FvBase;
    402     mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
    403     mMeasuredBaseFvIndex++;
    404   }
    405 
    406   return Status;
    407 }
    408 
    409 /**
    410   Measure main BIOS.
    411 
    412   @param[in]      PeiServices   Describes the list of possible PEI Services.
    413   @param[in]      TpmHandle     TPM handle.
    414 
    415   @retval EFI_SUCCESS           Operation completed successfully.
    416   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
    417   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
    418 
    419 **/
    420 EFI_STATUS
    421 EFIAPI
    422 MeasureMainBios (
    423   IN      EFI_PEI_SERVICES          **PeiServices,
    424   IN      TIS_TPM_HANDLE            TpmHandle
    425   )
    426 {
    427   EFI_STATUS                        Status;
    428   UINT32                            FvInstances;
    429   EFI_PEI_FV_HANDLE                 VolumeHandle;
    430   EFI_FV_INFO                       VolumeInfo;
    431   EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;
    432 
    433   FvInstances    = 0;
    434   while (TRUE) {
    435     //
    436     // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
    437     // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
    438     // platform for special CRTM TPM measuring.
    439     //
    440     Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);
    441     if (EFI_ERROR (Status)) {
    442       break;
    443     }
    444 
    445     //
    446     // Measure and record the firmware volume that is dispatched by PeiCore
    447     //
    448     Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
    449     ASSERT_EFI_ERROR (Status);
    450     //
    451     // Locate the corresponding FV_PPI according to founded FV's format guid
    452     //
    453     Status = PeiServicesLocatePpi (
    454                &VolumeInfo.FvFormat,
    455                0,
    456                NULL,
    457                (VOID**)&FvPpi
    458                );
    459     if (!EFI_ERROR (Status)) {
    460       MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
    461     }
    462 
    463     FvInstances++;
    464   }
    465 
    466   return EFI_SUCCESS;
    467 }
    468 
    469 /**
    470   Measure and record the Firmware Volum Information once FvInfoPPI install.
    471 
    472   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
    473   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
    474   @param[in] Ppi               Address of the PPI that was installed.
    475 
    476   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.
    477   @return Others               Fail to measure FV.
    478 
    479 **/
    480 EFI_STATUS
    481 EFIAPI
    482 FirmwareVolmeInfoPpiNotifyCallback (
    483   IN EFI_PEI_SERVICES               **PeiServices,
    484   IN EFI_PEI_NOTIFY_DESCRIPTOR      *NotifyDescriptor,
    485   IN VOID                           *Ppi
    486   )
    487 {
    488   EFI_PEI_FIRMWARE_VOLUME_INFO_PPI  *Fv;
    489   EFI_STATUS                        Status;
    490   EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;
    491   UINTN                             Index;
    492 
    493   Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
    494 
    495   //
    496   // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
    497   //
    498   Status = PeiServicesLocatePpi (
    499              &Fv->FvFormat,
    500              0,
    501              NULL,
    502              (VOID**)&FvPpi
    503              );
    504   if (EFI_ERROR (Status)) {
    505     return EFI_SUCCESS;
    506   }
    507 
    508   //
    509   // This is an FV from an FFS file, and the parent FV must have already been measured,
    510   // No need to measure twice, so just record the FV and return
    511   //
    512   if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
    513 
    514     ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
    515     if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
    516       //
    517       // Check whether FV is in the measured child FV list.
    518       //
    519       for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
    520         if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
    521           return EFI_SUCCESS;
    522         }
    523       }
    524       mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase   = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
    525       mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
    526       mMeasuredChildFvIndex++;
    527     }
    528     return EFI_SUCCESS;
    529   }
    530 
    531   return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
    532 }
    533 
    534 /**
    535   Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by corresponding PCDs.
    536   And lock physical presence if needed.
    537 
    538   @param[in] PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
    539   @param[in] NotifyDescriptor   Address of the notification descriptor data structure.
    540   @param[in] Ppi                Address of the PPI that was installed.
    541 
    542   @retval EFI_SUCCESS           Operation completed successfully.
    543   @retval EFI_ABORTED           physicalPresenceCMDEnable is locked.
    544   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
    545 
    546 **/
    547 EFI_STATUS
    548 EFIAPI
    549 PhysicalPresencePpiNotifyCallback (
    550   IN EFI_PEI_SERVICES               **PeiServices,
    551   IN EFI_PEI_NOTIFY_DESCRIPTOR      *NotifyDescriptor,
    552   IN VOID                           *Ppi
    553   )
    554 {
    555   EFI_STATUS                        Status;
    556   PEI_LOCK_PHYSICAL_PRESENCE_PPI    *LockPhysicalPresencePpi;
    557   BOOLEAN                           LifetimeLock;
    558   BOOLEAN                           CmdEnable;
    559   TIS_TPM_HANDLE                    TpmHandle;
    560   TPM_PHYSICAL_PRESENCE             PhysicalPresenceValue;
    561 
    562   TpmHandle        = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;
    563 
    564   Status = TpmCommGetCapability (PeiServices, TpmHandle, NULL, &LifetimeLock, &CmdEnable);
    565   if (EFI_ERROR (Status)) {
    566     return Status;
    567   }
    568 
    569   //
    570   // 1. Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by PCDs.
    571   //
    572   if (PcdGetBool (PcdPhysicalPresenceLifetimeLock) && !LifetimeLock) {
    573     //
    574     // Lock TPM LifetimeLock is required, and LifetimeLock is not locked yet.
    575     //
    576     PhysicalPresenceValue = TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK;
    577 
    578     if (PcdGetBool (PcdPhysicalPresenceCmdEnable)) {
    579       PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_ENABLE;
    580       CmdEnable = TRUE;
    581     } else {
    582       PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_DISABLE;
    583       CmdEnable = FALSE;
    584     }
    585 
    586     if (PcdGetBool (PcdPhysicalPresenceHwEnable)) {
    587       PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_ENABLE;
    588     } else {
    589       PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_DISABLE;
    590     }
    591 
    592     Status = TpmCommPhysicalPresence (
    593                PeiServices,
    594                TpmHandle,
    595                PhysicalPresenceValue
    596                );
    597     if (EFI_ERROR (Status)) {
    598       return Status;
    599     }
    600   }
    601 
    602   //
    603   // 2. Lock physical presence if it is required.
    604   //
    605   LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi;
    606   if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) {
    607     return EFI_SUCCESS;
    608   }
    609 
    610   if (!CmdEnable) {
    611     if (LifetimeLock) {
    612       //
    613       // physicalPresenceCMDEnable is locked, can't change.
    614       //
    615       return EFI_ABORTED;
    616     }
    617 
    618     //
    619     // Enable physical presence command
    620     // It is necessary in order to lock physical presence
    621     //
    622     Status = TpmCommPhysicalPresence (
    623                PeiServices,
    624                TpmHandle,
    625                TPM_PHYSICAL_PRESENCE_CMD_ENABLE
    626                );
    627     if (EFI_ERROR (Status)) {
    628       return Status;
    629     }
    630   }
    631 
    632   //
    633   // Lock physical presence
    634   //
    635   Status = TpmCommPhysicalPresence (
    636               PeiServices,
    637               TpmHandle,
    638               TPM_PHYSICAL_PRESENCE_LOCK
    639               );
    640   return Status;
    641 }
    642 
    643 /**
    644   Check if TPM chip is activeated or not.
    645 
    646   @param[in]      PeiServices   Describes the list of possible PEI Services.
    647   @param[in]      TpmHandle     TPM handle.
    648 
    649   @retval TRUE    TPM is activated.
    650   @retval FALSE   TPM is deactivated.
    651 
    652 **/
    653 BOOLEAN
    654 EFIAPI
    655 IsTpmUsable (
    656   IN      EFI_PEI_SERVICES          **PeiServices,
    657   IN      TIS_TPM_HANDLE            TpmHandle
    658   )
    659 {
    660   EFI_STATUS                        Status;
    661   BOOLEAN                           Deactivated;
    662 
    663   Status = TpmCommGetCapability (PeiServices, TpmHandle, &Deactivated, NULL, NULL);
    664   if (EFI_ERROR (Status)) {
    665     return FALSE;
    666   }
    667   return (BOOLEAN)(!Deactivated);
    668 }
    669 
    670 /**
    671   Do measurement after memory is ready.
    672 
    673   @param[in]      PeiServices   Describes the list of possible PEI Services.
    674 
    675   @retval EFI_SUCCESS           Operation completed successfully.
    676   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
    677   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
    678 
    679 **/
    680 EFI_STATUS
    681 EFIAPI
    682 PeimEntryMP (
    683   IN      EFI_PEI_SERVICES          **PeiServices
    684   )
    685 {
    686   EFI_STATUS                        Status;
    687   TIS_TPM_HANDLE                    TpmHandle;
    688 
    689   Status = PeiServicesLocatePpi (
    690                &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
    691                0,
    692                NULL,
    693                (VOID**)&mMeasurementExcludedFvPpi
    694                );
    695   // Do not check status, because it is optional
    696 
    697   mMeasuredBaseFvInfo  = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
    698   ASSERT (mMeasuredBaseFvInfo != NULL);
    699   mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
    700   ASSERT (mMeasuredChildFvInfo != NULL);
    701 
    702   TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
    703   Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);
    704   if (EFI_ERROR (Status)) {
    705     return Status;
    706   }
    707 
    708   if (IsTpmUsable (PeiServices, TpmHandle)) {
    709     if (PcdGet8 (PcdTpmScrtmPolicy) == 1) {
    710       Status = MeasureCRTMVersion (PeiServices, TpmHandle);
    711     }
    712 
    713     Status = MeasureMainBios (PeiServices, TpmHandle);
    714   }
    715 
    716   //
    717   // Post callbacks:
    718   // 1). for the FvInfoPpi services to measure and record
    719   // the additional Fvs to TPM
    720   // 2). for the OperatorPresencePpi service to determine whether to
    721   // lock the TPM
    722   //
    723   Status = PeiServicesNotifyPpi (&mNotifyList[0]);
    724   ASSERT_EFI_ERROR (Status);
    725 
    726   return Status;
    727 }
    728 
    729 /**
    730   Entry point of this module.
    731 
    732   @param[in] FileHandle   Handle of the file being invoked.
    733   @param[in] PeiServices  Describes the list of possible PEI Services.
    734 
    735   @return Status.
    736 
    737 **/
    738 EFI_STATUS
    739 EFIAPI
    740 PeimEntryMA (
    741   IN       EFI_PEI_FILE_HANDLE      FileHandle,
    742   IN CONST EFI_PEI_SERVICES         **PeiServices
    743   )
    744 {
    745   EFI_STATUS                        Status;
    746   EFI_STATUS                        Status2;
    747   EFI_BOOT_MODE                     BootMode;
    748   TIS_TPM_HANDLE                    TpmHandle;
    749 
    750   if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
    751     DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n"));
    752     return EFI_UNSUPPORTED;
    753   }
    754 
    755   if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
    756     DEBUG ((EFI_D_ERROR, "TPM error!\n"));
    757     return EFI_DEVICE_ERROR;
    758   }
    759 
    760   //
    761   // Initialize TPM device
    762   //
    763   Status = PeiServicesGetBootMode (&BootMode);
    764   ASSERT_EFI_ERROR (Status);
    765 
    766   //
    767   // In S3 path, skip shadow logic. no measurement is required
    768   //
    769   if (BootMode != BOOT_ON_S3_RESUME) {
    770     Status = (**PeiServices).RegisterForShadow(FileHandle);
    771     if (Status == EFI_ALREADY_STARTED) {
    772       mImageInMemory = TRUE;
    773     } else if (Status == EFI_NOT_FOUND) {
    774       ASSERT_EFI_ERROR (Status);
    775     }
    776   }
    777 
    778   if (!mImageInMemory) {
    779     TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
    780     Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);
    781     if (EFI_ERROR (Status)) {
    782       DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));
    783       goto Done;
    784     }
    785 
    786     if (PcdGet8 (PcdTpmInitializationPolicy) == 1) {
    787       Status = TpmCommStartup ((EFI_PEI_SERVICES**)PeiServices, TpmHandle, BootMode);
    788       if (EFI_ERROR (Status) ) {
    789         goto Done;
    790       }
    791     }
    792 
    793     //
    794     // TpmSelfTest is optional on S3 path, skip it to save S3 time
    795     //
    796     if (BootMode != BOOT_ON_S3_RESUME) {
    797       Status = TpmCommContinueSelfTest ((EFI_PEI_SERVICES**)PeiServices, TpmHandle);
    798       if (EFI_ERROR (Status)) {
    799         goto Done;
    800       }
    801     }
    802 
    803     //
    804     // Only intall TpmInitializedPpi on success
    805     //
    806     Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
    807     ASSERT_EFI_ERROR (Status);
    808   }
    809 
    810   if (mImageInMemory) {
    811     Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
    812     return Status;
    813   }
    814 
    815 Done:
    816   if (EFI_ERROR (Status)) {
    817     DEBUG ((EFI_D_ERROR, "TPM error! Build Hob\n"));
    818     BuildGuidHob (&gTpmErrorHobGuid,0);
    819     REPORT_STATUS_CODE (
    820       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    821       (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
    822       );
    823   }
    824   //
    825   // Always intall TpmInitializationDonePpi no matter success or fail.
    826   // Other driver can know TPM initialization state by TpmInitializedPpi.
    827   //
    828   Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
    829   ASSERT_EFI_ERROR (Status2);
    830 
    831   return Status;
    832 }
    833