]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / SecurityPkg / Library / Tpm2DeviceLibDTpm / Tpm2Ptp.c
index 40ab998004e255bcec27bf701d8c6e394d263f72..1f9ac5ab5a304d5ebd3acf9f78390dee421870c1 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 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>\r
 Copyright (c), Microsoft Corporation.\r
 SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
@@ -33,6 +33,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 //\r
 #define TPMCMDBUFLENGTH  0x500\r
 \r
+//\r
+// Max retry count according to Spec TCG PC Client Device Driver Design Principles\r
+// for TPM2.0, Version 1.1, Revision 0.04, Section 7.2.1\r
+//\r
+#define RETRY_CNT_MAX  3\r
+\r
 /**\r
   Check whether TPM PTP register exist.\r
 \r
@@ -153,6 +159,7 @@ PtpCrbTpmCommand (
   UINT32      TpmOutSize;\r
   UINT16      Data16;\r
   UINT32      Data32;\r
+  UINT8       RetryCnt;\r
 \r
   DEBUG_CODE_BEGIN ();\r
   UINTN  DebugSize;\r
@@ -179,53 +186,76 @@ PtpCrbTpmCommand (
   DEBUG_CODE_END ();\r
   TpmOutSize = 0;\r
 \r
-  //\r
-  // STEP 0:\r
-  // if CapCRbIdelByPass == 0, enforce Idle state before sending command\r
-  //\r
-  if ((GetCachedIdleByPass () == 0) && ((MmioRead32 ((UINTN)&CrbReg->CrbControlStatus) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE) == 0)) {\r
+  RetryCnt = 0;\r
+  while (TRUE) {\r
+    //\r
+    // STEP 0:\r
+    // if CapCRbIdelByPass == 0, enforce Idle state before sending command\r
+    //\r
+    if ((GetCachedIdleByPass () == 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
+        RetryCnt++;\r
+        if (RetryCnt < RETRY_CNT_MAX) {\r
+          MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
+          continue;\r
+        } else {\r
+          //\r
+          // Try to goIdle to recover TPM\r
+          //\r
+          Status = EFI_DEVICE_ERROR;\r
+          goto GoIdle_Exit;\r
+        }\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
+    //\r
+    MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);\r
     Status = PtpCrbWaitRegisterBits (\r
-               &CrbReg->CrbControlStatus,\r
-               PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
+               &CrbReg->CrbControlRequest,\r
                0,\r
+               PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY,\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
+      RetryCnt++;\r
+      if (RetryCnt < RETRY_CNT_MAX) {\r
+        MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
+        continue;\r
+      } else {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto GoIdle_Exit;\r
+      }\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
-  //\r
-  MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);\r
-  Status = PtpCrbWaitRegisterBits (\r
-             &CrbReg->CrbControlRequest,\r
-             0,\r
-             PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY,\r
-             PTP_TIMEOUT_C\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto GoIdle_Exit;\r
-  }\r
+    Status = PtpCrbWaitRegisterBits (\r
+               &CrbReg->CrbControlStatus,\r
+               0,\r
+               PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
+               PTP_TIMEOUT_C\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      RetryCnt++;\r
+      if (RetryCnt < RETRY_CNT_MAX) {\r
+        MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
+        continue;\r
+      } else {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto GoIdle_Exit;\r
+      }\r
+    }\r
 \r
-  Status = PtpCrbWaitRegisterBits (\r
-             &CrbReg->CrbControlStatus,\r
-             0,\r
-             PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
-             PTP_TIMEOUT_C\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto GoIdle_Exit;\r
+    break;\r
   }\r
 \r
   //\r
@@ -320,7 +350,7 @@ PtpCrbTpmCommand (
     // Command completed, but buffer is not enough\r
     //\r
     Status = EFI_BUFFER_TOO_SMALL;\r
-    goto GoReady_Exit;\r
+    goto GoIdle_Exit;\r
   }\r
 \r
   *SizeOut = TpmOutSize;\r
@@ -340,16 +370,6 @@ PtpCrbTpmCommand (
   DEBUG ((DEBUG_VERBOSE, "\n"));\r
   DEBUG_CODE_END ();\r
 \r
-GoReady_Exit:\r
-  //\r
-  // Goto Ready State if command is completed successfully and TPM support IdleBypass\r
-  // If not supported. flow down to GoIdle\r
-  //\r
-  if (GetCachedIdleByPass () == 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
@@ -361,19 +381,6 @@ GoIdle_Exit:
   //\r
   MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
 \r
-  //\r
-  // Only enforce Idle state transition if execution fails when CRBIdleBypass==1\r
-  // Leave regular Idle delay at the beginning of next command execution\r
-  //\r
-  if (GetCachedIdleByPass () == 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