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