summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c
new file mode 100644
index 00000000..8eee5b77
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/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 - 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"));
+}
+
+/**
+ 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;
+ 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].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 {
+ 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_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;
+}