2 Provides cache info for each package, core type, cache level and cache type.
4 Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "InternalCpuCacheInfoLib.h"
12 Print CpuCacheInfo array.
14 @param[in] CpuCacheInfo Pointer to the CpuCacheInfo array.
15 @param[in] CpuCacheInfoCount The length of CpuCacheInfo array.
19 CpuCacheInfoPrintCpuCacheInfoTable (
20 IN CPU_CACHE_INFO
*CpuCacheInfo
,
21 IN UINTN CpuCacheInfoCount
26 DEBUG ((DEBUG_INFO
, "+-------+--------------------------------------------------------------------------------------+\n"));
27 DEBUG ((DEBUG_INFO
, "| Index | Packge CoreType CacheLevel CacheType CacheWays (FA|DM) CacheSizeinKB CacheCount |\n"));
28 DEBUG ((DEBUG_INFO
, "+-------+--------------------------------------------------------------------------------------+\n"));
30 for (Index
= 0; Index
< CpuCacheInfoCount
; Index
++) {
33 "| %4x | %4x %2x %2x %2x %4x ( %x| %x) %8x %4x |\n",
35 CpuCacheInfo
[Index
].Package
,
36 CpuCacheInfo
[Index
].CoreType
,
37 CpuCacheInfo
[Index
].CacheLevel
,
38 CpuCacheInfo
[Index
].CacheType
,
39 CpuCacheInfo
[Index
].CacheWays
,
40 CpuCacheInfo
[Index
].FullyAssociativeCache
,
41 CpuCacheInfo
[Index
].DirectMappedCache
,
42 CpuCacheInfo
[Index
].CacheSizeinKB
,
43 CpuCacheInfo
[Index
].CacheCount
47 DEBUG ((DEBUG_INFO
, "+-------+--------------------------------------------------------------------------------------+\n"));
51 Function to compare CPU package ID, core type, cache level and cache type for use in QuickSort.
53 @param[in] Buffer1 pointer to CPU_CACHE_INFO poiner to compare
54 @param[in] Buffer2 pointer to second CPU_CACHE_INFO pointer to compare
56 @retval 0 Buffer1 equal to Buffer2
57 @retval 1 Buffer1 is greater than Buffer2
58 @retval -1 Buffer1 is less than Buffer2
63 IN CONST VOID
*Buffer1
,
64 IN CONST VOID
*Buffer2
67 CPU_CACHE_INFO_COMPARATOR Comparator1
, Comparator2
;
69 ZeroMem (&Comparator1
, sizeof (Comparator1
));
70 ZeroMem (&Comparator2
, sizeof (Comparator2
));
72 Comparator1
.Bits
.Package
= ((CPU_CACHE_INFO
*)Buffer1
)->Package
;
73 Comparator1
.Bits
.CoreType
= ((CPU_CACHE_INFO
*)Buffer1
)->CoreType
;
74 Comparator1
.Bits
.CacheLevel
= ((CPU_CACHE_INFO
*)Buffer1
)->CacheLevel
;
75 Comparator1
.Bits
.CacheType
= ((CPU_CACHE_INFO
*)Buffer1
)->CacheType
;
77 Comparator2
.Bits
.Package
= ((CPU_CACHE_INFO
*)Buffer2
)->Package
;
78 Comparator2
.Bits
.CoreType
= ((CPU_CACHE_INFO
*)Buffer2
)->CoreType
;
79 Comparator2
.Bits
.CacheLevel
= ((CPU_CACHE_INFO
*)Buffer2
)->CacheLevel
;
80 Comparator2
.Bits
.CacheType
= ((CPU_CACHE_INFO
*)Buffer2
)->CacheType
;
82 if (Comparator1
.Uint64
== Comparator2
.Uint64
) {
84 } else if (Comparator1
.Uint64
> Comparator2
.Uint64
) {
92 Get the total number of package and package ID in the platform.
94 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
95 @param[in] NumberOfProcessors Total number of logical processors in the platform.
96 @param[in, out] Package Pointer to the Package array.
98 @retval Return the total number of package and package ID in the platform.
101 CpuCacheInfoGetNumberOfPackages (
102 IN CPUID_PROCESSOR_INFO
*ProcessorInfo
,
103 IN UINTN NumberOfProcessors
,
104 IN OUT UINT32
*Package
107 UINTN ProcessorIndex
;
110 UINT32 CurrentPackage
;
114 for (ProcessorIndex
= 0; ProcessorIndex
< NumberOfProcessors
; ProcessorIndex
++) {
115 CurrentPackage
= ProcessorInfo
[ProcessorIndex
].Package
;
118 // For the package that already exists in Package array, break out the loop.
120 for (PackageIndex
= 0; PackageIndex
< PackageCount
; PackageIndex
++) {
121 if (CurrentPackage
== Package
[PackageIndex
]) {
127 // For the new package, save it in Package array.
129 if (PackageIndex
== PackageCount
) {
130 ASSERT (PackageCount
< MAX_NUM_OF_PACKAGE
);
131 Package
[PackageCount
++] = CurrentPackage
;
139 Get the number of CoreType of requested package.
141 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
142 @param[in] NumberOfProcessors Total number of logical processors in the platform.
143 @param[in] Package The requested package number.
145 @retval Return the number of CoreType of requested package.
148 CpuCacheInfoGetNumberOfCoreTypePerPackage (
149 IN CPUID_PROCESSOR_INFO
*ProcessorInfo
,
150 IN UINTN NumberOfProcessors
,
154 UINTN ProcessorIndex
;
156 // Core Type value comes from CPUID.1Ah.EAX[31:24].
157 // So max number of core types should be MAX_UINT8.
159 UINT8 CoreType
[MAX_UINT8
];
162 UINT8 CurrentCoreType
;
165 // CoreType array is empty.
169 for (ProcessorIndex
= 0; ProcessorIndex
< NumberOfProcessors
; ProcessorIndex
++) {
170 CurrentCoreType
= ProcessorInfo
[ProcessorIndex
].CoreType
;
172 if (ProcessorInfo
[ProcessorIndex
].Package
!= Package
) {
177 // For the type that already exists in CoreType array, break out the loop.
179 for (CoreTypeIndex
= 0; CoreTypeIndex
< CoreTypeCount
; CoreTypeIndex
++) {
180 if (CurrentCoreType
== CoreType
[CoreTypeIndex
]) {
186 // For the new type, save it in CoreType array.
188 if (CoreTypeIndex
== CoreTypeCount
) {
189 ASSERT (CoreTypeCount
< MAX_UINT8
);
190 CoreType
[CoreTypeCount
++] = CurrentCoreType
;
194 return CoreTypeCount
;
198 Collect core and cache information of calling processor via CPUID instructions.
200 @param[in, out] Buffer The pointer to private data buffer.
204 CpuCacheInfoCollectCoreAndCacheData (
208 UINTN ProcessorIndex
;
209 UINT32 CpuidMaxInput
;
210 UINT8 CacheParamLeafIndex
;
211 CPUID_CACHE_PARAMS_EAX CacheParamEax
;
212 CPUID_CACHE_PARAMS_EBX CacheParamEbx
;
213 UINT32 CacheParamEcx
;
214 CPUID_CACHE_PARAMS_EDX CacheParamEdx
;
215 CPUID_NATIVE_MODEL_ID_AND_CORE_TYPE_EAX NativeModelIdAndCoreTypeEax
;
216 COLLECT_CPUID_CACHE_DATA_CONTEXT
*Context
;
217 CPUID_CACHE_DATA
*CacheData
;
219 Context
= (COLLECT_CPUID_CACHE_DATA_CONTEXT
*)Buffer
;
220 ProcessorIndex
= CpuCacheInfoWhoAmI (Context
->MpServices
);
221 CacheData
= &Context
->CacheData
[MAX_NUM_OF_CACHE_PARAMS_LEAF
* ProcessorIndex
];
223 AsmCpuid (CPUID_SIGNATURE
, &CpuidMaxInput
, NULL
, NULL
, NULL
);
226 // get CoreType if CPUID_HYBRID_INFORMATION leaf is supported.
228 Context
->ProcessorInfo
[ProcessorIndex
].CoreType
= 0;
229 if (CpuidMaxInput
>= CPUID_HYBRID_INFORMATION
) {
230 AsmCpuidEx (CPUID_HYBRID_INFORMATION
, CPUID_HYBRID_INFORMATION_MAIN_LEAF
, &NativeModelIdAndCoreTypeEax
.Uint32
, NULL
, NULL
, NULL
);
231 Context
->ProcessorInfo
[ProcessorIndex
].CoreType
= (UINT8
)NativeModelIdAndCoreTypeEax
.Bits
.CoreType
;
235 // cache hierarchy starts with an index value of 0.
237 CacheParamLeafIndex
= 0;
239 while (CacheParamLeafIndex
< MAX_NUM_OF_CACHE_PARAMS_LEAF
) {
240 AsmCpuidEx (CPUID_CACHE_PARAMS
, CacheParamLeafIndex
, &CacheParamEax
.Uint32
, &CacheParamEbx
.Uint32
, &CacheParamEcx
, &CacheParamEdx
.Uint32
);
242 if (CacheParamEax
.Bits
.CacheType
== 0) {
246 CacheData
[CacheParamLeafIndex
].CacheLevel
= (UINT8
)CacheParamEax
.Bits
.CacheLevel
;
247 CacheData
[CacheParamLeafIndex
].CacheType
= (UINT8
)CacheParamEax
.Bits
.CacheType
;
248 CacheData
[CacheParamLeafIndex
].CacheWays
= (UINT16
)CacheParamEbx
.Bits
.Ways
;
249 CacheData
[CacheParamLeafIndex
].FullyAssociativeCache
= (UINT8
)CacheParamEax
.Bits
.FullyAssociativeCache
;
250 CacheData
[CacheParamLeafIndex
].DirectMappedCache
= (UINT8
)(CacheParamEdx
.Bits
.ComplexCacheIndexing
== 0);
251 CacheData
[CacheParamLeafIndex
].CacheShareBits
= (UINT16
)CacheParamEax
.Bits
.MaximumAddressableIdsForLogicalProcessors
;
252 CacheData
[CacheParamLeafIndex
].CacheSizeinKB
= (CacheParamEbx
.Bits
.Ways
+ 1) *
253 (CacheParamEbx
.Bits
.LinePartitions
+ 1) * (CacheParamEbx
.Bits
.LineSize
+ 1) * (CacheParamEcx
+ 1) / SIZE_1KB
;
255 CacheParamLeafIndex
++;
260 Collect CacheInfo data from the CacheData.
262 @param[in] CacheData Pointer to the CacheData array.
263 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
264 @param[in] NumberOfProcessors Total number of logical processors in the platform.
265 @param[in, out] CacheInfo Pointer to the CacheInfo array.
266 @param[in, out] CacheInfoCount As input, point to the length of response CacheInfo array.
267 As output, point to the actual length of response CacheInfo array.
269 @retval EFI_SUCCESS Function completed successfully.
270 @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated.
271 @retval EFI_BUFFER_TOO_SMALL CacheInfoCount is too small to hold the response CacheInfo
272 array. CacheInfoCount has been updated with the length needed
273 to complete the request.
276 CpuCacheInfoCollectCpuCacheInfoData (
277 IN CPUID_CACHE_DATA
*CacheData
,
278 IN CPUID_PROCESSOR_INFO
*ProcessorInfo
,
279 IN UINTN NumberOfProcessors
,
280 IN OUT CPU_CACHE_INFO
*CacheInfo
,
281 IN OUT UINTN
*CacheInfoCount
285 UINT32 NumberOfPackage
;
286 UINT32 Package
[MAX_NUM_OF_PACKAGE
];
288 UINTN TotalNumberOfCoreType
;
289 UINTN MaxCacheInfoCount
;
290 CPU_CACHE_INFO
*LocalCacheInfo
;
291 UINTN CacheInfoIndex
;
292 UINTN LocalCacheInfoCount
;
295 CPU_CACHE_INFO SortBuffer
;
298 // Get number of Packages and Package ID.
300 NumberOfPackage
= CpuCacheInfoGetNumberOfPackages (ProcessorInfo
, NumberOfProcessors
, Package
);
303 // Get number of core types for each package and count the total number.
304 // E.g. If Package1 and Package2 both have 2 core types, the total number is 4.
306 TotalNumberOfCoreType
= 0;
307 for (PackageIndex
= 0; PackageIndex
< NumberOfPackage
; PackageIndex
++) {
308 TotalNumberOfCoreType
+= CpuCacheInfoGetNumberOfCoreTypePerPackage (ProcessorInfo
, NumberOfProcessors
, Package
[PackageIndex
]);
311 MaxCacheInfoCount
= TotalNumberOfCoreType
* MAX_NUM_OF_CACHE_PARAMS_LEAF
;
312 LocalCacheInfo
= AllocatePages (EFI_SIZE_TO_PAGES (MaxCacheInfoCount
* sizeof (*LocalCacheInfo
)));
313 ASSERT (LocalCacheInfo
!= NULL
);
314 if (LocalCacheInfo
== NULL
) {
315 return EFI_OUT_OF_RESOURCES
;
318 LocalCacheInfoCount
= 0;
320 for (Index
= 0; Index
< NumberOfProcessors
* MAX_NUM_OF_CACHE_PARAMS_LEAF
; Index
++) {
321 if (CacheData
[Index
].CacheSizeinKB
== 0) {
326 // For the sharing caches, clear their CacheSize.
328 for (NextIndex
= Index
+ 1; NextIndex
< NumberOfProcessors
* MAX_NUM_OF_CACHE_PARAMS_LEAF
; NextIndex
++) {
329 if (CacheData
[NextIndex
].CacheSizeinKB
== 0) {
333 if ((CacheData
[Index
].CacheLevel
== CacheData
[NextIndex
].CacheLevel
) &&
334 (CacheData
[Index
].CacheType
== CacheData
[NextIndex
].CacheType
) &&
335 (ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].Package
== ProcessorInfo
[NextIndex
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].Package
) &&
336 (ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].CoreType
== ProcessorInfo
[NextIndex
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].CoreType
) &&
337 ((ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].ApicId
& ~CacheData
[Index
].CacheShareBits
) ==
338 (ProcessorInfo
[NextIndex
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].ApicId
& ~CacheData
[NextIndex
].CacheShareBits
)))
340 CacheData
[NextIndex
].CacheSizeinKB
= 0; // uses the sharing cache
345 // For the cache that already exists in LocalCacheInfo, increase its CacheCount.
347 for (CacheInfoIndex
= 0; CacheInfoIndex
< LocalCacheInfoCount
; CacheInfoIndex
++) {
348 if ((LocalCacheInfo
[CacheInfoIndex
].Package
== ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].Package
) &&
349 (LocalCacheInfo
[CacheInfoIndex
].CoreType
== ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].CoreType
) &&
350 (LocalCacheInfo
[CacheInfoIndex
].CacheLevel
== CacheData
[Index
].CacheLevel
) &&
351 (LocalCacheInfo
[CacheInfoIndex
].CacheType
== CacheData
[Index
].CacheType
))
353 LocalCacheInfo
[CacheInfoIndex
].CacheCount
++;
359 // For the new cache with different Package, CoreType, CacheLevel or CacheType, copy its
360 // data into LocalCacheInfo buffer.
362 if (CacheInfoIndex
== LocalCacheInfoCount
) {
363 ASSERT (LocalCacheInfoCount
< MaxCacheInfoCount
);
365 LocalCacheInfo
[LocalCacheInfoCount
].Package
= ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].Package
;
366 LocalCacheInfo
[LocalCacheInfoCount
].CoreType
= ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].CoreType
;
367 LocalCacheInfo
[LocalCacheInfoCount
].CacheLevel
= CacheData
[Index
].CacheLevel
;
368 LocalCacheInfo
[LocalCacheInfoCount
].CacheType
= CacheData
[Index
].CacheType
;
369 LocalCacheInfo
[LocalCacheInfoCount
].CacheWays
= CacheData
[Index
].CacheWays
;
370 LocalCacheInfo
[LocalCacheInfoCount
].FullyAssociativeCache
= CacheData
[Index
].FullyAssociativeCache
;
371 LocalCacheInfo
[LocalCacheInfoCount
].DirectMappedCache
= CacheData
[Index
].DirectMappedCache
;
372 LocalCacheInfo
[LocalCacheInfoCount
].CacheSizeinKB
= CacheData
[Index
].CacheSizeinKB
;
373 LocalCacheInfo
[LocalCacheInfoCount
].CacheCount
= 1;
375 LocalCacheInfoCount
++;
379 if (*CacheInfoCount
< LocalCacheInfoCount
) {
380 Status
= EFI_BUFFER_TOO_SMALL
;
383 // Sort LocalCacheInfo array by CPU package ID, core type, cache level and cache type.
385 QuickSort (LocalCacheInfo
, LocalCacheInfoCount
, sizeof (*LocalCacheInfo
), CpuCacheInfoCompare
, (VOID
*)&SortBuffer
);
386 CopyMem (CacheInfo
, LocalCacheInfo
, sizeof (*CacheInfo
) * LocalCacheInfoCount
);
388 CpuCacheInfoPrintCpuCacheInfoTable (CacheInfo
, LocalCacheInfoCount
);
390 Status
= EFI_SUCCESS
;
393 *CacheInfoCount
= LocalCacheInfoCount
;
395 FreePages (LocalCacheInfo
, EFI_SIZE_TO_PAGES (MaxCacheInfoCount
* sizeof (*LocalCacheInfo
)));
401 Get CpuCacheInfo data array. The array is sorted by CPU package ID, core type, cache level and cache type.
403 @param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array.
404 @param[in, out] CpuCacheInfoCount As input, point to the length of response CpuCacheInfo array.
405 As output, point to the actual length of response CpuCacheInfo array.
407 @retval EFI_SUCCESS Function completed successfully.
408 @retval EFI_INVALID_PARAMETER CpuCacheInfoCount is NULL.
409 @retval EFI_INVALID_PARAMETER CpuCacheInfo is NULL while CpuCacheInfoCount contains the value
411 @retval EFI_UNSUPPORTED Processor does not support CPUID_CACHE_PARAMS Leaf.
412 @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated.
413 @retval EFI_BUFFER_TOO_SMALL CpuCacheInfoCount is too small to hold the response CpuCacheInfo
414 array. CpuCacheInfoCount has been updated with the length needed
415 to complete the request.
420 IN OUT CPU_CACHE_INFO
*CpuCacheInfo
,
421 IN OUT UINTN
*CpuCacheInfoCount
425 UINT32 CpuidMaxInput
;
426 UINT32 NumberOfProcessors
;
427 UINTN CacheDataCount
;
428 UINTN ProcessorIndex
;
429 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
430 COLLECT_CPUID_CACHE_DATA_CONTEXT Context
;
432 if (CpuCacheInfoCount
== NULL
) {
433 return EFI_INVALID_PARAMETER
;
436 if ((*CpuCacheInfoCount
!= 0) && (CpuCacheInfo
== NULL
)) {
437 return EFI_INVALID_PARAMETER
;
440 AsmCpuid (CPUID_SIGNATURE
, &CpuidMaxInput
, NULL
, NULL
, NULL
);
441 if (CpuidMaxInput
< CPUID_CACHE_PARAMS
) {
442 return EFI_UNSUPPORTED
;
446 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.MpServices.
448 CpuCacheInfoGetMpServices (&Context
.MpServices
);
450 NumberOfProcessors
= CpuCacheInfoGetNumberOfProcessors (Context
.MpServices
);
453 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.ProcessorInfo.
455 Context
.ProcessorInfo
= AllocatePages (EFI_SIZE_TO_PAGES (NumberOfProcessors
* sizeof (*Context
.ProcessorInfo
)));
456 ASSERT (Context
.ProcessorInfo
!= NULL
);
457 if (Context
.ProcessorInfo
== NULL
) {
458 return EFI_OUT_OF_RESOURCES
;
462 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.CacheData.
463 // CacheData array consists of CPUID_CACHE_DATA data structure for each Cpuid Cache Parameter Leaf
464 // per logical processor. The array begin with data of each Cache Parameter Leaf of processor 0, followed
465 // by data of each Cache Parameter Leaf of processor 1 ...
467 CacheDataCount
= NumberOfProcessors
* MAX_NUM_OF_CACHE_PARAMS_LEAF
;
468 Context
.CacheData
= AllocatePages (EFI_SIZE_TO_PAGES (CacheDataCount
* sizeof (*Context
.CacheData
)));
469 ASSERT (Context
.CacheData
!= NULL
);
470 if (Context
.CacheData
== NULL
) {
471 FreePages (Context
.ProcessorInfo
, EFI_SIZE_TO_PAGES (NumberOfProcessors
* sizeof (*Context
.ProcessorInfo
)));
472 return EFI_OUT_OF_RESOURCES
;
475 ZeroMem (Context
.CacheData
, CacheDataCount
* sizeof (*Context
.CacheData
));
478 // Collect Package ID and APIC ID of all processors.
480 for (ProcessorIndex
= 0; ProcessorIndex
< NumberOfProcessors
; ProcessorIndex
++) {
481 CpuCacheInfoGetProcessorInfo (Context
.MpServices
, ProcessorIndex
, &ProcessorInfo
);
482 Context
.ProcessorInfo
[ProcessorIndex
].Package
= ProcessorInfo
.Location
.Package
;
483 Context
.ProcessorInfo
[ProcessorIndex
].ApicId
= (UINT32
)ProcessorInfo
.ProcessorId
;
487 // Wakeup all processors for CacheData(core type and cache data) collection.
489 CpuCacheInfoStartupAllCPUs (Context
.MpServices
, CpuCacheInfoCollectCoreAndCacheData
, &Context
);
492 // Collect CpuCacheInfo data from CacheData.
494 Status
= CpuCacheInfoCollectCpuCacheInfoData (Context
.CacheData
, Context
.ProcessorInfo
, NumberOfProcessors
, CpuCacheInfo
, CpuCacheInfoCount
);
496 FreePages (Context
.CacheData
, EFI_SIZE_TO_PAGES (CacheDataCount
* sizeof (*Context
.CacheData
)));
497 FreePages (Context
.ProcessorInfo
, EFI_SIZE_TO_PAGES (NumberOfProcessors
* sizeof (*Context
.ProcessorInfo
)));