Home | History | Annotate | Download | only in Tpm12DeviceLibDTpm
      1 /** @file
      2   TIS (TPM Interface Specification) functions used by TPM1.2.
      3 
      4 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <Uefi.h>
     17 #include <IndustryStandard/Tpm12.h>
     18 #include <Library/BaseLib.h>
     19 #include <Library/BaseMemoryLib.h>
     20 #include <Library/IoLib.h>
     21 #include <Library/TimerLib.h>
     22 #include <Library/DebugLib.h>
     23 #include <Library/Tpm12CommandLib.h>
     24 #include <Library/PcdLib.h>
     25 
     26 #include <IndustryStandard/TpmPtp.h>
     27 #include <IndustryStandard/TpmTis.h>
     28 
     29 typedef enum {
     30   PtpInterfaceTis,
     31   PtpInterfaceFifo,
     32   PtpInterfaceCrb,
     33   PtpInterfaceMax,
     34 } PTP_INTERFACE_TYPE;
     35 
     36 //
     37 // Max TPM command/reponse length
     38 //
     39 #define TPMCMDBUFLENGTH             1024
     40 
     41 /**
     42   Check whether TPM chip exist.
     43 
     44   @param[in] TisReg  Pointer to TIS register.
     45 
     46   @retval    TRUE    TPM chip exists.
     47   @retval    FALSE   TPM chip is not found.
     48 **/
     49 BOOLEAN
     50 Tpm12TisPcPresenceCheck (
     51   IN      TIS_PC_REGISTERS_PTR      TisReg
     52   )
     53 {
     54   UINT8                             RegRead;
     55 
     56   RegRead = MmioRead8 ((UINTN)&TisReg->Access);
     57   return (BOOLEAN)(RegRead != (UINT8)-1);
     58 }
     59 
     60 /**
     61   Return PTP interface type.
     62 
     63   @param[in] Register                Pointer to PTP register.
     64 
     65   @return PTP interface type.
     66 **/
     67 PTP_INTERFACE_TYPE
     68 Tpm12GetPtpInterface (
     69   IN VOID *Register
     70   )
     71 {
     72   PTP_CRB_INTERFACE_IDENTIFIER  InterfaceId;
     73   PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
     74 
     75   if (!Tpm12TisPcPresenceCheck (Register)) {
     76     return PtpInterfaceMax;
     77   }
     78   //
     79   // Check interface id
     80   //
     81   InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
     82   InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
     83 
     84   if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
     85       (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
     86       (InterfaceId.Bits.CapCRB != 0)) {
     87     return PtpInterfaceCrb;
     88   }
     89   if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
     90       (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
     91       (InterfaceId.Bits.CapFIFO != 0) &&
     92       (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
     93     return PtpInterfaceFifo;
     94   }
     95   return PtpInterfaceTis;
     96 }
     97 
     98 /**
     99   Check whether the value of a TPM chip register satisfies the input BIT setting.
    100 
    101   @param[in]  Register     Address port of register to be checked.
    102   @param[in]  BitSet       Check these data bits are set.
    103   @param[in]  BitClear     Check these data bits are clear.
    104   @param[in]  TimeOut      The max wait time (unit MicroSecond) when checking register.
    105 
    106   @retval     EFI_SUCCESS  The register satisfies the check bit.
    107   @retval     EFI_TIMEOUT  The register can't run into the expected status in time.
    108 **/
    109 EFI_STATUS
    110 Tpm12TisPcWaitRegisterBits (
    111   IN      UINT8                     *Register,
    112   IN      UINT8                     BitSet,
    113   IN      UINT8                     BitClear,
    114   IN      UINT32                    TimeOut
    115   )
    116 {
    117   UINT8                             RegRead;
    118   UINT32                            WaitTime;
    119 
    120   for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
    121     RegRead = MmioRead8 ((UINTN)Register);
    122     if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
    123       return EFI_SUCCESS;
    124     MicroSecondDelay (30);
    125   }
    126   return EFI_TIMEOUT;
    127 }
    128 
    129 /**
    130   Get BurstCount by reading the burstCount field of a TIS regiger
    131   in the time of default TIS_TIMEOUT_D.
    132 
    133   @param[in]  TisReg                Pointer to TIS register.
    134   @param[out] BurstCount            Pointer to a buffer to store the got BurstConut.
    135 
    136   @retval     EFI_SUCCESS           Get BurstCount.
    137   @retval     EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.
    138   @retval     EFI_TIMEOUT           BurstCount can't be got in time.
    139 **/
    140 EFI_STATUS
    141 Tpm12TisPcReadBurstCount (
    142   IN      TIS_PC_REGISTERS_PTR      TisReg,
    143      OUT  UINT16                    *BurstCount
    144   )
    145 {
    146   UINT32                            WaitTime;
    147   UINT8                             DataByte0;
    148   UINT8                             DataByte1;
    149 
    150   if (BurstCount == NULL || TisReg == NULL) {
    151     return EFI_INVALID_PARAMETER;
    152   }
    153 
    154   WaitTime = 0;
    155   do {
    156     //
    157     // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned,
    158     // so it needs to use MmioRead8 to read two times
    159     //
    160     DataByte0   = MmioRead8 ((UINTN)&TisReg->BurstCount);
    161     DataByte1   = MmioRead8 ((UINTN)&TisReg->BurstCount + 1);
    162     *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
    163     if (*BurstCount != 0) {
    164       return EFI_SUCCESS;
    165     }
    166     MicroSecondDelay (30);
    167     WaitTime += 30;
    168   } while (WaitTime < TIS_TIMEOUT_D);
    169 
    170   return EFI_TIMEOUT;
    171 }
    172 
    173 /**
    174   Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
    175   to Status Register in time.
    176 
    177   @param[in] TisReg                Pointer to TIS register.
    178 
    179   @retval    EFI_SUCCESS           TPM chip enters into ready state.
    180   @retval    EFI_INVALID_PARAMETER TisReg is NULL.
    181   @retval    EFI_TIMEOUT           TPM chip can't be set to ready state in time.
    182 **/
    183 EFI_STATUS
    184 Tpm12TisPcPrepareCommand (
    185   IN      TIS_PC_REGISTERS_PTR      TisReg
    186   )
    187 {
    188   EFI_STATUS                        Status;
    189 
    190   if (TisReg == NULL) {
    191     return EFI_INVALID_PARAMETER;
    192   }
    193 
    194   MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
    195   Status = Tpm12TisPcWaitRegisterBits (
    196              &TisReg->Status,
    197              TIS_PC_STS_READY,
    198              0,
    199              TIS_TIMEOUT_B
    200              );
    201   return Status;
    202 }
    203 
    204 /**
    205   Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
    206   to ACCESS Register in the time of default TIS_TIMEOUT_A.
    207 
    208   @param[in] TisReg                Pointer to TIS register.
    209 
    210   @retval    EFI_SUCCESS           Get the control of TPM chip.
    211   @retval    EFI_INVALID_PARAMETER TisReg is NULL.
    212   @retval    EFI_NOT_FOUND         TPM chip doesn't exit.
    213   @retval    EFI_TIMEOUT           Can't get the TPM control in time.
    214 **/
    215 EFI_STATUS
    216 Tpm12TisPcRequestUseTpm (
    217   IN      TIS_PC_REGISTERS_PTR      TisReg
    218   )
    219 {
    220   EFI_STATUS                        Status;
    221 
    222   if (TisReg == NULL) {
    223     return EFI_INVALID_PARAMETER;
    224   }
    225 
    226   if (!Tpm12TisPcPresenceCheck (TisReg)) {
    227     return EFI_NOT_FOUND;
    228   }
    229 
    230   MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
    231   Status = Tpm12TisPcWaitRegisterBits (
    232              &TisReg->Access,
    233              (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
    234              0,
    235              TIS_TIMEOUT_A
    236              );
    237   return Status;
    238 }
    239 
    240 /**
    241   Send a command to TPM for execution and return response data.
    242 
    243   @param[in]      TisReg        TPM register space base address.
    244   @param[in]      BufferIn      Buffer for command data.
    245   @param[in]      SizeIn        Size of command data.
    246   @param[in, out] BufferOut     Buffer for response data.
    247   @param[in, out] SizeOut       Size of response data.
    248 
    249   @retval EFI_SUCCESS           Operation completed successfully.
    250   @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.
    251   @retval EFI_DEVICE_ERROR      Unexpected device behavior.
    252   @retval EFI_UNSUPPORTED       Unsupported TPM version
    253 
    254 **/
    255 EFI_STATUS
    256 Tpm12TisTpmCommand (
    257   IN     TIS_PC_REGISTERS_PTR       TisReg,
    258   IN     UINT8                      *BufferIn,
    259   IN     UINT32                     SizeIn,
    260   IN OUT UINT8                      *BufferOut,
    261   IN OUT UINT32                     *SizeOut
    262   )
    263 {
    264   EFI_STATUS                        Status;
    265   UINT16                            BurstCount;
    266   UINT32                            Index;
    267   UINT32                            TpmOutSize;
    268   UINT16                            Data16;
    269   UINT32                            Data32;
    270   UINT16                            RspTag;
    271 
    272   DEBUG_CODE (
    273     UINTN  DebugSize;
    274 
    275     DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand Send - "));
    276     if (SizeIn > 0x100) {
    277       DebugSize = 0x40;
    278     } else {
    279       DebugSize = SizeIn;
    280     }
    281     for (Index = 0; Index < DebugSize; Index++) {
    282       DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
    283     }
    284     if (DebugSize != SizeIn) {
    285       DEBUG ((EFI_D_VERBOSE, "...... "));
    286       for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
    287         DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
    288       }
    289     }
    290     DEBUG ((EFI_D_VERBOSE, "\n"));
    291   );
    292   TpmOutSize = 0;
    293 
    294   Status = Tpm12TisPcPrepareCommand (TisReg);
    295   if (EFI_ERROR (Status)){
    296     DEBUG ((DEBUG_ERROR, "Tpm12 is not ready for command!\n"));
    297     return EFI_DEVICE_ERROR;
    298   }
    299   //
    300   // Send the command data to Tpm
    301   //
    302   Index = 0;
    303   while (Index < SizeIn) {
    304     Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
    305     if (EFI_ERROR (Status)) {
    306       Status = EFI_DEVICE_ERROR;
    307       goto Exit;
    308     }
    309     for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {
    310       MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));
    311       Index++;
    312     }
    313   }
    314   //
    315   // Check the Tpm status STS_EXPECT change from 1 to 0
    316   //
    317   Status = Tpm12TisPcWaitRegisterBits (
    318              &TisReg->Status,
    319              (UINT8) TIS_PC_VALID,
    320              TIS_PC_STS_EXPECT,
    321              TIS_TIMEOUT_C
    322              );
    323   if (EFI_ERROR (Status)) {
    324     DEBUG ((DEBUG_ERROR, "Tpm12 The send buffer too small!\n"));
    325     Status = EFI_BUFFER_TOO_SMALL;
    326     goto Exit;
    327   }
    328   //
    329   // Executed the TPM command and waiting for the response data ready
    330   //
    331   MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);
    332   Status = Tpm12TisPcWaitRegisterBits (
    333              &TisReg->Status,
    334              (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
    335              0,
    336              TIS_TIMEOUT_B
    337              );
    338   if (EFI_ERROR (Status)) {
    339     DEBUG ((DEBUG_ERROR, "Wait for Tpm12 response data time out!!\n"));
    340     Status = EFI_DEVICE_ERROR;
    341     goto Exit;
    342   }
    343   //
    344   // Get response data header
    345   //
    346   Index = 0;
    347   BurstCount = 0;
    348   while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
    349     Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
    350     if (EFI_ERROR (Status)) {
    351       Status = EFI_DEVICE_ERROR;
    352       goto Exit;
    353     }
    354     for (; BurstCount > 0; BurstCount--) {
    355       *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
    356       Index++;
    357       if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break;
    358     }
    359   }
    360   DEBUG_CODE (
    361     DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand ReceiveHeader - "));
    362     for (Index = 0; Index < sizeof (TPM_RSP_COMMAND_HDR); Index++) {
    363       DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
    364     }
    365     DEBUG ((EFI_D_VERBOSE, "\n"));
    366   );
    367   //
    368   // Check the response data header (tag, parasize and returncode)
    369   //
    370   CopyMem (&Data16, BufferOut, sizeof (UINT16));
    371   RspTag = SwapBytes16 (Data16);
    372   if (RspTag != TPM_TAG_RSP_COMMAND && RspTag != TPM_TAG_RSP_AUTH1_COMMAND && RspTag != TPM_TAG_RSP_AUTH2_COMMAND) {
    373     DEBUG ((EFI_D_ERROR, "TPM12: Response tag error - current tag value is %x\n", RspTag));
    374     Status = EFI_UNSUPPORTED;
    375     goto Exit;
    376   }
    377 
    378   CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
    379   TpmOutSize  = SwapBytes32 (Data32);
    380   if (*SizeOut < TpmOutSize) {
    381     Status = EFI_BUFFER_TOO_SMALL;
    382     goto Exit;
    383   }
    384   *SizeOut = TpmOutSize;
    385   //
    386   // Continue reading the remaining data
    387   //
    388   while ( Index < TpmOutSize ) {
    389     for (; BurstCount > 0; BurstCount--) {
    390       *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
    391       Index++;
    392       if (Index == TpmOutSize) {
    393         Status = EFI_SUCCESS;
    394         goto Exit;
    395       }
    396     }
    397     Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
    398     if (EFI_ERROR (Status)) {
    399       Status = EFI_DEVICE_ERROR;
    400       goto Exit;
    401     }
    402   }
    403 Exit:
    404   DEBUG_CODE (
    405     DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand Receive - "));
    406     for (Index = 0; Index < TpmOutSize; Index++) {
    407       DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
    408     }
    409     DEBUG ((EFI_D_VERBOSE, "\n"));
    410   );
    411   MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
    412   return Status;
    413 }
    414 
    415 /**
    416   This service enables the sending of commands to the TPM12.
    417 
    418   @param[in]      InputParameterBlockSize  Size of the TPM12 input parameter block.
    419   @param[in]      InputParameterBlock      Pointer to the TPM12 input parameter block.
    420   @param[in,out]  OutputParameterBlockSize Size of the TPM12 output parameter block.
    421   @param[in]      OutputParameterBlock     Pointer to the TPM12 output parameter block.
    422 
    423   @retval EFI_SUCCESS            The command byte stream was successfully sent to the device and a response was successfully received.
    424   @retval EFI_DEVICE_ERROR       The command was not successfully sent to the device or a response was not successfully received from the device.
    425   @retval EFI_BUFFER_TOO_SMALL   The output parameter block is too small.
    426 **/
    427 EFI_STATUS
    428 EFIAPI
    429 Tpm12SubmitCommand (
    430   IN UINT32            InputParameterBlockSize,
    431   IN UINT8             *InputParameterBlock,
    432   IN OUT UINT32        *OutputParameterBlockSize,
    433   IN UINT8             *OutputParameterBlock
    434   )
    435 {
    436   PTP_INTERFACE_TYPE  PtpInterface;
    437 
    438   //
    439   // Special handle for TPM1.2 to check PTP too, because PTP/TIS share same register address.
    440   //
    441   PtpInterface = Tpm12GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
    442   switch (PtpInterface) {
    443   case PtpInterfaceFifo:
    444   case PtpInterfaceTis:
    445     return Tpm12TisTpmCommand (
    446              (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
    447              InputParameterBlock,
    448              InputParameterBlockSize,
    449              OutputParameterBlock,
    450              OutputParameterBlockSize
    451              );
    452   case PtpInterfaceCrb:
    453     //
    454     // No need to support CRB because it is only accept TPM2 command.
    455     //
    456   default:
    457     return EFI_DEVICE_ERROR;
    458   }
    459 
    460 }
    461 
    462 /**
    463   Check whether the value of a TPM chip register satisfies the input BIT setting.
    464 
    465   @param[in]  Register     Address port of register to be checked.
    466   @param[in]  BitSet       Check these data bits are set.
    467   @param[in]  BitClear     Check these data bits are clear.
    468   @param[in]  TimeOut      The max wait time (unit MicroSecond) when checking register.
    469 
    470   @retval     EFI_SUCCESS  The register satisfies the check bit.
    471   @retval     EFI_TIMEOUT  The register can't run into the expected status in time.
    472 **/
    473 EFI_STATUS
    474 Tpm12PtpCrbWaitRegisterBits (
    475   IN      UINT32                    *Register,
    476   IN      UINT32                    BitSet,
    477   IN      UINT32                    BitClear,
    478   IN      UINT32                    TimeOut
    479   )
    480 {
    481   UINT32                            RegRead;
    482   UINT32                            WaitTime;
    483 
    484   for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
    485     RegRead = MmioRead32 ((UINTN)Register);
    486     if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0) {
    487       return EFI_SUCCESS;
    488     }
    489     MicroSecondDelay (30);
    490   }
    491   return EFI_TIMEOUT;
    492 }
    493 
    494 /**
    495   Get the control of TPM chip.
    496 
    497   @param[in] CrbReg                Pointer to CRB register.
    498 
    499   @retval    EFI_SUCCESS           Get the control of TPM chip.
    500   @retval    EFI_INVALID_PARAMETER CrbReg is NULL.
    501   @retval    EFI_NOT_FOUND         TPM chip doesn't exit.
    502   @retval    EFI_TIMEOUT           Can't get the TPM control in time.
    503 **/
    504 EFI_STATUS
    505 Tpm12PtpCrbRequestUseTpm (
    506   IN      PTP_CRB_REGISTERS_PTR      CrbReg
    507   )
    508 {
    509   EFI_STATUS                        Status;
    510 
    511   MmioWrite32((UINTN)&CrbReg->LocalityControl, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS);
    512   Status = Tpm12PtpCrbWaitRegisterBits (
    513              &CrbReg->LocalityStatus,
    514              PTP_CRB_LOCALITY_STATUS_GRANTED,
    515              0,
    516              PTP_TIMEOUT_A
    517              );
    518   return Status;
    519 }
    520 
    521 /**
    522   This service requests use TPM12.
    523 
    524   @retval EFI_SUCCESS      Get the control of TPM12 chip.
    525   @retval EFI_NOT_FOUND    TPM12 not found.
    526   @retval EFI_DEVICE_ERROR Unexpected device behavior.
    527 **/
    528 EFI_STATUS
    529 EFIAPI
    530 Tpm12RequestUseTpm (
    531   VOID
    532   )
    533 {
    534   PTP_INTERFACE_TYPE  PtpInterface;
    535 
    536   //
    537   // Special handle for TPM1.2 to check PTP too, because PTP/TIS share same register address.
    538   // Some other program might leverage this function to check the existence of TPM chip.
    539   //
    540   PtpInterface = Tpm12GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
    541   switch (PtpInterface) {
    542   case PtpInterfaceCrb:
    543     return Tpm12PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
    544   case PtpInterfaceFifo:
    545   case PtpInterfaceTis:
    546     return Tpm12TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
    547   default:
    548     return EFI_NOT_FOUND;
    549   }
    550 }
    551