123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- /** @file
- Provides cache info for each package, core type, cache level and cache type.
- Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
- 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 (FA|DM) CacheSizeinKB CacheCount |\n"));
- DEBUG ((DEBUG_INFO, "+-------+--------------------------------------------------------------------------------------+\n"));
- for (Index = 0; Index < CpuCacheInfoCount; Index++) {
- DEBUG ((
- DEBUG_INFO,
- "| %4x | %4x %2x %2x %2x %4x ( %x| %x) %8x %4x |\n",
- Index,
- CpuCacheInfo[Index].Package,
- CpuCacheInfo[Index].CoreType,
- CpuCacheInfo[Index].CacheLevel,
- CpuCacheInfo[Index].CacheType,
- CpuCacheInfo[Index].CacheWays,
- CpuCacheInfo[Index].FullyAssociativeCache,
- CpuCacheInfo[Index].DirectMappedCache,
- CpuCacheInfo[Index].CacheSizeinKB,
- CpuCacheInfo[Index].CacheCount
- ));
- }
- DEBUG ((DEBUG_INFO, "+-------+--------------------------------------------------------------------------------------+\n"));
- }
- /**
- Function to compare CPU package ID, core type, cache level and cache type for use in QuickSort.
- @param[in] Buffer1 pointer to CPU_CACHE_INFO poiner to compare
- @param[in] Buffer2 pointer to second CPU_CACHE_INFO pointer to compare
- @retval 0 Buffer1 equal to Buffer2
- @retval 1 Buffer1 is greater than Buffer2
- @retval -1 Buffer1 is less than Buffer2
- **/
- INTN
- EFIAPI
- CpuCacheInfoCompare (
- IN CONST VOID *Buffer1,
- IN CONST VOID *Buffer2
- )
- {
- CPU_CACHE_INFO_COMPARATOR Comparator1, Comparator2;
- ZeroMem (&Comparator1, sizeof (Comparator1));
- ZeroMem (&Comparator2, sizeof (Comparator2));
- Comparator1.Bits.Package = ((CPU_CACHE_INFO *)Buffer1)->Package;
- Comparator1.Bits.CoreType = ((CPU_CACHE_INFO *)Buffer1)->CoreType;
- Comparator1.Bits.CacheLevel = ((CPU_CACHE_INFO *)Buffer1)->CacheLevel;
- Comparator1.Bits.CacheType = ((CPU_CACHE_INFO *)Buffer1)->CacheType;
- Comparator2.Bits.Package = ((CPU_CACHE_INFO *)Buffer2)->Package;
- Comparator2.Bits.CoreType = ((CPU_CACHE_INFO *)Buffer2)->CoreType;
- Comparator2.Bits.CacheLevel = ((CPU_CACHE_INFO *)Buffer2)->CacheLevel;
- Comparator2.Bits.CacheType = ((CPU_CACHE_INFO *)Buffer2)->CacheType;
- if (Comparator1.Uint64 == Comparator2.Uint64) {
- return 0;
- } else if (Comparator1.Uint64 > Comparator2.Uint64) {
- return 1;
- } else {
- return -1;
- }
- }
- /**
- 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_CACHE_PARAMS_EDX CacheParamEdx;
- 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_MAIN_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, &CacheParamEdx.Uint32);
- 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].FullyAssociativeCache = (UINT8)CacheParamEax.Bits.FullyAssociativeCache;
- CacheData[CacheParamLeafIndex].DirectMappedCache = (UINT8)(CacheParamEdx.Bits.ComplexCacheIndexing == 0);
- 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;
- CPU_CACHE_INFO SortBuffer;
- //
- // 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].FullyAssociativeCache = CacheData[Index].FullyAssociativeCache;
- LocalCacheInfo[LocalCacheInfoCount].DirectMappedCache = CacheData[Index].DirectMappedCache;
- LocalCacheInfo[LocalCacheInfoCount].CacheSizeinKB = CacheData[Index].CacheSizeinKB;
- LocalCacheInfo[LocalCacheInfoCount].CacheCount = 1;
- LocalCacheInfoCount++;
- }
- }
- if (*CacheInfoCount < LocalCacheInfoCount) {
- Status = EFI_BUFFER_TOO_SMALL;
- } else {
- //
- // Sort LocalCacheInfo array by CPU package ID, core type, cache level and cache type.
- //
- QuickSort (LocalCacheInfo, LocalCacheInfoCount, sizeof (*LocalCacheInfo), CpuCacheInfoCompare, (VOID *)&SortBuffer);
- 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. The array is sorted by CPU package ID, core type, cache level and cache type.
- @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_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.
- //
- CpuCacheInfoGetMpServices (&Context.MpServices);
- 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;
- }
|