]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c
SecurityPkg:Tpm2DeviceLibDTpm: Support TPM command cancel
[mirror_edk2.git] / SecurityPkg / Library / Tpm2DeviceLibDTpm / Tpm2Ptp.c
1 /** @file
2 PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library.
3
4 Copyright (c) 2015 - 2018, 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 <IndustryStandard/Tpm20.h>
16
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/IoLib.h>
20 #include <Library/TimerLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/Tpm2DeviceLib.h>
23 #include <Library/PcdLib.h>
24
25 #include <IndustryStandard/TpmPtp.h>
26 #include <IndustryStandard/TpmTis.h>
27
28 typedef enum {
29 PtpInterfaceTis,
30 PtpInterfaceFifo,
31 PtpInterfaceCrb,
32 PtpInterfaceMax,
33 } PTP_INTERFACE_TYPE;
34
35 //
36 // Execution of the command may take from several seconds to minutes for certain
37 // commands, such as key generation.
38 //
39 #define PTP_TIMEOUT_MAX (90000 * 1000) // 90s
40
41 //
42 // Max TPM command/reponse length
43 //
44 #define TPMCMDBUFLENGTH 0x500
45
46 /**
47 Check whether TPM PTP register exist.
48
49 @param[in] Reg Pointer to PTP register.
50
51 @retval TRUE TPM PTP exists.
52 @retval FALSE TPM PTP is not found.
53 **/
54 BOOLEAN
55 Tpm2IsPtpPresence (
56 IN VOID *Reg
57 )
58 {
59 UINT8 RegRead;
60
61 RegRead = MmioRead8 ((UINTN)Reg);
62 if (RegRead == 0xFF) {
63 //
64 // No TPM chip
65 //
66 return FALSE;
67 }
68 return TRUE;
69 }
70
71 /**
72 Check whether the value of a TPM chip register satisfies the input BIT setting.
73
74 @param[in] Register Address port of register to be checked.
75 @param[in] BitSet Check these data bits are set.
76 @param[in] BitClear Check these data bits are clear.
77 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
78
79 @retval EFI_SUCCESS The register satisfies the check bit.
80 @retval EFI_TIMEOUT The register can't run into the expected status in time.
81 **/
82 EFI_STATUS
83 PtpCrbWaitRegisterBits (
84 IN UINT32 *Register,
85 IN UINT32 BitSet,
86 IN UINT32 BitClear,
87 IN UINT32 TimeOut
88 )
89 {
90 UINT32 RegRead;
91 UINT32 WaitTime;
92
93 for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
94 RegRead = MmioRead32 ((UINTN)Register);
95 if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0) {
96 return EFI_SUCCESS;
97 }
98 MicroSecondDelay (30);
99 }
100 return EFI_TIMEOUT;
101 }
102
103 /**
104 Get the control of TPM chip.
105
106 @param[in] CrbReg Pointer to CRB register.
107
108 @retval EFI_SUCCESS Get the control of TPM chip.
109 @retval EFI_INVALID_PARAMETER CrbReg is NULL.
110 @retval EFI_NOT_FOUND TPM chip doesn't exit.
111 @retval EFI_TIMEOUT Can't get the TPM control in time.
112 **/
113 EFI_STATUS
114 PtpCrbRequestUseTpm (
115 IN PTP_CRB_REGISTERS_PTR CrbReg
116 )
117 {
118 EFI_STATUS Status;
119
120 if (!Tpm2IsPtpPresence (CrbReg)) {
121 return EFI_NOT_FOUND;
122 }
123
124 MmioWrite32((UINTN)&CrbReg->LocalityControl, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS);
125 Status = PtpCrbWaitRegisterBits (
126 &CrbReg->LocalityStatus,
127 PTP_CRB_LOCALITY_STATUS_GRANTED,
128 0,
129 PTP_TIMEOUT_A
130 );
131 return Status;
132 }
133
134 /**
135 Send a command to TPM for execution and return response data.
136
137 @param[in] CrbReg TPM register space base address.
138 @param[in] BufferIn Buffer for command data.
139 @param[in] SizeIn Size of command data.
140 @param[in, out] BufferOut Buffer for response data.
141 @param[in, out] SizeOut Size of response data.
142
143 @retval EFI_SUCCESS Operation completed successfully.
144 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
145 @retval EFI_DEVICE_ERROR Unexpected device behavior.
146 @retval EFI_UNSUPPORTED Unsupported TPM version
147
148 **/
149 EFI_STATUS
150 PtpCrbTpmCommand (
151 IN PTP_CRB_REGISTERS_PTR CrbReg,
152 IN UINT8 *BufferIn,
153 IN UINT32 SizeIn,
154 IN OUT UINT8 *BufferOut,
155 IN OUT UINT32 *SizeOut
156 )
157 {
158 EFI_STATUS Status;
159 UINT32 Index;
160 UINT32 TpmOutSize;
161 UINT16 Data16;
162 UINT32 Data32;
163
164 DEBUG_CODE (
165 UINTN DebugSize;
166
167 DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Send - "));
168 if (SizeIn > 0x100) {
169 DebugSize = 0x40;
170 } else {
171 DebugSize = SizeIn;
172 }
173 for (Index = 0; Index < DebugSize; Index++) {
174 DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
175 }
176 if (DebugSize != SizeIn) {
177 DEBUG ((EFI_D_VERBOSE, "...... "));
178 for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
179 DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
180 }
181 }
182 DEBUG ((EFI_D_VERBOSE, "\n"));
183 );
184 TpmOutSize = 0;
185
186 //
187 // STEP 0:
188 // Ready is any time the TPM is ready to receive a command, following a write
189 // of 1 by software to Request.cmdReady, as indicated by the Status field
190 // being cleared to 0.
191 //
192 MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);
193 Status = PtpCrbWaitRegisterBits (
194 &CrbReg->CrbControlRequest,
195 0,
196 PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY,
197 PTP_TIMEOUT_C
198 );
199 if (EFI_ERROR (Status)) {
200 Status = EFI_DEVICE_ERROR;
201 goto Exit;
202 }
203 Status = PtpCrbWaitRegisterBits (
204 &CrbReg->CrbControlStatus,
205 0,
206 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,
207 PTP_TIMEOUT_C
208 );
209 if (EFI_ERROR (Status)) {
210 Status = EFI_DEVICE_ERROR;
211 goto Exit;
212 }
213
214 //
215 // STEP 1:
216 // Command Reception occurs following a Ready state between the write of the
217 // first byte of a command to the Command Buffer and the receipt of a write
218 // of 1 to Start.
219 //
220 for (Index = 0; Index < SizeIn; Index++) {
221 MmioWrite8 ((UINTN)&CrbReg->CrbDataBuffer[Index], BufferIn[Index]);
222 }
223 MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandAddressHigh, (UINT32)RShiftU64 ((UINTN)CrbReg->CrbDataBuffer, 32));
224 MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandAddressLow, (UINT32)(UINTN)CrbReg->CrbDataBuffer);
225 MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandSize, sizeof(CrbReg->CrbDataBuffer));
226
227 MmioWrite64 ((UINTN)&CrbReg->CrbControlResponseAddrss, (UINT32)(UINTN)CrbReg->CrbDataBuffer);
228 MmioWrite32 ((UINTN)&CrbReg->CrbControlResponseSize, sizeof(CrbReg->CrbDataBuffer));
229
230 //
231 // STEP 2:
232 // Command Execution occurs after receipt of a 1 to Start and the TPM
233 // clearing Start to 0.
234 //
235 MmioWrite32((UINTN)&CrbReg->CrbControlStart, PTP_CRB_CONTROL_START);
236 Status = PtpCrbWaitRegisterBits (
237 &CrbReg->CrbControlStart,
238 0,
239 PTP_CRB_CONTROL_START,
240 PTP_TIMEOUT_MAX
241 );
242 if (EFI_ERROR (Status)) {
243 //
244 // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,
245 // Expect TPM_RC_CANCELLED or successfully completed response.
246 //
247 MmioWrite32((UINTN)&CrbReg->CrbControlCancel, PTP_CRB_CONTROL_CANCEL);
248 Status = PtpCrbWaitRegisterBits (
249 &CrbReg->CrbControlStart,
250 0,
251 PTP_CRB_CONTROL_START,
252 PTP_TIMEOUT_B
253 );
254 MmioWrite32((UINTN)&CrbReg->CrbControlCancel, 0);
255
256 if (EFI_ERROR(Status)) {
257 //
258 // Still in Command Execution state. Try to goIdle, the behavior is agnostic.
259 //
260 Status = EFI_DEVICE_ERROR;
261 goto Exit;
262 }
263 }
264
265 //
266 // STEP 3:
267 // Command Completion occurs after completion of a command (indicated by the
268 // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
269 // software to Request.goIdle.
270 //
271
272 //
273 // Get response data header
274 //
275 for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
276 BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]);
277 }
278 DEBUG_CODE (
279 DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand ReceiveHeader - "));
280 for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
281 DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
282 }
283 DEBUG ((EFI_D_VERBOSE, "\n"));
284 );
285 //
286 // Check the reponse data header (tag, parasize and returncode)
287 //
288 CopyMem (&Data16, BufferOut, sizeof (UINT16));
289 // TPM2 should not use this RSP_COMMAND
290 if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) {
291 DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND));
292 Status = EFI_UNSUPPORTED;
293 goto Exit;
294 }
295
296 CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
297 TpmOutSize = SwapBytes32 (Data32);
298 if (*SizeOut < TpmOutSize) {
299 Status = EFI_BUFFER_TOO_SMALL;
300 goto Exit;
301 }
302 *SizeOut = TpmOutSize;
303 //
304 // Continue reading the remaining data
305 //
306 for (Index = sizeof (TPM2_RESPONSE_HEADER); Index < TpmOutSize; Index++) {
307 BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]);
308 }
309 Exit:
310 DEBUG_CODE (
311 DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Receive - "));
312 for (Index = 0; Index < TpmOutSize; Index++) {
313 DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
314 }
315 DEBUG ((EFI_D_VERBOSE, "\n"));
316 );
317
318 //
319 // STEP 4:
320 // Idle is any time TPM_CRB_CTRL_STS_x.Status.goIdle is 1.
321 //
322 MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);
323 return Status;
324 }
325
326 /**
327 Send a command to TPM for execution and return response data.
328
329 @param[in] TisReg TPM register space base address.
330 @param[in] BufferIn Buffer for command data.
331 @param[in] SizeIn Size of command data.
332 @param[in, out] BufferOut Buffer for response data.
333 @param[in, out] SizeOut Size of response data.
334
335 @retval EFI_SUCCESS Operation completed successfully.
336 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
337 @retval EFI_DEVICE_ERROR Unexpected device behavior.
338 @retval EFI_UNSUPPORTED Unsupported TPM version
339
340 **/
341 EFI_STATUS
342 Tpm2TisTpmCommand (
343 IN TIS_PC_REGISTERS_PTR TisReg,
344 IN UINT8 *BufferIn,
345 IN UINT32 SizeIn,
346 IN OUT UINT8 *BufferOut,
347 IN OUT UINT32 *SizeOut
348 );
349
350 /**
351 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
352 to ACCESS Register in the time of default TIS_TIMEOUT_A.
353
354 @param[in] TisReg Pointer to TIS register.
355
356 @retval EFI_SUCCESS Get the control of TPM chip.
357 @retval EFI_INVALID_PARAMETER TisReg is NULL.
358 @retval EFI_NOT_FOUND TPM chip doesn't exit.
359 @retval EFI_TIMEOUT Can't get the TPM control in time.
360 **/
361 EFI_STATUS
362 TisPcRequestUseTpm (
363 IN TIS_PC_REGISTERS_PTR TisReg
364 );
365
366 /**
367 Return PTP interface type.
368
369 @param[in] Register Pointer to PTP register.
370
371 @return PTP interface type.
372 **/
373 PTP_INTERFACE_TYPE
374 Tpm2GetPtpInterface (
375 IN VOID *Register
376 )
377 {
378 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
379 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
380
381 if (!Tpm2IsPtpPresence (Register)) {
382 return PtpInterfaceMax;
383 }
384 //
385 // Check interface id
386 //
387 InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
388 InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
389
390 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
391 (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
392 (InterfaceId.Bits.CapCRB != 0)) {
393 return PtpInterfaceCrb;
394 }
395 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
396 (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
397 (InterfaceId.Bits.CapFIFO != 0) &&
398 (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
399 return PtpInterfaceFifo;
400 }
401 return PtpInterfaceTis;
402 }
403
404 /**
405 Dump PTP register information.
406
407 @param[in] Register Pointer to PTP register.
408 **/
409 VOID
410 DumpPtpInfo (
411 IN VOID *Register
412 )
413 {
414 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
415 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
416 UINT8 StatusEx;
417 UINT16 Vid;
418 UINT16 Did;
419 UINT8 Rid;
420 PTP_INTERFACE_TYPE PtpInterface;
421
422 if (!Tpm2IsPtpPresence (Register)) {
423 return ;
424 }
425
426 InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
427 InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
428 StatusEx = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->StatusEx);
429
430 //
431 // Dump InterfaceId Register for PTP
432 //
433 DEBUG ((EFI_D_INFO, "InterfaceId - 0x%08x\n", InterfaceId.Uint32));
434 DEBUG ((EFI_D_INFO, " InterfaceType - 0x%02x\n", InterfaceId.Bits.InterfaceType));
435 if (InterfaceId.Bits.InterfaceType != PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) {
436 DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%02x\n", InterfaceId.Bits.InterfaceVersion));
437 DEBUG ((EFI_D_INFO, " CapFIFO - 0x%x\n", InterfaceId.Bits.CapFIFO));
438 DEBUG ((EFI_D_INFO, " CapCRB - 0x%x\n", InterfaceId.Bits.CapCRB));
439 }
440
441 //
442 // Dump Capability Register for TIS and FIFO
443 //
444 DEBUG ((EFI_D_INFO, "InterfaceCapability - 0x%08x\n", InterfaceCapability.Uint32));
445 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) ||
446 (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO)) {
447 DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%x\n", InterfaceCapability.Bits.InterfaceVersion));
448 }
449
450 //
451 // Dump StatusEx Register for PTP FIFO
452 //
453 DEBUG ((EFI_D_INFO, "StatusEx - 0x%02x\n", StatusEx));
454 if (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP) {
455 DEBUG ((EFI_D_INFO, " TpmFamily - 0x%x\n", (StatusEx & PTP_FIFO_STS_EX_TPM_FAMILY) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET));
456 }
457
458 Vid = 0xFFFF;
459 Did = 0xFFFF;
460 Rid = 0xFF;
461 PtpInterface = Tpm2GetPtpInterface (Register);
462 DEBUG ((EFI_D_INFO, "PtpInterface - %x\n", PtpInterface));
463 switch (PtpInterface) {
464 case PtpInterfaceCrb:
465 Vid = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Vid);
466 Did = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Did);
467 Rid = (UINT8)InterfaceId.Bits.Rid;
468 break;
469 case PtpInterfaceFifo:
470 case PtpInterfaceTis:
471 Vid = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Vid);
472 Did = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Did);
473 Rid = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Rid);
474 break;
475 default:
476 break;
477 }
478 DEBUG ((EFI_D_INFO, "VID - 0x%04x\n", Vid));
479 DEBUG ((EFI_D_INFO, "DID - 0x%04x\n", Did));
480 DEBUG ((EFI_D_INFO, "RID - 0x%02x\n", Rid));
481 }
482
483 /**
484 This service enables the sending of commands to the TPM2.
485
486 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
487 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
488 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
489 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
490
491 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
492 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
493 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
494 **/
495 EFI_STATUS
496 EFIAPI
497 DTpm2SubmitCommand (
498 IN UINT32 InputParameterBlockSize,
499 IN UINT8 *InputParameterBlock,
500 IN OUT UINT32 *OutputParameterBlockSize,
501 IN UINT8 *OutputParameterBlock
502 )
503 {
504 PTP_INTERFACE_TYPE PtpInterface;
505
506 PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
507 switch (PtpInterface) {
508 case PtpInterfaceCrb:
509 return PtpCrbTpmCommand (
510 (PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
511 InputParameterBlock,
512 InputParameterBlockSize,
513 OutputParameterBlock,
514 OutputParameterBlockSize
515 );
516 case PtpInterfaceFifo:
517 case PtpInterfaceTis:
518 return Tpm2TisTpmCommand (
519 (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
520 InputParameterBlock,
521 InputParameterBlockSize,
522 OutputParameterBlock,
523 OutputParameterBlockSize
524 );
525 default:
526 return EFI_NOT_FOUND;
527 }
528 }
529
530 /**
531 This service requests use TPM2.
532
533 @retval EFI_SUCCESS Get the control of TPM2 chip.
534 @retval EFI_NOT_FOUND TPM2 not found.
535 @retval EFI_DEVICE_ERROR Unexpected device behavior.
536 **/
537 EFI_STATUS
538 EFIAPI
539 DTpm2RequestUseTpm (
540 VOID
541 )
542 {
543 PTP_INTERFACE_TYPE PtpInterface;
544
545 PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
546 switch (PtpInterface) {
547 case PtpInterfaceCrb:
548 return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
549 case PtpInterfaceFifo:
550 case PtpInterfaceTis:
551 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
552 default:
553 return EFI_NOT_FOUND;
554 }
555 }