Home | History | Annotate | Download | only in Tpm12DeviceLibInfineonI2c
      1 /** @file
      2   Basic TIS (TPM Interface Specification) functions for Infineon I2C TPM.
      3 
      4   Copyright (c) 2013 - 2016, 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 #include <Library/Tpm12DeviceLib.h>
     17 #include <Library/BaseLib.h>
     18 #include <Library/TimerLib.h>
     19 #include <Library/DebugLib.h>
     20 #include <Library/I2cLib.h>
     21 
     22 //
     23 // Default TPM (Infineon SLB9645) I2C Slave Device Address on Crosshill board.
     24 //
     25 #define TPM_I2C_SLAVE_DEVICE_ADDRESS              0x20
     26 
     27 //
     28 // Default Infineon SLB9645 TPM I2C mapped registers (SLB9645 I2C Comm. Protocol Application Note).
     29 //
     30 #define INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT     0x0
     31 #define INFINEON_TPM_STS_0_ADDRESS_DEFAULT        0x01
     32 #define INFINEON_TPM_BURST0_COUNT_0_DEFAULT       0x02
     33 #define INFINEON_TPM_BURST1_COUNT_0_DEFAULT       0x03
     34 #define INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT  0x05
     35 #define INFINEON_TPM_DID_VID_0_DEFAULT            0x09
     36 
     37 //
     38 // Max. retry count for read transfers (as recommended by Infineon).
     39 //
     40 #define READ_RETRY  3
     41 
     42 //
     43 // Guard time of 250us between I2C read and next I2C write transfer (as recommended by Infineon).
     44 //
     45 #define GUARD_TIME  250
     46 
     47 //
     48 // Define bits of ACCESS and STATUS registers
     49 //
     50 
     51 ///
     52 /// This bit is a 1 to indicate that the other bits in this register are valid.
     53 ///
     54 #define TIS_PC_VALID                BIT7
     55 ///
     56 /// Indicate that this locality is active.
     57 ///
     58 #define TIS_PC_ACC_ACTIVE           BIT5
     59 ///
     60 /// Set to 1 to indicate that this locality had the TPM taken away while
     61 /// this locality had the TIS_PC_ACC_ACTIVE bit set.
     62 ///
     63 #define TIS_PC_ACC_SEIZED           BIT4
     64 ///
     65 /// Set to 1 to indicate that TPM MUST reset the
     66 /// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the
     67 /// locality that is writing this bit.
     68 ///
     69 #define TIS_PC_ACC_SEIZE            BIT3
     70 ///
     71 /// When this bit is 1, another locality is requesting usage of the TPM.
     72 ///
     73 #define TIS_PC_ACC_PENDIND          BIT2
     74 ///
     75 /// Set to 1 to indicate that this locality is requesting to use TPM.
     76 ///
     77 #define TIS_PC_ACC_RQUUSE           BIT1
     78 ///
     79 /// A value of 1 indicates that a T/OS has not been established on the platform
     80 ///
     81 #define TIS_PC_ACC_ESTABLISH        BIT0
     82 
     83 ///
     84 /// When this bit is 1, TPM is in the Ready state,
     85 /// indicating it is ready to receive a new command.
     86 ///
     87 #define TIS_PC_STS_READY            BIT6
     88 ///
     89 /// Write a 1 to this bit to cause the TPM to execute that command.
     90 ///
     91 #define TIS_PC_STS_GO               BIT5
     92 ///
     93 /// This bit indicates that the TPM has data available as a response.
     94 ///
     95 #define TIS_PC_STS_DATA             BIT4
     96 ///
     97 /// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.
     98 ///
     99 #define TIS_PC_STS_EXPECT           BIT3
    100 ///
    101 /// Writes a 1 to this bit to force the TPM to re-send the response.
    102 ///
    103 #define TIS_PC_STS_RETRY            BIT1
    104 
    105 //
    106 // Default TimeOut values in microseconds
    107 //
    108 #define TIS_TIMEOUT_A               (750  * 1000)  // 750ms
    109 #define TIS_TIMEOUT_B               (2000 * 1000)  // 2s
    110 #define TIS_TIMEOUT_C               (750  * 1000)  // 750ms
    111 #define TIS_TIMEOUT_D               (750  * 1000)  // 750ms
    112 
    113 //
    114 // Global variable to indicate if TPM I2C Read Transfer has previously occurred.
    115 // NOTE: Given the GUARD_TIME requirement (TpmAccess.h), if this library loaded
    116 // by PEI Drivers this global variable required to be resident in R/W memory
    117 //
    118 BOOLEAN mI2CPrevReadTransfer = FALSE;
    119 
    120 /**
    121   Writes single byte data to TPM specified by I2C register address.
    122 
    123   @param[in]  TpmAddress  The register to write.
    124   @param[in]  Data        The data to write to the register.
    125 
    126 **/
    127 VOID
    128 TpmWriteByte (
    129   IN UINTN  TpmAddress,
    130   IN UINT8  Data
    131   )
    132 {
    133   EFI_STATUS              Status;
    134   UINTN                   WriteLength;
    135   UINT8                   WriteData[2];
    136   EFI_I2C_DEVICE_ADDRESS  I2CDeviceAddr;
    137 
    138   //
    139   // Setup I2C Slave device address and address mode (7-bit).
    140   //
    141   I2CDeviceAddr.I2CDeviceAddress = TPM_I2C_SLAVE_DEVICE_ADDRESS;
    142 
    143   //
    144   // As recommended by Infineon (SLB9645 I2C Communication protocol application
    145   // note revision 1.0) wait 250 microseconds between a read and a write transfer.
    146   //
    147   if (mI2CPrevReadTransfer) {
    148     MicroSecondDelay (GUARD_TIME);
    149   }
    150 
    151   //
    152   // Write to TPM register.
    153   //
    154   WriteLength = 2;
    155   WriteData[0] = (UINT8)TpmAddress;
    156   WriteData[1] = Data;
    157 
    158   Status = I2cWriteMultipleByte (
    159              I2CDeviceAddr,
    160              EfiI2CSevenBitAddrMode,
    161              &WriteLength,
    162              &WriteData
    163              );
    164   if (EFI_ERROR(Status)) {
    165     DEBUG ((EFI_D_ERROR, "TpmWriteByte(): I2C Write to TPM address %0x failed (%r)\n", TpmAddress, Status));
    166     ASSERT (FALSE);  // Writes to TPM should always succeed.
    167   }
    168 
    169   mI2CPrevReadTransfer = FALSE;
    170 }
    171 
    172 /**
    173   Reads single byte data from TPM specified by I2C register address.
    174 
    175   Due to stability issues when using I2C combined write/read transfers (with
    176   RESTART) to TPM (specifically read from status register), a single write is
    177   performed followed by single read (with STOP condition in between).
    178 
    179   @param[in] TpmAddress  Address of register  to read.
    180 
    181   @return  The value register read.
    182 
    183 **/
    184 UINT8
    185 TpmReadByte (
    186   IN UINTN  TpmAddress
    187   )
    188 {
    189   UINT8                   Data[1];
    190   UINT8                   ReadData;
    191   UINT8                   ReadCount;
    192 
    193   EFI_I2C_DEVICE_ADDRESS  I2CDeviceAddr;
    194   EFI_I2C_ADDR_MODE       I2CAddrMode;
    195 
    196   EFI_STATUS              Status;
    197 
    198   Status = EFI_SUCCESS;
    199   ReadData  = 0xFF;
    200   ReadCount = 0;
    201 
    202   //
    203   // Locate I2C protocol for TPM I2C access.
    204   //
    205   I2CDeviceAddr.I2CDeviceAddress = TPM_I2C_SLAVE_DEVICE_ADDRESS;
    206   I2CAddrMode = EfiI2CSevenBitAddrMode;
    207 
    208   //
    209   // As recommended by Infineon (SLB9645 I2C Communication protocol application
    210   // note revision 1.0) retry up to 3 times if TPM status, access or burst count
    211   // registers return 0xFF.
    212   //
    213   while ((ReadData == 0xFF) && (ReadCount < READ_RETRY)) {
    214     //
    215     // As recommended by Infineon (SLB9645 I2C Communication protocol application
    216     // note revision 1.0) wait 250 microseconds between a read and a write transfer.
    217     //
    218     if (mI2CPrevReadTransfer) {
    219       MicroSecondDelay (GUARD_TIME);
    220     }
    221 
    222     //
    223     // Write address to TPM.
    224     //
    225     Data[0] = (UINT8)TpmAddress;
    226     Status = I2cWriteByte (
    227                I2CDeviceAddr,
    228                I2CAddrMode,
    229                &Data
    230                );
    231 
    232     if (EFI_ERROR(Status)) {
    233       DEBUG ((EFI_D_INFO, "TpmReadByte(): write to TPM address %0x failed (%r)\n", TpmAddress, Status));
    234     }
    235 
    236     mI2CPrevReadTransfer = FALSE;
    237 
    238     //
    239     // Read data from TPM.
    240     //
    241     Data[0] = (UINT8)TpmAddress;
    242     Status = I2cReadByte (
    243                I2CDeviceAddr,
    244                I2CAddrMode,
    245                &Data
    246                );
    247 
    248     if (EFI_ERROR(Status)) {
    249       DEBUG ((EFI_D_INFO, "TpmReadByte(): read from TPM address %0x failed (%r)\n", TpmAddress, Status));
    250       ReadData = 0xFF;
    251     } else {
    252       ReadData = Data[0];
    253     }
    254 
    255     //
    256     // Only need to retry 3 times for TPM status, access, and burst count registers.
    257     // If read transfer is to TPM Data FIFO, do not retry, exit loop.
    258     //
    259     if (TpmAddress == INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT) {
    260       ReadCount = READ_RETRY;
    261     } else {
    262       ReadCount++;
    263     }
    264 
    265     mI2CPrevReadTransfer = TRUE;
    266   }
    267 
    268   if (EFI_ERROR(Status)) {
    269     //
    270     //  Only reads to access register allowed to fail.
    271     //
    272     if (TpmAddress != INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT) {
    273       DEBUG ((EFI_D_ERROR, "TpmReadByte(): read from TPM address %0x failed\n", TpmAddress));
    274       ASSERT_EFI_ERROR (Status);
    275     }
    276   }
    277   return ReadData;
    278 }
    279 
    280 /**
    281   Check whether the value of a TPM chip register satisfies the input BIT setting.
    282 
    283   @param[in] Register  TPM register to be checked.
    284   @param[in] BitSet    Check these data bits are set.
    285   @param[in] BitClear  Check these data bits are clear.
    286   @param[in] TimeOut   The max wait time (unit MicroSecond) when checking register.
    287 
    288   @retval EFI_SUCCESS  The register satisfies the check bit.
    289   @retval EFI_TIMEOUT  The register can't run into the expected status in time.
    290 **/
    291 EFI_STATUS
    292 TisPcWaitRegisterBits (
    293   IN UINTN   Register,
    294   IN UINT8   BitSet,
    295   IN UINT8   BitClear,
    296   IN UINT32  TimeOut
    297   )
    298 {
    299   UINT8   RegRead;
    300   UINT32  WaitTime;
    301 
    302   for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
    303     RegRead = TpmReadByte (Register);
    304     if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
    305       return EFI_SUCCESS;
    306     MicroSecondDelay (30);
    307   }
    308   return EFI_TIMEOUT;
    309 }
    310 
    311 /**
    312   Get BurstCount by reading the burstCount field of a TIS register
    313   in the time of default TIS_TIMEOUT_D.
    314 
    315   @param[out] BurstCount  Pointer to a buffer to store the got BurstConut.
    316 
    317   @retval EFI_SUCCESS            Get BurstCount.
    318   @retval EFI_INVALID_PARAMETER  BurstCount is NULL.
    319   @retval EFI_TIMEOUT            BurstCount can't be got in time.
    320 **/
    321 EFI_STATUS
    322 TisPcReadBurstCount (
    323   OUT UINT16  *BurstCount
    324   )
    325 {
    326   UINT32  WaitTime;
    327   UINT8   DataByte0;
    328   UINT8   DataByte1;
    329 
    330   if (BurstCount == NULL) {
    331     return EFI_INVALID_PARAMETER;
    332   }
    333 
    334   WaitTime = 0;
    335   do {
    336     //
    337     // BurstCount is UINT16, but it is not 2bytes aligned,
    338     // so it needs to use TpmReadByte to read two times
    339     //
    340     DataByte0   = TpmReadByte (INFINEON_TPM_BURST0_COUNT_0_DEFAULT);
    341     DataByte1   = TpmReadByte (INFINEON_TPM_BURST1_COUNT_0_DEFAULT);
    342     *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
    343     if (*BurstCount != 0) {
    344       return EFI_SUCCESS;
    345     }
    346     MicroSecondDelay (30);
    347     WaitTime += 30;
    348   } while (WaitTime < TIS_TIMEOUT_D);
    349 
    350   return EFI_TIMEOUT;
    351 }
    352 
    353 /**
    354   Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
    355   to Status Register in time.
    356 
    357   @retval EFI_SUCCESS  TPM chip enters into ready state.
    358   @retval EFI_TIMEOUT  TPM chip can't be set to ready state in time.
    359 **/
    360 EFI_STATUS
    361 TisPcPrepareCommand (
    362   VOID
    363   )
    364 {
    365   EFI_STATUS  Status;
    366 
    367   TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
    368   Status = TisPcWaitRegisterBits (
    369              INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
    370              TIS_PC_STS_READY,
    371              0,
    372              TIS_TIMEOUT_B
    373              );
    374   return Status;
    375 }
    376 
    377 /**
    378   This service requests use TPM12.
    379 
    380   @retval EFI_SUCCESS      Get the control of TPM12 chip.
    381   @retval EFI_NOT_FOUND    TPM12 not found.
    382   @retval EFI_DEVICE_ERROR Unexpected device behavior.
    383 **/
    384 EFI_STATUS
    385 EFIAPI
    386 Tpm12RequestUseTpm (
    387   VOID
    388   )
    389 {
    390   EFI_STATUS  Status;
    391 
    392   //
    393   // Check to see if TPM exists
    394   //
    395   if (TpmReadByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT) == 0xFF) {
    396     return EFI_NOT_FOUND;
    397   }
    398 
    399   TpmWriteByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT, TIS_PC_ACC_RQUUSE);
    400 
    401   //
    402   // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A
    403   //
    404   Status = TisPcWaitRegisterBits (
    405              INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT,
    406              (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
    407              0,
    408              TIS_TIMEOUT_A
    409              );
    410   return Status;
    411 }
    412 
    413 /**
    414   Send command to TPM for execution.
    415 
    416   @param[in] TpmBuffer   Buffer for TPM command data.
    417   @param[in] DataLength  TPM command data length.
    418 
    419   @retval EFI_SUCCESS  Operation completed successfully.
    420   @retval EFI_TIMEOUT  The register can't run into the expected status in time.
    421 
    422 **/
    423 EFI_STATUS
    424 TisPcSend (
    425   IN UINT8   *TpmBuffer,
    426   IN UINT32  DataLength
    427   )
    428 {
    429   UINT16      BurstCount;
    430   UINT32      Index;
    431   EFI_STATUS  Status;
    432 
    433   Status = TisPcPrepareCommand ();
    434   if (EFI_ERROR (Status)){
    435     DEBUG ((DEBUG_ERROR, "The TPM is not ready!\n"));
    436     goto Done;
    437   }
    438   Index = 0;
    439   while (Index < DataLength) {
    440     Status = TisPcReadBurstCount (&BurstCount);
    441     if (EFI_ERROR (Status)) {
    442       Status = EFI_TIMEOUT;
    443       goto Done;
    444     }
    445     for (; BurstCount > 0 && Index < DataLength; BurstCount--) {
    446       TpmWriteByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT, *(TpmBuffer + Index));
    447       Index++;
    448     }
    449   }
    450   //
    451   // Ensure the TPM status STS_EXPECT change from 1 to 0
    452   //
    453   Status = TisPcWaitRegisterBits (
    454              INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
    455              (UINT8) TIS_PC_VALID,
    456              TIS_PC_STS_EXPECT,
    457              TIS_TIMEOUT_C
    458              );
    459   if (EFI_ERROR (Status)) {
    460     goto Done;
    461   }
    462 
    463   //
    464   // Start the command
    465   //
    466   TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_GO);
    467 
    468 Done:
    469   if (EFI_ERROR (Status))  {
    470     //
    471     // Ensure the TPM state change from "Reception" to "Idle/Ready"
    472     //
    473     TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
    474   }
    475 
    476   return Status;
    477 }
    478 
    479 /**
    480   Receive response data of last command from TPM.
    481 
    482   @param[out] TpmBuffer  Buffer for response data.
    483   @param[out] RespSize   Response data length.
    484 
    485   @retval EFI_SUCCESS           Operation completed successfully.
    486   @retval EFI_TIMEOUT           The register can't run into the expected status in time.
    487   @retval EFI_DEVICE_ERROR      Unexpected device status.
    488   @retval EFI_BUFFER_TOO_SMALL  Response data is too long.
    489 
    490 **/
    491 EFI_STATUS
    492 TisPcReceive (
    493   OUT UINT8   *TpmBuffer,
    494   OUT UINT32  *RespSize
    495   )
    496 {
    497   EFI_STATUS           Status;
    498   UINT16               BurstCount;
    499   UINT32               Index;
    500   UINT32               ResponseSize;
    501   TPM_RSP_COMMAND_HDR  *ResponseHeader;
    502 
    503   //
    504   // Wait for the command completion
    505   //
    506   Status = TisPcWaitRegisterBits (
    507              INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
    508              (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
    509              0,
    510              TIS_TIMEOUT_B
    511              );
    512   if (EFI_ERROR (Status)) {
    513     Status = EFI_TIMEOUT;
    514     goto Done;
    515   }
    516   //
    517   // Read the response data header and check it
    518   //
    519   Index = 0;
    520   BurstCount = 0;
    521   while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
    522     Status = TisPcReadBurstCount (&BurstCount);
    523     if (EFI_ERROR (Status)) {
    524       Status = EFI_TIMEOUT;
    525       goto Done;
    526     }
    527     for (; BurstCount > 0 ; BurstCount--) {
    528       *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT);
    529       Index++;
    530       if (Index == sizeof (TPM_RSP_COMMAND_HDR))
    531         break;
    532     }
    533   }
    534 
    535   //
    536   // Check the response data header (tag, parasize and returncode)
    537   //
    538   ResponseHeader = (TPM_RSP_COMMAND_HDR *)TpmBuffer;
    539   if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) {
    540     Status = EFI_DEVICE_ERROR;
    541     goto Done;
    542   }
    543 
    544   ResponseSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize));
    545   if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {
    546     Status = EFI_SUCCESS;
    547     goto Done;
    548   }
    549   if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {
    550     Status = EFI_DEVICE_ERROR;
    551     goto Done;
    552   }
    553   if (*RespSize < ResponseSize) {
    554     Status = EFI_BUFFER_TOO_SMALL;
    555     goto Done;
    556   }
    557   *RespSize = ResponseSize;
    558 
    559   //
    560   // Continue reading the remaining data
    561   //
    562   while (Index < ResponseSize) {
    563     for (; BurstCount > 0 ; BurstCount--) {
    564       *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT);
    565       Index++;
    566       if (Index == ResponseSize) {
    567         Status = EFI_SUCCESS;
    568         goto Done;
    569       }
    570     }
    571     Status = TisPcReadBurstCount (&BurstCount);
    572     if (EFI_ERROR (Status) && (Index < ResponseSize)) {
    573       Status = EFI_DEVICE_ERROR;
    574       goto Done;
    575     }
    576   }
    577 
    578 Done:
    579   //
    580   // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"
    581   //
    582   TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
    583 
    584   return Status;
    585 }
    586 
    587 /**
    588   This service enables the sending of commands to the TPM12.
    589 
    590   @param[in]     InputParameterBlockSize   Size of the TPM12 input parameter block.
    591   @param[in]     InputParameterBlock       Pointer to the TPM12 input parameter block.
    592   @param[in,out] OutputParameterBlockSize  Size of the TPM12 output parameter block.
    593   @param[in]     OutputParameterBlock      Pointer to the TPM12 output parameter block.
    594 
    595   @retval EFI_SUCCESS           The command byte stream was successfully sent to
    596                                 the device and a response was successfully received.
    597   @retval EFI_DEVICE_ERROR      The command was not successfully sent to the
    598                                 device or a response was not successfully received
    599                                 from the device.
    600   @retval EFI_BUFFER_TOO_SMALL  The output parameter block is too small.
    601 **/
    602 EFI_STATUS
    603 EFIAPI
    604 Tpm12SubmitCommand (
    605   IN UINT32      InputParameterBlockSize,
    606   IN UINT8       *InputParameterBlock,
    607   IN OUT UINT32  *OutputParameterBlockSize,
    608   IN UINT8       *OutputParameterBlock
    609   )
    610 {
    611   EFI_STATUS  Status;
    612 
    613   Status = TisPcSend (InputParameterBlock, InputParameterBlockSize);
    614   if (!EFI_ERROR (Status)) {
    615     Status = TisPcReceive (OutputParameterBlock, OutputParameterBlockSize);
    616   }
    617   return Status;
    618 }
    619