Tpm2Tis.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /** @file
  2. TIS (TPM Interface Specification) functions used by dTPM2.0 library.
  3. Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
  4. (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <IndustryStandard/Tpm20.h>
  8. #include <Library/BaseLib.h>
  9. #include <Library/BaseMemoryLib.h>
  10. #include <Library/IoLib.h>
  11. #include <Library/TimerLib.h>
  12. #include <Library/DebugLib.h>
  13. #include <Library/Tpm2DeviceLib.h>
  14. #include <Library/PcdLib.h>
  15. #include <IndustryStandard/TpmTis.h>
  16. #define TIS_TIMEOUT_MAX (90000 * 1000) // 90s
  17. //
  18. // Max TPM command/reponse length
  19. //
  20. #define TPMCMDBUFLENGTH 0x500
  21. /**
  22. Check whether TPM chip exist.
  23. @param[in] TisReg Pointer to TIS register.
  24. @retval TRUE TPM chip exists.
  25. @retval FALSE TPM chip is not found.
  26. **/
  27. BOOLEAN
  28. TisPcPresenceCheck (
  29. IN TIS_PC_REGISTERS_PTR TisReg
  30. )
  31. {
  32. UINT8 RegRead;
  33. RegRead = MmioRead8 ((UINTN)&TisReg->Access);
  34. return (BOOLEAN)(RegRead != (UINT8)-1);
  35. }
  36. /**
  37. Check whether the value of a TPM chip register satisfies the input BIT setting.
  38. @param[in] Register Address port of register to be checked.
  39. @param[in] BitSet Check these data bits are set.
  40. @param[in] BitClear Check these data bits are clear.
  41. @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
  42. @retval EFI_SUCCESS The register satisfies the check bit.
  43. @retval EFI_TIMEOUT The register can't run into the expected status in time.
  44. **/
  45. EFI_STATUS
  46. TisPcWaitRegisterBits (
  47. IN UINT8 *Register,
  48. IN UINT8 BitSet,
  49. IN UINT8 BitClear,
  50. IN UINT32 TimeOut
  51. )
  52. {
  53. UINT8 RegRead;
  54. UINT32 WaitTime;
  55. for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
  56. RegRead = MmioRead8 ((UINTN)Register);
  57. if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
  58. return EFI_SUCCESS;
  59. MicroSecondDelay (30);
  60. }
  61. return EFI_TIMEOUT;
  62. }
  63. /**
  64. Get BurstCount by reading the burstCount field of a TIS regiger
  65. in the time of default TIS_TIMEOUT_D.
  66. @param[in] TisReg Pointer to TIS register.
  67. @param[out] BurstCount Pointer to a buffer to store the got BurstCount.
  68. @retval EFI_SUCCESS Get BurstCount.
  69. @retval EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.
  70. @retval EFI_TIMEOUT BurstCount can't be got in time.
  71. **/
  72. EFI_STATUS
  73. TisPcReadBurstCount (
  74. IN TIS_PC_REGISTERS_PTR TisReg,
  75. OUT UINT16 *BurstCount
  76. )
  77. {
  78. UINT32 WaitTime;
  79. UINT8 DataByte0;
  80. UINT8 DataByte1;
  81. if (BurstCount == NULL || TisReg == NULL) {
  82. return EFI_INVALID_PARAMETER;
  83. }
  84. WaitTime = 0;
  85. do {
  86. //
  87. // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned,
  88. // so it needs to use MmioRead8 to read two times
  89. //
  90. DataByte0 = MmioRead8 ((UINTN)&TisReg->BurstCount);
  91. DataByte1 = MmioRead8 ((UINTN)&TisReg->BurstCount + 1);
  92. *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
  93. if (*BurstCount != 0) {
  94. return EFI_SUCCESS;
  95. }
  96. MicroSecondDelay (30);
  97. WaitTime += 30;
  98. } while (WaitTime < TIS_TIMEOUT_D);
  99. return EFI_TIMEOUT;
  100. }
  101. /**
  102. Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
  103. to Status Register in time.
  104. @param[in] TisReg Pointer to TIS register.
  105. @retval EFI_SUCCESS TPM chip enters into ready state.
  106. @retval EFI_INVALID_PARAMETER TisReg is NULL.
  107. @retval EFI_TIMEOUT TPM chip can't be set to ready state in time.
  108. **/
  109. EFI_STATUS
  110. TisPcPrepareCommand (
  111. IN TIS_PC_REGISTERS_PTR TisReg
  112. )
  113. {
  114. EFI_STATUS Status;
  115. if (TisReg == NULL) {
  116. return EFI_INVALID_PARAMETER;
  117. }
  118. MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
  119. Status = TisPcWaitRegisterBits (
  120. &TisReg->Status,
  121. TIS_PC_STS_READY,
  122. 0,
  123. TIS_TIMEOUT_B
  124. );
  125. return Status;
  126. }
  127. /**
  128. Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
  129. to ACCESS Register in the time of default TIS_TIMEOUT_A.
  130. @param[in] TisReg Pointer to TIS register.
  131. @retval EFI_SUCCESS Get the control of TPM chip.
  132. @retval EFI_INVALID_PARAMETER TisReg is NULL.
  133. @retval EFI_NOT_FOUND TPM chip doesn't exit.
  134. @retval EFI_TIMEOUT Can't get the TPM control in time.
  135. **/
  136. EFI_STATUS
  137. TisPcRequestUseTpm (
  138. IN TIS_PC_REGISTERS_PTR TisReg
  139. )
  140. {
  141. EFI_STATUS Status;
  142. if (TisReg == NULL) {
  143. return EFI_INVALID_PARAMETER;
  144. }
  145. if (!TisPcPresenceCheck (TisReg)) {
  146. return EFI_NOT_FOUND;
  147. }
  148. MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
  149. Status = TisPcWaitRegisterBits (
  150. &TisReg->Access,
  151. (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
  152. 0,
  153. TIS_TIMEOUT_A
  154. );
  155. return Status;
  156. }
  157. /**
  158. Send a command to TPM for execution and return response data.
  159. @param[in] TisReg TPM register space base address.
  160. @param[in] BufferIn Buffer for command data.
  161. @param[in] SizeIn Size of command data.
  162. @param[in, out] BufferOut Buffer for response data.
  163. @param[in, out] SizeOut Size of response data.
  164. @retval EFI_SUCCESS Operation completed successfully.
  165. @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
  166. @retval EFI_DEVICE_ERROR Unexpected device behavior.
  167. @retval EFI_UNSUPPORTED Unsupported TPM version
  168. **/
  169. EFI_STATUS
  170. Tpm2TisTpmCommand (
  171. IN TIS_PC_REGISTERS_PTR TisReg,
  172. IN UINT8 *BufferIn,
  173. IN UINT32 SizeIn,
  174. IN OUT UINT8 *BufferOut,
  175. IN OUT UINT32 *SizeOut
  176. )
  177. {
  178. EFI_STATUS Status;
  179. UINT16 BurstCount;
  180. UINT32 Index;
  181. UINT32 TpmOutSize;
  182. UINT16 Data16;
  183. UINT32 Data32;
  184. DEBUG_CODE (
  185. UINTN DebugSize;
  186. DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand Send - "));
  187. if (SizeIn > 0x100) {
  188. DebugSize = 0x40;
  189. } else {
  190. DebugSize = SizeIn;
  191. }
  192. for (Index = 0; Index < DebugSize; Index++) {
  193. DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
  194. }
  195. if (DebugSize != SizeIn) {
  196. DEBUG ((EFI_D_VERBOSE, "...... "));
  197. for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
  198. DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
  199. }
  200. }
  201. DEBUG ((EFI_D_VERBOSE, "\n"));
  202. );
  203. TpmOutSize = 0;
  204. Status = TisPcPrepareCommand (TisReg);
  205. if (EFI_ERROR (Status)){
  206. DEBUG ((DEBUG_ERROR, "Tpm2 is not ready for command!\n"));
  207. return EFI_DEVICE_ERROR;
  208. }
  209. //
  210. // Send the command data to Tpm
  211. //
  212. Index = 0;
  213. while (Index < SizeIn) {
  214. Status = TisPcReadBurstCount (TisReg, &BurstCount);
  215. if (EFI_ERROR (Status)) {
  216. Status = EFI_DEVICE_ERROR;
  217. goto Exit;
  218. }
  219. for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {
  220. MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));
  221. Index++;
  222. }
  223. }
  224. //
  225. // Check the Tpm status STS_EXPECT change from 1 to 0
  226. //
  227. Status = TisPcWaitRegisterBits (
  228. &TisReg->Status,
  229. (UINT8) TIS_PC_VALID,
  230. TIS_PC_STS_EXPECT,
  231. TIS_TIMEOUT_C
  232. );
  233. if (EFI_ERROR (Status)) {
  234. DEBUG ((DEBUG_ERROR, "Tpm2 The send buffer too small!\n"));
  235. Status = EFI_BUFFER_TOO_SMALL;
  236. goto Exit;
  237. }
  238. //
  239. // Executed the TPM command and waiting for the response data ready
  240. //
  241. MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);
  242. //
  243. // NOTE: That may take many seconds to minutes for certain commands, such as key generation.
  244. //
  245. Status = TisPcWaitRegisterBits (
  246. &TisReg->Status,
  247. (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
  248. 0,
  249. TIS_TIMEOUT_MAX
  250. );
  251. if (EFI_ERROR (Status)) {
  252. //
  253. // dataAvail check timeout. Cancel the currently executing command by writing commandCancel,
  254. // Expect TPM_RC_CANCELLED or successfully completed response.
  255. //
  256. DEBUG ((DEBUG_ERROR, "Wait for Tpm2 response data time out. Trying to cancel the command!!\n"));
  257. MmioWrite32((UINTN)&TisReg->Status, TIS_PC_STS_CANCEL);
  258. Status = TisPcWaitRegisterBits (
  259. &TisReg->Status,
  260. (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
  261. 0,
  262. TIS_TIMEOUT_B
  263. );
  264. //
  265. // Do not clear CANCEL bit here because Writes of 0 to this bit are ignored
  266. //
  267. if (EFI_ERROR (Status)) {
  268. //
  269. // Cancel executing command fail to get any response
  270. // Try to abort the command with write of a 1 to commandReady in Command Execution state
  271. //
  272. Status = EFI_DEVICE_ERROR;
  273. goto Exit;
  274. }
  275. }
  276. //
  277. // Get response data header
  278. //
  279. Index = 0;
  280. BurstCount = 0;
  281. while (Index < sizeof (TPM2_RESPONSE_HEADER)) {
  282. Status = TisPcReadBurstCount (TisReg, &BurstCount);
  283. if (EFI_ERROR (Status)) {
  284. Status = EFI_DEVICE_ERROR;
  285. goto Exit;
  286. }
  287. for (; BurstCount > 0; BurstCount--) {
  288. *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
  289. Index++;
  290. if (Index == sizeof (TPM2_RESPONSE_HEADER)) break;
  291. }
  292. }
  293. DEBUG_CODE (
  294. DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand ReceiveHeader - "));
  295. for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
  296. DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
  297. }
  298. DEBUG ((EFI_D_VERBOSE, "\n"));
  299. );
  300. //
  301. // Check the reponse data header (tag,parasize and returncode )
  302. //
  303. CopyMem (&Data16, BufferOut, sizeof (UINT16));
  304. // TPM2 should not use this RSP_COMMAND
  305. if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) {
  306. DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND));
  307. Status = EFI_UNSUPPORTED;
  308. goto Exit;
  309. }
  310. CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
  311. TpmOutSize = SwapBytes32 (Data32);
  312. if (*SizeOut < TpmOutSize) {
  313. Status = EFI_BUFFER_TOO_SMALL;
  314. goto Exit;
  315. }
  316. *SizeOut = TpmOutSize;
  317. //
  318. // Continue reading the remaining data
  319. //
  320. while ( Index < TpmOutSize ) {
  321. for (; BurstCount > 0; BurstCount--) {
  322. *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
  323. Index++;
  324. if (Index == TpmOutSize) {
  325. Status = EFI_SUCCESS;
  326. goto Exit;
  327. }
  328. }
  329. Status = TisPcReadBurstCount (TisReg, &BurstCount);
  330. if (EFI_ERROR (Status)) {
  331. Status = EFI_DEVICE_ERROR;
  332. goto Exit;
  333. }
  334. }
  335. Exit:
  336. DEBUG_CODE (
  337. DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand Receive - "));
  338. for (Index = 0; Index < TpmOutSize; Index++) {
  339. DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
  340. }
  341. DEBUG ((EFI_D_VERBOSE, "\n"));
  342. );
  343. MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
  344. return Status;
  345. }
  346. /**
  347. This service enables the sending of commands to the TPM2.
  348. @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
  349. @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
  350. @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
  351. @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
  352. @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
  353. @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
  354. @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
  355. **/
  356. EFI_STATUS
  357. EFIAPI
  358. DTpm2TisSubmitCommand (
  359. IN UINT32 InputParameterBlockSize,
  360. IN UINT8 *InputParameterBlock,
  361. IN OUT UINT32 *OutputParameterBlockSize,
  362. IN UINT8 *OutputParameterBlock
  363. )
  364. {
  365. return Tpm2TisTpmCommand (
  366. (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
  367. InputParameterBlock,
  368. InputParameterBlockSize,
  369. OutputParameterBlock,
  370. OutputParameterBlockSize
  371. );
  372. }
  373. /**
  374. This service requests use TPM2.
  375. @retval EFI_SUCCESS Get the control of TPM2 chip.
  376. @retval EFI_NOT_FOUND TPM2 not found.
  377. @retval EFI_DEVICE_ERROR Unexpected device behavior.
  378. **/
  379. EFI_STATUS
  380. EFIAPI
  381. DTpm2TisRequestUseTpm (
  382. VOID
  383. )
  384. {
  385. return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
  386. }