/** @file Set TPM device type This module initializes the TPM device type based on a CRB over FF-A interface Copyright (C) 2025, Arm Ltd. SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): - https://developer.arm.com/documentation/den0138/latest/ **/ #include #include #include #include #include #include #include #include #define TPM2_FFA_SERVICE_MAJOR_VERSION (1) #define TPM2_FFA_SERVICE_MINOR_VERSION (0) STATIC CONST EFI_PEI_PPI_DESCRIPTOR mTpmSelectedPpi = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiTpmDeviceSelectedGuid, NULL }; STATIC CONST EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = { EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gPeiTpmInitializationDonePpiGuid, NULL }; /** Check the Tpm Service Interface version. See the CRB over FF-A spec 6.1. all of arguments' value based on the specification. @param [in] TpmPartId TPM service partition id. @retval EFI_SUCCESS @retval EFI_DEVICE_ERROR Failed to communicate TPM SP. @retval EFI_UNSUPPORTED Unsupported version of TPM service **/ STATIC EFI_STATUS EFIAPI Tpm2FfaCheckInterfaceVersion ( IN UINT16 TpmPartId ) { EFI_STATUS Status; DIRECT_MSG_ARGS TpmArgs; UINT16 MajorVer; UINT16 MinorVer; ZeroMem (&TpmArgs, sizeof (DIRECT_MSG_ARGS)); TpmArgs.Arg0 = TPM2_FFA_GET_INTERFACE_VERSION; Status = ArmFfaLibMsgSendDirectReq2 (TpmPartId, &gTpm2ServiceFfaGuid, &TpmArgs); while (Status == EFI_INTERRUPT_PENDING) { // We are assuming vCPU0 of the TPM SP since it is UP. Status = ArmFfaLibRun (TpmPartId, 0x00, &TpmArgs); } if (EFI_ERROR (Status) || (TpmArgs.Arg0 != TPM2_FFA_SUCCESS_OK_RESULTS_RETURNED)) { DEBUG (( DEBUG_ERROR, "%a: Failed to get interface version... Status: %r, TpmArgs.Arg0: 0x%x\n", __func__, Status, TpmArgs.Arg0 )); return EFI_DEVICE_ERROR; } MajorVer = (TpmArgs.Arg1 & TPM2_FFA_SERVICE_MAJOR_VER_MASK) >> TPM2_FFA_SERVICE_MAJOR_VER_SHIFT; MinorVer = (TpmArgs.Arg1 & TPM2_FFA_SERVICE_MINOR_VER_MASK) >> TPM2_FFA_SERVICE_MINOR_VER_SHIFT; if ((MajorVer != TPM2_FFA_SERVICE_MAJOR_VERSION) || (MinorVer < TPM2_FFA_SERVICE_MINOR_VERSION)) { DEBUG (( DEBUG_ERROR, "%a: Wrong Tpm Ffa Interface Version...: v%d.%d\n", __func__, MajorVer, MinorVer )); return EFI_UNSUPPORTED; } return EFI_SUCCESS; } /** The entry point for Tcg2 configuration driver. @param FileHandle Handle of the file being invoked. @param PeiServices Describes the list of possible PEI Services. **/ EFI_STATUS EFIAPI Tcg2ConfigFfaPeimEntryPoint ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; UINTN Size; UINT16 PartId; UINT16 TpmPartId; EFI_FFA_PART_INFO_DESC *TpmPartInfo; VOID *TxBuffer; UINT64 TxBufferSize; VOID *RxBuffer; UINT64 RxBufferSize; UINT32 Count; CONST EFI_PEI_PPI_DESCRIPTOR *PpiList; GUID *TpmInstanceGuid; DEBUG ((DEBUG_INFO, "%a\n", __func__)); TpmInstanceGuid = &gEfiTpmDeviceInstanceNoneGuid; PpiList = &mTpmInitializationDonePpiList; Status = ArmFfaLibPartitionIdGet (&PartId); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to get partition-id. Status: %r\n", Status)); goto Cleanup; } Status = ArmFfaLibGetRxTxBuffers ( &TxBuffer, &TxBufferSize, &RxBuffer, &RxBufferSize ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to get Rx/Tx Buffer. Status: %r\n", Status)); goto Cleanup; } Status = ArmFfaLibPartitionInfoGet ( &gTpm2ServiceFfaGuid, FFA_PART_INFO_FLAG_TYPE_DESC, &Count, (UINT32 *)&Size ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to get Tpm2 partition info. Status: %r\n", Status)); goto Cleanup; } if ((Count != 1) || (Size < sizeof (EFI_FFA_PART_INFO_DESC))) { Status = EFI_INVALID_PARAMETER; DEBUG ((DEBUG_ERROR, "Invalid partition Info(%g). Count: %d, Size: %d\n", &gTpm2ServiceFfaGuid, Count, Size)); ArmFfaLibRxRelease (PartId); goto Cleanup; } TpmPartInfo = (EFI_FFA_PART_INFO_DESC *)RxBuffer; TpmPartId = TpmPartInfo->PartitionId; ArmFfaLibRxRelease (PartId); Status = Tpm2FfaCheckInterfaceVersion (TpmPartId); if (EFI_ERROR (Status)) { goto Cleanup; } /* * Set the PcdTpmInstanceGuid to TPM using CRB over FF-A * So that Tpm2DeviceLibRouterPei/Dxe can communicate with * TPM secure partition. */ TpmInstanceGuid = &gTpm2ServiceFfaGuid; PpiList = &mTpmSelectedPpi; Cleanup: Size = sizeof (GUID); Status = PcdSetPtrS ( PcdTpmInstanceGuid, &Size, TpmInstanceGuid ); ASSERT_EFI_ERROR (Status); Status = PeiServicesInstallPpi (PpiList); return Status; }