1 /** @file 2 PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library. 3 4 Copyright (c) 2015 - 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 <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 Status = EFI_DEVICE_ERROR; 244 goto Exit; 245 } 246 247 // 248 // STEP 3: 249 // Command Completion occurs after completion of a command (indicated by the 250 // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the 251 // software to Request.goIdle. 252 // 253 254 // 255 // Get response data header 256 // 257 for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) { 258 BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]); 259 } 260 DEBUG_CODE ( 261 DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand ReceiveHeader - ")); 262 for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) { 263 DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index])); 264 } 265 DEBUG ((EFI_D_VERBOSE, "\n")); 266 ); 267 // 268 // Check the reponse data header (tag, parasize and returncode) 269 // 270 CopyMem (&Data16, BufferOut, sizeof (UINT16)); 271 // TPM2 should not use this RSP_COMMAND 272 if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) { 273 DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND)); 274 Status = EFI_UNSUPPORTED; 275 goto Exit; 276 } 277 278 CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32)); 279 TpmOutSize = SwapBytes32 (Data32); 280 if (*SizeOut < TpmOutSize) { 281 Status = EFI_BUFFER_TOO_SMALL; 282 goto Exit; 283 } 284 *SizeOut = TpmOutSize; 285 // 286 // Continue reading the remaining data 287 // 288 for (Index = sizeof (TPM2_RESPONSE_HEADER); Index < TpmOutSize; Index++) { 289 BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]); 290 } 291 Exit: 292 DEBUG_CODE ( 293 DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Receive - ")); 294 for (Index = 0; Index < TpmOutSize; Index++) { 295 DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index])); 296 } 297 DEBUG ((EFI_D_VERBOSE, "\n")); 298 ); 299 300 // 301 // STEP 4: 302 // Idle is any time TPM_CRB_CTRL_STS_x.Status.goIdle is 1. 303 // 304 MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE); 305 return Status; 306 } 307 308 /** 309 Send a command to TPM for execution and return response data. 310 311 @param[in] TisReg TPM register space base address. 312 @param[in] BufferIn Buffer for command data. 313 @param[in] SizeIn Size of command data. 314 @param[in, out] BufferOut Buffer for response data. 315 @param[in, out] SizeOut Size of response data. 316 317 @retval EFI_SUCCESS Operation completed successfully. 318 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. 319 @retval EFI_DEVICE_ERROR Unexpected device behavior. 320 @retval EFI_UNSUPPORTED Unsupported TPM version 321 322 **/ 323 EFI_STATUS 324 Tpm2TisTpmCommand ( 325 IN TIS_PC_REGISTERS_PTR TisReg, 326 IN UINT8 *BufferIn, 327 IN UINT32 SizeIn, 328 IN OUT UINT8 *BufferOut, 329 IN OUT UINT32 *SizeOut 330 ); 331 332 /** 333 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE 334 to ACCESS Register in the time of default TIS_TIMEOUT_A. 335 336 @param[in] TisReg Pointer to TIS register. 337 338 @retval EFI_SUCCESS Get the control of TPM chip. 339 @retval EFI_INVALID_PARAMETER TisReg is NULL. 340 @retval EFI_NOT_FOUND TPM chip doesn't exit. 341 @retval EFI_TIMEOUT Can't get the TPM control in time. 342 **/ 343 EFI_STATUS 344 TisPcRequestUseTpm ( 345 IN TIS_PC_REGISTERS_PTR TisReg 346 ); 347 348 /** 349 Return PTP interface type. 350 351 @param[in] Register Pointer to PTP register. 352 353 @return PTP interface type. 354 **/ 355 PTP_INTERFACE_TYPE 356 Tpm2GetPtpInterface ( 357 IN VOID *Register 358 ) 359 { 360 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; 361 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability; 362 363 if (!Tpm2IsPtpPresence (Register)) { 364 return PtpInterfaceMax; 365 } 366 // 367 // Check interface id 368 // 369 InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); 370 InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability); 371 372 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) && 373 (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) && 374 (InterfaceId.Bits.CapCRB != 0)) { 375 return PtpInterfaceCrb; 376 } 377 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) && 378 (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) && 379 (InterfaceId.Bits.CapFIFO != 0) && 380 (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) { 381 return PtpInterfaceFifo; 382 } 383 return PtpInterfaceTis; 384 } 385 386 /** 387 Dump PTP register information. 388 389 @param[in] Register Pointer to PTP register. 390 **/ 391 VOID 392 DumpPtpInfo ( 393 IN VOID *Register 394 ) 395 { 396 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; 397 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability; 398 UINT8 StatusEx; 399 UINT16 Vid; 400 UINT16 Did; 401 UINT8 Rid; 402 PTP_INTERFACE_TYPE PtpInterface; 403 404 if (!Tpm2IsPtpPresence (Register)) { 405 return ; 406 } 407 408 InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); 409 InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability); 410 StatusEx = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->StatusEx); 411 412 // 413 // Dump InterfaceId Register for PTP 414 // 415 DEBUG ((EFI_D_INFO, "InterfaceId - 0x%08x\n", InterfaceId.Uint32)); 416 DEBUG ((EFI_D_INFO, " InterfaceType - 0x%02x\n", InterfaceId.Bits.InterfaceType)); 417 if (InterfaceId.Bits.InterfaceType != PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) { 418 DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%02x\n", InterfaceId.Bits.InterfaceVersion)); 419 DEBUG ((EFI_D_INFO, " CapFIFO - 0x%x\n", InterfaceId.Bits.CapFIFO)); 420 DEBUG ((EFI_D_INFO, " CapCRB - 0x%x\n", InterfaceId.Bits.CapCRB)); 421 } 422 423 // 424 // Dump Capability Register for TIS and FIFO 425 // 426 DEBUG ((EFI_D_INFO, "InterfaceCapability - 0x%08x\n", InterfaceCapability.Uint32)); 427 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) || 428 (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO)) { 429 DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%x\n", InterfaceCapability.Bits.InterfaceVersion)); 430 } 431 432 // 433 // Dump StatusEx Register for PTP FIFO 434 // 435 DEBUG ((EFI_D_INFO, "StatusEx - 0x%02x\n", StatusEx)); 436 if (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP) { 437 DEBUG ((EFI_D_INFO, " TpmFamily - 0x%x\n", (StatusEx & PTP_FIFO_STS_EX_TPM_FAMILY) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET)); 438 } 439 440 Vid = 0xFFFF; 441 Did = 0xFFFF; 442 Rid = 0xFF; 443 PtpInterface = Tpm2GetPtpInterface (Register); 444 DEBUG ((EFI_D_INFO, "PtpInterface - %x\n", PtpInterface)); 445 switch (PtpInterface) { 446 case PtpInterfaceCrb: 447 Vid = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Vid); 448 Did = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Did); 449 Rid = (UINT8)InterfaceId.Bits.Rid; 450 break; 451 case PtpInterfaceFifo: 452 case PtpInterfaceTis: 453 Vid = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Vid); 454 Did = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Did); 455 Rid = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Rid); 456 break; 457 default: 458 break; 459 } 460 DEBUG ((EFI_D_INFO, "VID - 0x%04x\n", Vid)); 461 DEBUG ((EFI_D_INFO, "DID - 0x%04x\n", Did)); 462 DEBUG ((EFI_D_INFO, "RID - 0x%02x\n", Rid)); 463 } 464 465 /** 466 This service enables the sending of commands to the TPM2. 467 468 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. 469 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. 470 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. 471 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. 472 473 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. 474 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. 475 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. 476 **/ 477 EFI_STATUS 478 EFIAPI 479 DTpm2SubmitCommand ( 480 IN UINT32 InputParameterBlockSize, 481 IN UINT8 *InputParameterBlock, 482 IN OUT UINT32 *OutputParameterBlockSize, 483 IN UINT8 *OutputParameterBlock 484 ) 485 { 486 PTP_INTERFACE_TYPE PtpInterface; 487 488 PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); 489 switch (PtpInterface) { 490 case PtpInterfaceCrb: 491 return PtpCrbTpmCommand ( 492 (PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress), 493 InputParameterBlock, 494 InputParameterBlockSize, 495 OutputParameterBlock, 496 OutputParameterBlockSize 497 ); 498 case PtpInterfaceFifo: 499 case PtpInterfaceTis: 500 return Tpm2TisTpmCommand ( 501 (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress), 502 InputParameterBlock, 503 InputParameterBlockSize, 504 OutputParameterBlock, 505 OutputParameterBlockSize 506 ); 507 default: 508 return EFI_NOT_FOUND; 509 } 510 } 511 512 /** 513 This service requests use TPM2. 514 515 @retval EFI_SUCCESS Get the control of TPM2 chip. 516 @retval EFI_NOT_FOUND TPM2 not found. 517 @retval EFI_DEVICE_ERROR Unexpected device behavior. 518 **/ 519 EFI_STATUS 520 EFIAPI 521 DTpm2RequestUseTpm ( 522 VOID 523 ) 524 { 525 PTP_INTERFACE_TYPE PtpInterface; 526 527 PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); 528 switch (PtpInterface) { 529 case PtpInterfaceCrb: 530 return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress)); 531 case PtpInterfaceFifo: 532 case PtpInterfaceTis: 533 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress)); 534 default: 535 return EFI_NOT_FOUND; 536 } 537 } 538