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