/** @file TrEE configuration module. ;****************************************************************************** ;* Copyright (c) 2013 - 2019, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TPM_INSTANCE_ID_LIST { \ {TPM_DEVICE_INTERFACE_NONE, TPM_DEVICE_NULL}, \ {TPM_DEVICE_INTERFACE_TPM12, TPM_DEVICE_1_2}, \ {TPM_DEVICE_INTERFACE_TPM20_DTPM, TPM_DEVICE_2_0}, \ {TPM_DEVICE_INTERFACE_TCM, TPM_DEVICE_TCM}, \ } typedef struct { GUID TpmInstanceGuid; UINT8 TpmDevice; } TPM_INSTANCE_ID; TPM_INSTANCE_ID mTpmInstanceId[] = TPM_INSTANCE_ID_LIST; CONST EFI_PEI_PPI_DESCRIPTOR gTpmSelectedPpi = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiTpmDeviceSelectedGuid, NULL }; EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = { EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gPeiTpmInitializationDonePpiGuid, NULL }; /** Callback for TrEE configuration driver. @param FileHandle Handle of the file being invoked. @param NotifyDescriptor Describes the list of possible PEI Services. @retval EFI_SUCCES Convert variable to PCD successfully. @retval Others Fail to convert variable to PCD. **/ EFI_STATUS EFIAPI BootModePpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ); /** Install TpmSelectedPpi at memory discovered to notify other drivers. @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param[in] NotifyDescriptor Address of the notification descriptor data structure. @param[in] Ppi Address of the PPI that was installed. @retval EFI_SUCCESS Operation completed successfully. @retval Others Operation failed. **/ EFI_STATUS EFIAPI MemoryDiscoveredPpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ); EFI_PEI_NOTIFY_DESCRIPTOR mBootModeNotifyList[] = { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiMasterBootModePpiGuid, BootModePpiNotifyCallback }; EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList = { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiMemoryDiscoveredPpiGuid, MemoryDiscoveredPpiNotifyCallback }; /** Install TpmSelectedPpi to notify other drivers. @retval EFI_SUCCESS Operation completed successfully. @retval Others Operation failed. **/ STATIC EFI_STATUS TpmSelectionDone ( ) { EFI_STATUS Status; // // Selection done // Status = PeiServicesInstallPpi (&gTpmSelectedPpi); ASSERT_EFI_ERROR (Status); // // Even if no TPM is selected or detected, we still need intall TpmInitializationDonePpi. // Because TcgPei or TrEEPei will not run, but we still need a way to notify other driver. // Other driver can know TPM initialization state by TpmInitializedPpi. // Also, install TpmInitializationDonePpi if TPM has been hidden. // if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || PcdGetBool (PcdTpmHide)) { Status = PeiServicesInstallPpi (&mTpmInitializationDonePpiList); ASSERT_EFI_ERROR (Status); // // Remove Type 43(TPM Device) from SMBIOS table // Status = PcdSetBoolS (PcdActiveSmbiosType043, FALSE); ASSERT_EFI_ERROR (Status); } return Status; } /** Install TpmSelectedPpi at memory discovered to notify other drivers. @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param[in] NotifyDescriptor Address of the notification descriptor data structure. @param[in] Ppi Address of the PPI that was installed. @retval EFI_SUCCESS Operation completed successfully. @retval Others Operation failed. **/ EFI_STATUS EFIAPI MemoryDiscoveredPpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { return TpmSelectionDone (); } /** Send TPM_ContinueSelfTest command to TPM. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_TIMEOUT The register can't run into the expected status in time. @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. @retval EFI_DEVICE_ERROR Unexpected device behavior. **/ EFI_STATUS TpmContinueSelfTest ( VOID ) { EFI_STATUS Status; UINT32 TpmRecvSize; UINT32 TpmSendSize; TPM_RQU_COMMAND_HDR SendBuffer; UINT8 RecvBuffer[20]; // // send Tpm command TPM_ORD_ContinueSelfTest // TpmRecvSize = 20; TpmSendSize = sizeof (TPM_RQU_COMMAND_HDR); SendBuffer.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); SendBuffer.paramSize = SwapBytes32 (TpmSendSize); SendBuffer.ordinal = SwapBytes32 (TPM_ORD_ContinueSelfTest); Status = Tpm12SubmitCommand (TpmSendSize, (UINT8 *)&SendBuffer, &TpmRecvSize, RecvBuffer); return Status; } /** This routine return if TCM present. @retval TRUE dTPM present @retval FALSE dTPM not present **/ BOOLEAN IsTcmPresent ( VOID ) { return !EFI_ERROR (TisPcRequestUseTcm ()); } /** This routine return if dTPM (1.2 or 2.0) present. @retval TRUE dTPM present @retval FALSE dTPM not present **/ BOOLEAN IsDtpmPresent ( VOID ) { UINT8 RegRead; RegRead = MmioRead8 ((UINTN)PcdGet64 (PcdTpmBaseAddress)); if (RegRead == 0xFF) { DEBUG ((EFI_D_ERROR, "DetectTpmDevice: Dtpm not present\n")); return FALSE; } else { DEBUG ((EFI_D_ERROR, "DetectTpmDevice: Dtpm present\n")); return TRUE; } } /** This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration. @param SetupTpmDevice TpmDevice configuration in setup driver @param ByPassTpmInit If TRUE, tries TpmSelfTest to identify TPM. If FALSE, tries TpmStartup to identify TPM. @return TpmDevice configuration **/ UINT8 DetectTpmDevice ( IN UINT8 SetupTpmDevice, IN BOOLEAN ByPassTpmInit ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; UINT32 TpmPolicy; Status = PeiServicesGetBootMode (&BootMode); ASSERT_EFI_ERROR (Status); // // In S3, we rely on normal boot Detection // if (BootMode == BOOT_ON_S3_RESUME) { DEBUG ((EFI_D_ERROR, "DetectTpmDevice: S3 mode\n")); DEBUG ((EFI_D_ERROR, "TpmDevice from DeviceDetection: %x\n", SetupTpmDevice)); if (PcdGetBool (PcdTpmHide)) { // // Activate the TPM when TPM is hidden, in order to prevent the time-out of // following command executions. // For CRB-interface of TPM, returned error is acceptable. // Tpm12RequestUseTpm (); } return SetupTpmDevice; } DEBUG ((EFI_D_ERROR, "DetectTpmDevice:\n")); if (!IsDtpmPresent ()) { // // dTPM not available // return TPM_DEVICE_NULL; } if ((PcdGet32 (PcdPeiTpmPolicy) & SKIP_PEI_TPM_AUTO_DETECTION) != 0) { DEBUG ((EFI_D_INFO, "PeiTpmPolicy: Skip TPM auto detection\n")); return TPM_DEVICE_NULL; } if (IsTcmPresent ()) { // // TCM detected // DEBUG ((EFI_D_ERROR, "TCM detected.\n")); return TPM_DEVICE_TCM; } // // Check if it is TPM1.2 or TPM2.0 by tring TPM1.2 command at first // Status = Tpm12RequestUseTpm (); if (EFI_ERROR (Status)) { return TPM_DEVICE_2_0; } if (ByPassTpmInit) { Status = TpmContinueSelfTest (); TpmPolicy = PcdGet32 (PcdPeiTpmPolicy) | SKIP_TPM_SELF_TEST; } else { Status = Tpm12Startup (TPM_ST_CLEAR); TpmPolicy = PcdGet32 (PcdPeiTpmPolicy) | SKIP_TPM_STARTUP; } if (EFI_ERROR (Status)) { return TPM_DEVICE_2_0; } Status = PcdSet32S (PcdPeiTpmPolicy, TpmPolicy); ASSERT_EFI_ERROR (Status); return TPM_DEVICE_1_2; } /** Callback for TrEE configuration driver. @param FileHandle Handle of the file being invoked. @param NotifyDescriptor Describes the list of possible PEI Services. @retval EFI_SUCCES Convert variable to PCD successfully. @retval Others Fail to convert variable to PCD. **/ EFI_STATUS EFIAPI BootModePpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; KERNEL_CONFIGURATION KernelConfiguration; UINTN Size; UINTN Index; UINT8 TpmDevice; BOOLEAN ByPassTpmInit; if (!CompareGuid (NotifyDescriptor->Guid, &gEfiPeiMasterBootModePpiGuid)) { return EFI_UNSUPPORTED; } Status = GetKernelConfiguration (&KernelConfiguration); if (EFI_ERROR (Status) || KernelConfiguration.TpmDevice > TPM_DEVICE_MAX) { // // Variable not ready or incorrect, set default value // if (PcdGetBool (PcdH2OTpm2Supported)) { KernelConfiguration.TpmDevice = TPM_DEVICE_2_0; } else { KernelConfiguration.TpmDevice = TPM_DEVICE_1_2; } KernelConfiguration.TpmHide = 0; } Status = PcdSetBoolS (PcdTpmHide, KernelConfiguration.TpmHide); ASSERT_EFI_ERROR (Status); Status = PcdSet8S (PcdTrEEProtocolVersion, KernelConfiguration.TrEEVersion); ASSERT_EFI_ERROR (Status); // // Although we have setup variable info, we still need detect TPM device manually. // DEBUG ((EFI_D_ERROR, "KernelConfiguration.TpmDevice from Setup: %x\n", KernelConfiguration.TpmDevice)); if (PcdGetBool (PcdTpmAutoDetection)) { ByPassTpmInit = ((PcdGet32 (PcdPeiTpmPolicy) & SKIP_TPM_STARTUP) == 0) ? FALSE : TRUE; TpmDevice = DetectTpmDevice (KernelConfiguration.TpmDevice, ByPassTpmInit); DEBUG ((EFI_D_ERROR, "TpmDevice final: %x\n", TpmDevice)); if (TpmDevice != TPM_DEVICE_NULL) { KernelConfiguration.TpmDevice = TpmDevice; } } else { TpmDevice = KernelConfiguration.TpmDevice; } // // Check whether the selected TPM is changed. // Don't hide TPM if TPM is changed // switch (TpmDevice) { case TPM_DEVICE_2_0: if (KernelConfiguration.TpmDeviceOk == 1) { Status = PcdSetBoolS (PcdTpmHide, FALSE); ASSERT_EFI_ERROR (Status); } break; case TPM_DEVICE_1_2: case TPM_DEVICE_TCM: if (KernelConfiguration.Tpm2DeviceOk == 1) { Status = PcdSetBoolS (PcdTpmHide, FALSE); ASSERT_EFI_ERROR (Status); } break; } // // Convert variable to PCD. // for (Index = 0; Index < sizeof (mTpmInstanceId) / sizeof (mTpmInstanceId[0]); Index++) { if (TpmDevice == mTpmInstanceId[Index].TpmDevice) { Size = sizeof (mTpmInstanceId[Index].TpmInstanceGuid); Status = PcdSetPtrS (PcdTpmInstanceGuid, &Size, &mTpmInstanceId[Index].TpmInstanceGuid); ASSERT_EFI_ERROR (Status); break; } } if ((PcdGet32 (PcdPeiTpmPolicy) & TPM2_STARTUP_IN_MP) == 0) { Status = TpmSelectionDone (); } else { // // Postpone TpmSelectedPpi installation to memory discovered // Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList); } ASSERT_EFI_ERROR (Status); return Status; } /** The entry point for TrEE configuration driver. @param FileHandle Handle of the file being invoked. @param PeiServices Describes the list of possible PEI Services. @retval EFI_SUCCES Successfully registers BootMode service to be invoked @retval Others Fail to register a callback **/ EFI_STATUS EFIAPI TrEEConfigPeimEntryPoint ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; Status = PeiServicesNotifyPpi (mBootModeNotifyList); ASSERT_EFI_ERROR (Status); return Status; }