CpuCacheInfoLib.c 19 KB

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