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
++) {
31 DEBUG ((DEBUG_INFO
, "| %4x | %4x %2x %2x %2x %4x ( %x| %x) %8x %4x |\n",
32 Index
, CpuCacheInfo
[Index
].Package
, CpuCacheInfo
[Index
].CoreType
, CpuCacheInfo
[Index
].CacheLevel
,
33 CpuCacheInfo
[Index
].CacheType
, CpuCacheInfo
[Index
].CacheWays
, CpuCacheInfo
[Index
].FullyAssociativeCache
,
34 CpuCacheInfo
[Index
].DirectMappedCache
, CpuCacheInfo
[Index
].CacheSizeinKB
, CpuCacheInfo
[Index
].CacheCount
));
37 DEBUG ((DEBUG_INFO
, "+-------+--------------------------------------------------------------------------------------+\n"));
41 Function to compare CPU package ID, core type, cache level and cache type for use in QuickSort.
43 @param[in] Buffer1 pointer to CPU_CACHE_INFO poiner to compare
44 @param[in] Buffer2 pointer to second CPU_CACHE_INFO pointer to compare
46 @retval 0 Buffer1 equal to Buffer2
47 @retval 1 Buffer1 is greater than Buffer2
48 @retval -1 Buffer1 is less than Buffer2
53 IN CONST VOID
*Buffer1
,
54 IN CONST VOID
*Buffer2
57 CPU_CACHE_INFO_COMPARATOR Comparator1
, Comparator2
;
59 ZeroMem (&Comparator1
, sizeof (Comparator1
));
60 ZeroMem (&Comparator2
, sizeof (Comparator2
));
62 Comparator1
.Bits
.Package
= ((CPU_CACHE_INFO
*)Buffer1
)->Package
;
63 Comparator1
.Bits
.CoreType
= ((CPU_CACHE_INFO
*)Buffer1
)->CoreType
;
64 Comparator1
.Bits
.CacheLevel
= ((CPU_CACHE_INFO
*)Buffer1
)->CacheLevel
;
65 Comparator1
.Bits
.CacheType
= ((CPU_CACHE_INFO
*)Buffer1
)->CacheType
;
67 Comparator2
.Bits
.Package
= ((CPU_CACHE_INFO
*)Buffer2
)->Package
;
68 Comparator2
.Bits
.CoreType
= ((CPU_CACHE_INFO
*)Buffer2
)->CoreType
;
69 Comparator2
.Bits
.CacheLevel
= ((CPU_CACHE_INFO
*)Buffer2
)->CacheLevel
;
70 Comparator2
.Bits
.CacheType
= ((CPU_CACHE_INFO
*)Buffer2
)->CacheType
;
72 if (Comparator1
.Uint64
== Comparator2
.Uint64
) {
74 } else if (Comparator1
.Uint64
> Comparator2
.Uint64
) {
82 Get the total number of package and package ID in the platform.
84 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
85 @param[in] NumberOfProcessors Total number of logical processors in the platform.
86 @param[in, out] Package Pointer to the Package array.
88 @retval Return the total number of package and package ID in the platform.
91 CpuCacheInfoGetNumberOfPackages (
92 IN CPUID_PROCESSOR_INFO
*ProcessorInfo
,
93 IN UINTN NumberOfProcessors
,
94 IN OUT UINT32
*Package
100 UINT32 CurrentPackage
;
104 for (ProcessorIndex
= 0; ProcessorIndex
< NumberOfProcessors
; ProcessorIndex
++) {
105 CurrentPackage
= ProcessorInfo
[ProcessorIndex
].Package
;
108 // For the package that already exists in Package array, break out the loop.
110 for (PackageIndex
= 0; PackageIndex
< PackageCount
; PackageIndex
++) {
111 if (CurrentPackage
== Package
[PackageIndex
]) {
117 // For the new package, save it in Package array.
119 if (PackageIndex
== PackageCount
) {
120 ASSERT (PackageCount
< MAX_NUM_OF_PACKAGE
);
121 Package
[PackageCount
++] = CurrentPackage
;
129 Get the number of CoreType of requested package.
131 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
132 @param[in] NumberOfProcessors Total number of logical processors in the platform.
133 @param[in] Package The requested package number.
135 @retval Return the number of CoreType of requested package.
138 CpuCacheInfoGetNumberOfCoreTypePerPackage(
139 IN CPUID_PROCESSOR_INFO
*ProcessorInfo
,
140 IN UINTN NumberOfProcessors
,
144 UINTN ProcessorIndex
;
146 // Core Type value comes from CPUID.1Ah.EAX[31:24].
147 // So max number of core types should be MAX_UINT8.
149 UINT8 CoreType
[MAX_UINT8
];
152 UINT8 CurrentCoreType
;
155 // CoreType array is empty.
159 for (ProcessorIndex
= 0; ProcessorIndex
< NumberOfProcessors
; ProcessorIndex
++) {
160 CurrentCoreType
= ProcessorInfo
[ProcessorIndex
].CoreType
;
162 if (ProcessorInfo
[ProcessorIndex
].Package
!= Package
) {
167 // For the type that already exists in CoreType array, break out the loop.
169 for (CoreTypeIndex
= 0; CoreTypeIndex
< CoreTypeCount
; CoreTypeIndex
++) {
170 if (CurrentCoreType
== CoreType
[CoreTypeIndex
]) {
176 // For the new type, save it in CoreType array.
178 if (CoreTypeIndex
== CoreTypeCount
) {
179 ASSERT (CoreTypeCount
< MAX_UINT8
);
180 CoreType
[CoreTypeCount
++] = CurrentCoreType
;
184 return CoreTypeCount
;
188 Collect core and cache information of calling processor via CPUID instructions.
190 @param[in, out] Buffer The pointer to private data buffer.
194 CpuCacheInfoCollectCoreAndCacheData (
198 UINTN ProcessorIndex
;
199 UINT32 CpuidMaxInput
;
200 UINT8 CacheParamLeafIndex
;
201 CPUID_CACHE_PARAMS_EAX CacheParamEax
;
202 CPUID_CACHE_PARAMS_EBX CacheParamEbx
;
203 UINT32 CacheParamEcx
;
204 CPUID_CACHE_PARAMS_EDX CacheParamEdx
;
205 CPUID_NATIVE_MODEL_ID_AND_CORE_TYPE_EAX NativeModelIdAndCoreTypeEax
;
206 COLLECT_CPUID_CACHE_DATA_CONTEXT
*Context
;
207 CPUID_CACHE_DATA
*CacheData
;
209 Context
= (COLLECT_CPUID_CACHE_DATA_CONTEXT
*)Buffer
;
210 ProcessorIndex
= CpuCacheInfoWhoAmI (Context
->MpServices
);
211 CacheData
= &Context
->CacheData
[MAX_NUM_OF_CACHE_PARAMS_LEAF
* ProcessorIndex
];
213 AsmCpuid (CPUID_SIGNATURE
, &CpuidMaxInput
, NULL
, NULL
, NULL
);
216 // get CoreType if CPUID_HYBRID_INFORMATION leaf is supported.
218 Context
->ProcessorInfo
[ProcessorIndex
].CoreType
= 0;
219 if (CpuidMaxInput
>= CPUID_HYBRID_INFORMATION
) {
220 AsmCpuidEx (CPUID_HYBRID_INFORMATION
, CPUID_HYBRID_INFORMATION_MAIN_LEAF
, &NativeModelIdAndCoreTypeEax
.Uint32
, NULL
, NULL
, NULL
);
221 Context
->ProcessorInfo
[ProcessorIndex
].CoreType
= (UINT8
) NativeModelIdAndCoreTypeEax
.Bits
.CoreType
;
225 // cache hierarchy starts with an index value of 0.
227 CacheParamLeafIndex
= 0;
229 while (CacheParamLeafIndex
< MAX_NUM_OF_CACHE_PARAMS_LEAF
) {
230 AsmCpuidEx (CPUID_CACHE_PARAMS
, CacheParamLeafIndex
, &CacheParamEax
.Uint32
, &CacheParamEbx
.Uint32
, &CacheParamEcx
, &CacheParamEdx
.Uint32
);
232 if (CacheParamEax
.Bits
.CacheType
== 0) {
236 CacheData
[CacheParamLeafIndex
].CacheLevel
= (UINT8
)CacheParamEax
.Bits
.CacheLevel
;
237 CacheData
[CacheParamLeafIndex
].CacheType
= (UINT8
)CacheParamEax
.Bits
.CacheType
;
238 CacheData
[CacheParamLeafIndex
].CacheWays
= (UINT16
)CacheParamEbx
.Bits
.Ways
;
239 CacheData
[CacheParamLeafIndex
].FullyAssociativeCache
= (UINT8
)CacheParamEax
.Bits
.FullyAssociativeCache
;
240 CacheData
[CacheParamLeafIndex
].DirectMappedCache
= (UINT8
)(CacheParamEdx
.Bits
.ComplexCacheIndexing
== 0);
241 CacheData
[CacheParamLeafIndex
].CacheShareBits
= (UINT16
)CacheParamEax
.Bits
.MaximumAddressableIdsForLogicalProcessors
;
242 CacheData
[CacheParamLeafIndex
].CacheSizeinKB
= (CacheParamEbx
.Bits
.Ways
+ 1) *
243 (CacheParamEbx
.Bits
.LinePartitions
+ 1) * (CacheParamEbx
.Bits
.LineSize
+ 1) * (CacheParamEcx
+ 1) / SIZE_1KB
;
245 CacheParamLeafIndex
++;
250 Collect CacheInfo data from the CacheData.
252 @param[in] CacheData Pointer to the CacheData array.
253 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
254 @param[in] NumberOfProcessors Total number of logical processors in the platform.
255 @param[in, out] CacheInfo Pointer to the CacheInfo array.
256 @param[in, out] CacheInfoCount As input, point to the length of response CacheInfo array.
257 As output, point to the actual length of response CacheInfo array.
259 @retval EFI_SUCCESS Function completed successfully.
260 @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated.
261 @retval EFI_BUFFER_TOO_SMALL CacheInfoCount is too small to hold the response CacheInfo
262 array. CacheInfoCount has been updated with the length needed
263 to complete the request.
266 CpuCacheInfoCollectCpuCacheInfoData (
267 IN CPUID_CACHE_DATA
*CacheData
,
268 IN CPUID_PROCESSOR_INFO
*ProcessorInfo
,
269 IN UINTN NumberOfProcessors
,
270 IN OUT CPU_CACHE_INFO
*CacheInfo
,
271 IN OUT UINTN
*CacheInfoCount
275 UINT32 NumberOfPackage
;
276 UINT32 Package
[MAX_NUM_OF_PACKAGE
];
278 UINTN TotalNumberOfCoreType
;
279 UINTN MaxCacheInfoCount
;
280 CPU_CACHE_INFO
*LocalCacheInfo
;
281 UINTN CacheInfoIndex
;
282 UINTN LocalCacheInfoCount
;
287 // Get number of Packages and Package ID.
289 NumberOfPackage
= CpuCacheInfoGetNumberOfPackages (ProcessorInfo
, NumberOfProcessors
, Package
);
292 // Get number of core types for each package and count the total number.
293 // E.g. If Package1 and Package2 both have 2 core types, the total number is 4.
295 TotalNumberOfCoreType
= 0;
296 for (PackageIndex
= 0; PackageIndex
< NumberOfPackage
; PackageIndex
++) {
297 TotalNumberOfCoreType
+= CpuCacheInfoGetNumberOfCoreTypePerPackage (ProcessorInfo
, NumberOfProcessors
, Package
[PackageIndex
]);
300 MaxCacheInfoCount
= TotalNumberOfCoreType
* MAX_NUM_OF_CACHE_PARAMS_LEAF
;
301 LocalCacheInfo
= AllocatePages (EFI_SIZE_TO_PAGES (MaxCacheInfoCount
* sizeof (*LocalCacheInfo
)));
302 ASSERT (LocalCacheInfo
!= NULL
);
303 if (LocalCacheInfo
== NULL
) {
304 return EFI_OUT_OF_RESOURCES
;
307 LocalCacheInfoCount
= 0;
309 for (Index
= 0; Index
< NumberOfProcessors
* MAX_NUM_OF_CACHE_PARAMS_LEAF
; Index
++) {
310 if (CacheData
[Index
].CacheSizeinKB
== 0) {
315 // For the sharing caches, clear their CacheSize.
317 for (NextIndex
= Index
+ 1; NextIndex
< NumberOfProcessors
* MAX_NUM_OF_CACHE_PARAMS_LEAF
; NextIndex
++) {
318 if (CacheData
[NextIndex
].CacheSizeinKB
== 0) {
322 if (CacheData
[Index
].CacheLevel
== CacheData
[NextIndex
].CacheLevel
&&
323 CacheData
[Index
].CacheType
== CacheData
[NextIndex
].CacheType
&&
324 ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].Package
== ProcessorInfo
[NextIndex
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].Package
&&
325 ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].CoreType
== ProcessorInfo
[NextIndex
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].CoreType
&&
326 (ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].ApicId
& ~CacheData
[Index
].CacheShareBits
) ==
327 (ProcessorInfo
[NextIndex
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].ApicId
& ~CacheData
[NextIndex
].CacheShareBits
)) {
328 CacheData
[NextIndex
].CacheSizeinKB
= 0; // uses the sharing cache
333 // For the cache that already exists in LocalCacheInfo, increase its CacheCount.
335 for (CacheInfoIndex
= 0; CacheInfoIndex
< LocalCacheInfoCount
; CacheInfoIndex
++) {
336 if (LocalCacheInfo
[CacheInfoIndex
].Package
== ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].Package
&&
337 LocalCacheInfo
[CacheInfoIndex
].CoreType
== ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].CoreType
&&
338 LocalCacheInfo
[CacheInfoIndex
].CacheLevel
== CacheData
[Index
].CacheLevel
&&
339 LocalCacheInfo
[CacheInfoIndex
].CacheType
== CacheData
[Index
].CacheType
) {
340 LocalCacheInfo
[CacheInfoIndex
].CacheCount
++;
346 // For the new cache with different Package, CoreType, CacheLevel or CacheType, copy its
347 // data into LocalCacheInfo buffer.
349 if (CacheInfoIndex
== LocalCacheInfoCount
) {
350 ASSERT (LocalCacheInfoCount
< MaxCacheInfoCount
);
352 LocalCacheInfo
[LocalCacheInfoCount
].Package
= ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].Package
;
353 LocalCacheInfo
[LocalCacheInfoCount
].CoreType
= ProcessorInfo
[Index
/ MAX_NUM_OF_CACHE_PARAMS_LEAF
].CoreType
;
354 LocalCacheInfo
[LocalCacheInfoCount
].CacheLevel
= CacheData
[Index
].CacheLevel
;
355 LocalCacheInfo
[LocalCacheInfoCount
].CacheType
= CacheData
[Index
].CacheType
;
356 LocalCacheInfo
[LocalCacheInfoCount
].CacheWays
= CacheData
[Index
].CacheWays
;
357 LocalCacheInfo
[LocalCacheInfoCount
].FullyAssociativeCache
= CacheData
[Index
].FullyAssociativeCache
;
358 LocalCacheInfo
[LocalCacheInfoCount
].DirectMappedCache
= CacheData
[Index
].DirectMappedCache
;
359 LocalCacheInfo
[LocalCacheInfoCount
].CacheSizeinKB
= CacheData
[Index
].CacheSizeinKB
;
360 LocalCacheInfo
[LocalCacheInfoCount
].CacheCount
= 1;
362 LocalCacheInfoCount
++;
366 if (*CacheInfoCount
< LocalCacheInfoCount
) {
367 Status
= EFI_BUFFER_TOO_SMALL
;
370 // Sort LocalCacheInfo array by CPU package ID, core type, cache level and cache type.
372 PerformQuickSort (LocalCacheInfo
, LocalCacheInfoCount
, sizeof (*LocalCacheInfo
), (SORT_COMPARE
) CpuCacheInfoCompare
);
373 CopyMem (CacheInfo
, LocalCacheInfo
, sizeof (*CacheInfo
) * LocalCacheInfoCount
);
375 CpuCacheInfoPrintCpuCacheInfoTable (CacheInfo
, LocalCacheInfoCount
);
377 Status
= EFI_SUCCESS
;
380 *CacheInfoCount
= LocalCacheInfoCount
;
382 FreePages (LocalCacheInfo
, EFI_SIZE_TO_PAGES (MaxCacheInfoCount
* sizeof (*LocalCacheInfo
)));
388 Get CpuCacheInfo data array. The array is sorted by CPU package ID, core type, cache level and cache type.
390 @param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array.
391 @param[in, out] CpuCacheInfoCount As input, point to the length of response CpuCacheInfo array.
392 As output, point to the actual length of response CpuCacheInfo array.
394 @retval EFI_SUCCESS Function completed successfully.
395 @retval EFI_INVALID_PARAMETER CpuCacheInfoCount is NULL.
396 @retval EFI_INVALID_PARAMETER CpuCacheInfo is NULL while CpuCacheInfoCount contains the value
398 @retval EFI_UNSUPPORTED Processor does not support CPUID_CACHE_PARAMS Leaf.
399 @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated.
400 @retval EFI_BUFFER_TOO_SMALL CpuCacheInfoCount is too small to hold the response CpuCacheInfo
401 array. CpuCacheInfoCount has been updated with the length needed
402 to complete the request.
407 IN OUT CPU_CACHE_INFO
*CpuCacheInfo
,
408 IN OUT UINTN
*CpuCacheInfoCount
412 UINT32 CpuidMaxInput
;
413 UINT32 NumberOfProcessors
;
414 UINTN CacheDataCount
;
415 UINTN ProcessorIndex
;
416 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
417 COLLECT_CPUID_CACHE_DATA_CONTEXT Context
;
419 if (CpuCacheInfoCount
== NULL
) {
420 return EFI_INVALID_PARAMETER
;
423 if (*CpuCacheInfoCount
!= 0 && CpuCacheInfo
== NULL
) {
424 return EFI_INVALID_PARAMETER
;
427 AsmCpuid (CPUID_SIGNATURE
, &CpuidMaxInput
, NULL
, NULL
, NULL
);
428 if (CpuidMaxInput
< CPUID_CACHE_PARAMS
) {
429 return EFI_UNSUPPORTED
;
433 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.MpServices.
435 CpuCacheInfoGetMpServices (&Context
.MpServices
);
437 NumberOfProcessors
= CpuCacheInfoGetNumberOfProcessors (Context
.MpServices
);
440 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.ProcessorInfo.
442 Context
.ProcessorInfo
= AllocatePages (EFI_SIZE_TO_PAGES (NumberOfProcessors
* sizeof (*Context
.ProcessorInfo
)));
443 ASSERT (Context
.ProcessorInfo
!= NULL
);
444 if (Context
.ProcessorInfo
== NULL
) {
445 return EFI_OUT_OF_RESOURCES
;
448 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.CacheData.
449 // CacheData array consists of CPUID_CACHE_DATA data structure for each Cpuid Cache Parameter Leaf
450 // per logical processor. The array begin with data of each Cache Parameter Leaf of processor 0, followed
451 // by data of each Cache Parameter Leaf of processor 1 ...
453 CacheDataCount
= NumberOfProcessors
* MAX_NUM_OF_CACHE_PARAMS_LEAF
;
454 Context
.CacheData
= AllocatePages (EFI_SIZE_TO_PAGES (CacheDataCount
* sizeof (*Context
.CacheData
)));
455 ASSERT (Context
.CacheData
!= NULL
);
456 if (Context
.CacheData
== NULL
) {
457 FreePages (Context
.ProcessorInfo
, EFI_SIZE_TO_PAGES (NumberOfProcessors
* sizeof (*Context
.ProcessorInfo
)));
458 return EFI_OUT_OF_RESOURCES
;
461 ZeroMem (Context
.CacheData
, CacheDataCount
* sizeof (*Context
.CacheData
));
464 // Collect Package ID and APIC ID of all processors.
466 for (ProcessorIndex
= 0; ProcessorIndex
< NumberOfProcessors
; ProcessorIndex
++) {
467 CpuCacheInfoGetProcessorInfo (Context
.MpServices
, ProcessorIndex
, &ProcessorInfo
);
468 Context
.ProcessorInfo
[ProcessorIndex
].Package
= ProcessorInfo
.Location
.Package
;
469 Context
.ProcessorInfo
[ProcessorIndex
].ApicId
= (UINT32
) ProcessorInfo
.ProcessorId
;
473 // Wakeup all processors for CacheData(core type and cache data) collection.
475 CpuCacheInfoStartupAllCPUs (Context
.MpServices
, CpuCacheInfoCollectCoreAndCacheData
, &Context
);
478 // Collect CpuCacheInfo data from CacheData.
480 Status
= CpuCacheInfoCollectCpuCacheInfoData (Context
.CacheData
, Context
.ProcessorInfo
, NumberOfProcessors
, CpuCacheInfo
, CpuCacheInfoCount
);
482 FreePages (Context
.CacheData
, EFI_SIZE_TO_PAGES (CacheDataCount
* sizeof (*Context
.CacheData
)));
483 FreePages (Context
.ProcessorInfo
, EFI_SIZE_TO_PAGES (NumberOfProcessors
* sizeof (*Context
.ProcessorInfo
)));