]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c
UefiCpuPkg/CpuCacheInfoLib: Add new CpuCacheInfoLib.
[mirror_edk2.git] / UefiCpuPkg / Library / CpuCacheInfoLib / CpuCacheInfoLib.c
CommitLineData
83facfd1
LY
1/** @file\r
2 Provides cache info for each package, core type, cache level and cache type.\r
3\r
4 Copyright (c) 2020 Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "InternalCpuCacheInfoLib.h"\r
10\r
11/**\r
12 Print CpuCacheInfo array.\r
13\r
14 @param[in] CpuCacheInfo Pointer to the CpuCacheInfo array.\r
15 @param[in] CpuCacheInfoCount The length of CpuCacheInfo array.\r
16\r
17**/\r
18VOID\r
19CpuCacheInfoPrintCpuCacheInfoTable (\r
20 IN CPU_CACHE_INFO *CpuCacheInfo,\r
21 IN UINTN CpuCacheInfoCount\r
22 )\r
23{\r
24 UINTN Index;\r
25\r
26 DEBUG ((DEBUG_INFO, "+-------+-------------------------------------------------------------------------------+\n"));\r
27 DEBUG ((DEBUG_INFO, "| Index | Packge CoreType CacheLevel CacheType CacheWays CacheSizeinKB CacheCount |\n"));\r
28 DEBUG ((DEBUG_INFO, "+-------+-------------------------------------------------------------------------------+\n"));\r
29\r
30 for (Index = 0; Index < CpuCacheInfoCount; Index++) {\r
31 DEBUG ((DEBUG_INFO, "| %4x | %4x %2x %2x %2x %4x %8x %4x |\n", Index,\r
32 CpuCacheInfo[Index].Package, CpuCacheInfo[Index].CoreType, CpuCacheInfo[Index].CacheLevel,\r
33 CpuCacheInfo[Index].CacheType, CpuCacheInfo[Index].CacheWays, CpuCacheInfo[Index].CacheSizeinKB,\r
34 CpuCacheInfo[Index].CacheCount));\r
35 }\r
36\r
37 DEBUG ((DEBUG_INFO, "+-------+-------------------------------------------------------------------------------+\n"));\r
38}\r
39\r
40/**\r
41 Get the total number of package and package ID in the platform.\r
42\r
43 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.\r
44 @param[in] NumberOfProcessors Total number of logical processors in the platform.\r
45 @param[in, out] Package Pointer to the Package array.\r
46\r
47 @retval Return the total number of package and package ID in the platform.\r
48**/\r
49UINT32\r
50CpuCacheInfoGetNumberOfPackages (\r
51 IN CPUID_PROCESSOR_INFO *ProcessorInfo,\r
52 IN UINTN NumberOfProcessors,\r
53 IN OUT UINT32 *Package\r
54 )\r
55{\r
56 UINTN ProcessorIndex;\r
57 UINT32 PackageIndex;\r
58 UINT32 PackageCount;\r
59 UINT32 CurrentPackage;\r
60\r
61 PackageCount = 0;\r
62\r
63 for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) {\r
64 CurrentPackage = ProcessorInfo[ProcessorIndex].Package;\r
65\r
66 //\r
67 // For the package that already exists in Package array, break out the loop.\r
68 //\r
69 for (PackageIndex = 0; PackageIndex < PackageCount; PackageIndex++) {\r
70 if (CurrentPackage == Package[PackageIndex]) {\r
71 break;\r
72 }\r
73 }\r
74\r
75 //\r
76 // For the new package, save it in Package array.\r
77 //\r
78 if (PackageIndex == PackageCount) {\r
79 ASSERT (PackageCount < MAX_NUM_OF_PACKAGE);\r
80 Package[PackageCount++] = CurrentPackage;\r
81 }\r
82 }\r
83\r
84 return PackageCount;\r
85}\r
86\r
87/**\r
88 Get the number of CoreType of requested package.\r
89\r
90 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.\r
91 @param[in] NumberOfProcessors Total number of logical processors in the platform.\r
92 @param[in] Package The requested package number.\r
93\r
94 @retval Return the number of CoreType of requested package.\r
95**/\r
96UINTN\r
97CpuCacheInfoGetNumberOfCoreTypePerPackage(\r
98 IN CPUID_PROCESSOR_INFO *ProcessorInfo,\r
99 IN UINTN NumberOfProcessors,\r
100 IN UINTN Package\r
101 )\r
102{\r
103 UINTN ProcessorIndex;\r
104 //\r
105 // Core Type value comes from CPUID.1Ah.EAX[31:24].\r
106 // So max number of core types should be MAX_UINT8.\r
107 //\r
108 UINT8 CoreType[MAX_UINT8];\r
109 UINTN CoreTypeIndex;\r
110 UINTN CoreTypeCount;\r
111 UINT8 CurrentCoreType;\r
112\r
113 //\r
114 // CoreType array is empty.\r
115 //\r
116 CoreTypeCount = 0;\r
117\r
118 for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) {\r
119 CurrentCoreType = ProcessorInfo[ProcessorIndex].CoreType;\r
120\r
121 if (ProcessorInfo[ProcessorIndex].Package != Package) {\r
122 continue;\r
123 }\r
124\r
125 //\r
126 // For the type that already exists in CoreType array, break out the loop.\r
127 //\r
128 for (CoreTypeIndex = 0; CoreTypeIndex < CoreTypeCount; CoreTypeIndex++) {\r
129 if (CurrentCoreType == CoreType[CoreTypeIndex]) {\r
130 break;\r
131 }\r
132 }\r
133\r
134 //\r
135 // For the new type, save it in CoreType array.\r
136 //\r
137 if (CoreTypeIndex == CoreTypeCount) {\r
138 ASSERT (CoreTypeCount < MAX_UINT8);\r
139 CoreType[CoreTypeCount++] = CurrentCoreType;\r
140 }\r
141 }\r
142\r
143 return CoreTypeCount;\r
144}\r
145\r
146/**\r
147 Collect core and cache information of calling processor via CPUID instructions.\r
148\r
149 @param[in, out] Buffer The pointer to private data buffer.\r
150**/\r
151VOID\r
152EFIAPI\r
153CpuCacheInfoCollectCoreAndCacheData (\r
154 IN OUT VOID *Buffer\r
155 )\r
156{\r
157 UINTN ProcessorIndex;\r
158 UINT32 CpuidMaxInput;\r
159 UINT8 CacheParamLeafIndex;\r
160 CPUID_CACHE_PARAMS_EAX CacheParamEax;\r
161 CPUID_CACHE_PARAMS_EBX CacheParamEbx;\r
162 UINT32 CacheParamEcx;\r
163 CPUID_NATIVE_MODEL_ID_AND_CORE_TYPE_EAX NativeModelIdAndCoreTypeEax;\r
164 COLLECT_CPUID_CACHE_DATA_CONTEXT *Context;\r
165 CPUID_CACHE_DATA *CacheData;\r
166\r
167 Context = (COLLECT_CPUID_CACHE_DATA_CONTEXT *)Buffer;\r
168 ProcessorIndex = CpuCacheInfoWhoAmI (Context->MpServices);\r
169 CacheData = &Context->CacheData[MAX_NUM_OF_CACHE_PARAMS_LEAF * ProcessorIndex];\r
170\r
171 AsmCpuid (CPUID_SIGNATURE, &CpuidMaxInput, NULL, NULL, NULL);\r
172\r
173 //\r
174 // get CoreType if CPUID_HYBRID_INFORMATION leaf is supported.\r
175 //\r
176 Context->ProcessorInfo[ProcessorIndex].CoreType = 0;\r
177 if (CpuidMaxInput >= CPUID_HYBRID_INFORMATION) {\r
178 AsmCpuidEx (CPUID_HYBRID_INFORMATION, CPUID_HYBRID_INFORMATION_SUB_LEAF, &NativeModelIdAndCoreTypeEax.Uint32, NULL, NULL, NULL);\r
179 Context->ProcessorInfo[ProcessorIndex].CoreType = (UINT8) NativeModelIdAndCoreTypeEax.Bits.CoreType;\r
180 }\r
181\r
182 //\r
183 // cache hierarchy starts with an index value of 0.\r
184 //\r
185 CacheParamLeafIndex = 0;\r
186\r
187 while (CacheParamLeafIndex < MAX_NUM_OF_CACHE_PARAMS_LEAF) {\r
188 AsmCpuidEx (CPUID_CACHE_PARAMS, CacheParamLeafIndex, &CacheParamEax.Uint32, &CacheParamEbx.Uint32, &CacheParamEcx, NULL);\r
189\r
190 if (CacheParamEax.Bits.CacheType == 0) {\r
191 break;\r
192 }\r
193\r
194 CacheData[CacheParamLeafIndex].CacheLevel = (UINT8)CacheParamEax.Bits.CacheLevel;\r
195 CacheData[CacheParamLeafIndex].CacheType = (UINT8)CacheParamEax.Bits.CacheType;\r
196 CacheData[CacheParamLeafIndex].CacheWays = (UINT16)CacheParamEbx.Bits.Ways;\r
197 CacheData[CacheParamLeafIndex].CacheShareBits = (UINT16)CacheParamEax.Bits.MaximumAddressableIdsForLogicalProcessors;\r
198 CacheData[CacheParamLeafIndex].CacheSizeinKB = (CacheParamEbx.Bits.Ways + 1) *\r
199 (CacheParamEbx.Bits.LinePartitions + 1) * (CacheParamEbx.Bits.LineSize + 1) * (CacheParamEcx + 1) / SIZE_1KB;\r
200\r
201 CacheParamLeafIndex++;\r
202 }\r
203}\r
204\r
205/**\r
206 Collect CacheInfo data from the CacheData.\r
207\r
208 @param[in] CacheData Pointer to the CacheData array.\r
209 @param[in] ProcessorInfo Pointer to the ProcessorInfo array.\r
210 @param[in] NumberOfProcessors Total number of logical processors in the platform.\r
211 @param[in, out] CacheInfo Pointer to the CacheInfo array.\r
212 @param[in, out] CacheInfoCount As input, point to the length of response CacheInfo array.\r
213 As output, point to the actual length of response CacheInfo array.\r
214\r
215 @retval EFI_SUCCESS Function completed successfully.\r
216 @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated.\r
217 @retval EFI_BUFFER_TOO_SMALL CacheInfoCount is too small to hold the response CacheInfo\r
218 array. CacheInfoCount has been updated with the length needed\r
219 to complete the request.\r
220**/\r
221EFI_STATUS\r
222CpuCacheInfoCollectCpuCacheInfoData (\r
223 IN CPUID_CACHE_DATA *CacheData,\r
224 IN CPUID_PROCESSOR_INFO *ProcessorInfo,\r
225 IN UINTN NumberOfProcessors,\r
226 IN OUT CPU_CACHE_INFO *CacheInfo,\r
227 IN OUT UINTN *CacheInfoCount\r
228 )\r
229{\r
230 EFI_STATUS Status;\r
231 UINT32 NumberOfPackage;\r
232 UINT32 Package[MAX_NUM_OF_PACKAGE];\r
233 UINTN PackageIndex;\r
234 UINTN TotalNumberOfCoreType;\r
235 UINTN MaxCacheInfoCount;\r
236 CPU_CACHE_INFO *LocalCacheInfo;\r
237 UINTN CacheInfoIndex;\r
238 UINTN LocalCacheInfoCount;\r
239 UINTN Index;\r
240 UINTN NextIndex;\r
241\r
242 //\r
243 // Get number of Packages and Package ID.\r
244 //\r
245 NumberOfPackage = CpuCacheInfoGetNumberOfPackages (ProcessorInfo, NumberOfProcessors, Package);\r
246\r
247 //\r
248 // Get number of core types for each package and count the total number.\r
249 // E.g. If Package1 and Package2 both have 2 core types, the total number is 4.\r
250 //\r
251 TotalNumberOfCoreType = 0;\r
252 for (PackageIndex = 0; PackageIndex < NumberOfPackage; PackageIndex++) {\r
253 TotalNumberOfCoreType += CpuCacheInfoGetNumberOfCoreTypePerPackage (ProcessorInfo, NumberOfProcessors, Package[PackageIndex]);\r
254 }\r
255\r
256 MaxCacheInfoCount = TotalNumberOfCoreType * MAX_NUM_OF_CACHE_PARAMS_LEAF;\r
257 LocalCacheInfo = AllocatePages (EFI_SIZE_TO_PAGES (MaxCacheInfoCount * sizeof (*LocalCacheInfo)));\r
258 ASSERT (LocalCacheInfo != NULL);\r
259 if (LocalCacheInfo == NULL) {\r
260 return EFI_OUT_OF_RESOURCES;\r
261 }\r
262\r
263 LocalCacheInfoCount = 0;\r
264\r
265 for (Index = 0; Index < NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF; Index++) {\r
266 if (CacheData[Index].CacheSizeinKB == 0) {\r
267 continue;\r
268 }\r
269\r
270 //\r
271 // For the sharing caches, clear their CacheSize.\r
272 //\r
273 for (NextIndex = Index + 1; NextIndex < NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF; NextIndex++) {\r
274 if (CacheData[NextIndex].CacheSizeinKB == 0) {\r
275 continue;\r
276 }\r
277\r
278 if (CacheData[Index].CacheLevel == CacheData[NextIndex].CacheLevel &&\r
279 CacheData[Index].CacheType == CacheData[NextIndex].CacheType &&\r
280 ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package == ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package &&\r
281 ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType == ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType &&\r
282 (ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].ApicId & ~CacheData[Index].CacheShareBits) ==\r
283 (ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].ApicId & ~CacheData[NextIndex].CacheShareBits)) {\r
284 CacheData[NextIndex].CacheSizeinKB = 0; // uses the sharing cache\r
285 }\r
286 }\r
287\r
288 //\r
289 // For the cache that already exists in LocalCacheInfo, increase its CacheCount.\r
290 //\r
291 for (CacheInfoIndex = 0; CacheInfoIndex < LocalCacheInfoCount; CacheInfoIndex++) {\r
292 if (LocalCacheInfo[CacheInfoIndex].Package == ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package &&\r
293 LocalCacheInfo[CacheInfoIndex].CoreType == ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType &&\r
294 LocalCacheInfo[CacheInfoIndex].CacheLevel == CacheData[Index].CacheLevel &&\r
295 LocalCacheInfo[CacheInfoIndex].CacheType == CacheData[Index].CacheType) {\r
296 LocalCacheInfo[CacheInfoIndex].CacheCount++;\r
297 break;\r
298 }\r
299 }\r
300\r
301 //\r
302 // For the new cache with different Package, CoreType, CacheLevel or CacheType, copy its\r
303 // data into LocalCacheInfo buffer.\r
304 //\r
305 if (CacheInfoIndex == LocalCacheInfoCount) {\r
306 ASSERT (LocalCacheInfoCount < MaxCacheInfoCount);\r
307\r
308 LocalCacheInfo[LocalCacheInfoCount].Package = ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package;\r
309 LocalCacheInfo[LocalCacheInfoCount].CoreType = ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType;\r
310 LocalCacheInfo[LocalCacheInfoCount].CacheLevel = CacheData[Index].CacheLevel;\r
311 LocalCacheInfo[LocalCacheInfoCount].CacheType = CacheData[Index].CacheType;\r
312 LocalCacheInfo[LocalCacheInfoCount].CacheWays = CacheData[Index].CacheWays;\r
313 LocalCacheInfo[LocalCacheInfoCount].CacheSizeinKB = CacheData[Index].CacheSizeinKB;\r
314 LocalCacheInfo[LocalCacheInfoCount].CacheCount = 1;\r
315\r
316 LocalCacheInfoCount++;\r
317 }\r
318 }\r
319\r
320 if (*CacheInfoCount < LocalCacheInfoCount) {\r
321 Status = EFI_BUFFER_TOO_SMALL;\r
322 } else {\r
323 CopyMem (CacheInfo, LocalCacheInfo, sizeof (*CacheInfo) * LocalCacheInfoCount);\r
324 DEBUG_CODE (\r
325 CpuCacheInfoPrintCpuCacheInfoTable (CacheInfo, LocalCacheInfoCount);\r
326 );\r
327 Status = EFI_SUCCESS;\r
328 }\r
329\r
330 *CacheInfoCount = LocalCacheInfoCount;\r
331\r
332 FreePages (LocalCacheInfo, EFI_SIZE_TO_PAGES (MaxCacheInfoCount * sizeof (*LocalCacheInfo)));\r
333\r
334 return Status;\r
335}\r
336\r
337/**\r
338 Get CpuCacheInfo data array.\r
339\r
340 @param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array.\r
341 @param[in, out] CpuCacheInfoCount As input, point to the length of response CpuCacheInfo array.\r
342 As output, point to the actual length of response CpuCacheInfo array.\r
343\r
344 @retval EFI_SUCCESS Function completed successfully.\r
345 @retval EFI_INVALID_PARAMETER CpuCacheInfoCount is NULL.\r
346 @retval EFI_INVALID_PARAMETER CpuCacheInfo is NULL while CpuCacheInfoCount contains the value\r
347 greater than zero.\r
348 @retval EFI_UNSUPPORTED Processor does not support CPUID_CACHE_PARAMS Leaf.\r
349 @retval EFI_NOT_FOUND EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL interface\r
350 is not found.\r
351 @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated.\r
352 @retval EFI_BUFFER_TOO_SMALL CpuCacheInfoCount is too small to hold the response CpuCacheInfo\r
353 array. CpuCacheInfoCount has been updated with the length needed\r
354 to complete the request.\r
355**/\r
356EFI_STATUS\r
357EFIAPI\r
358GetCpuCacheInfo (\r
359 IN OUT CPU_CACHE_INFO *CpuCacheInfo,\r
360 IN OUT UINTN *CpuCacheInfoCount\r
361 )\r
362{\r
363 EFI_STATUS Status;\r
364 UINT32 CpuidMaxInput;\r
365 UINT32 NumberOfProcessors;\r
366 UINTN CacheDataCount;\r
367 UINTN ProcessorIndex;\r
368 EFI_PROCESSOR_INFORMATION ProcessorInfo;\r
369 COLLECT_CPUID_CACHE_DATA_CONTEXT Context;\r
370\r
371 if (CpuCacheInfoCount == NULL) {\r
372 return EFI_INVALID_PARAMETER;\r
373 }\r
374\r
375 if (*CpuCacheInfoCount != 0 && CpuCacheInfo == NULL) {\r
376 return EFI_INVALID_PARAMETER;\r
377 }\r
378\r
379 AsmCpuid (CPUID_SIGNATURE, &CpuidMaxInput, NULL, NULL, NULL);\r
380 if (CpuidMaxInput < CPUID_CACHE_PARAMS) {\r
381 return EFI_UNSUPPORTED;\r
382 }\r
383\r
384 //\r
385 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.MpServices.\r
386 //\r
387 Status = CpuCacheInfoGetMpServices (&Context.MpServices);\r
388 if (EFI_ERROR(Status)) {\r
389 return Status;\r
390 }\r
391\r
392 NumberOfProcessors = CpuCacheInfoGetNumberOfProcessors (Context.MpServices);\r
393\r
394 //\r
395 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.ProcessorInfo.\r
396 //\r
397 Context.ProcessorInfo = AllocatePages (EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo)));\r
398 ASSERT (Context.ProcessorInfo != NULL);\r
399 if (Context.ProcessorInfo == NULL) {\r
400 return EFI_OUT_OF_RESOURCES;\r
401 }\r
402 //\r
403 // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.CacheData.\r
404 // CacheData array consists of CPUID_CACHE_DATA data structure for each Cpuid Cache Parameter Leaf\r
405 // per logical processor. The array begin with data of each Cache Parameter Leaf of processor 0, followed\r
406 // by data of each Cache Parameter Leaf of processor 1 ...\r
407 //\r
408 CacheDataCount = NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF;\r
409 Context.CacheData = AllocatePages (EFI_SIZE_TO_PAGES (CacheDataCount * sizeof (*Context.CacheData)));\r
410 ASSERT (Context.CacheData != NULL);\r
411 if (Context.CacheData == NULL) {\r
412 FreePages (Context.ProcessorInfo, EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo)));\r
413 return EFI_OUT_OF_RESOURCES;\r
414 }\r
415\r
416 ZeroMem (Context.CacheData, CacheDataCount * sizeof (*Context.CacheData));\r
417\r
418 //\r
419 // Collect Package ID and APIC ID of all processors.\r
420 //\r
421 for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) {\r
422 CpuCacheInfoGetProcessorInfo (Context.MpServices, ProcessorIndex, &ProcessorInfo);\r
423 Context.ProcessorInfo[ProcessorIndex].Package = ProcessorInfo.Location.Package;\r
424 Context.ProcessorInfo[ProcessorIndex].ApicId = (UINT32) ProcessorInfo.ProcessorId;\r
425 }\r
426\r
427 //\r
428 // Wakeup all processors for CacheData(core type and cache data) collection.\r
429 //\r
430 CpuCacheInfoStartupAllCPUs (Context.MpServices, CpuCacheInfoCollectCoreAndCacheData, &Context);\r
431\r
432 //\r
433 // Collect CpuCacheInfo data from CacheData.\r
434 //\r
435 Status = CpuCacheInfoCollectCpuCacheInfoData (Context.CacheData, Context.ProcessorInfo, NumberOfProcessors, CpuCacheInfo, CpuCacheInfoCount);\r
436\r
437 FreePages (Context.CacheData, EFI_SIZE_TO_PAGES (CacheDataCount * sizeof (*Context.CacheData)));\r
438 FreePages (Context.ProcessorInfo, EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo)));\r
439\r
440 return Status;\r
441}\r