/** @file Update and publish processors' BIST information. Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "CpuMpPei.h" EFI_SEC_PLATFORM_INFORMATION2_PPI mSecPlatformInformation2Ppi = { SecPlatformInformation2 }; EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformation2Ppi = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiSecPlatformInformation2PpiGuid, &mSecPlatformInformation2Ppi }; /** Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI. @param PeiServices The pointer to the PEI Services Table. @param StructureSize The pointer to the variable describing size of the input buffer. @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2. @retval EFI_SUCCESS The data was successfully returned. @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to hold the record is returned in StructureSize. **/ EFI_STATUS EFIAPI SecPlatformInformation2 ( IN CONST EFI_PEI_SERVICES **PeiServices, IN OUT UINT64 *StructureSize, OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2 ) { EFI_HOB_GUID_TYPE *GuidHob; VOID *DataInHob; UINTN DataSize; GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformation2PpiGuid); if (GuidHob == NULL) { *StructureSize = 0; return EFI_SUCCESS; } DataInHob = GET_GUID_HOB_DATA (GuidHob); DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob); // // return the information from BistHob // if ((*StructureSize) < (UINT64) DataSize) { *StructureSize = (UINT64) DataSize; return EFI_BUFFER_TOO_SMALL; } *StructureSize = (UINT64) DataSize; CopyMem (PlatformInformationRecord2, DataInHob, DataSize); return EFI_SUCCESS; } /** Worker function to get CPUs' BIST by calling SecPlatformInformationPpi or SecPlatformInformation2Ppi. @param PeiServices Pointer to PEI Services Table @param Guid PPI Guid @param PpiDescriptor Return a pointer to instance of the EFI_PEI_PPI_DESCRIPTOR @param BistInformationData Pointer to BIST information data @param BistInformationSize Return the size in bytes of BIST information @retval EFI_SUCCESS Retrieve of the BIST data successfully @retval EFI_NOT_FOUND No sec platform information(2) ppi export @retval EFI_DEVICE_ERROR Failed to get CPU Information **/ EFI_STATUS GetBistInfoFromPpi ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_GUID *Guid, OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor, OUT VOID **BistInformationData, OUT UINT64 *BistInformationSize OPTIONAL ) { EFI_STATUS Status; EFI_SEC_PLATFORM_INFORMATION2_PPI *SecPlatformInformation2Ppi; EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2; UINT64 InformationSize; Status = PeiServicesLocatePpi ( Guid, // GUID 0, // INSTANCE PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR (VOID **)&SecPlatformInformation2Ppi // PPI ); if (Status == EFI_NOT_FOUND) { return EFI_NOT_FOUND; } if (Status == EFI_SUCCESS) { // // Get the size of the sec platform information2(BSP/APs' BIST data) // InformationSize = 0; SecPlatformInformation2 = NULL; Status = SecPlatformInformation2Ppi->PlatformInformation2 ( PeiServices, &InformationSize, SecPlatformInformation2 ); if (Status == EFI_BUFFER_TOO_SMALL) { Status = PeiServicesAllocatePool ( (UINTN) InformationSize, (VOID **) &SecPlatformInformation2 ); if (Status == EFI_SUCCESS) { // // Retrieve BIST data // Status = SecPlatformInformation2Ppi->PlatformInformation2 ( PeiServices, &InformationSize, SecPlatformInformation2 ); if (Status == EFI_SUCCESS) { *BistInformationData = SecPlatformInformation2; if (BistInformationSize != NULL) { *BistInformationSize = InformationSize; } return EFI_SUCCESS; } } } } return EFI_DEVICE_ERROR; } /** Collects BIST data from PPI. This function collects BIST data from Sec Platform Information2 PPI or SEC Platform Information PPI. @param PeiServices Pointer to PEI Services Table **/ VOID CollectBistDataFromPpi ( IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; EFI_PEI_PPI_DESCRIPTOR *SecInformationDescriptor; EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2; EFI_SEC_PLATFORM_INFORMATION_RECORD *SecPlatformInformation; UINTN NumberOfData; EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance; EFI_SEC_PLATFORM_INFORMATION_CPU BspCpuInstance; UINTN ProcessorNumber; UINTN CpuIndex; EFI_PROCESSOR_INFORMATION ProcessorInfo; EFI_HEALTH_FLAGS BistData; UINTN NumberOfProcessors; UINTN NumberOfEnabledProcessors; UINTN BistInformationSize; EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2; EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstanceInHob; MpInitLibGetNumberOfProcessors(&NumberOfProcessors, &NumberOfEnabledProcessors); BistInformationSize = sizeof (EFI_SEC_PLATFORM_INFORMATION_RECORD2) + sizeof (EFI_SEC_PLATFORM_INFORMATION_CPU) * NumberOfProcessors; Status = PeiServicesAllocatePool ( (UINTN) BistInformationSize, (VOID **) &PlatformInformationRecord2 ); ASSERT_EFI_ERROR (Status); PlatformInformationRecord2->NumberOfCpus = (UINT32)NumberOfProcessors; SecPlatformInformation2 = NULL; SecPlatformInformation = NULL; NumberOfData = 0; CpuInstance = NULL; // // Get BIST information from Sec Platform Information2 Ppi firstly // Status = GetBistInfoFromPpi ( PeiServices, &gEfiSecPlatformInformation2PpiGuid, &SecInformationDescriptor, (VOID *) &SecPlatformInformation2, NULL ); if (Status == EFI_SUCCESS) { // // Sec Platform Information2 PPI includes BSP/APs' BIST information // NumberOfData = SecPlatformInformation2->NumberOfCpus; CpuInstance = SecPlatformInformation2->CpuInstance; } else { // // Otherwise, get BIST information from Sec Platform Information Ppi // Status = GetBistInfoFromPpi ( PeiServices, &gEfiSecPlatformInformationPpiGuid, &SecInformationDescriptor, (VOID *) &SecPlatformInformation, NULL ); if (Status == EFI_SUCCESS) { NumberOfData = 1; // // SEC Platform Information only includes BSP's BIST information // and does not have BSP's APIC ID // BspCpuInstance.CpuLocation = GetInitialApicId (); BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32; CpuInstance = &BspCpuInstance; } else { DEBUG ((EFI_D_INFO, "Does not find any stored CPU BIST information from PPI!\n")); } } for (ProcessorNumber = 0; ProcessorNumber < NumberOfProcessors; ProcessorNumber ++) { MpInitLibGetProcessorInfo (ProcessorNumber, &ProcessorInfo, &BistData); for (CpuIndex = 0; CpuIndex < NumberOfData; CpuIndex ++) { ASSERT (CpuInstance != NULL); if (ProcessorInfo.ProcessorId == CpuInstance[CpuIndex].CpuLocation) { // // Update processor's BIST data if it is already stored before // BistData = CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags; } } if (BistData.Uint32 != 0) { // // Report Status Code that self test is failed // REPORT_STATUS_CODE ( EFI_ERROR_CODE | EFI_ERROR_MAJOR, (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST) ); } DEBUG ((EFI_D_INFO, " APICID - 0x%08x, BIST - 0x%08x\n", (UINT32) ProcessorInfo.ProcessorId, BistData )); CpuInstanceInHob = PlatformInformationRecord2->CpuInstance; CpuInstanceInHob[ProcessorNumber].CpuLocation = (UINT32) ProcessorInfo.ProcessorId; CpuInstanceInHob[ProcessorNumber].InfoRecord.IA32HealthFlags = BistData; } // // Build SecPlatformInformation2 PPI GUIDed HOB that also could be consumed // by CPU MP driver to get CPU BIST data // BuildGuidDataHob ( &gEfiSecPlatformInformation2PpiGuid, PlatformInformationRecord2, (UINTN) BistInformationSize ); if (SecPlatformInformation2 != NULL) { if (NumberOfData < NumberOfProcessors) { // // Reinstall SecPlatformInformation2 PPI to include new BIST information // Status = PeiServicesReInstallPpi ( SecInformationDescriptor, &mPeiSecPlatformInformation2Ppi ); ASSERT_EFI_ERROR (Status); } } else { // // Install SecPlatformInformation2 PPI // Status = PeiServicesInstallPpi (&mPeiSecPlatformInformation2Ppi); ASSERT_EFI_ERROR(Status); } }