diff --git a/UefiCpuPkg/Include/Library/CpuCacheInfoLib.h b/UefiCpuPkg/Include/Library/CpuCacheInfoLib.h new file mode 100644 index 0000000000..a23b8b12b5 --- /dev/null +++ b/UefiCpuPkg/Include/Library/CpuCacheInfoLib.h @@ -0,0 +1,76 @@ +/** @file + Header file for CPU Cache info Library. + + Copyright (c) 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _CPU_CACHE_INFO_LIB_H_ +#define _CPU_CACHE_INFO_LIB_H_ + +typedef struct { + // + // Package number. + // + UINT32 Package; + // + // Core type of logical processor. + // Value = CPUID.1Ah:EAX[31:24] + // + UINT8 CoreType; + // + // Level of the cache that this package's this type of logical processor corresponds to. + // Value = CPUID.04h:EAX[07:05] + // + UINT8 CacheLevel : 3; + // + // Type of the cache that this package's this type of logical processor corresponds to. + // Value = CPUID.04h:EAX[04:00] + // + UINT8 CacheType : 5; + // + // Ways of associativity. + // Value = CPUID.04h:EBX[31:22] + // + UINT16 CacheWays; + // + // Size of single cache that this package's this type of logical processor corresponds to. + // Value = (CPUID.04h:EBX[31:22] + 1) * (CPUID.04h:EBX[21:12] + 1) * + // (CPUID.04h:EBX[11:00] + 1) * (CPUID.04h:ECX[31:00] + 1) + // + UINT32 CacheSizeinKB; + // + // Number of the cache that this package's this type of logical processor corresponds to. + // Have subtracted the number of caches that are shared. + // + UINT16 CacheCount; +} CPU_CACHE_INFO; + +/** + Get CpuCacheInfo data array. + + @param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array. + @param[in, out] CpuCacheInfoCount As input, point to the length of response CpuCacheInfo array. + As output, point to the actual length of response CpuCacheInfo array. + + @retval EFI_SUCCESS Function completed successfully. + @retval EFI_INVALID_PARAMETER CpuCacheInfoCount is NULL. + @retval EFI_INVALID_PARAMETER CpuCacheInfo is NULL while CpuCacheInfoCount contains the value + greater than zero. + @retval EFI_UNSUPPORTED Processor does not support CPUID_CACHE_PARAMS Leaf. + @retval EFI_NOT_FOUND EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL interface + is not found. + @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated. + @retval EFI_BUFFER_TOO_SMALL CpuCacheInfoCount is too small to hold the response CpuCacheInfo + array. CpuCacheInfoCount has been updated with the length needed + to complete the request. +**/ +EFI_STATUS +EFIAPI +GetCpuCacheInfo ( + IN OUT CPU_CACHE_INFO *CpuCacheInfo, + IN OUT UINTN *CpuCacheInfoCount + ); + +#endif diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c b/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c new file mode 100644 index 0000000000..6b87be261a --- /dev/null +++ b/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c @@ -0,0 +1,441 @@ +/** @file + Provides cache info for each package, core type, cache level and cache type. + + Copyright (c) 2020 Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCpuCacheInfoLib.h" + +/** + Print CpuCacheInfo array. + + @param[in] CpuCacheInfo Pointer to the CpuCacheInfo array. + @param[in] CpuCacheInfoCount The length of CpuCacheInfo array. + +**/ +VOID +CpuCacheInfoPrintCpuCacheInfoTable ( + IN CPU_CACHE_INFO *CpuCacheInfo, + IN UINTN CpuCacheInfoCount + ) +{ + UINTN Index; + + DEBUG ((DEBUG_INFO, "+-------+-------------------------------------------------------------------------------+\n")); + DEBUG ((DEBUG_INFO, "| Index | Packge CoreType CacheLevel CacheType CacheWays CacheSizeinKB CacheCount |\n")); + DEBUG ((DEBUG_INFO, "+-------+-------------------------------------------------------------------------------+\n")); + + for (Index = 0; Index < CpuCacheInfoCount; Index++) { + DEBUG ((DEBUG_INFO, "| %4x | %4x %2x %2x %2x %4x %8x %4x |\n", Index, + CpuCacheInfo[Index].Package, CpuCacheInfo[Index].CoreType, CpuCacheInfo[Index].CacheLevel, + CpuCacheInfo[Index].CacheType, CpuCacheInfo[Index].CacheWays, CpuCacheInfo[Index].CacheSizeinKB, + CpuCacheInfo[Index].CacheCount)); + } + + DEBUG ((DEBUG_INFO, "+-------+-------------------------------------------------------------------------------+\n")); +} + +/** + Get the total number of package and package ID in the platform. + + @param[in] ProcessorInfo Pointer to the ProcessorInfo array. + @param[in] NumberOfProcessors Total number of logical processors in the platform. + @param[in, out] Package Pointer to the Package array. + + @retval Return the total number of package and package ID in the platform. +**/ +UINT32 +CpuCacheInfoGetNumberOfPackages ( + IN CPUID_PROCESSOR_INFO *ProcessorInfo, + IN UINTN NumberOfProcessors, + IN OUT UINT32 *Package + ) +{ + UINTN ProcessorIndex; + UINT32 PackageIndex; + UINT32 PackageCount; + UINT32 CurrentPackage; + + PackageCount = 0; + + for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) { + CurrentPackage = ProcessorInfo[ProcessorIndex].Package; + + // + // For the package that already exists in Package array, break out the loop. + // + for (PackageIndex = 0; PackageIndex < PackageCount; PackageIndex++) { + if (CurrentPackage == Package[PackageIndex]) { + break; + } + } + + // + // For the new package, save it in Package array. + // + if (PackageIndex == PackageCount) { + ASSERT (PackageCount < MAX_NUM_OF_PACKAGE); + Package[PackageCount++] = CurrentPackage; + } + } + + return PackageCount; +} + +/** + Get the number of CoreType of requested package. + + @param[in] ProcessorInfo Pointer to the ProcessorInfo array. + @param[in] NumberOfProcessors Total number of logical processors in the platform. + @param[in] Package The requested package number. + + @retval Return the number of CoreType of requested package. +**/ +UINTN +CpuCacheInfoGetNumberOfCoreTypePerPackage( + IN CPUID_PROCESSOR_INFO *ProcessorInfo, + IN UINTN NumberOfProcessors, + IN UINTN Package + ) +{ + UINTN ProcessorIndex; + // + // Core Type value comes from CPUID.1Ah.EAX[31:24]. + // So max number of core types should be MAX_UINT8. + // + UINT8 CoreType[MAX_UINT8]; + UINTN CoreTypeIndex; + UINTN CoreTypeCount; + UINT8 CurrentCoreType; + + // + // CoreType array is empty. + // + CoreTypeCount = 0; + + for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) { + CurrentCoreType = ProcessorInfo[ProcessorIndex].CoreType; + + if (ProcessorInfo[ProcessorIndex].Package != Package) { + continue; + } + + // + // For the type that already exists in CoreType array, break out the loop. + // + for (CoreTypeIndex = 0; CoreTypeIndex < CoreTypeCount; CoreTypeIndex++) { + if (CurrentCoreType == CoreType[CoreTypeIndex]) { + break; + } + } + + // + // For the new type, save it in CoreType array. + // + if (CoreTypeIndex == CoreTypeCount) { + ASSERT (CoreTypeCount < MAX_UINT8); + CoreType[CoreTypeCount++] = CurrentCoreType; + } + } + + return CoreTypeCount; +} + +/** + Collect core and cache information of calling processor via CPUID instructions. + + @param[in, out] Buffer The pointer to private data buffer. +**/ +VOID +EFIAPI +CpuCacheInfoCollectCoreAndCacheData ( + IN OUT VOID *Buffer + ) +{ + UINTN ProcessorIndex; + UINT32 CpuidMaxInput; + UINT8 CacheParamLeafIndex; + CPUID_CACHE_PARAMS_EAX CacheParamEax; + CPUID_CACHE_PARAMS_EBX CacheParamEbx; + UINT32 CacheParamEcx; + CPUID_NATIVE_MODEL_ID_AND_CORE_TYPE_EAX NativeModelIdAndCoreTypeEax; + COLLECT_CPUID_CACHE_DATA_CONTEXT *Context; + CPUID_CACHE_DATA *CacheData; + + Context = (COLLECT_CPUID_CACHE_DATA_CONTEXT *)Buffer; + ProcessorIndex = CpuCacheInfoWhoAmI (Context->MpServices); + CacheData = &Context->CacheData[MAX_NUM_OF_CACHE_PARAMS_LEAF * ProcessorIndex]; + + AsmCpuid (CPUID_SIGNATURE, &CpuidMaxInput, NULL, NULL, NULL); + + // + // get CoreType if CPUID_HYBRID_INFORMATION leaf is supported. + // + Context->ProcessorInfo[ProcessorIndex].CoreType = 0; + if (CpuidMaxInput >= CPUID_HYBRID_INFORMATION) { + AsmCpuidEx (CPUID_HYBRID_INFORMATION, CPUID_HYBRID_INFORMATION_SUB_LEAF, &NativeModelIdAndCoreTypeEax.Uint32, NULL, NULL, NULL); + Context->ProcessorInfo[ProcessorIndex].CoreType = (UINT8) NativeModelIdAndCoreTypeEax.Bits.CoreType; + } + + // + // cache hierarchy starts with an index value of 0. + // + CacheParamLeafIndex = 0; + + while (CacheParamLeafIndex < MAX_NUM_OF_CACHE_PARAMS_LEAF) { + AsmCpuidEx (CPUID_CACHE_PARAMS, CacheParamLeafIndex, &CacheParamEax.Uint32, &CacheParamEbx.Uint32, &CacheParamEcx, NULL); + + if (CacheParamEax.Bits.CacheType == 0) { + break; + } + + CacheData[CacheParamLeafIndex].CacheLevel = (UINT8)CacheParamEax.Bits.CacheLevel; + CacheData[CacheParamLeafIndex].CacheType = (UINT8)CacheParamEax.Bits.CacheType; + CacheData[CacheParamLeafIndex].CacheWays = (UINT16)CacheParamEbx.Bits.Ways; + CacheData[CacheParamLeafIndex].CacheShareBits = (UINT16)CacheParamEax.Bits.MaximumAddressableIdsForLogicalProcessors; + CacheData[CacheParamLeafIndex].CacheSizeinKB = (CacheParamEbx.Bits.Ways + 1) * + (CacheParamEbx.Bits.LinePartitions + 1) * (CacheParamEbx.Bits.LineSize + 1) * (CacheParamEcx + 1) / SIZE_1KB; + + CacheParamLeafIndex++; + } +} + +/** + Collect CacheInfo data from the CacheData. + + @param[in] CacheData Pointer to the CacheData array. + @param[in] ProcessorInfo Pointer to the ProcessorInfo array. + @param[in] NumberOfProcessors Total number of logical processors in the platform. + @param[in, out] CacheInfo Pointer to the CacheInfo array. + @param[in, out] CacheInfoCount As input, point to the length of response CacheInfo array. + As output, point to the actual length of response CacheInfo array. + + @retval EFI_SUCCESS Function completed successfully. + @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated. + @retval EFI_BUFFER_TOO_SMALL CacheInfoCount is too small to hold the response CacheInfo + array. CacheInfoCount has been updated with the length needed + to complete the request. +**/ +EFI_STATUS +CpuCacheInfoCollectCpuCacheInfoData ( + IN CPUID_CACHE_DATA *CacheData, + IN CPUID_PROCESSOR_INFO *ProcessorInfo, + IN UINTN NumberOfProcessors, + IN OUT CPU_CACHE_INFO *CacheInfo, + IN OUT UINTN *CacheInfoCount + ) +{ + EFI_STATUS Status; + UINT32 NumberOfPackage; + UINT32 Package[MAX_NUM_OF_PACKAGE]; + UINTN PackageIndex; + UINTN TotalNumberOfCoreType; + UINTN MaxCacheInfoCount; + CPU_CACHE_INFO *LocalCacheInfo; + UINTN CacheInfoIndex; + UINTN LocalCacheInfoCount; + UINTN Index; + UINTN NextIndex; + + // + // Get number of Packages and Package ID. + // + NumberOfPackage = CpuCacheInfoGetNumberOfPackages (ProcessorInfo, NumberOfProcessors, Package); + + // + // Get number of core types for each package and count the total number. + // E.g. If Package1 and Package2 both have 2 core types, the total number is 4. + // + TotalNumberOfCoreType = 0; + for (PackageIndex = 0; PackageIndex < NumberOfPackage; PackageIndex++) { + TotalNumberOfCoreType += CpuCacheInfoGetNumberOfCoreTypePerPackage (ProcessorInfo, NumberOfProcessors, Package[PackageIndex]); + } + + MaxCacheInfoCount = TotalNumberOfCoreType * MAX_NUM_OF_CACHE_PARAMS_LEAF; + LocalCacheInfo = AllocatePages (EFI_SIZE_TO_PAGES (MaxCacheInfoCount * sizeof (*LocalCacheInfo))); + ASSERT (LocalCacheInfo != NULL); + if (LocalCacheInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + LocalCacheInfoCount = 0; + + for (Index = 0; Index < NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF; Index++) { + if (CacheData[Index].CacheSizeinKB == 0) { + continue; + } + + // + // For the sharing caches, clear their CacheSize. + // + for (NextIndex = Index + 1; NextIndex < NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF; NextIndex++) { + if (CacheData[NextIndex].CacheSizeinKB == 0) { + continue; + } + + if (CacheData[Index].CacheLevel == CacheData[NextIndex].CacheLevel && + CacheData[Index].CacheType == CacheData[NextIndex].CacheType && + ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package == ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package && + ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType == ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType && + (ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].ApicId & ~CacheData[Index].CacheShareBits) == + (ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].ApicId & ~CacheData[NextIndex].CacheShareBits)) { + CacheData[NextIndex].CacheSizeinKB = 0; // uses the sharing cache + } + } + + // + // For the cache that already exists in LocalCacheInfo, increase its CacheCount. + // + for (CacheInfoIndex = 0; CacheInfoIndex < LocalCacheInfoCount; CacheInfoIndex++) { + if (LocalCacheInfo[CacheInfoIndex].Package == ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package && + LocalCacheInfo[CacheInfoIndex].CoreType == ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType && + LocalCacheInfo[CacheInfoIndex].CacheLevel == CacheData[Index].CacheLevel && + LocalCacheInfo[CacheInfoIndex].CacheType == CacheData[Index].CacheType) { + LocalCacheInfo[CacheInfoIndex].CacheCount++; + break; + } + } + + // + // For the new cache with different Package, CoreType, CacheLevel or CacheType, copy its + // data into LocalCacheInfo buffer. + // + if (CacheInfoIndex == LocalCacheInfoCount) { + ASSERT (LocalCacheInfoCount < MaxCacheInfoCount); + + LocalCacheInfo[LocalCacheInfoCount].Package = ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package; + LocalCacheInfo[LocalCacheInfoCount].CoreType = ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType; + LocalCacheInfo[LocalCacheInfoCount].CacheLevel = CacheData[Index].CacheLevel; + LocalCacheInfo[LocalCacheInfoCount].CacheType = CacheData[Index].CacheType; + LocalCacheInfo[LocalCacheInfoCount].CacheWays = CacheData[Index].CacheWays; + LocalCacheInfo[LocalCacheInfoCount].CacheSizeinKB = CacheData[Index].CacheSizeinKB; + LocalCacheInfo[LocalCacheInfoCount].CacheCount = 1; + + LocalCacheInfoCount++; + } + } + + if (*CacheInfoCount < LocalCacheInfoCount) { + Status = EFI_BUFFER_TOO_SMALL; + } else { + CopyMem (CacheInfo, LocalCacheInfo, sizeof (*CacheInfo) * LocalCacheInfoCount); + DEBUG_CODE ( + CpuCacheInfoPrintCpuCacheInfoTable (CacheInfo, LocalCacheInfoCount); + ); + Status = EFI_SUCCESS; + } + + *CacheInfoCount = LocalCacheInfoCount; + + FreePages (LocalCacheInfo, EFI_SIZE_TO_PAGES (MaxCacheInfoCount * sizeof (*LocalCacheInfo))); + + return Status; +} + +/** + Get CpuCacheInfo data array. + + @param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array. + @param[in, out] CpuCacheInfoCount As input, point to the length of response CpuCacheInfo array. + As output, point to the actual length of response CpuCacheInfo array. + + @retval EFI_SUCCESS Function completed successfully. + @retval EFI_INVALID_PARAMETER CpuCacheInfoCount is NULL. + @retval EFI_INVALID_PARAMETER CpuCacheInfo is NULL while CpuCacheInfoCount contains the value + greater than zero. + @retval EFI_UNSUPPORTED Processor does not support CPUID_CACHE_PARAMS Leaf. + @retval EFI_NOT_FOUND EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL interface + is not found. + @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated. + @retval EFI_BUFFER_TOO_SMALL CpuCacheInfoCount is too small to hold the response CpuCacheInfo + array. CpuCacheInfoCount has been updated with the length needed + to complete the request. +**/ +EFI_STATUS +EFIAPI +GetCpuCacheInfo ( + IN OUT CPU_CACHE_INFO *CpuCacheInfo, + IN OUT UINTN *CpuCacheInfoCount + ) +{ + EFI_STATUS Status; + UINT32 CpuidMaxInput; + UINT32 NumberOfProcessors; + UINTN CacheDataCount; + UINTN ProcessorIndex; + EFI_PROCESSOR_INFORMATION ProcessorInfo; + COLLECT_CPUID_CACHE_DATA_CONTEXT Context; + + if (CpuCacheInfoCount == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*CpuCacheInfoCount != 0 && CpuCacheInfo == NULL) { + return EFI_INVALID_PARAMETER; + } + + AsmCpuid (CPUID_SIGNATURE, &CpuidMaxInput, NULL, NULL, NULL); + if (CpuidMaxInput < CPUID_CACHE_PARAMS) { + return EFI_UNSUPPORTED; + } + + // + // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.MpServices. + // + Status = CpuCacheInfoGetMpServices (&Context.MpServices); + if (EFI_ERROR(Status)) { + return Status; + } + + NumberOfProcessors = CpuCacheInfoGetNumberOfProcessors (Context.MpServices); + + // + // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.ProcessorInfo. + // + Context.ProcessorInfo = AllocatePages (EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo))); + ASSERT (Context.ProcessorInfo != NULL); + if (Context.ProcessorInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.CacheData. + // CacheData array consists of CPUID_CACHE_DATA data structure for each Cpuid Cache Parameter Leaf + // per logical processor. The array begin with data of each Cache Parameter Leaf of processor 0, followed + // by data of each Cache Parameter Leaf of processor 1 ... + // + CacheDataCount = NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF; + Context.CacheData = AllocatePages (EFI_SIZE_TO_PAGES (CacheDataCount * sizeof (*Context.CacheData))); + ASSERT (Context.CacheData != NULL); + if (Context.CacheData == NULL) { + FreePages (Context.ProcessorInfo, EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo))); + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (Context.CacheData, CacheDataCount * sizeof (*Context.CacheData)); + + // + // Collect Package ID and APIC ID of all processors. + // + for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) { + CpuCacheInfoGetProcessorInfo (Context.MpServices, ProcessorIndex, &ProcessorInfo); + Context.ProcessorInfo[ProcessorIndex].Package = ProcessorInfo.Location.Package; + Context.ProcessorInfo[ProcessorIndex].ApicId = (UINT32) ProcessorInfo.ProcessorId; + } + + // + // Wakeup all processors for CacheData(core type and cache data) collection. + // + CpuCacheInfoStartupAllCPUs (Context.MpServices, CpuCacheInfoCollectCoreAndCacheData, &Context); + + // + // Collect CpuCacheInfo data from CacheData. + // + Status = CpuCacheInfoCollectCpuCacheInfoData (Context.CacheData, Context.ProcessorInfo, NumberOfProcessors, CpuCacheInfo, CpuCacheInfoCount); + + FreePages (Context.CacheData, EFI_SIZE_TO_PAGES (CacheDataCount * sizeof (*Context.CacheData))); + FreePages (Context.ProcessorInfo, EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo))); + + return Status; +} diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.uni b/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.uni new file mode 100644 index 0000000000..1bc801f15f --- /dev/null +++ b/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.uni @@ -0,0 +1,15 @@ +// /** @file +// CPU Cache Info Library +// +// Provides cache info for each package, core type, cache level and cache type. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "CPU Cache Info Library" + +#string STR_MODULE_DESCRIPTION #language en-US "Provides cache info for each package, core type, cache level and cache type." diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.c b/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.c new file mode 100644 index 0000000000..bb788e3614 --- /dev/null +++ b/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.c @@ -0,0 +1,120 @@ +/** @file + Provides cache info for each package, core type, cache level and cache type. + + Copyright (c) 2020 Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +/** + Get EFI_MP_SERVICES_PROTOCOL pointer. + + @param[out] MpServices A pointer to the buffer where EFI_MP_SERVICES_PROTOCOL is stored + + @retval EFI_SUCCESS EFI_MP_SERVICES_PROTOCOL interface is returned + @retval EFI_NOT_FOUND EFI_MP_SERVICES_PROTOCOL interface is not found +**/ +EFI_STATUS +CpuCacheInfoGetMpServices ( + OUT MP_SERVICES *MpServices + ) +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices->Protocol); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Activate all of the logical processors. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure A pointer to the function to be run on enabled logical processors. + @param[in] ProcedureArgument The parameter passed into Procedure for all enabled logical processors. +**/ +VOID +CpuCacheInfoStartupAllCPUs ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument + ) +{ + EFI_STATUS Status; + + Status = MpServices.Protocol->StartupAllAPs (MpServices.Protocol, Procedure, FALSE, NULL, 0, ProcedureArgument, NULL); + ASSERT_EFI_ERROR (Status); + + Procedure (ProcedureArgument); +} + +/** + Get detailed information of the requested logical processor. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNum The requested logical processor number. + @param[out] ProcessorInfo A pointer to the buffer where the processor information is stored +**/ +VOID +CpuCacheInfoGetProcessorInfo ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNum, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfo + ) +{ + EFI_STATUS Status; + + Status = MpServices.Protocol->GetProcessorInfo (MpServices.Protocol, ProcessorNum, ProcessorInfo); + ASSERT_EFI_ERROR (Status); +} + +/** + Get the logical processor number. + + @param[in] MpServices MP_SERVICES structure. + + @retval Return the logical processor number. +**/ +UINT32 +CpuCacheInfoWhoAmI ( + IN MP_SERVICES MpServices + ) +{ + EFI_STATUS Status; + UINTN ProcessorNum; + + Status = MpServices.Protocol->WhoAmI (MpServices.Protocol, &ProcessorNum); + ASSERT_EFI_ERROR (Status); + + return (UINT32)ProcessorNum; +} + +/** + Get the total number of logical processors in the platform. + + @param[in] MpServices MP_SERVICES structure. + + @retval Return the total number of logical processors. +**/ +UINT32 +CpuCacheInfoGetNumberOfProcessors ( + IN MP_SERVICES MpServices + ) +{ + EFI_STATUS Status; + UINTN NumberOfProcessor; + UINTN NumberOfEnabledProcessor; + + Status = MpServices.Protocol->GetNumberOfProcessors (MpServices.Protocol, &NumberOfProcessor, &NumberOfEnabledProcessor); + ASSERT_EFI_ERROR (Status); + + return (UINT32)NumberOfProcessor; +} diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf b/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf new file mode 100644 index 0000000000..1fd45380b8 --- /dev/null +++ b/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf @@ -0,0 +1,43 @@ +## @file +# CPU Cache Info Library instance for DXE driver. +# +# Provides cache info for each package, core type, cache level and cache type. +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeCpuCacheInfoLib + FILE_GUID = B25C288F-C309-41F1-8325-37E64DC5EA3D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = CpuCacheInfoLib|DXE_DRIVER UEFI_APPLICATION + MODULE_UNI_FILE = CpuCacheInfoLib.uni + +[Sources] + InternalCpuCacheInfoLib.h + CpuCacheInfoLib.c + DxeCpuCacheInfoLib.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + +[Protocols] + gEfiMpServiceProtocolGuid + +[Pcd] + +[Depex] + TRUE diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h b/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h new file mode 100644 index 0000000000..de56db9c0c --- /dev/null +++ b/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h @@ -0,0 +1,159 @@ +/** @file + Internal header file for CPU Cache info Library. + + Copyright (c) 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _INTERNAL_CPU_CACHE_INFO_LIB_H_ +#define _INTERNAL_CPU_CACHE_INFO_LIB_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + // + // Package ID, the information comes from + // EFI_CPU_PHYSICAL_LOCATION.Package + // + UINT32 Package; + // + // APIC ID, the information comes from + // EFI_PROCESSOR_INFORMATION.ProcessorId + // + UINT32 ApicId; + // + // Core type of logical processor. + // Value = CPUID.1Ah:EAX[31:24] + // + UINT8 CoreType; +} CPUID_PROCESSOR_INFO; + +typedef struct { + // + // Level of the cache. + // Value = CPUID.04h:EAX[07:05] + // + UINT8 CacheLevel : 3; + // + // Type of the cache. + // Value = CPUID.04h:EAX[04:00] + // + UINT8 CacheType : 5; + // + // Ways of associativity. + // Value = CPUID.04h:EBX[31:22] + // + UINT16 CacheWays; + // + // Cache share bits. + // Value = CPUID.04h:EAX[25:14] + // + UINT16 CacheShareBits; + // + // Size of single cache. + // Value = (CPUID.04h:EBX[31:22] + 1) * (CPUID.04h:EBX[21:12] + 1) * + // (CPUID.04h:EBX[11:00] + 1) * (CPUID.04h:ECX[31:00] + 1) + // + UINT32 CacheSizeinKB; +} CPUID_CACHE_DATA; + +typedef union { + EDKII_PEI_MP_SERVICES2_PPI *Ppi; + EFI_MP_SERVICES_PROTOCOL *Protocol; +} MP_SERVICES; + +typedef struct { + MP_SERVICES MpServices; + CPUID_PROCESSOR_INFO *ProcessorInfo; + CPUID_CACHE_DATA *CacheData; +} COLLECT_CPUID_CACHE_DATA_CONTEXT; + + +/* + Defines the maximum count of Deterministic Cache Parameters Leaf of all APs and BSP. + To save boot time, skip starting up all APs to calculate each AP's count of Deterministic + Cache Parameters Leaf, so use a definition instead. + Anyway, definition value will be checked in CpuCacheInfoCollectCoreAndCacheData function. +*/ +#define MAX_NUM_OF_CACHE_PARAMS_LEAF 6 + +/* + Defines the maximum count of packages. +*/ +#define MAX_NUM_OF_PACKAGE 100 + +/** + Get EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL pointer. + + @param[out] MpServices A pointer to the buffer where EDKII_PEI_MP_SERVICES2_PPI or + EFI_MP_SERVICES_PROTOCOL is stored + + @retval EFI_SUCCESS EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL interface is returned + @retval EFI_NOT_FOUND EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL interface is not found +**/ +EFI_STATUS +CpuCacheInfoGetMpServices ( + OUT MP_SERVICES *MpServices + ); + +/** + Activate all of the logical processors. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure A pointer to the function to be run on enabled logical processors. + @param[in] ProcedureArgument The parameter passed into Procedure for all enabled logical processors. +**/ +VOID +CpuCacheInfoStartupAllCPUs ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument + ); + +/** + Get detailed information of the requested logical processor. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNum The requested logical processor number. + @param[out] ProcessorInfo A pointer to the buffer where the processor information is stored +**/ +VOID +CpuCacheInfoGetProcessorInfo ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNum, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfo + ); + +/** + Get the logical processor number. + + @param[in] MpServices MP_SERVICES structure. + + @retval Return the logical processor number. +**/ +UINT32 +CpuCacheInfoWhoAmI ( + IN MP_SERVICES MpServices + ); + +/** + Get the total number of logical processors in the platform. + + @param[in] MpServices MP_SERVICES structure. + + @retval Return the total number of logical processors. +**/ +UINT32 +CpuCacheInfoGetNumberOfProcessors ( + IN MP_SERVICES MpServices + ); +#endif diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.c b/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.c new file mode 100644 index 0000000000..06c160421b --- /dev/null +++ b/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.c @@ -0,0 +1,119 @@ +/** @file + Provides cache info for each package, core type, cache level and cache type. + + Copyright (c) 2020 Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include + +/** + Get EDKII_PEI_MP_SERVICES2_PPI pointer. + + @param[out] MpServices A pointer to the buffer where EDKII_PEI_MP_SERVICES2_PPI is stored + + @retval EFI_SUCCESS EDKII_PEI_MP_SERVICES2_PPI interface is returned + @retval EFI_NOT_FOUND EDKII_PEI_MP_SERVICES2_PPI interface is not found +**/ +EFI_STATUS +CpuCacheInfoGetMpServices ( + OUT MP_SERVICES *MpServices + ) +{ + EFI_STATUS Status; + + Status = PeiServicesLocatePpi (&gEdkiiPeiMpServices2PpiGuid, 0, NULL, (VOID **)&MpServices->Ppi); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Activate all of the logical processors. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure A pointer to the function to be run on enabled logical processors. + @param[in] ProcedureArgument The parameter passed into Procedure for all enabled logical processors. +**/ +VOID +CpuCacheInfoStartupAllCPUs ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument + ) +{ + EFI_STATUS Status; + + Status = MpServices.Ppi->StartupAllCPUs (MpServices.Ppi, Procedure, 0, ProcedureArgument); + ASSERT_EFI_ERROR (Status); +} + +/** + Get detailed information of the requested logical processor. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNum The requested logical processor number. + @param[out] ProcessorInfo A pointer to the buffer where the processor information is stored +**/ +VOID +CpuCacheInfoGetProcessorInfo ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNum, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfo + ) +{ + EFI_STATUS Status; + + Status = MpServices.Ppi->GetProcessorInfo (MpServices.Ppi, ProcessorNum, ProcessorInfo); + ASSERT_EFI_ERROR (Status); +} + +/** + Get the logical processor number. + + @param[in] MpServices MP_SERVICES structure. + + @retval Return the logical processor number. +**/ +UINT32 +CpuCacheInfoWhoAmI ( + IN MP_SERVICES MpServices + ) +{ + EFI_STATUS Status; + UINTN ProcessorNum; + + Status = MpServices.Ppi->WhoAmI (MpServices.Ppi, &ProcessorNum); + ASSERT_EFI_ERROR (Status); + + return (UINT32)ProcessorNum; +} + +/** + Get the total number of logical processors in the platform. + + @param[in] MpServices MP_SERVICES structure. + + @retval Return the total number of logical processors. +**/ +UINT32 +CpuCacheInfoGetNumberOfProcessors ( + IN MP_SERVICES MpServices + ) +{ + EFI_STATUS Status; + UINTN NumberOfProcessor; + UINTN NumberOfEnabledProcessor; + + Status = MpServices.Ppi->GetNumberOfProcessors (MpServices.Ppi, &NumberOfProcessor, &NumberOfEnabledProcessor); + ASSERT_EFI_ERROR (Status); + + return (UINT32)NumberOfProcessor; +} diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf b/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf new file mode 100644 index 0000000000..c8aa33c95a --- /dev/null +++ b/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf @@ -0,0 +1,43 @@ +## @file +# CPU Cache Info Library instance for PEI module. +# +# Provides cache info for each package, core type, cache level and cache type. +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiCpuCacheInfoLib + FILE_GUID = CFEE2DBE-53B2-4916-84CA-0BA83C3DDA6E + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = CpuCacheInfoLib|PEIM + MODULE_UNI_FILE = CpuCacheInfoLib.uni + +[Sources] + InternalCpuCacheInfoLib.h + CpuCacheInfoLib.c + PeiCpuCacheInfoLib.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + MemoryAllocationLib + PeiServicesTablePointerLib + +[Ppis] + gEdkiiPeiMpServices2PpiGuid + +[Pcd] + +[Depex] + TRUE diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index d83c084467..a639ce5412 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -56,6 +56,9 @@ ## @libraryclass Provides function to support VMGEXIT processing. VmgExitLib|Include/Library/VmgExitLib.h + ## @libraryclass Provides function to get CPU cache information. + CpuCacheInfoLib|Include/Library/CpuCacheInfoLib.h + [Guids] gUefiCpuPkgTokenSpaceGuid = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }} gMsegSmramGuid = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }} diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index b2b6d78a71..5834eafaa2 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -75,6 +75,7 @@ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf MpInitLib|UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf RegisterCpuFeaturesLib|UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.inf + CpuCacheInfoLib|UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf [LibraryClasses.IA32.PEIM, LibraryClasses.X64.PEIM] PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf @@ -86,6 +87,7 @@ CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf RegisterCpuFeaturesLib|UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.inf + CpuCacheInfoLib|UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf [LibraryClasses.common.DXE_SMM_DRIVER] SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf @@ -109,6 +111,8 @@ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf + UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf + UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf [Components.IA32, Components.X64] UefiCpuPkg/CpuDxe/CpuDxe.inf