TisPc.c 17 KB

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