]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c
SecurityPkg: Tpm2DeviceLib: Enable CapCRBIdleBypass support
[mirror_edk2.git] / SecurityPkg / Library / Tpm2DeviceLibDTpm / Tpm2Ptp.c
index a627bbdedf7a220221b1512f379c87dc42c8339d..ad2f188b463662eb89e84a01ef933dfa5f6ba444 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library.\r
 \r
-Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -25,13 +25,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <IndustryStandard/TpmPtp.h>\r
 #include <IndustryStandard/TpmTis.h>\r
 \r
-typedef enum {\r
-  PtpInterfaceTis,\r
-  PtpInterfaceFifo,\r
-  PtpInterfaceCrb,\r
-  PtpInterfaceMax,\r
-} PTP_INTERFACE_TYPE;\r
-\r
 //\r
 // Execution of the command may take from several seconds to minutes for certain\r
 // commands, such as key generation.\r
@@ -52,7 +45,7 @@ typedef enum {
   @retval    FALSE   TPM PTP is not found.\r
 **/\r
 BOOLEAN\r
-IsPtpPresence (\r
+Tpm2IsPtpPresence (\r
   IN VOID *Reg\r
   )\r
 {\r
@@ -117,7 +110,7 @@ PtpCrbRequestUseTpm (
 {\r
   EFI_STATUS                        Status;\r
 \r
-  if (!IsPtpPresence (CrbReg)) {\r
+  if (!Tpm2IsPtpPresence (CrbReg)) {\r
     return EFI_NOT_FOUND;\r
   }\r
 \r
@@ -181,10 +174,30 @@ PtpCrbTpmCommand (
     }\r
     DEBUG ((EFI_D_VERBOSE, "\n"));\r
   );\r
-  TpmOutSize = 0;\r
+  TpmOutSize         = 0;\r
 \r
   //\r
   // STEP 0:\r
+  // if CapCRbIdelByPass == 0, enforce Idle state before sending command\r
+  //\r
+  if (PcdGet8(PcdCRBIdleByPass) == 0 && (MmioRead32((UINTN)&CrbReg->CrbControlStatus) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE) == 0){\r
+    Status = PtpCrbWaitRegisterBits (\r
+              &CrbReg->CrbControlStatus,\r
+              PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
+              0,\r
+              PTP_TIMEOUT_C\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Try to goIdle to recover TPM\r
+      //\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto GoIdle_Exit;\r
+    }\r
+  }\r
+\r
+  //\r
+  // STEP 1:\r
   // Ready is any time the TPM is ready to receive a command, following a write\r
   // of 1 by software to Request.cmdReady, as indicated by the Status field\r
   // being cleared to 0.\r
@@ -198,7 +211,7 @@ PtpCrbTpmCommand (
              );\r
   if (EFI_ERROR (Status)) {\r
     Status = EFI_DEVICE_ERROR;\r
-    goto Exit;\r
+    goto GoIdle_Exit;\r
   }\r
   Status = PtpCrbWaitRegisterBits (\r
              &CrbReg->CrbControlStatus,\r
@@ -208,11 +221,11 @@ PtpCrbTpmCommand (
              );\r
   if (EFI_ERROR (Status)) {\r
     Status = EFI_DEVICE_ERROR;\r
-    goto Exit;\r
+    goto GoIdle_Exit;\r
   }\r
 \r
   //\r
-  // STEP 1:\r
+  // STEP 2:\r
   // Command Reception occurs following a Ready state between the write of the\r
   // first byte of a command to the Command Buffer and the receipt of a write\r
   // of 1 to Start.\r
@@ -228,7 +241,7 @@ PtpCrbTpmCommand (
   MmioWrite32 ((UINTN)&CrbReg->CrbControlResponseSize, sizeof(CrbReg->CrbDataBuffer));\r
 \r
   //\r
-  // STEP 2:\r
+  // STEP 3:\r
   // Command Execution occurs after receipt of a 1 to Start and the TPM\r
   // clearing Start to 0.\r
   //\r
@@ -240,12 +253,30 @@ PtpCrbTpmCommand (
              PTP_TIMEOUT_MAX\r
              );\r
   if (EFI_ERROR (Status)) {\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto Exit;\r
+    //\r
+    // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,\r
+    // Expect TPM_RC_CANCELLED or successfully completed response.\r
+    //\r
+    MmioWrite32((UINTN)&CrbReg->CrbControlCancel, PTP_CRB_CONTROL_CANCEL);\r
+    Status = PtpCrbWaitRegisterBits (\r
+               &CrbReg->CrbControlStart,\r
+               0,\r
+               PTP_CRB_CONTROL_START,\r
+               PTP_TIMEOUT_B\r
+               );\r
+    MmioWrite32((UINTN)&CrbReg->CrbControlCancel, 0);\r
+\r
+    if (EFI_ERROR(Status)) {\r
+      //\r
+      // Still in Command Execution state. Try to goIdle, the behavior is agnostic.\r
+      //\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto GoIdle_Exit;\r
+    }\r
   }\r
 \r
   //\r
-  // STEP 3:\r
+  // STEP 4:\r
   // Command Completion occurs after completion of a command (indicated by the\r
   // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the\r
   // software to Request.goIdle.\r
@@ -272,14 +303,17 @@ PtpCrbTpmCommand (
   if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) {\r
     DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND));\r
     Status = EFI_UNSUPPORTED;\r
-    goto Exit;\r
+    goto GoIdle_Exit;\r
   }\r
 \r
   CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));\r
   TpmOutSize  = SwapBytes32 (Data32);\r
   if (*SizeOut < TpmOutSize) {\r
+    //\r
+    // Command completed, but buffer is not enough\r
+    //\r
     Status = EFI_BUFFER_TOO_SMALL;\r
-    goto Exit;\r
+    goto GoReady_Exit;\r
   }\r
   *SizeOut = TpmOutSize;\r
   //\r
@@ -288,7 +322,7 @@ PtpCrbTpmCommand (
   for (Index = sizeof (TPM2_RESPONSE_HEADER); Index < TpmOutSize; Index++) {\r
     BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]);\r
   }\r
-Exit:\r
+\r
   DEBUG_CODE (\r
     DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Receive - "));\r
     for (Index = 0; Index < TpmOutSize; Index++) {\r
@@ -297,11 +331,40 @@ Exit:
     DEBUG ((EFI_D_VERBOSE, "\n"));\r
   );\r
 \r
+GoReady_Exit:\r
   //\r
-  // STEP 4:\r
-  // Idle is any time TPM_CRB_CTRL_STS_x.Status.goIdle is 1.\r
+  // Goto Ready State if command is completed succesfully and TPM support IdleBypass\r
+  // If not supported. flow down to GoIdle\r
+  //\r
+  if (PcdGet8(PcdCRBIdleByPass) == 1) {\r
+    MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Do not wait for state transition for TIMEOUT_C\r
+  // This function will try to wait 2 TIMEOUT_C at the beginning in next call.\r
+  //\r
+GoIdle_Exit:\r
+\r
+  //\r
+  //  Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1.\r
   //\r
   MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
+\r
+  //\r
+  // Only enforce Idle state transition if execution fails when CRBIndleBypass==1\r
+  // Leave regular Idle delay at the beginning of next command execution\r
+  //\r
+  if (PcdGet8(PcdCRBIdleByPass) == 1){\r
+    Status = PtpCrbWaitRegisterBits (\r
+               &CrbReg->CrbControlStatus,\r
+               PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
+               0,\r
+               PTP_TIMEOUT_C\r
+               );\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
@@ -352,16 +415,16 @@ TisPcRequestUseTpm (
 \r
   @return PTP interface type.\r
 **/\r
-PTP_INTERFACE_TYPE\r
-GetPtpInterface (\r
+TPM2_PTP_INTERFACE_TYPE\r
+Tpm2GetPtpInterface (\r
   IN VOID *Register\r
   )\r
 {\r
   PTP_CRB_INTERFACE_IDENTIFIER  InterfaceId;\r
   PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;\r
 \r
-  if (!IsPtpPresence (Register)) {\r
-    return PtpInterfaceMax;\r
+  if (!Tpm2IsPtpPresence (Register)) {\r
+    return Tpm2PtpInterfaceMax;\r
   }\r
   //\r
   // Check interface id\r
@@ -372,15 +435,37 @@ GetPtpInterface (
   if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&\r
       (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&\r
       (InterfaceId.Bits.CapCRB != 0)) {\r
-    return PtpInterfaceCrb;\r
+    return Tpm2PtpInterfaceCrb;\r
   }\r
   if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&\r
       (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&\r
       (InterfaceId.Bits.CapFIFO != 0) &&\r
       (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {\r
-    return PtpInterfaceFifo;\r
+    return Tpm2PtpInterfaceFifo;\r
   }\r
-  return PtpInterfaceTis;\r
+  return Tpm2PtpInterfaceTis;\r
+}\r
+\r
+/**\r
+  Return PTP CRB interface IdleByPass state.\r
+\r
+  @param[in] Register                Pointer to PTP register.\r
+\r
+  @return PTP CRB interface IdleByPass state.\r
+**/\r
+UINT8\r
+Tpm2GetIdleByPass (\r
+  IN VOID *Register\r
+  )\r
+{\r
+  PTP_CRB_INTERFACE_IDENTIFIER  InterfaceId;\r
+\r
+  //\r
+  // Check interface id\r
+  //\r
+  InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);\r
+\r
+  return (UINT8)(InterfaceId.Bits.CapCRBIdleBypass);\r
 }\r
 \r
 /**\r
@@ -399,9 +484,9 @@ DumpPtpInfo (
   UINT16                        Vid;\r
   UINT16                        Did;\r
   UINT8                         Rid;\r
-  PTP_INTERFACE_TYPE            PtpInterface;\r
+  TPM2_PTP_INTERFACE_TYPE       PtpInterface;\r
 \r
-  if (!IsPtpPresence (Register)) {\r
+  if (!Tpm2IsPtpPresence (Register)) {\r
     return ;\r
   }\r
 \r
@@ -440,16 +525,16 @@ DumpPtpInfo (
   Vid = 0xFFFF;\r
   Did = 0xFFFF;\r
   Rid = 0xFF;\r
-  PtpInterface = GetPtpInterface (Register);\r
+  PtpInterface = PcdGet8(PcdActiveTpmInterfaceType);\r
   DEBUG ((EFI_D_INFO, "PtpInterface - %x\n", PtpInterface));\r
   switch (PtpInterface) {\r
-  case PtpInterfaceCrb:\r
+  case Tpm2PtpInterfaceCrb:\r
     Vid = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Vid);\r
     Did = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Did);\r
     Rid = (UINT8)InterfaceId.Bits.Rid;\r
     break;\r
-  case PtpInterfaceFifo:\r
-  case PtpInterfaceTis:\r
+  case Tpm2PtpInterfaceFifo:\r
+  case Tpm2PtpInterfaceTis:\r
     Vid = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Vid);\r
     Did = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Did);\r
     Rid = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Rid);\r
@@ -483,11 +568,11 @@ DTpm2SubmitCommand (
   IN UINT8             *OutputParameterBlock\r
   )\r
 {\r
-  PTP_INTERFACE_TYPE  PtpInterface;\r
+  TPM2_PTP_INTERFACE_TYPE  PtpInterface;\r
 \r
-  PtpInterface = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));\r
+  PtpInterface = PcdGet8(PcdActiveTpmInterfaceType);\r
   switch (PtpInterface) {\r
-  case PtpInterfaceCrb:\r
+  case Tpm2PtpInterfaceCrb:\r
     return PtpCrbTpmCommand (\r
            (PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),\r
            InputParameterBlock,\r
@@ -495,8 +580,8 @@ DTpm2SubmitCommand (
            OutputParameterBlock,\r
            OutputParameterBlockSize\r
            );\r
-  case PtpInterfaceFifo:\r
-  case PtpInterfaceTis:\r
+  case Tpm2PtpInterfaceFifo:\r
+  case Tpm2PtpInterfaceTis:\r
     return Tpm2TisTpmCommand (\r
            (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),\r
            InputParameterBlock,\r
@@ -522,14 +607,14 @@ DTpm2RequestUseTpm (
   VOID\r
   )\r
 {\r
-  PTP_INTERFACE_TYPE  PtpInterface;\r
+  TPM2_PTP_INTERFACE_TYPE  PtpInterface;\r
 \r
-  PtpInterface = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));\r
+  PtpInterface = PcdGet8(PcdActiveTpmInterfaceType);\r
   switch (PtpInterface) {\r
-  case PtpInterfaceCrb:\r
+  case Tpm2PtpInterfaceCrb:\r
     return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));\r
-  case PtpInterfaceFifo:\r
-  case PtpInterfaceTis:\r
+  case Tpm2PtpInterfaceFifo:\r
+  case Tpm2PtpInterfaceTis:\r
     return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));\r
   default:\r
     return EFI_NOT_FOUND;\r