diff --git a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c index 3feb64df7e..e6fe563b40 100644 --- a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c +++ b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c @@ -31,6 +31,18 @@ Tpm2GetPtpInterface ( IN VOID *Register ); +/** + Return PTP CRB interface IdleByPass state. + + @param[in] Register Pointer to PTP register. + + @return PTP CRB interface IdleByPass state. +**/ +UINT8 +Tpm2GetIdleByPass ( + IN VOID *Register + ); + /** This service enables the sending of commands to the TPM2. @@ -140,6 +152,7 @@ Tpm2DeviceLibConstructor ( ) { TPM2_PTP_INTERFACE_TYPE PtpInterface; + UINT8 IdleByPass; // // Cache current active TpmInterfaceType only when needed @@ -148,5 +161,11 @@ Tpm2DeviceLibConstructor ( PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); PcdSet8S(PcdActiveTpmInterfaceType, PtpInterface); } + + if (PcdGet8(PcdActiveTpmInterfaceType) == PtpInterfaceCrb && PcdGet8(PcdCRBIdleByPass) == 0xFF) { + IdleByPass = Tpm2GetIdleByPass((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + PcdSet8S(PcdCRBIdleByPass, IdleByPass); + } + return EFI_SUCCESS; } diff --git a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf index 634bbae847..2e54a78cc0 100644 --- a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf +++ b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf @@ -55,3 +55,4 @@ [Pcd] gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdCRBIdleByPass ## PRODUCES \ No newline at end of file diff --git a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c index 01f78bf0be..edcdb72a79 100644 --- a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c +++ b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c @@ -34,6 +34,18 @@ Tpm2GetPtpInterface ( IN VOID *Register ); +/** + Return PTP CRB interface IdleByPass state. + + @param[in] Register Pointer to PTP register. + + @return PTP CRB interface IdleByPass state. +**/ +UINT8 +Tpm2GetIdleByPass ( + IN VOID *Register + ); + /** Dump PTP register information. @@ -97,6 +109,7 @@ Tpm2InstanceLibDTpmConstructor ( { EFI_STATUS Status; TPM2_PTP_INTERFACE_TYPE PtpInterface; + UINT8 IdleByPass; Status = Tpm2RegisterTpm2DeviceLib (&mDTpm2InternalTpm2Device); if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) { @@ -111,6 +124,12 @@ Tpm2InstanceLibDTpmConstructor ( PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); PcdSet8S(PcdActiveTpmInterfaceType, PtpInterface); } + + if (PcdGet8(PcdActiveTpmInterfaceType) == PtpInterfaceCrb && PcdGet8(PcdCRBIdleByPass) == 0xFF) { + IdleByPass = Tpm2GetIdleByPass((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + PcdSet8S(PcdCRBIdleByPass, IdleByPass); + } + DumpPtpInfo ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); } return EFI_SUCCESS; diff --git a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf index 876a5a63c4..24e4c35d55 100644 --- a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf +++ b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf @@ -50,4 +50,5 @@ [Pcd] gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES - gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## PRODUCES \ No newline at end of file + gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdCRBIdleByPass ## PRODUCES \ No newline at end of file diff --git a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c index 1bc153a2c0..ad2f188b46 100644 --- a/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c +++ b/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c @@ -174,10 +174,30 @@ PtpCrbTpmCommand ( } DEBUG ((EFI_D_VERBOSE, "\n")); ); - TpmOutSize = 0; + TpmOutSize = 0; // // STEP 0: + // if CapCRbIdelByPass == 0, enforce Idle state before sending command + // + if (PcdGet8(PcdCRBIdleByPass) == 0 && (MmioRead32((UINTN)&CrbReg->CrbControlStatus) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE) == 0){ + Status = PtpCrbWaitRegisterBits ( + &CrbReg->CrbControlStatus, + PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE, + 0, + PTP_TIMEOUT_C + ); + if (EFI_ERROR (Status)) { + // + // Try to goIdle to recover TPM + // + Status = EFI_DEVICE_ERROR; + goto GoIdle_Exit; + } + } + + // + // STEP 1: // Ready is any time the TPM is ready to receive a command, following a write // of 1 by software to Request.cmdReady, as indicated by the Status field // being cleared to 0. @@ -191,7 +211,7 @@ PtpCrbTpmCommand ( ); if (EFI_ERROR (Status)) { Status = EFI_DEVICE_ERROR; - goto Exit; + goto GoIdle_Exit; } Status = PtpCrbWaitRegisterBits ( &CrbReg->CrbControlStatus, @@ -201,11 +221,11 @@ PtpCrbTpmCommand ( ); if (EFI_ERROR (Status)) { Status = EFI_DEVICE_ERROR; - goto Exit; + goto GoIdle_Exit; } // - // STEP 1: + // STEP 2: // Command Reception occurs following a Ready state between the write of the // first byte of a command to the Command Buffer and the receipt of a write // of 1 to Start. @@ -221,7 +241,7 @@ PtpCrbTpmCommand ( MmioWrite32 ((UINTN)&CrbReg->CrbControlResponseSize, sizeof(CrbReg->CrbDataBuffer)); // - // STEP 2: + // STEP 3: // Command Execution occurs after receipt of a 1 to Start and the TPM // clearing Start to 0. // @@ -251,12 +271,12 @@ PtpCrbTpmCommand ( // Still in Command Execution state. Try to goIdle, the behavior is agnostic. // Status = EFI_DEVICE_ERROR; - goto Exit; + goto GoIdle_Exit; } } // - // STEP 3: + // STEP 4: // Command Completion occurs after completion of a command (indicated by the // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the // software to Request.goIdle. @@ -283,14 +303,17 @@ PtpCrbTpmCommand ( if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) { DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND)); Status = EFI_UNSUPPORTED; - goto Exit; + goto GoIdle_Exit; } CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32)); TpmOutSize = SwapBytes32 (Data32); if (*SizeOut < TpmOutSize) { + // + // Command completed, but buffer is not enough + // Status = EFI_BUFFER_TOO_SMALL; - goto Exit; + goto GoReady_Exit; } *SizeOut = TpmOutSize; // @@ -299,7 +322,7 @@ PtpCrbTpmCommand ( for (Index = sizeof (TPM2_RESPONSE_HEADER); Index < TpmOutSize; Index++) { BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]); } -Exit: + DEBUG_CODE ( DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Receive - ")); for (Index = 0; Index < TpmOutSize; Index++) { @@ -308,11 +331,40 @@ Exit: DEBUG ((EFI_D_VERBOSE, "\n")); ); +GoReady_Exit: // - // STEP 4: - // Idle is any time TPM_CRB_CTRL_STS_x.Status.goIdle is 1. + // Goto Ready State if command is completed succesfully and TPM support IdleBypass + // If not supported. flow down to GoIdle + // + if (PcdGet8(PcdCRBIdleByPass) == 1) { + MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY); + return Status; + } + + // + // Do not wait for state transition for TIMEOUT_C + // This function will try to wait 2 TIMEOUT_C at the beginning in next call. + // +GoIdle_Exit: + + // + // Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1. // MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE); + + // + // Only enforce Idle state transition if execution fails when CRBIndleBypass==1 + // Leave regular Idle delay at the beginning of next command execution + // + if (PcdGet8(PcdCRBIdleByPass) == 1){ + Status = PtpCrbWaitRegisterBits ( + &CrbReg->CrbControlStatus, + PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE, + 0, + PTP_TIMEOUT_C + ); + } + return Status; } @@ -394,6 +446,28 @@ Tpm2GetPtpInterface ( return Tpm2PtpInterfaceTis; } +/** + Return PTP CRB interface IdleByPass state. + + @param[in] Register Pointer to PTP register. + + @return PTP CRB interface IdleByPass state. +**/ +UINT8 +Tpm2GetIdleByPass ( + IN VOID *Register + ) +{ + PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; + + // + // Check interface id + // + InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); + + return (UINT8)(InterfaceId.Bits.CapCRBIdleBypass); +} + /** Dump PTP register information. diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index 60f1c0a0e3..e24b563bdb 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -474,5 +474,15 @@ # @Prompt current active TPM interface type. gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType|0xFF|UINT8|0x0001001E + ## This PCD records IdleByass status supported by current active TPM interface. + # Accodingt to TCG PTP spec 1.3, TPM with CRB interface can skip idle state and + # diretcly move to CmdReady state.
+ # 0x00 - Do not support IdleByPass.
+ # 0x01 - Support IdleByPass.
+ # 0xFF - IdleByPass State is not synced with TPM hardware.
+ # + # @Prompt IdleByass status supported by current active TPM interface. + gEfiSecurityPkgTokenSpaceGuid.PcdCRBIdleByPass|0xFF|UINT8|0x0001001F + [UserExtensions.TianoCore."ExtraFiles"] SecurityPkgExtra.uni diff --git a/SecurityPkg/SecurityPkg.uni b/SecurityPkg/SecurityPkg.uni index c34250e423..000bc83d80 100644 --- a/SecurityPkg/SecurityPkg.uni +++ b/SecurityPkg/SecurityPkg.uni @@ -254,4 +254,12 @@ "0x00 - FIFO interface as defined in TIS 1.3 is active.
\n" "0x01 - FIFO interface as defined in PTP for TPM 2.0 is active.
\n" "0x02 - CRB interface is active.
\n" - "0xFF - Contains no current active TPM interface type
" \ No newline at end of file + "0xFF - Contains no current active TPM interface type
" + +#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdCRBIdleByPass_PROMPT #language en-US "IdleByass status supported by current active TPM interface." + +#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdCRBIdleByPass_HELP #language en-US "This PCD records IdleByass status supported by current active TPM interface.\n" + "Accodingt to TCG PTP spec 1.3, TPM with CRB interface can skip idle state and diretcly move to CmdReady state.
" + "0x01 - Do not support IdleByPass.
\n" + "0x02 - Support IdleByPass.
\n" + "0xFF - IdleByPass State is not synced with TPM hardware.
" \ No newline at end of file