1 /** @file
2   Basic TIS (TPM Interface Specification) functions.
3 
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "CommonHeader.h"
10 
11 /**
12   Check whether TPM chip exist.
13 
14   @param[in] TisReg  Pointer to TIS register.
15 
16   @retval    TRUE    TPM chip exists.
17   @retval    FALSE   TPM chip is not found.
18 **/
19 BOOLEAN
TisPcPresenceCheck(IN TIS_PC_REGISTERS_PTR TisReg)20 TisPcPresenceCheck (
21   IN      TIS_PC_REGISTERS_PTR      TisReg
22   )
23 {
24   UINT8                             RegRead;
25 
26   RegRead = MmioRead8 ((UINTN)&TisReg->Access);
27   return (BOOLEAN)(RegRead != (UINT8)-1);
28 }
29 
30 /**
31   Check whether the value of a TPM chip register satisfies the input BIT setting.
32 
33   @param[in]  Register     Address port of register to be checked.
34   @param[in]  BitSet       Check these data bits are set.
35   @param[in]  BitClear     Check these data bits are clear.
36   @param[in]  TimeOut      The max wait time (unit MicroSecond) when checking register.
37 
38   @retval     EFI_SUCCESS  The register satisfies the check bit.
39   @retval     EFI_TIMEOUT  The register can't run into the expected status in time.
40 **/
41 EFI_STATUS
42 EFIAPI
TisPcWaitRegisterBits(IN UINT8 * Register,IN UINT8 BitSet,IN UINT8 BitClear,IN UINT32 TimeOut)43 TisPcWaitRegisterBits (
44   IN      UINT8                     *Register,
45   IN      UINT8                     BitSet,
46   IN      UINT8                     BitClear,
47   IN      UINT32                    TimeOut
48   )
49 {
50   UINT8                             RegRead;
51   UINT32                            WaitTime;
52 
53   for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
54     RegRead = MmioRead8 ((UINTN)Register);
55     if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
56       return EFI_SUCCESS;
57     MicroSecondDelay (30);
58   }
59   return EFI_TIMEOUT;
60 }
61 
62 /**
63   Get BurstCount by reading the burstCount field of a TIS register
64   in the time of default TIS_TIMEOUT_D.
65 
66   @param[in]  TisReg                Pointer to TIS register.
67   @param[out] BurstCount            Pointer to a buffer to store the got BurstCount.
68 
69   @retval     EFI_SUCCESS           Get BurstCount.
70   @retval     EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.
71   @retval     EFI_TIMEOUT           BurstCount can't be got in time.
72 **/
73 EFI_STATUS
74 EFIAPI
TisPcReadBurstCount(IN TIS_PC_REGISTERS_PTR TisReg,OUT UINT16 * BurstCount)75 TisPcReadBurstCount (
76   IN      TIS_PC_REGISTERS_PTR      TisReg,
77      OUT  UINT16                    *BurstCount
78   )
79 {
80   UINT32                            WaitTime;
81   UINT8                             DataByte0;
82   UINT8                             DataByte1;
83 
84   if (BurstCount == NULL || TisReg == NULL) {
85     return EFI_INVALID_PARAMETER;
86   }
87 
88   WaitTime = 0;
89   do {
90     //
91     // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned,
92     // so it needs to use MmioRead8 to read two times
93     //
94     DataByte0   = MmioRead8 ((UINTN)&TisReg->BurstCount);
95     DataByte1   = MmioRead8 ((UINTN)&TisReg->BurstCount + 1);
96     *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
97     if (*BurstCount != 0) {
98       return EFI_SUCCESS;
99     }
100     MicroSecondDelay (30);
101     WaitTime += 30;
102   } while (WaitTime < TIS_TIMEOUT_D);
103 
104   return EFI_TIMEOUT;
105 }
106 
107 /**
108   Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
109   to Status Register in time.
110 
111   @param[in] TisReg                Pointer to TIS register.
112 
113   @retval    EFI_SUCCESS           TPM chip enters into ready state.
114   @retval    EFI_INVALID_PARAMETER TisReg is NULL.
115   @retval    EFI_TIMEOUT           TPM chip can't be set to ready state in time.
116 **/
117 EFI_STATUS
118 EFIAPI
TisPcPrepareCommand(IN TIS_PC_REGISTERS_PTR TisReg)119 TisPcPrepareCommand (
120   IN      TIS_PC_REGISTERS_PTR      TisReg
121   )
122 {
123   EFI_STATUS                        Status;
124 
125   if (TisReg == NULL) {
126     return EFI_INVALID_PARAMETER;
127   }
128 
129   MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
130   Status = TisPcWaitRegisterBits (
131              &TisReg->Status,
132              TIS_PC_STS_READY,
133              0,
134              TIS_TIMEOUT_B
135              );
136   return Status;
137 }
138 
139 /**
140   Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
141   to ACCESS Register in the time of default TIS_TIMEOUT_A.
142 
143   @param[in] TisReg                Pointer to TIS register.
144 
145   @retval    EFI_SUCCESS           Get the control of TPM chip.
146   @retval    EFI_INVALID_PARAMETER TisReg is NULL.
147   @retval    EFI_NOT_FOUND         TPM chip doesn't exit.
148   @retval    EFI_TIMEOUT           Can't get the TPM control in time.
149 **/
150 EFI_STATUS
151 EFIAPI
TisPcRequestUseTpm(IN TIS_PC_REGISTERS_PTR TisReg)152 TisPcRequestUseTpm (
153   IN      TIS_PC_REGISTERS_PTR      TisReg
154   )
155 {
156   EFI_STATUS                        Status;
157 
158   if (TisReg == NULL) {
159     return EFI_INVALID_PARAMETER;
160   }
161 
162   if (!TisPcPresenceCheck (TisReg)) {
163     return EFI_NOT_FOUND;
164   }
165 
166   MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
167   //
168   // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A
169   //
170   Status = TisPcWaitRegisterBits (
171              &TisReg->Access,
172              (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
173              0,
174              TIS_TIMEOUT_A
175              );
176   return Status;
177 }
178