]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / RegisterCpuFeaturesLib / RegisterCpuFeaturesLib.c
CommitLineData
80c4b236
JF
1/** @file\r
2 CPU Register Table Library functions.\r
3\r
cefad282 4 Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>\r
0acd8697 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
80c4b236
JF
6\r
7**/\r
8\r
9#include "RegisterCpuFeatures.h"\r
10\r
80c4b236
JF
11/**\r
12 Function that uses DEBUG() macros to display the contents of a a CPU feature bit mask.\r
13\r
14 @param[in] FeatureMask A pointer to the CPU feature bit mask.\r
3dafa038
ED
15 @param[in] BitMaskSize CPU feature bits mask buffer size.\r
16\r
80c4b236
JF
17**/\r
18VOID\r
19DumpCpuFeatureMask (\r
053e878b
MK
20 IN UINT8 *FeatureMask,\r
21 IN UINT32 BitMaskSize\r
80c4b236
JF
22 )\r
23{\r
053e878b
MK
24 UINTN Index;\r
25 UINT8 *Data8;\r
80c4b236 26\r
053e878b 27 Data8 = (UINT8 *)FeatureMask;\r
80c4b236
JF
28 for (Index = 0; Index < BitMaskSize; Index++) {\r
29 DEBUG ((DEBUG_INFO, " %02x ", *Data8++));\r
30 }\r
053e878b 31\r
80c4b236
JF
32 DEBUG ((DEBUG_INFO, "\n"));\r
33}\r
34\r
35/**\r
36 Dump CPU feature name or CPU feature bit mask.\r
37\r
38 @param[in] CpuFeature Pointer to CPU_FEATURES_ENTRY\r
3dafa038
ED
39 @param[in] BitMaskSize CPU feature bits mask buffer size.\r
40\r
80c4b236
JF
41**/\r
42VOID\r
43DumpCpuFeature (\r
3dafa038
ED
44 IN CPU_FEATURES_ENTRY *CpuFeature,\r
45 IN UINT32 BitMaskSize\r
80c4b236
JF
46 )\r
47{\r
80c4b236
JF
48 if (CpuFeature->FeatureName != NULL) {\r
49 DEBUG ((DEBUG_INFO, "FeatureName: %a\n", CpuFeature->FeatureName));\r
50 } else {\r
51 DEBUG ((DEBUG_INFO, "FeatureMask = "));\r
3dafa038 52 DumpCpuFeatureMask (CpuFeature->FeatureMask, BitMaskSize);\r
80c4b236
JF
53 }\r
54}\r
55\r
56/**\r
57 Determines if the feature bit mask is in dependent CPU feature bit mask buffer.\r
58\r
59 @param[in] FeatureMask Pointer to CPU feature bit mask\r
60 @param[in] DependentBitMask Pointer to dependent CPU feature bit mask buffer\r
61\r
62 @retval TRUE The feature bit mask is in dependent CPU feature bit mask buffer.\r
63 @retval FALSE The feature bit mask is not in dependent CPU feature bit mask buffer.\r
64**/\r
65BOOLEAN\r
66IsBitMaskMatchCheck (\r
053e878b
MK
67 IN UINT8 *FeatureMask,\r
68 IN UINT8 *DependentBitMask\r
80c4b236
JF
69 )\r
70{\r
3dafa038
ED
71 UINTN Index;\r
72 UINT8 *Data1;\r
73 UINT8 *Data2;\r
74 CPU_FEATURES_DATA *CpuFeaturesData;\r
80c4b236 75\r
3dafa038 76 CpuFeaturesData = GetCpuFeaturesData ();\r
80c4b236
JF
77\r
78 Data1 = FeatureMask;\r
79 Data2 = DependentBitMask;\r
3dafa038 80 for (Index = 0; Index < CpuFeaturesData->BitMaskSize; Index++) {\r
80c4b236
JF
81 if (((*(Data1++)) & (*(Data2++))) != 0) {\r
82 return TRUE;\r
83 }\r
84 }\r
053e878b 85\r
80c4b236
JF
86 return FALSE;\r
87}\r
88\r
c1528b85
ED
89/**\r
90 Try to find the specify cpu featuren in former/after feature list.\r
91\r
92 @param[in] FeatureList Pointer to dependent CPU feature list\r
93 @param[in] CurrentEntry Pointer to current CPU feature entry.\r
94 @param[in] SearchFormer Find in former feature or after features.\r
95 @param[in] FeatureMask Pointer to CPU feature bit mask\r
96\r
97 @retval TRUE The feature bit mask is in dependent CPU feature bit mask buffer.\r
98 @retval FALSE The feature bit mask is not in dependent CPU feature bit mask buffer.\r
99**/\r
100BOOLEAN\r
101FindSpecifyFeature (\r
053e878b
MK
102 IN LIST_ENTRY *FeatureList,\r
103 IN LIST_ENTRY *CurrentEntry,\r
104 IN BOOLEAN SearchFormer,\r
105 IN UINT8 *FeatureMask\r
c1528b85
ED
106 )\r
107{\r
053e878b
MK
108 CPU_FEATURES_ENTRY *CpuFeature;\r
109 LIST_ENTRY *NextEntry;\r
c1528b85
ED
110\r
111 //\r
112 // Check whether exist the not neighborhood entry first.\r
113 // If not exist, return FALSE means not found status.\r
114 //\r
115 if (SearchFormer) {\r
116 NextEntry = CurrentEntry->BackLink;\r
117 if (IsNull (FeatureList, NextEntry)) {\r
118 return FALSE;\r
119 }\r
120\r
121 NextEntry = NextEntry->BackLink;\r
122 if (IsNull (FeatureList, NextEntry)) {\r
123 return FALSE;\r
124 }\r
125\r
126 NextEntry = CurrentEntry->BackLink->BackLink;\r
127 } else {\r
128 NextEntry = CurrentEntry->ForwardLink;\r
129 if (IsNull (FeatureList, NextEntry)) {\r
130 return FALSE;\r
131 }\r
132\r
133 NextEntry = NextEntry->ForwardLink;\r
134 if (IsNull (FeatureList, NextEntry)) {\r
135 return FALSE;\r
136 }\r
137\r
138 NextEntry = CurrentEntry->ForwardLink->ForwardLink;\r
139 }\r
140\r
141 while (!IsNull (FeatureList, NextEntry)) {\r
142 CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (NextEntry);\r
143\r
144 if (IsBitMaskMatchCheck (FeatureMask, CpuFeature->FeatureMask)) {\r
145 return TRUE;\r
146 }\r
147\r
148 if (SearchFormer) {\r
149 NextEntry = NextEntry->BackLink;\r
150 } else {\r
151 NextEntry = NextEntry->ForwardLink;\r
152 }\r
153 }\r
154\r
155 return FALSE;\r
156}\r
157\r
b3c71b47
ED
158/**\r
159 Return feature dependence result.\r
160\r
1475b83f
ED
161 @param[in] CpuFeature Pointer to CPU feature.\r
162 @param[in] Before Check before dependence or after.\r
163 @param[in] NextCpuFeatureMask Pointer to next CPU feature Mask.\r
b3c71b47
ED
164\r
165 @retval return the dependence result.\r
166**/\r
167CPU_FEATURE_DEPENDENCE_TYPE\r
168DetectFeatureScope (\r
053e878b
MK
169 IN CPU_FEATURES_ENTRY *CpuFeature,\r
170 IN BOOLEAN Before,\r
171 IN UINT8 *NextCpuFeatureMask\r
b3c71b47
ED
172 )\r
173{\r
1475b83f
ED
174 //\r
175 // if need to check before type dependence but the feature after current feature is not\r
176 // exist, means this before type dependence not valid, just return NoneDepType.\r
177 // Just like Feature A has a dependence of feature B, but Feature B not installed, so\r
178 // Feature A maybe insert to the last entry of the list. In this case, for below code,\r
179 // Featrure A has depend of feature B, but it is the last entry of the list, so the\r
180 // NextCpuFeatureMask is NULL, so the dependence for feature A here is useless and code\r
181 // just return NoneDepType.\r
182 //\r
183 if (NextCpuFeatureMask == NULL) {\r
184 return NoneDepType;\r
185 }\r
186\r
b3c71b47 187 if (Before) {\r
1475b83f 188 if ((CpuFeature->PackageBeforeFeatureBitMask != NULL) &&\r
053e878b
MK
189 IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->PackageBeforeFeatureBitMask))\r
190 {\r
b3c71b47
ED
191 return PackageDepType;\r
192 }\r
193\r
1475b83f 194 if ((CpuFeature->CoreBeforeFeatureBitMask != NULL) &&\r
053e878b
MK
195 IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->CoreBeforeFeatureBitMask))\r
196 {\r
b3c71b47
ED
197 return CoreDepType;\r
198 }\r
199\r
0f1ddb21 200 if ((CpuFeature->ThreadBeforeFeatureBitMask != NULL) &&\r
053e878b
MK
201 IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->ThreadBeforeFeatureBitMask))\r
202 {\r
b3c71b47
ED
203 return ThreadDepType;\r
204 }\r
205\r
206 return NoneDepType;\r
207 }\r
208\r
1475b83f 209 if ((CpuFeature->PackageAfterFeatureBitMask != NULL) &&\r
053e878b
MK
210 IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->PackageAfterFeatureBitMask))\r
211 {\r
b3c71b47
ED
212 return PackageDepType;\r
213 }\r
214\r
1475b83f 215 if ((CpuFeature->CoreAfterFeatureBitMask != NULL) &&\r
053e878b
MK
216 IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->CoreAfterFeatureBitMask))\r
217 {\r
b3c71b47
ED
218 return CoreDepType;\r
219 }\r
220\r
0f1ddb21 221 if ((CpuFeature->ThreadAfterFeatureBitMask != NULL) &&\r
053e878b
MK
222 IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->ThreadAfterFeatureBitMask))\r
223 {\r
b3c71b47
ED
224 return ThreadDepType;\r
225 }\r
226\r
227 return NoneDepType;\r
228}\r
229\r
c1528b85
ED
230/**\r
231 Return feature dependence result.\r
232\r
233 @param[in] CpuFeature Pointer to CPU feature.\r
234 @param[in] Before Check before dependence or after.\r
235 @param[in] FeatureList Pointer to CPU feature list.\r
236\r
237 @retval return the dependence result.\r
238**/\r
239CPU_FEATURE_DEPENDENCE_TYPE\r
240DetectNoneNeighborhoodFeatureScope (\r
053e878b
MK
241 IN CPU_FEATURES_ENTRY *CpuFeature,\r
242 IN BOOLEAN Before,\r
243 IN LIST_ENTRY *FeatureList\r
c1528b85
ED
244 )\r
245{\r
246 if (Before) {\r
247 if ((CpuFeature->PackageBeforeFeatureBitMask != NULL) &&\r
053e878b
MK
248 FindSpecifyFeature (FeatureList, &CpuFeature->Link, FALSE, CpuFeature->PackageBeforeFeatureBitMask))\r
249 {\r
c1528b85
ED
250 return PackageDepType;\r
251 }\r
252\r
253 if ((CpuFeature->CoreBeforeFeatureBitMask != NULL) &&\r
053e878b
MK
254 FindSpecifyFeature (FeatureList, &CpuFeature->Link, FALSE, CpuFeature->CoreBeforeFeatureBitMask))\r
255 {\r
c1528b85
ED
256 return CoreDepType;\r
257 }\r
258\r
0f1ddb21 259 if ((CpuFeature->ThreadBeforeFeatureBitMask != NULL) &&\r
053e878b
MK
260 FindSpecifyFeature (FeatureList, &CpuFeature->Link, FALSE, CpuFeature->ThreadBeforeFeatureBitMask))\r
261 {\r
c1528b85
ED
262 return ThreadDepType;\r
263 }\r
264\r
265 return NoneDepType;\r
266 }\r
267\r
268 if ((CpuFeature->PackageAfterFeatureBitMask != NULL) &&\r
053e878b
MK
269 FindSpecifyFeature (FeatureList, &CpuFeature->Link, TRUE, CpuFeature->PackageAfterFeatureBitMask))\r
270 {\r
c1528b85
ED
271 return PackageDepType;\r
272 }\r
273\r
274 if ((CpuFeature->CoreAfterFeatureBitMask != NULL) &&\r
053e878b
MK
275 FindSpecifyFeature (FeatureList, &CpuFeature->Link, TRUE, CpuFeature->CoreAfterFeatureBitMask))\r
276 {\r
c1528b85
ED
277 return CoreDepType;\r
278 }\r
279\r
0f1ddb21 280 if ((CpuFeature->ThreadAfterFeatureBitMask != NULL) &&\r
053e878b
MK
281 FindSpecifyFeature (FeatureList, &CpuFeature->Link, TRUE, CpuFeature->ThreadAfterFeatureBitMask))\r
282 {\r
c1528b85
ED
283 return ThreadDepType;\r
284 }\r
285\r
286 return NoneDepType;\r
287}\r
288\r
b3c71b47
ED
289/**\r
290 Base on dependence relationship to asjust feature dependence.\r
291\r
1c15179c 292 ONLY when the feature before(or after) the find feature also has\r
b3c71b47
ED
293 dependence with the find feature. In this case, driver need to base\r
294 on dependce relationship to decide how to insert current feature and\r
295 adjust the feature dependence.\r
296\r
1c15179c
ED
297 @param[in, out] PreviousFeature CPU feature current before the find one.\r
298 @param[in, out] CurrentFeature Cpu feature need to adjust.\r
1475b83f 299 @param[in] FindFeature Cpu feature which current feature depends.\r
1c15179c 300 @param[in] Before Before or after dependence relationship.\r
b3c71b47
ED
301\r
302 @retval TRUE means the current feature dependence has been adjusted.\r
303\r
304 @retval FALSE means the previous feature dependence has been adjusted.\r
305 or previous feature has no dependence with the find one.\r
306\r
307**/\r
308BOOLEAN\r
309AdjustFeaturesDependence (\r
053e878b
MK
310 IN OUT CPU_FEATURES_ENTRY *PreviousFeature,\r
311 IN OUT CPU_FEATURES_ENTRY *CurrentFeature,\r
312 IN CPU_FEATURES_ENTRY *FindFeature,\r
313 IN BOOLEAN Before\r
b3c71b47
ED
314 )\r
315{\r
053e878b
MK
316 CPU_FEATURE_DEPENDENCE_TYPE PreDependType;\r
317 CPU_FEATURE_DEPENDENCE_TYPE CurrentDependType;\r
b3c71b47 318\r
053e878b
MK
319 PreDependType = DetectFeatureScope (PreviousFeature, Before, FindFeature->FeatureMask);\r
320 CurrentDependType = DetectFeatureScope (CurrentFeature, Before, FindFeature->FeatureMask);\r
b3c71b47
ED
321\r
322 //\r
323 // If previous feature has no dependence with the find featue.\r
324 // return FALSE.\r
325 //\r
326 if (PreDependType == NoneDepType) {\r
327 return FALSE;\r
328 }\r
329\r
330 //\r
1c15179c 331 // If both feature have dependence, keep the one which needs use more\r
b3c71b47
ED
332 // processors and clear the dependence for the other one.\r
333 //\r
334 if (PreDependType >= CurrentDependType) {\r
b3c71b47
ED
335 return TRUE;\r
336 } else {\r
b3c71b47
ED
337 return FALSE;\r
338 }\r
339}\r
340\r
341/**\r
342 Base on dependence relationship to asjust feature order.\r
343\r
1c15179c
ED
344 @param[in] FeatureList Pointer to CPU feature list\r
345 @param[in, out] FindEntry The entry this feature depend on.\r
346 @param[in, out] CurrentEntry The entry for this feature.\r
347 @param[in] Before Before or after dependence relationship.\r
b3c71b47
ED
348\r
349**/\r
350VOID\r
351AdjustEntry (\r
053e878b
MK
352 IN LIST_ENTRY *FeatureList,\r
353 IN OUT LIST_ENTRY *FindEntry,\r
354 IN OUT LIST_ENTRY *CurrentEntry,\r
355 IN BOOLEAN Before\r
b3c71b47
ED
356 )\r
357{\r
053e878b
MK
358 LIST_ENTRY *PreviousEntry;\r
359 CPU_FEATURES_ENTRY *PreviousFeature;\r
360 CPU_FEATURES_ENTRY *CurrentFeature;\r
361 CPU_FEATURES_ENTRY *FindFeature;\r
b3c71b47
ED
362\r
363 //\r
364 // For CPU feature which has core or package type dependence, later code need to insert\r
365 // AcquireSpinLock/ReleaseSpinLock logic to sequency the execute order.\r
366 // So if driver finds both feature A and B need to execute before feature C, driver will\r
367 // base on dependence type of feature A and B to update the logic here.\r
368 // For example, feature A has package type dependence and feature B has core type dependence,\r
369 // because package type dependence need to wait for more processors which has strong dependence\r
1c15179c
ED
370 // than core type dependence. So driver will adjust the feature order to B -> A -> C. and driver\r
371 // will remove the feature dependence in feature B.\r
b3c71b47
ED
372 // Driver just needs to make sure before feature C been executed, feature A has finished its task\r
373 // in all all thread. Feature A finished in all threads also means feature B have finshed in all\r
374 // threads.\r
375 //\r
376 if (Before) {\r
377 PreviousEntry = GetPreviousNode (FeatureList, FindEntry);\r
0acd8697 378 } else {\r
b3c71b47
ED
379 PreviousEntry = GetNextNode (FeatureList, FindEntry);\r
380 }\r
381\r
053e878b 382 CurrentFeature = CPU_FEATURE_ENTRY_FROM_LINK (CurrentEntry);\r
b3c71b47
ED
383 RemoveEntryList (CurrentEntry);\r
384\r
385 if (IsNull (FeatureList, PreviousEntry)) {\r
386 //\r
387 // If not exist the previous or next entry, just insert the current entry.\r
388 //\r
389 if (Before) {\r
390 InsertTailList (FindEntry, CurrentEntry);\r
391 } else {\r
392 InsertHeadList (FindEntry, CurrentEntry);\r
393 }\r
394 } else {\r
395 //\r
396 // If exist the previous or next entry, need to check it before insert curent entry.\r
397 //\r
398 PreviousFeature = CPU_FEATURE_ENTRY_FROM_LINK (PreviousEntry);\r
1475b83f 399 FindFeature = CPU_FEATURE_ENTRY_FROM_LINK (FindEntry);\r
b3c71b47 400\r
1475b83f 401 if (AdjustFeaturesDependence (PreviousFeature, CurrentFeature, FindFeature, Before)) {\r
b3c71b47
ED
402 //\r
403 // Return TRUE means current feature dependence has been cleared and the previous\r
404 // feature dependence has been kept and used. So insert current feature before (or after)\r
405 // the previous feature.\r
406 //\r
407 if (Before) {\r
408 InsertTailList (PreviousEntry, CurrentEntry);\r
409 } else {\r
410 InsertHeadList (PreviousEntry, CurrentEntry);\r
411 }\r
412 } else {\r
413 if (Before) {\r
414 InsertTailList (FindEntry, CurrentEntry);\r
415 } else {\r
416 InsertHeadList (FindEntry, CurrentEntry);\r
417 }\r
418 }\r
419 }\r
0acd8697
MK
420}\r
421\r
b3c71b47
ED
422/**\r
423 Checks and adjusts current CPU features per dependency relationship.\r
424\r
425 @param[in] FeatureList Pointer to CPU feature list\r
426 @param[in] CurrentEntry Pointer to current checked CPU feature\r
427 @param[in] FeatureMask The feature bit mask.\r
428\r
429 @retval return Swapped info.\r
430**/\r
431BOOLEAN\r
432InsertToBeforeEntry (\r
053e878b
MK
433 IN LIST_ENTRY *FeatureList,\r
434 IN LIST_ENTRY *CurrentEntry,\r
435 IN UINT8 *FeatureMask\r
b3c71b47
ED
436 )\r
437{\r
053e878b
MK
438 LIST_ENTRY *CheckEntry;\r
439 CPU_FEATURES_ENTRY *CheckFeature;\r
440 BOOLEAN Swapped;\r
b3c71b47
ED
441\r
442 Swapped = FALSE;\r
443\r
444 //\r
445 // Check all features dispatched before this entry\r
446 //\r
447 CheckEntry = GetFirstNode (FeatureList);\r
448 while (CheckEntry != CurrentEntry) {\r
449 CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry);\r
450 if (IsBitMaskMatchCheck (CheckFeature->FeatureMask, FeatureMask)) {\r
451 AdjustEntry (FeatureList, CheckEntry, CurrentEntry, TRUE);\r
452 Swapped = TRUE;\r
453 break;\r
454 }\r
053e878b 455\r
b3c71b47
ED
456 CheckEntry = CheckEntry->ForwardLink;\r
457 }\r
458\r
459 return Swapped;\r
460}\r
461\r
462/**\r
463 Checks and adjusts current CPU features per dependency relationship.\r
464\r
465 @param[in] FeatureList Pointer to CPU feature list\r
466 @param[in] CurrentEntry Pointer to current checked CPU feature\r
467 @param[in] FeatureMask The feature bit mask.\r
468\r
469 @retval return Swapped info.\r
470**/\r
471BOOLEAN\r
472InsertToAfterEntry (\r
053e878b
MK
473 IN LIST_ENTRY *FeatureList,\r
474 IN LIST_ENTRY *CurrentEntry,\r
475 IN UINT8 *FeatureMask\r
b3c71b47
ED
476 )\r
477{\r
053e878b
MK
478 LIST_ENTRY *CheckEntry;\r
479 CPU_FEATURES_ENTRY *CheckFeature;\r
480 BOOLEAN Swapped;\r
b3c71b47
ED
481\r
482 Swapped = FALSE;\r
483\r
484 //\r
485 // Check all features dispatched after this entry\r
486 //\r
487 CheckEntry = GetNextNode (FeatureList, CurrentEntry);\r
488 while (!IsNull (FeatureList, CheckEntry)) {\r
489 CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry);\r
490 if (IsBitMaskMatchCheck (CheckFeature->FeatureMask, FeatureMask)) {\r
491 AdjustEntry (FeatureList, CheckEntry, CurrentEntry, FALSE);\r
492 Swapped = TRUE;\r
493 break;\r
494 }\r
053e878b 495\r
b3c71b47
ED
496 CheckEntry = CheckEntry->ForwardLink;\r
497 }\r
498\r
499 return Swapped;\r
500}\r
501\r
80c4b236
JF
502/**\r
503 Checks and adjusts CPU features order per dependency relationship.\r
504\r
505 @param[in] FeatureList Pointer to CPU feature list\r
506**/\r
507VOID\r
508CheckCpuFeaturesDependency (\r
053e878b 509 IN LIST_ENTRY *FeatureList\r
80c4b236
JF
510 )\r
511{\r
053e878b
MK
512 LIST_ENTRY *CurrentEntry;\r
513 CPU_FEATURES_ENTRY *CpuFeature;\r
514 LIST_ENTRY *CheckEntry;\r
515 CPU_FEATURES_ENTRY *CheckFeature;\r
516 BOOLEAN Swapped;\r
517 LIST_ENTRY *TempEntry;\r
518 LIST_ENTRY *NextEntry;\r
80c4b236
JF
519\r
520 CurrentEntry = GetFirstNode (FeatureList);\r
521 while (!IsNull (FeatureList, CurrentEntry)) {\r
053e878b 522 Swapped = FALSE;\r
80c4b236 523 CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (CurrentEntry);\r
053e878b 524 NextEntry = CurrentEntry->ForwardLink;\r
80c4b236
JF
525 if (CpuFeature->BeforeAll) {\r
526 //\r
527 // Check all features dispatched before this entry\r
528 //\r
529 CheckEntry = GetFirstNode (FeatureList);\r
530 while (CheckEntry != CurrentEntry) {\r
531 CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry);\r
532 if (!CheckFeature->BeforeAll) {\r
533 //\r
534 // If this feature has no BeforeAll flag and is dispatched before CpuFeature,\r
535 // insert currentEntry before Checked feature\r
536 //\r
537 RemoveEntryList (CurrentEntry);\r
538 InsertTailList (CheckEntry, CurrentEntry);\r
539 Swapped = TRUE;\r
540 break;\r
541 }\r
053e878b 542\r
80c4b236
JF
543 CheckEntry = CheckEntry->ForwardLink;\r
544 }\r
053e878b 545\r
80c4b236 546 if (Swapped) {\r
b3c71b47 547 CurrentEntry = NextEntry;\r
80c4b236
JF
548 continue;\r
549 }\r
550 }\r
551\r
552 if (CpuFeature->AfterAll) {\r
553 //\r
554 // Check all features dispatched after this entry\r
555 //\r
556 CheckEntry = GetNextNode (FeatureList, CurrentEntry);\r
557 while (!IsNull (FeatureList, CheckEntry)) {\r
558 CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry);\r
559 if (!CheckFeature->AfterAll) {\r
560 //\r
561 // If this feature has no AfterAll flag and is dispatched after CpuFeature,\r
562 // insert currentEntry after Checked feature\r
563 //\r
564 TempEntry = GetNextNode (FeatureList, CurrentEntry);\r
565 RemoveEntryList (CurrentEntry);\r
566 InsertHeadList (CheckEntry, CurrentEntry);\r
567 CurrentEntry = TempEntry;\r
053e878b 568 Swapped = TRUE;\r
80c4b236
JF
569 break;\r
570 }\r
053e878b 571\r
80c4b236
JF
572 CheckEntry = CheckEntry->ForwardLink;\r
573 }\r
053e878b 574\r
80c4b236 575 if (Swapped) {\r
b3c71b47 576 CurrentEntry = NextEntry;\r
80c4b236
JF
577 continue;\r
578 }\r
579 }\r
580\r
0f1ddb21
RN
581 if (CpuFeature->ThreadBeforeFeatureBitMask != NULL) {\r
582 Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->ThreadBeforeFeatureBitMask);\r
80c4b236
JF
583 if (Swapped) {\r
584 continue;\r
585 }\r
586 }\r
587\r
0f1ddb21
RN
588 if (CpuFeature->ThreadAfterFeatureBitMask != NULL) {\r
589 Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->ThreadAfterFeatureBitMask);\r
b3c71b47 590 if (Swapped) {\r
b3c71b47
ED
591 continue;\r
592 }\r
593 }\r
594\r
595 if (CpuFeature->CoreBeforeFeatureBitMask != NULL) {\r
596 Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->CoreBeforeFeatureBitMask);\r
597 if (Swapped) {\r
b3c71b47 598 continue;\r
80c4b236 599 }\r
b3c71b47
ED
600 }\r
601\r
602 if (CpuFeature->CoreAfterFeatureBitMask != NULL) {\r
603 Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->CoreAfterFeatureBitMask);\r
80c4b236
JF
604 if (Swapped) {\r
605 continue;\r
606 }\r
607 }\r
b3c71b47
ED
608\r
609 if (CpuFeature->PackageBeforeFeatureBitMask != NULL) {\r
610 Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->PackageBeforeFeatureBitMask);\r
611 if (Swapped) {\r
b3c71b47
ED
612 continue;\r
613 }\r
614 }\r
615\r
616 if (CpuFeature->PackageAfterFeatureBitMask != NULL) {\r
617 Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->PackageAfterFeatureBitMask);\r
618 if (Swapped) {\r
b3c71b47
ED
619 continue;\r
620 }\r
621 }\r
622\r
80c4b236
JF
623 CurrentEntry = CurrentEntry->ForwardLink;\r
624 }\r
625}\r
626\r
627/**\r
628 Worker function to register CPU Feature.\r
629\r
3dafa038 630 @param[in] CpuFeaturesData Pointer to CPU feature data structure.\r
80c4b236
JF
631 @param[in] CpuFeature Pointer to CPU feature entry\r
632\r
633 @retval RETURN_SUCCESS The CPU feature was successfully registered.\r
634 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to register\r
635 the CPU feature.\r
636 @retval RETURN_UNSUPPORTED Registration of the CPU feature is not\r
637 supported due to a circular dependency between\r
638 BEFORE and AFTER features.\r
639**/\r
640RETURN_STATUS\r
641RegisterCpuFeatureWorker (\r
053e878b
MK
642 IN CPU_FEATURES_DATA *CpuFeaturesData,\r
643 IN CPU_FEATURES_ENTRY *CpuFeature\r
80c4b236
JF
644 )\r
645{\r
053e878b
MK
646 EFI_STATUS Status;\r
647 CPU_FEATURES_ENTRY *CpuFeatureEntry;\r
648 LIST_ENTRY *Entry;\r
649 BOOLEAN FeatureExist;\r
80c4b236 650\r
053e878b 651 FeatureExist = FALSE;\r
80c4b236 652 CpuFeatureEntry = NULL;\r
053e878b 653 Entry = GetFirstNode (&CpuFeaturesData->FeatureList);\r
80c4b236
JF
654 while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {\r
655 CpuFeatureEntry = CPU_FEATURE_ENTRY_FROM_LINK (Entry);\r
3dafa038 656 if (CompareMem (CpuFeature->FeatureMask, CpuFeatureEntry->FeatureMask, CpuFeaturesData->BitMaskSize) == 0) {\r
80c4b236
JF
657 //\r
658 // If this feature already registered\r
659 //\r
660 FeatureExist = TRUE;\r
661 break;\r
662 }\r
053e878b 663\r
80c4b236
JF
664 Entry = Entry->ForwardLink;\r
665 }\r
666\r
667 if (!FeatureExist) {\r
668 DEBUG ((DEBUG_INFO, "[NEW] "));\r
3dafa038 669 DumpCpuFeature (CpuFeature, CpuFeaturesData->BitMaskSize);\r
80c4b236
JF
670 InsertTailList (&CpuFeaturesData->FeatureList, &CpuFeature->Link);\r
671 CpuFeaturesData->FeaturesCount++;\r
672 } else {\r
673 DEBUG ((DEBUG_INFO, "[OVERRIDE] "));\r
3dafa038 674 DumpCpuFeature (CpuFeature, CpuFeaturesData->BitMaskSize);\r
80c4b236
JF
675 ASSERT (CpuFeatureEntry != NULL);\r
676 //\r
677 // Overwrite original parameters of CPU feature\r
678 //\r
679 if (CpuFeature->GetConfigDataFunc != NULL) {\r
680 CpuFeatureEntry->GetConfigDataFunc = CpuFeature->GetConfigDataFunc;\r
681 }\r
053e878b 682\r
80c4b236
JF
683 if (CpuFeature->SupportFunc != NULL) {\r
684 CpuFeatureEntry->SupportFunc = CpuFeature->SupportFunc;\r
685 }\r
053e878b 686\r
80c4b236
JF
687 if (CpuFeature->InitializeFunc != NULL) {\r
688 CpuFeatureEntry->InitializeFunc = CpuFeature->InitializeFunc;\r
689 }\r
053e878b 690\r
80c4b236
JF
691 if (CpuFeature->FeatureName != NULL) {\r
692 if (CpuFeatureEntry->FeatureName == NULL) {\r
693 CpuFeatureEntry->FeatureName = AllocatePool (CPU_FEATURE_NAME_SIZE);\r
694 ASSERT (CpuFeatureEntry->FeatureName != NULL);\r
695 }\r
053e878b 696\r
80c4b236
JF
697 Status = AsciiStrCpyS (CpuFeatureEntry->FeatureName, CPU_FEATURE_NAME_SIZE, CpuFeature->FeatureName);\r
698 ASSERT_EFI_ERROR (Status);\r
699 FreePool (CpuFeature->FeatureName);\r
700 }\r
053e878b 701\r
0f1ddb21
RN
702 if (CpuFeature->ThreadBeforeFeatureBitMask != NULL) {\r
703 if (CpuFeatureEntry->ThreadBeforeFeatureBitMask != NULL) {\r
704 FreePool (CpuFeatureEntry->ThreadBeforeFeatureBitMask);\r
80c4b236 705 }\r
053e878b 706\r
0f1ddb21 707 CpuFeatureEntry->ThreadBeforeFeatureBitMask = CpuFeature->ThreadBeforeFeatureBitMask;\r
80c4b236 708 }\r
053e878b 709\r
0f1ddb21
RN
710 if (CpuFeature->ThreadAfterFeatureBitMask != NULL) {\r
711 if (CpuFeatureEntry->ThreadAfterFeatureBitMask != NULL) {\r
712 FreePool (CpuFeatureEntry->ThreadAfterFeatureBitMask);\r
80c4b236 713 }\r
053e878b 714\r
0f1ddb21 715 CpuFeatureEntry->ThreadAfterFeatureBitMask = CpuFeature->ThreadAfterFeatureBitMask;\r
80c4b236 716 }\r
053e878b 717\r
b3c71b47
ED
718 if (CpuFeature->CoreBeforeFeatureBitMask != NULL) {\r
719 if (CpuFeatureEntry->CoreBeforeFeatureBitMask != NULL) {\r
720 FreePool (CpuFeatureEntry->CoreBeforeFeatureBitMask);\r
721 }\r
053e878b 722\r
b3c71b47
ED
723 CpuFeatureEntry->CoreBeforeFeatureBitMask = CpuFeature->CoreBeforeFeatureBitMask;\r
724 }\r
053e878b 725\r
b3c71b47
ED
726 if (CpuFeature->CoreAfterFeatureBitMask != NULL) {\r
727 if (CpuFeatureEntry->CoreAfterFeatureBitMask != NULL) {\r
728 FreePool (CpuFeatureEntry->CoreAfterFeatureBitMask);\r
729 }\r
053e878b 730\r
b3c71b47
ED
731 CpuFeatureEntry->CoreAfterFeatureBitMask = CpuFeature->CoreAfterFeatureBitMask;\r
732 }\r
053e878b 733\r
b3c71b47
ED
734 if (CpuFeature->PackageBeforeFeatureBitMask != NULL) {\r
735 if (CpuFeatureEntry->PackageBeforeFeatureBitMask != NULL) {\r
736 FreePool (CpuFeatureEntry->PackageBeforeFeatureBitMask);\r
737 }\r
053e878b 738\r
b3c71b47
ED
739 CpuFeatureEntry->PackageBeforeFeatureBitMask = CpuFeature->PackageBeforeFeatureBitMask;\r
740 }\r
053e878b 741\r
b3c71b47
ED
742 if (CpuFeature->PackageAfterFeatureBitMask != NULL) {\r
743 if (CpuFeatureEntry->PackageAfterFeatureBitMask != NULL) {\r
744 FreePool (CpuFeatureEntry->PackageAfterFeatureBitMask);\r
745 }\r
053e878b 746\r
b3c71b47
ED
747 CpuFeatureEntry->PackageAfterFeatureBitMask = CpuFeature->PackageAfterFeatureBitMask;\r
748 }\r
749\r
80c4b236
JF
750 CpuFeatureEntry->BeforeAll = CpuFeature->BeforeAll;\r
751 CpuFeatureEntry->AfterAll = CpuFeature->AfterAll;\r
752\r
753 FreePool (CpuFeature->FeatureMask);\r
754 FreePool (CpuFeature);\r
755 }\r
053e878b 756\r
80c4b236
JF
757 //\r
758 // Verify CPU features dependency can change CPU feature order\r
759 //\r
760 CheckCpuFeaturesDependency (&CpuFeaturesData->FeatureList);\r
761 return RETURN_SUCCESS;\r
762}\r
763\r
764/**\r
765 Sets CPU feature bit mask in CPU feature bit mask buffer.\r
766\r
767 @param[in] FeaturesBitMask Pointer to CPU feature bit mask buffer\r
768 @param[in] Feature The bit number of the CPU feature\r
769 @param[in] BitMaskSize CPU feature bit mask buffer size\r
770**/\r
771VOID\r
772SetCpuFeaturesBitMask (\r
053e878b
MK
773 IN UINT8 **FeaturesBitMask,\r
774 IN UINT32 Feature,\r
775 IN UINTN BitMaskSize\r
80c4b236
JF
776 )\r
777{\r
053e878b 778 UINT8 *CpuFeaturesBitMask;\r
80c4b236
JF
779\r
780 ASSERT (FeaturesBitMask != NULL);\r
781 CpuFeaturesBitMask = *FeaturesBitMask;\r
782 if (CpuFeaturesBitMask == NULL) {\r
783 CpuFeaturesBitMask = AllocateZeroPool (BitMaskSize);\r
784 ASSERT (CpuFeaturesBitMask != NULL);\r
785 *FeaturesBitMask = CpuFeaturesBitMask;\r
786 }\r
787\r
788 CpuFeaturesBitMask += (Feature / 8);\r
053e878b 789 *CpuFeaturesBitMask |= (UINT8)(1 << (Feature % 8));\r
80c4b236
JF
790}\r
791\r
792/**\r
793 Registers a CPU Feature.\r
794\r
795 @param[in] FeatureName A Null-terminated Ascii string indicates CPU feature\r
796 name.\r
797 @param[in] GetConfigDataFunc CPU feature get configuration data function. This\r
798 is an optional parameter that may be NULL. If NULL,\r
799 then the most recently registered function for the\r
800 CPU feature is used. If no functions are registered\r
801 for a CPU feature, then the CPU configuration data\r
802 for the registered feature is NULL.\r
803 @param[in] SupportFunc CPU feature support function. This is an optional\r
804 parameter that may be NULL. If NULL, then the most\r
805 recently registered function for the CPU feature is\r
806 used. If no functions are registered for a CPU\r
807 feature, then the CPU feature is assumed to be\r
808 supported by all CPUs.\r
809 @param[in] InitializeFunc CPU feature initialize function. This is an optional\r
810 parameter that may be NULL. If NULL, then the most\r
811 recently registered function for the CPU feature is\r
812 used. If no functions are registered for a CPU\r
813 feature, then the CPU feature initialization is\r
814 skipped.\r
815 @param[in] ... Variable argument list of UINT32 CPU feature value.\r
816 Values with no modifiers are the features provided\r
817 by the registered functions.\r
818 Values with CPU_FEATURE_BEFORE modifier are features\r
819 that must be initialized after the features provided\r
820 by the registered functions are used.\r
821 Values with CPU_FEATURE_AFTER modifier are features\r
822 that must be initialized before the features provided\r
823 by the registered functions are used.\r
824 The last argument in this variable argument list must\r
825 always be CPU_FEATURE_END.\r
826\r
827 @retval RETURN_SUCCESS The CPU feature was successfully registered.\r
828 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to register\r
829 the CPU feature.\r
830 @retval RETURN_UNSUPPORTED Registration of the CPU feature is not\r
831 supported due to a circular dependency between\r
832 BEFORE and AFTER features.\r
b3c71b47
ED
833 @retval RETURN_NOT_READY CPU feature PCD PcdCpuFeaturesUserConfiguration\r
834 not updated by Platform driver yet.\r
80c4b236
JF
835\r
836 @note This service could be called by BSP only.\r
837**/\r
838RETURN_STATUS\r
839EFIAPI\r
840RegisterCpuFeature (\r
053e878b
MK
841 IN CHAR8 *FeatureName OPTIONAL,\r
842 IN CPU_FEATURE_GET_CONFIG_DATA GetConfigDataFunc OPTIONAL,\r
843 IN CPU_FEATURE_SUPPORT SupportFunc OPTIONAL,\r
844 IN CPU_FEATURE_INITIALIZE InitializeFunc OPTIONAL,\r
80c4b236
JF
845 ...\r
846 )\r
847{\r
053e878b
MK
848 EFI_STATUS Status;\r
849 VA_LIST Marker;\r
850 UINT32 Feature;\r
851 CPU_FEATURES_ENTRY *CpuFeature;\r
852 UINT8 *FeatureMask;\r
853 UINT8 *ThreadBeforeFeatureBitMask;\r
854 UINT8 *ThreadAfterFeatureBitMask;\r
855 UINT8 *CoreBeforeFeatureBitMask;\r
856 UINT8 *CoreAfterFeatureBitMask;\r
857 UINT8 *PackageBeforeFeatureBitMask;\r
858 UINT8 *PackageAfterFeatureBitMask;\r
859 BOOLEAN BeforeAll;\r
860 BOOLEAN AfterAll;\r
861 CPU_FEATURES_DATA *CpuFeaturesData;\r
80c4b236 862\r
b3c71b47 863 FeatureMask = NULL;\r
0f1ddb21
RN
864 ThreadBeforeFeatureBitMask = NULL;\r
865 ThreadAfterFeatureBitMask = NULL;\r
b3c71b47
ED
866 CoreBeforeFeatureBitMask = NULL;\r
867 CoreAfterFeatureBitMask = NULL;\r
868 PackageBeforeFeatureBitMask = NULL;\r
869 PackageAfterFeatureBitMask = NULL;\r
053e878b
MK
870 BeforeAll = FALSE;\r
871 AfterAll = FALSE;\r
80c4b236 872\r
3dafa038
ED
873 CpuFeaturesData = GetCpuFeaturesData ();\r
874 if (CpuFeaturesData->FeaturesCount == 0) {\r
875 InitializeListHead (&CpuFeaturesData->FeatureList);\r
876 InitializeSpinLock (&CpuFeaturesData->CpuFlags.MemoryMappedLock);\r
3dafa038
ED
877 //\r
878 // Code assumes below three PCDs have PCD same buffer size.\r
879 //\r
880 ASSERT (PcdGetSize (PcdCpuFeaturesSetting) == PcdGetSize (PcdCpuFeaturesCapability));\r
881 ASSERT (PcdGetSize (PcdCpuFeaturesSetting) == PcdGetSize (PcdCpuFeaturesSupport));\r
053e878b 882 CpuFeaturesData->BitMaskSize = (UINT32)PcdGetSize (PcdCpuFeaturesSetting);\r
3dafa038 883 }\r
80c4b236
JF
884\r
885 VA_START (Marker, InitializeFunc);\r
886 Feature = VA_ARG (Marker, UINT32);\r
887 while (Feature != CPU_FEATURE_END) {\r
0f1ddb21
RN
888 //\r
889 // It's invalid to require a feature is before AND after all other features.\r
890 //\r
053e878b
MK
891 ASSERT (\r
892 (Feature & (CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL))\r
893 != (CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL)\r
894 );\r
0f1ddb21
RN
895\r
896 //\r
897 // It's invalid to require feature A is before AND after before feature B,\r
898 // either in thread level, core level or package level.\r
899 //\r
053e878b
MK
900 ASSERT (\r
901 (Feature & (CPU_FEATURE_THREAD_BEFORE | CPU_FEATURE_THREAD_AFTER))\r
902 != (CPU_FEATURE_THREAD_BEFORE | CPU_FEATURE_THREAD_AFTER)\r
903 );\r
904 ASSERT (\r
905 (Feature & (CPU_FEATURE_CORE_BEFORE | CPU_FEATURE_CORE_AFTER))\r
906 != (CPU_FEATURE_CORE_BEFORE | CPU_FEATURE_CORE_AFTER)\r
907 );\r
908 ASSERT (\r
909 (Feature & (CPU_FEATURE_PACKAGE_BEFORE | CPU_FEATURE_PACKAGE_AFTER))\r
910 != (CPU_FEATURE_PACKAGE_BEFORE | CPU_FEATURE_PACKAGE_AFTER)\r
911 );\r
707e6be7 912 if (Feature < CPU_FEATURE_THREAD_BEFORE) {\r
80c4b236
JF
913 BeforeAll = ((Feature & CPU_FEATURE_BEFORE_ALL) != 0) ? TRUE : FALSE;\r
914 AfterAll = ((Feature & CPU_FEATURE_AFTER_ALL) != 0) ? TRUE : FALSE;\r
915 Feature &= ~(CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL);\r
916 ASSERT (FeatureMask == NULL);\r
3dafa038 917 SetCpuFeaturesBitMask (&FeatureMask, Feature, CpuFeaturesData->BitMaskSize);\r
707e6be7 918 } else if ((Feature & CPU_FEATURE_THREAD_BEFORE) != 0) {\r
0f1ddb21 919 SetCpuFeaturesBitMask (&ThreadBeforeFeatureBitMask, Feature & ~CPU_FEATURE_THREAD_BEFORE, CpuFeaturesData->BitMaskSize);\r
707e6be7 920 } else if ((Feature & CPU_FEATURE_THREAD_AFTER) != 0) {\r
0f1ddb21 921 SetCpuFeaturesBitMask (&ThreadAfterFeatureBitMask, Feature & ~CPU_FEATURE_THREAD_AFTER, CpuFeaturesData->BitMaskSize);\r
b3c71b47 922 } else if ((Feature & CPU_FEATURE_CORE_BEFORE) != 0) {\r
3dafa038 923 SetCpuFeaturesBitMask (&CoreBeforeFeatureBitMask, Feature & ~CPU_FEATURE_CORE_BEFORE, CpuFeaturesData->BitMaskSize);\r
b3c71b47 924 } else if ((Feature & CPU_FEATURE_CORE_AFTER) != 0) {\r
3dafa038 925 SetCpuFeaturesBitMask (&CoreAfterFeatureBitMask, Feature & ~CPU_FEATURE_CORE_AFTER, CpuFeaturesData->BitMaskSize);\r
b3c71b47 926 } else if ((Feature & CPU_FEATURE_PACKAGE_BEFORE) != 0) {\r
3dafa038 927 SetCpuFeaturesBitMask (&PackageBeforeFeatureBitMask, Feature & ~CPU_FEATURE_PACKAGE_BEFORE, CpuFeaturesData->BitMaskSize);\r
b3c71b47 928 } else if ((Feature & CPU_FEATURE_PACKAGE_AFTER) != 0) {\r
3dafa038 929 SetCpuFeaturesBitMask (&PackageAfterFeatureBitMask, Feature & ~CPU_FEATURE_PACKAGE_AFTER, CpuFeaturesData->BitMaskSize);\r
80c4b236 930 }\r
053e878b 931\r
80c4b236
JF
932 Feature = VA_ARG (Marker, UINT32);\r
933 }\r
053e878b 934\r
80c4b236
JF
935 VA_END (Marker);\r
936\r
937 CpuFeature = AllocateZeroPool (sizeof (CPU_FEATURES_ENTRY));\r
938 ASSERT (CpuFeature != NULL);\r
b3c71b47
ED
939 CpuFeature->Signature = CPU_FEATURE_ENTRY_SIGNATURE;\r
940 CpuFeature->FeatureMask = FeatureMask;\r
0f1ddb21
RN
941 CpuFeature->ThreadBeforeFeatureBitMask = ThreadBeforeFeatureBitMask;\r
942 CpuFeature->ThreadAfterFeatureBitMask = ThreadAfterFeatureBitMask;\r
b3c71b47
ED
943 CpuFeature->CoreBeforeFeatureBitMask = CoreBeforeFeatureBitMask;\r
944 CpuFeature->CoreAfterFeatureBitMask = CoreAfterFeatureBitMask;\r
945 CpuFeature->PackageBeforeFeatureBitMask = PackageBeforeFeatureBitMask;\r
946 CpuFeature->PackageAfterFeatureBitMask = PackageAfterFeatureBitMask;\r
947 CpuFeature->BeforeAll = BeforeAll;\r
948 CpuFeature->AfterAll = AfterAll;\r
949 CpuFeature->GetConfigDataFunc = GetConfigDataFunc;\r
950 CpuFeature->SupportFunc = SupportFunc;\r
951 CpuFeature->InitializeFunc = InitializeFunc;\r
80c4b236 952 if (FeatureName != NULL) {\r
053e878b 953 CpuFeature->FeatureName = AllocatePool (CPU_FEATURE_NAME_SIZE);\r
80c4b236
JF
954 ASSERT (CpuFeature->FeatureName != NULL);\r
955 Status = AsciiStrCpyS (CpuFeature->FeatureName, CPU_FEATURE_NAME_SIZE, FeatureName);\r
956 ASSERT_EFI_ERROR (Status);\r
957 }\r
958\r
3dafa038 959 Status = RegisterCpuFeatureWorker (CpuFeaturesData, CpuFeature);\r
80c4b236
JF
960 ASSERT_EFI_ERROR (Status);\r
961\r
962 return RETURN_SUCCESS;\r
963}\r
964\r
a6daab1f 965/**\r
b3c71b47 966 Return ACPI_CPU_DATA data.\r
a6daab1f 967\r
b3c71b47 968 @return Pointer to ACPI_CPU_DATA data.\r
a6daab1f 969**/\r
a6daab1f 970ACPI_CPU_DATA *\r
b3c71b47 971GetAcpiCpuData (\r
a6daab1f
ED
972 VOID\r
973 )\r
974{\r
053e878b
MK
975 EFI_STATUS Status;\r
976 UINTN NumberOfCpus;\r
977 UINTN NumberOfEnabledProcessors;\r
978 ACPI_CPU_DATA *AcpiCpuData;\r
979 UINTN TableSize;\r
980 CPU_REGISTER_TABLE *RegisterTable;\r
981 UINTN Index;\r
982 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;\r
983\r
984 AcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);\r
cefad282 985 if (AcpiCpuData == NULL) {\r
053e878b 986 AcpiCpuData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (ACPI_CPU_DATA)));\r
cefad282
RN
987 ASSERT (AcpiCpuData != NULL);\r
988 ZeroMem (AcpiCpuData, sizeof (ACPI_CPU_DATA));\r
a6daab1f 989\r
cefad282
RN
990 //\r
991 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
992 //\r
993 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);\r
994 ASSERT_EFI_ERROR (Status);\r
b3c71b47 995\r
cefad282
RN
996 GetNumberOfProcessor (&NumberOfCpus, &NumberOfEnabledProcessors);\r
997 AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;\r
998 }\r
a6daab1f 999\r
053e878b
MK
1000 if ((AcpiCpuData->CpuFeatureInitData.RegisterTable == 0) ||\r
1001 (AcpiCpuData->CpuFeatureInitData.PreSmmInitRegisterTable == 0))\r
1002 {\r
cefad282
RN
1003 //\r
1004 // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs\r
1005 //\r
053e878b
MK
1006 NumberOfCpus = AcpiCpuData->NumberOfCpus;\r
1007 TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE);\r
1008 RegisterTable = AllocatePages (EFI_SIZE_TO_PAGES (TableSize));\r
cefad282 1009 ASSERT (RegisterTable != NULL);\r
a6daab1f 1010\r
cefad282
RN
1011 for (Index = 0; Index < NumberOfCpus; Index++) {\r
1012 Status = GetProcessorInformation (Index, &ProcessorInfoBuffer);\r
1013 ASSERT_EFI_ERROR (Status);\r
a6daab1f 1014\r
cefad282
RN
1015 RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
1016 RegisterTable[Index].TableLength = 0;\r
1017 RegisterTable[Index].AllocatedSize = 0;\r
1018 RegisterTable[Index].RegisterTableEntry = 0;\r
a6daab1f 1019\r
cefad282
RN
1020 RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
1021 RegisterTable[NumberOfCpus + Index].TableLength = 0;\r
1022 RegisterTable[NumberOfCpus + Index].AllocatedSize = 0;\r
1023 RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0;\r
1024 }\r
053e878b 1025\r
010753b7
LY
1026 if (AcpiCpuData->CpuFeatureInitData.RegisterTable == 0) {\r
1027 AcpiCpuData->CpuFeatureInitData.RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable;\r
cefad282 1028 }\r
053e878b 1029\r
010753b7
LY
1030 if (AcpiCpuData->CpuFeatureInitData.PreSmmInitRegisterTable == 0) {\r
1031 AcpiCpuData->CpuFeatureInitData.PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus);\r
cefad282 1032 }\r
a6daab1f 1033 }\r
a6daab1f
ED
1034\r
1035 return AcpiCpuData;\r
1036}\r
1037\r
1038/**\r
1039 Enlarges CPU register table for each processor.\r
1040\r
1041 @param[in, out] RegisterTable Pointer processor's CPU register table\r
1042**/\r
1043STATIC\r
1044VOID\r
1045EnlargeRegisterTable (\r
053e878b 1046 IN OUT CPU_REGISTER_TABLE *RegisterTable\r
a6daab1f
ED
1047 )\r
1048{\r
1049 EFI_PHYSICAL_ADDRESS Address;\r
1050 UINTN UsedPages;\r
1051\r
1052 UsedPages = RegisterTable->AllocatedSize / EFI_PAGE_SIZE;\r
053e878b 1053 Address = (UINTN)AllocatePages (UsedPages + 1);\r
a6daab1f
ED
1054 ASSERT (Address != 0);\r
1055\r
1056 //\r
1057 // If there are records existing in the register table, then copy its contents\r
1058 // to new region and free the old one.\r
1059 //\r
1060 if (RegisterTable->AllocatedSize > 0) {\r
1061 CopyMem (\r
053e878b
MK
1062 (VOID *)(UINTN)Address,\r
1063 (VOID *)(UINTN)RegisterTable->RegisterTableEntry,\r
a6daab1f
ED
1064 RegisterTable->AllocatedSize\r
1065 );\r
1066\r
1067 FreePages ((VOID *)(UINTN)RegisterTable->RegisterTableEntry, UsedPages);\r
1068 }\r
1069\r
1070 //\r
1071 // Adjust the allocated size and register table base address.\r
1072 //\r
1073 RegisterTable->AllocatedSize += EFI_PAGE_SIZE;\r
1074 RegisterTable->RegisterTableEntry = Address;\r
1075}\r
1076\r
80c4b236
JF
1077/**\r
1078 Add an entry in specified register table.\r
1079\r
1080 This function adds an entry in specified register table, with given register type,\r
1081 register index, bit section and value.\r
1082\r
1083 @param[in] PreSmmFlag If TRUE, entry will be added into PreSmm register table\r
1084 If FALSE, entry will be added into register table\r
1085 @param[in] ProcessorNumber The index of the CPU to add a register table entry\r
1086 @param[in] RegisterType Type of the register to program\r
1087 @param[in] Index Index of the register to program\r
1088 @param[in] ValidBitStart Start of the bit section\r
1089 @param[in] ValidBitLength Length of the bit section\r
1090 @param[in] Value Value to write\r
35c2809b
ED
1091 @param[in] TestThenWrite Whether need to test current Value before writing.\r
1092\r
80c4b236
JF
1093**/\r
1094VOID\r
1095CpuRegisterTableWriteWorker (\r
053e878b
MK
1096 IN BOOLEAN PreSmmFlag,\r
1097 IN UINTN ProcessorNumber,\r
1098 IN REGISTER_TYPE RegisterType,\r
1099 IN UINT64 Index,\r
1100 IN UINT8 ValidBitStart,\r
1101 IN UINT8 ValidBitLength,\r
1102 IN UINT64 Value,\r
1103 IN BOOLEAN TestThenWrite\r
80c4b236
JF
1104 )\r
1105{\r
053e878b
MK
1106 CPU_FEATURES_DATA *CpuFeaturesData;\r
1107 ACPI_CPU_DATA *AcpiCpuData;\r
1108 CPU_REGISTER_TABLE *RegisterTable;\r
1109 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;\r
80c4b236
JF
1110\r
1111 CpuFeaturesData = GetCpuFeaturesData ();\r
1112 if (CpuFeaturesData->RegisterTable == NULL) {\r
b3c71b47 1113 AcpiCpuData = GetAcpiCpuData ();\r
010753b7 1114 ASSERT ((AcpiCpuData != NULL) && (AcpiCpuData->CpuFeatureInitData.RegisterTable != 0));\r
053e878b
MK
1115 CpuFeaturesData->RegisterTable = (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->CpuFeatureInitData.RegisterTable;\r
1116 CpuFeaturesData->PreSmmRegisterTable = (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->CpuFeatureInitData.PreSmmInitRegisterTable;\r
80c4b236
JF
1117 }\r
1118\r
1119 if (PreSmmFlag) {\r
1120 RegisterTable = &CpuFeaturesData->PreSmmRegisterTable[ProcessorNumber];\r
1121 } else {\r
1122 RegisterTable = &CpuFeaturesData->RegisterTable[ProcessorNumber];\r
1123 }\r
1124\r
1125 if (RegisterTable->TableLength == RegisterTable->AllocatedSize / sizeof (CPU_REGISTER_TABLE_ENTRY)) {\r
1126 EnlargeRegisterTable (RegisterTable);\r
1127 }\r
1128\r
1129 //\r
1130 // Append entry in the register table.\r
1131 //\r
053e878b 1132 RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *)(UINTN)RegisterTable->RegisterTableEntry;\r
80c4b236 1133 RegisterTableEntry[RegisterTable->TableLength].RegisterType = RegisterType;\r
053e878b
MK
1134 RegisterTableEntry[RegisterTable->TableLength].Index = (UINT32)Index;\r
1135 RegisterTableEntry[RegisterTable->TableLength].HighIndex = (UINT32)RShiftU64 (Index, 32);\r
80c4b236
JF
1136 RegisterTableEntry[RegisterTable->TableLength].ValidBitStart = ValidBitStart;\r
1137 RegisterTableEntry[RegisterTable->TableLength].ValidBitLength = ValidBitLength;\r
1138 RegisterTableEntry[RegisterTable->TableLength].Value = Value;\r
35c2809b 1139 RegisterTableEntry[RegisterTable->TableLength].TestThenWrite = TestThenWrite;\r
80c4b236
JF
1140\r
1141 RegisterTable->TableLength++;\r
1142}\r
1143\r
1144/**\r
1145 Adds an entry in specified register table.\r
1146\r
1147 This function adds an entry in specified register table, with given register type,\r
1148 register index, bit section and value.\r
1149\r
1150 @param[in] ProcessorNumber The index of the CPU to add a register table entry\r
1151 @param[in] RegisterType Type of the register to program\r
1152 @param[in] Index Index of the register to program\r
1153 @param[in] ValueMask Mask of bits in register to write\r
1154 @param[in] Value Value to write\r
1155\r
1156 @note This service could be called by BSP only.\r
1157**/\r
1158VOID\r
1159EFIAPI\r
1160CpuRegisterTableWrite (\r
053e878b
MK
1161 IN UINTN ProcessorNumber,\r
1162 IN REGISTER_TYPE RegisterType,\r
1163 IN UINT64 Index,\r
1164 IN UINT64 ValueMask,\r
1165 IN UINT64 Value\r
80c4b236
JF
1166 )\r
1167{\r
053e878b
MK
1168 UINT8 Start;\r
1169 UINT8 End;\r
1170 UINT8 Length;\r
80c4b236 1171\r
053e878b 1172 Start = (UINT8)LowBitSet64 (ValueMask);\r
80c4b236
JF
1173 End = (UINT8)HighBitSet64 (ValueMask);\r
1174 Length = End - Start + 1;\r
35c2809b
ED
1175 CpuRegisterTableWriteWorker (FALSE, ProcessorNumber, RegisterType, Index, Start, Length, Value, FALSE);\r
1176}\r
1177\r
1178/**\r
1179 Adds an entry in specified register table.\r
1180\r
1181 This function adds an entry in specified register table, with given register type,\r
1182 register index, bit section and value.\r
1183\r
1184 @param[in] ProcessorNumber The index of the CPU to add a register table entry\r
1185 @param[in] RegisterType Type of the register to program\r
1186 @param[in] Index Index of the register to program\r
1187 @param[in] ValueMask Mask of bits in register to write\r
1188 @param[in] Value Value to write\r
1189\r
1190 @note This service could be called by BSP only.\r
1191**/\r
1192VOID\r
1193EFIAPI\r
1194CpuRegisterTableTestThenWrite (\r
053e878b
MK
1195 IN UINTN ProcessorNumber,\r
1196 IN REGISTER_TYPE RegisterType,\r
1197 IN UINT64 Index,\r
1198 IN UINT64 ValueMask,\r
1199 IN UINT64 Value\r
35c2809b
ED
1200 )\r
1201{\r
053e878b
MK
1202 UINT8 Start;\r
1203 UINT8 End;\r
1204 UINT8 Length;\r
35c2809b 1205\r
053e878b 1206 Start = (UINT8)LowBitSet64 (ValueMask);\r
35c2809b
ED
1207 End = (UINT8)HighBitSet64 (ValueMask);\r
1208 Length = End - Start + 1;\r
1209 CpuRegisterTableWriteWorker (FALSE, ProcessorNumber, RegisterType, Index, Start, Length, Value, TRUE);\r
80c4b236
JF
1210}\r
1211\r
1212/**\r
1213 Adds an entry in specified Pre-SMM register table.\r
1214\r
1215 This function adds an entry in specified register table, with given register type,\r
1216 register index, bit section and value.\r
1217\r
1218 @param[in] ProcessorNumber The index of the CPU to add a register table entry.\r
1219 @param[in] RegisterType Type of the register to program\r
1220 @param[in] Index Index of the register to program\r
1221 @param[in] ValueMask Mask of bits in register to write\r
1222 @param[in] Value Value to write\r
1223\r
1224 @note This service could be called by BSP only.\r
1225**/\r
1226VOID\r
1227EFIAPI\r
1228PreSmmCpuRegisterTableWrite (\r
053e878b
MK
1229 IN UINTN ProcessorNumber,\r
1230 IN REGISTER_TYPE RegisterType,\r
1231 IN UINT64 Index,\r
1232 IN UINT64 ValueMask,\r
1233 IN UINT64 Value\r
80c4b236
JF
1234 )\r
1235{\r
1236 UINT8 Start;\r
1237 UINT8 End;\r
1238 UINT8 Length;\r
1239\r
053e878b 1240 Start = (UINT8)LowBitSet64 (ValueMask);\r
80c4b236
JF
1241 End = (UINT8)HighBitSet64 (ValueMask);\r
1242 Length = End - Start + 1;\r
35c2809b 1243 CpuRegisterTableWriteWorker (TRUE, ProcessorNumber, RegisterType, Index, Start, Length, Value, FALSE);\r
80c4b236
JF
1244}\r
1245\r
1246/**\r
1247 Worker function to determine if a CPU feature is set in input CPU feature bit mask buffer.\r
1248\r
1249 @param[in] CpuBitMask CPU feature bit mask buffer\r
1250 @param[in] CpuBitMaskSize The size of CPU feature bit mask buffer\r
1251 @param[in] Feature The bit number of the CPU feature\r
1252\r
f664032e
ED
1253 @retval TRUE The CPU feature is set in CpuBitMask.\r
1254 @retval FALSE The CPU feature is not set in CpuBitMask.\r
80c4b236
JF
1255\r
1256**/\r
1257BOOLEAN\r
1258IsCpuFeatureSetInCpuPcd (\r
053e878b
MK
1259 IN UINT8 *CpuBitMask,\r
1260 IN UINTN CpuBitMaskSize,\r
1261 IN UINT32 Feature\r
80c4b236
JF
1262 )\r
1263{\r
1264 if ((Feature >> 3) >= CpuBitMaskSize) {\r
1265 return FALSE;\r
1266 }\r
053e878b 1267\r
80c4b236
JF
1268 return ((*(CpuBitMask + (Feature >> 3)) & (1 << (Feature & 0x07))) != 0);\r
1269}\r
1270\r
1271/**\r
1272 Determines if a CPU feature is enabled in PcdCpuFeaturesSupport bit mask.\r
1273 If a CPU feature is disabled in PcdCpuFeaturesSupport then all the code/data\r
1274 associated with that feature should be optimized away if compiler\r
1275 optimizations are enabled.\r
1276\r
1277 @param[in] Feature The bit number of the CPU feature to check in the PCD\r
1278 PcdCpuFeaturesSupport\r
1279\r
1280 @retval TRUE The CPU feature is set in PcdCpuFeaturesSupport.\r
1281 @retval FALSE The CPU feature is not set in PcdCpuFeaturesSupport.\r
1282\r
1283 @note This service could be called by BSP only.\r
1284**/\r
1285BOOLEAN\r
1286EFIAPI\r
1287IsCpuFeatureSupported (\r
053e878b 1288 IN UINT32 Feature\r
80c4b236
JF
1289 )\r
1290{\r
1291 return IsCpuFeatureSetInCpuPcd (\r
1292 (UINT8 *)PcdGetPtr (PcdCpuFeaturesSupport),\r
1293 PcdGetSize (PcdCpuFeaturesSupport),\r
1294 Feature\r
1295 );\r
1296}\r
1297\r
1298/**\r
1299 Determines if a CPU feature is set in PcdCpuFeaturesSetting bit mask.\r
1300\r
1301 @param[in] Feature The bit number of the CPU feature to check in the PCD\r
1302 PcdCpuFeaturesSetting\r
1303\r
1304 @retval TRUE The CPU feature is set in PcdCpuFeaturesSetting.\r
1305 @retval FALSE The CPU feature is not set in PcdCpuFeaturesSetting.\r
1306\r
1307 @note This service could be called by BSP only.\r
1308**/\r
1309BOOLEAN\r
1310EFIAPI\r
1311IsCpuFeatureInSetting (\r
053e878b 1312 IN UINT32 Feature\r
80c4b236
JF
1313 )\r
1314{\r
1315 return IsCpuFeatureSetInCpuPcd (\r
1316 (UINT8 *)PcdGetPtr (PcdCpuFeaturesSetting),\r
1317 PcdGetSize (PcdCpuFeaturesSetting),\r
1318 Feature\r
1319 );\r
1320}\r
1321\r
80c4b236
JF
1322/**\r
1323 Switches to assigned BSP after CPU features initialization.\r
1324\r
1325 @param[in] ProcessorNumber The index of the CPU executing this function.\r
1326\r
1327 @note This service could be called by BSP only.\r
1328**/\r
1329VOID\r
1330EFIAPI\r
1331SwitchBspAfterFeaturesInitialize (\r
053e878b 1332 IN UINTN ProcessorNumber\r
80c4b236
JF
1333 )\r
1334{\r
053e878b 1335 CPU_FEATURES_DATA *CpuFeaturesData;\r
80c4b236 1336\r
053e878b 1337 CpuFeaturesData = GetCpuFeaturesData ();\r
80c4b236
JF
1338 CpuFeaturesData->BspNumber = ProcessorNumber;\r
1339}\r