• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   TIS (TPM Interface Specification) functions used by TPM1.2.
3 
4 Copyright (c) 2013 - 2015, 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 //
27 // Set structure alignment to 1-byte
28 //
29 #pragma pack (1)
30 
31 //
32 // Register set map as specified in TIS specification Chapter 10
33 //
34 typedef struct {
35   ///
36   /// Used to gain ownership for this particular port.
37   ///
38   UINT8                             Access;             // 0
39   UINT8                             Reserved1[7];       // 1
40   ///
41   /// Controls interrupts.
42   ///
43   UINT32                            IntEnable;          // 8
44   ///
45   /// SIRQ vector to be used by the TPM.
46   ///
47   UINT8                             IntVector;          // 0ch
48   UINT8                             Reserved2[3];       // 0dh
49   ///
50   /// What caused interrupt.
51   ///
52   UINT32                            IntSts;             // 10h
53   ///
54   /// Shows which interrupts are supported by that particular TPM.
55   ///
56   UINT32                            IntfCapability;     // 14h
57   ///
58   /// Status Register. Provides status of the TPM.
59   ///
60   UINT8                             Status;             // 18h
61   ///
62   /// Number of consecutive writes that can be done to the TPM.
63   ///
64   UINT16                            BurstCount;         // 19h
65   UINT8                             Reserved3[9];
66   ///
67   /// Read or write FIFO, depending on transaction.
68   ///
69   UINT32                            DataFifo;           // 24h
70   UINT8                             Reserved4[0xed8];   // 28h
71   ///
72   /// Vendor ID
73   ///
74   UINT16                            Vid;                // 0f00h
75   ///
76   /// Device ID
77   ///
78   UINT16                            Did;                // 0f02h
79   ///
80   /// Revision ID
81   ///
82   UINT8                             Rid;                // 0f04h
83   ///
84   /// TCG defined configuration registers.
85   ///
86   UINT8                             TcgDefined[0x7b];   // 0f05h
87   ///
88   /// Alias to I/O legacy space.
89   ///
90   UINT32                            LegacyAddress1;     // 0f80h
91   ///
92   /// Additional 8 bits for I/O legacy space extension.
93   ///
94   UINT32                            LegacyAddress1Ex;   // 0f84h
95   ///
96   /// Alias to second I/O legacy space.
97   ///
98   UINT32                            LegacyAddress2;     // 0f88h
99   ///
100   /// Additional 8 bits for second I/O legacy space extension.
101   ///
102   UINT32                            LegacyAddress2Ex;   // 0f8ch
103   ///
104   /// Vendor-defined configuration registers.
105   ///
106   UINT8                             VendorDefined[0x70];// 0f90h
107 } TIS_PC_REGISTERS;
108 
109 //
110 // Restore original structure alignment
111 //
112 #pragma pack ()
113 
114 //
115 // Define pointer types used to access TIS registers on PC
116 //
117 typedef TIS_PC_REGISTERS  *TIS_PC_REGISTERS_PTR;
118 
119 //
120 // Define bits of ACCESS and STATUS registers
121 //
122 
123 ///
124 /// This bit is a 1 to indicate that the other bits in this register are valid.
125 ///
126 #define TIS_PC_VALID                BIT7
127 ///
128 /// Indicate that this locality is active.
129 ///
130 #define TIS_PC_ACC_ACTIVE           BIT5
131 ///
132 /// Set to 1 to indicate that this locality had the TPM taken away while
133 /// this locality had the TIS_PC_ACC_ACTIVE bit set.
134 ///
135 #define TIS_PC_ACC_SEIZED           BIT4
136 ///
137 /// Set to 1 to indicate that TPM MUST reset the
138 /// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the
139 /// locality that is writing this bit.
140 ///
141 #define TIS_PC_ACC_SEIZE            BIT3
142 ///
143 /// When this bit is 1, another locality is requesting usage of the TPM.
144 ///
145 #define TIS_PC_ACC_PENDIND          BIT2
146 ///
147 /// Set to 1 to indicate that this locality is requesting to use TPM.
148 ///
149 #define TIS_PC_ACC_RQUUSE           BIT1
150 ///
151 /// A value of 1 indicates that a T/OS has not been established on the platform
152 ///
153 #define TIS_PC_ACC_ESTABLISH        BIT0
154 
155 ///
156 /// When this bit is 1, TPM is in the Ready state,
157 /// indicating it is ready to receive a new command.
158 ///
159 #define TIS_PC_STS_READY            BIT6
160 ///
161 /// Write a 1 to this bit to cause the TPM to execute that command.
162 ///
163 #define TIS_PC_STS_GO               BIT5
164 ///
165 /// This bit indicates that the TPM has data available as a response.
166 ///
167 #define TIS_PC_STS_DATA             BIT4
168 ///
169 /// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.
170 ///
171 #define TIS_PC_STS_EXPECT           BIT3
172 ///
173 /// Writes a 1 to this bit to force the TPM to re-send the response.
174 ///
175 #define TIS_PC_STS_RETRY            BIT1
176 
177 //
178 // Default TimeOut value
179 //
180 #define TIS_TIMEOUT_A               (750  * 1000)  // 750ms
181 #define TIS_TIMEOUT_B               (2000 * 1000)  // 2s
182 #define TIS_TIMEOUT_C               (750  * 1000)  // 750ms
183 #define TIS_TIMEOUT_D               (750  * 1000)  // 750ms
184 
185 //
186 // Max TPM command/reponse length
187 //
188 #define TPMCMDBUFLENGTH             1024
189 
190 /**
191   Check whether TPM chip exist.
192 
193   @param[in] TisReg  Pointer to TIS register.
194 
195   @retval    TRUE    TPM chip exists.
196   @retval    FALSE   TPM chip is not found.
197 **/
198 BOOLEAN
Tpm12TisPcPresenceCheck(IN TIS_PC_REGISTERS_PTR TisReg)199 Tpm12TisPcPresenceCheck (
200   IN      TIS_PC_REGISTERS_PTR      TisReg
201   )
202 {
203   UINT8                             RegRead;
204 
205   RegRead = MmioRead8 ((UINTN)&TisReg->Access);
206   return (BOOLEAN)(RegRead != (UINT8)-1);
207 }
208 
209 /**
210   Check whether the value of a TPM chip register satisfies the input BIT setting.
211 
212   @param[in]  Register     Address port of register to be checked.
213   @param[in]  BitSet       Check these data bits are set.
214   @param[in]  BitClear     Check these data bits are clear.
215   @param[in]  TimeOut      The max wait time (unit MicroSecond) when checking register.
216 
217   @retval     EFI_SUCCESS  The register satisfies the check bit.
218   @retval     EFI_TIMEOUT  The register can't run into the expected status in time.
219 **/
220 EFI_STATUS
Tpm12TisPcWaitRegisterBits(IN UINT8 * Register,IN UINT8 BitSet,IN UINT8 BitClear,IN UINT32 TimeOut)221 Tpm12TisPcWaitRegisterBits (
222   IN      UINT8                     *Register,
223   IN      UINT8                     BitSet,
224   IN      UINT8                     BitClear,
225   IN      UINT32                    TimeOut
226   )
227 {
228   UINT8                             RegRead;
229   UINT32                            WaitTime;
230 
231   for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
232     RegRead = MmioRead8 ((UINTN)Register);
233     if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
234       return EFI_SUCCESS;
235     MicroSecondDelay (30);
236   }
237   return EFI_TIMEOUT;
238 }
239 
240 /**
241   Get BurstCount by reading the burstCount field of a TIS regiger
242   in the time of default TIS_TIMEOUT_D.
243 
244   @param[in]  TisReg                Pointer to TIS register.
245   @param[out] BurstCount            Pointer to a buffer to store the got BurstConut.
246 
247   @retval     EFI_SUCCESS           Get BurstCount.
248   @retval     EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.
249   @retval     EFI_TIMEOUT           BurstCount can't be got in time.
250 **/
251 EFI_STATUS
Tpm12TisPcReadBurstCount(IN TIS_PC_REGISTERS_PTR TisReg,OUT UINT16 * BurstCount)252 Tpm12TisPcReadBurstCount (
253   IN      TIS_PC_REGISTERS_PTR      TisReg,
254      OUT  UINT16                    *BurstCount
255   )
256 {
257   UINT32                            WaitTime;
258   UINT8                             DataByte0;
259   UINT8                             DataByte1;
260 
261   if (BurstCount == NULL || TisReg == NULL) {
262     return EFI_INVALID_PARAMETER;
263   }
264 
265   WaitTime = 0;
266   do {
267     //
268     // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned,
269     // so it needs to use MmioRead8 to read two times
270     //
271     DataByte0   = MmioRead8 ((UINTN)&TisReg->BurstCount);
272     DataByte1   = MmioRead8 ((UINTN)&TisReg->BurstCount + 1);
273     *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
274     if (*BurstCount != 0) {
275       return EFI_SUCCESS;
276     }
277     MicroSecondDelay (30);
278     WaitTime += 30;
279   } while (WaitTime < TIS_TIMEOUT_D);
280 
281   return EFI_TIMEOUT;
282 }
283 
284 /**
285   Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
286   to Status Register in time.
287 
288   @param[in] TisReg                Pointer to TIS register.
289 
290   @retval    EFI_SUCCESS           TPM chip enters into ready state.
291   @retval    EFI_INVALID_PARAMETER TisReg is NULL.
292   @retval    EFI_TIMEOUT           TPM chip can't be set to ready state in time.
293 **/
294 EFI_STATUS
Tpm12TisPcPrepareCommand(IN TIS_PC_REGISTERS_PTR TisReg)295 Tpm12TisPcPrepareCommand (
296   IN      TIS_PC_REGISTERS_PTR      TisReg
297   )
298 {
299   EFI_STATUS                        Status;
300 
301   if (TisReg == NULL) {
302     return EFI_INVALID_PARAMETER;
303   }
304 
305   MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
306   Status = Tpm12TisPcWaitRegisterBits (
307              &TisReg->Status,
308              TIS_PC_STS_READY,
309              0,
310              TIS_TIMEOUT_B
311              );
312   return Status;
313 }
314 
315 /**
316   Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
317   to ACCESS Register in the time of default TIS_TIMEOUT_A.
318 
319   @param[in] TisReg                Pointer to TIS register.
320 
321   @retval    EFI_SUCCESS           Get the control of TPM chip.
322   @retval    EFI_INVALID_PARAMETER TisReg is NULL.
323   @retval    EFI_NOT_FOUND         TPM chip doesn't exit.
324   @retval    EFI_TIMEOUT           Can't get the TPM control in time.
325 **/
326 EFI_STATUS
Tpm12TisPcRequestUseTpm(IN TIS_PC_REGISTERS_PTR TisReg)327 Tpm12TisPcRequestUseTpm (
328   IN      TIS_PC_REGISTERS_PTR      TisReg
329   )
330 {
331   EFI_STATUS                        Status;
332 
333   if (TisReg == NULL) {
334     return EFI_INVALID_PARAMETER;
335   }
336 
337   if (!Tpm12TisPcPresenceCheck (TisReg)) {
338     return EFI_NOT_FOUND;
339   }
340 
341   MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
342   Status = Tpm12TisPcWaitRegisterBits (
343              &TisReg->Access,
344              (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
345              0,
346              TIS_TIMEOUT_A
347              );
348   return Status;
349 }
350 
351 /**
352   Send a command to TPM for execution and return response data.
353 
354   @param[in]      TisReg        TPM register space base address.
355   @param[in]      BufferIn      Buffer for command data.
356   @param[in]      SizeIn        Size of command data.
357   @param[in, out] BufferOut     Buffer for response data.
358   @param[in, out] SizeOut       Size of response data.
359 
360   @retval EFI_SUCCESS           Operation completed successfully.
361   @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.
362   @retval EFI_DEVICE_ERROR      Unexpected device behavior.
363   @retval EFI_UNSUPPORTED       Unsupported TPM version
364 
365 **/
366 EFI_STATUS
Tpm12TisTpmCommand(IN TIS_PC_REGISTERS_PTR TisReg,IN UINT8 * BufferIn,IN UINT32 SizeIn,IN OUT UINT8 * BufferOut,IN OUT UINT32 * SizeOut)367 Tpm12TisTpmCommand (
368   IN     TIS_PC_REGISTERS_PTR       TisReg,
369   IN     UINT8                      *BufferIn,
370   IN     UINT32                     SizeIn,
371   IN OUT UINT8                      *BufferOut,
372   IN OUT UINT32                     *SizeOut
373   )
374 {
375   EFI_STATUS                        Status;
376   UINT16                            BurstCount;
377   UINT32                            Index;
378   UINT32                            TpmOutSize;
379   UINT16                            Data16;
380   UINT32                            Data32;
381 
382   DEBUG_CODE (
383     UINTN  DebugSize;
384 
385     DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand Send - "));
386     if (SizeIn > 0x100) {
387       DebugSize = 0x40;
388     } else {
389       DebugSize = SizeIn;
390     }
391     for (Index = 0; Index < DebugSize; Index++) {
392       DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
393     }
394     if (DebugSize != SizeIn) {
395       DEBUG ((EFI_D_VERBOSE, "...... "));
396       for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
397         DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
398       }
399     }
400     DEBUG ((EFI_D_VERBOSE, "\n"));
401   );
402   TpmOutSize = 0;
403 
404   Status = Tpm12TisPcPrepareCommand (TisReg);
405   if (EFI_ERROR (Status)){
406     DEBUG ((DEBUG_ERROR, "Tpm12 is not ready for command!\n"));
407     return EFI_DEVICE_ERROR;
408   }
409   //
410   // Send the command data to Tpm
411   //
412   Index = 0;
413   while (Index < SizeIn) {
414     Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
415     if (EFI_ERROR (Status)) {
416       Status = EFI_DEVICE_ERROR;
417       goto Exit;
418     }
419     for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {
420       MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));
421       Index++;
422     }
423   }
424   //
425   // Check the Tpm status STS_EXPECT change from 1 to 0
426   //
427   Status = Tpm12TisPcWaitRegisterBits (
428              &TisReg->Status,
429              (UINT8) TIS_PC_VALID,
430              TIS_PC_STS_EXPECT,
431              TIS_TIMEOUT_C
432              );
433   if (EFI_ERROR (Status)) {
434     DEBUG ((DEBUG_ERROR, "Tpm12 The send buffer too small!\n"));
435     Status = EFI_BUFFER_TOO_SMALL;
436     goto Exit;
437   }
438   //
439   // Executed the TPM command and waiting for the response data ready
440   //
441   MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);
442   Status = Tpm12TisPcWaitRegisterBits (
443              &TisReg->Status,
444              (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
445              0,
446              TIS_TIMEOUT_B
447              );
448   if (EFI_ERROR (Status)) {
449     DEBUG ((DEBUG_ERROR, "Wait for Tpm12 response data time out!!\n"));
450     Status = EFI_DEVICE_ERROR;
451     goto Exit;
452   }
453   //
454   // Get response data header
455   //
456   Index = 0;
457   BurstCount = 0;
458   while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
459     Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
460     if (EFI_ERROR (Status)) {
461       Status = EFI_DEVICE_ERROR;
462       goto Exit;
463     }
464     for (; BurstCount > 0; BurstCount--) {
465       *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
466       Index++;
467       if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break;
468     }
469   }
470   DEBUG_CODE (
471     DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand ReceiveHeader - "));
472     for (Index = 0; Index < sizeof (TPM_RSP_COMMAND_HDR); Index++) {
473       DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
474     }
475     DEBUG ((EFI_D_VERBOSE, "\n"));
476   );
477   //
478   // Check the reponse data header (tag,parasize and returncode )
479   //
480   CopyMem (&Data16, BufferOut, sizeof (UINT16));
481   if (SwapBytes16 (Data16) != TPM_TAG_RSP_COMMAND) {
482     DEBUG ((EFI_D_ERROR, "TPM12: TPM_ST_RSP error - %x\n", TPM_TAG_RSP_COMMAND));
483     Status = EFI_UNSUPPORTED;
484     goto Exit;
485   }
486 
487   CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
488   TpmOutSize  = SwapBytes32 (Data32);
489   if (*SizeOut < TpmOutSize) {
490     Status = EFI_BUFFER_TOO_SMALL;
491     goto Exit;
492   }
493   *SizeOut = TpmOutSize;
494   //
495   // Continue reading the remaining data
496   //
497   while ( Index < TpmOutSize ) {
498     for (; BurstCount > 0; BurstCount--) {
499       *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
500       Index++;
501       if (Index == TpmOutSize) {
502         Status = EFI_SUCCESS;
503         goto Exit;
504       }
505     }
506     Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
507     if (EFI_ERROR (Status)) {
508       Status = EFI_DEVICE_ERROR;
509       goto Exit;
510     }
511   }
512 Exit:
513   DEBUG_CODE (
514     DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand Receive - "));
515     for (Index = 0; Index < TpmOutSize; Index++) {
516       DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
517     }
518     DEBUG ((EFI_D_VERBOSE, "\n"));
519   );
520   MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
521   return Status;
522 }
523 
524 /**
525   This service enables the sending of commands to the TPM12.
526 
527   @param[in]      InputParameterBlockSize  Size of the TPM12 input parameter block.
528   @param[in]      InputParameterBlock      Pointer to the TPM12 input parameter block.
529   @param[in,out]  OutputParameterBlockSize Size of the TPM12 output parameter block.
530   @param[in]      OutputParameterBlock     Pointer to the TPM12 output parameter block.
531 
532   @retval EFI_SUCCESS            The command byte stream was successfully sent to the device and a response was successfully received.
533   @retval EFI_DEVICE_ERROR       The command was not successfully sent to the device or a response was not successfully received from the device.
534   @retval EFI_BUFFER_TOO_SMALL   The output parameter block is too small.
535 **/
536 EFI_STATUS
537 EFIAPI
Tpm12SubmitCommand(IN UINT32 InputParameterBlockSize,IN UINT8 * InputParameterBlock,IN OUT UINT32 * OutputParameterBlockSize,IN UINT8 * OutputParameterBlock)538 Tpm12SubmitCommand (
539   IN UINT32            InputParameterBlockSize,
540   IN UINT8             *InputParameterBlock,
541   IN OUT UINT32        *OutputParameterBlockSize,
542   IN UINT8             *OutputParameterBlock
543   )
544 {
545   return Tpm12TisTpmCommand (
546            (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
547            InputParameterBlock,
548            InputParameterBlockSize,
549            OutputParameterBlock,
550            OutputParameterBlockSize
551            );
552 }
553 
554 /**
555   This service requests use TPM12.
556 
557   @retval EFI_SUCCESS      Get the control of TPM12 chip.
558   @retval EFI_NOT_FOUND    TPM12 not found.
559   @retval EFI_DEVICE_ERROR Unexpected device behavior.
560 **/
561 EFI_STATUS
562 EFIAPI
Tpm12RequestUseTpm(VOID)563 Tpm12RequestUseTpm (
564   VOID
565   )
566 {
567   return Tpm12TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
568 }
569