• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
TpmWriteByte(IN UINTN TpmAddress,IN UINT8 Data)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
TpmReadByte(IN UINTN TpmAddress)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
TisPcWaitRegisterBits(IN UINTN Register,IN UINT8 BitSet,IN UINT8 BitClear,IN UINT32 TimeOut)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
TisPcReadBurstCount(OUT UINT16 * BurstCount)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
TisPcPrepareCommand(VOID)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
Tpm12RequestUseTpm(VOID)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
TisPcSend(IN UINT8 * TpmBuffer,IN UINT32 DataLength)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
TisPcReceive(OUT UINT8 * TpmBuffer,OUT UINT32 * RespSize)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
Tpm12SubmitCommand(IN UINT32 InputParameterBlockSize,IN UINT8 * InputParameterBlock,IN OUT UINT32 * OutputParameterBlockSize,IN UINT8 * OutputParameterBlock)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