]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
CommitLineData
3e8ad6bd
JF
1/** @file\r
2 CPU MP Initialize Library common functions.\r
3\r
d1abb876 4 Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>\r
4c0f6e34
LD
5 Copyright (c) 2020, AMD Inc. All rights reserved.<BR>\r
6\r
0acd8697 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
3e8ad6bd
JF
8\r
9**/\r
10\r
11#include "MpLib.h"\r
a89f558d 12#include <Library/CcExitLib.h>\r
7b7508ad
TL
13#include <Register/Amd/Fam17Msr.h>\r
14#include <Register/Amd/Ghcb.h>\r
3e8ad6bd 15\r
053e878b 16EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;\r
4c0f6e34 17\r
d1abb876
ZL
18/**\r
19 Save the volatile registers required to be restored following INIT IPI.\r
20\r
21 @param[out] VolatileRegisters Returns buffer saved the volatile resisters\r
22**/\r
23VOID\r
24SaveVolatileRegisters (\r
25 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters\r
26 );\r
27\r
28/**\r
29 Restore the volatile registers following INIT IPI.\r
30\r
31 @param[in] VolatileRegisters Pointer to volatile resisters\r
32 @param[in] IsRestoreDr TRUE: Restore DRx if supported\r
33 FALSE: Do not restore DRx\r
34**/\r
35VOID\r
36RestoreVolatileRegisters (\r
37 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,\r
38 IN BOOLEAN IsRestoreDr\r
39 );\r
40\r
7c3f2a12
JF
41/**\r
42 The function will check if BSP Execute Disable is enabled.\r
844b2d07
JF
43\r
44 DxeIpl may have enabled Execute Disable for BSP, APs need to\r
45 get the status and sync up the settings.\r
46 If BSP's CR0.Paging is not set, BSP execute Disble feature is\r
47 not working actually.\r
7c3f2a12
JF
48\r
49 @retval TRUE BSP Execute Disable is enabled.\r
50 @retval FALSE BSP Execute Disable is not enabled.\r
51**/\r
52BOOLEAN\r
53IsBspExecuteDisableEnabled (\r
54 VOID\r
55 )\r
56{\r
57 UINT32 Eax;\r
58 CPUID_EXTENDED_CPU_SIG_EDX Edx;\r
59 MSR_IA32_EFER_REGISTER EferMsr;\r
60 BOOLEAN Enabled;\r
844b2d07 61 IA32_CR0 Cr0;\r
7c3f2a12 62\r
053e878b 63 Enabled = FALSE;\r
844b2d07
JF
64 Cr0.UintN = AsmReadCr0 ();\r
65 if (Cr0.Bits.PG != 0) {\r
7c3f2a12 66 //\r
844b2d07 67 // If CR0 Paging bit is set\r
7c3f2a12 68 //\r
844b2d07
JF
69 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);\r
70 if (Eax >= CPUID_EXTENDED_CPU_SIG) {\r
71 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);\r
7c3f2a12 72 //\r
844b2d07
JF
73 // CPUID 0x80000001\r
74 // Bit 20: Execute Disable Bit available.\r
7c3f2a12 75 //\r
844b2d07
JF
76 if (Edx.Bits.NX != 0) {\r
77 EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);\r
78 //\r
79 // MSR 0xC0000080\r
80 // Bit 11: Execute Disable Bit enable.\r
81 //\r
82 if (EferMsr.Bits.NXE != 0) {\r
83 Enabled = TRUE;\r
84 }\r
7c3f2a12
JF
85 }\r
86 }\r
87 }\r
88\r
89 return Enabled;\r
90}\r
91\r
41be0da5
JF
92/**\r
93 Worker function for SwitchBSP().\r
94\r
95 Worker function for SwitchBSP(), assigned to the AP which is intended\r
96 to become BSP.\r
97\r
98 @param[in] Buffer Pointer to CPU MP Data\r
99**/\r
100VOID\r
101EFIAPI\r
102FutureBSPProc (\r
053e878b 103 IN VOID *Buffer\r
41be0da5
JF
104 )\r
105{\r
053e878b 106 CPU_MP_DATA *DataInHob;\r
41be0da5 107\r
053e878b 108 DataInHob = (CPU_MP_DATA *)Buffer;\r
d1abb876
ZL
109 //\r
110 // Save and restore volatile registers when switch BSP\r
111 //\r
112 SaveVolatileRegisters (&DataInHob->APInfo.VolatileRegisters);\r
41be0da5 113 AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);\r
d1abb876 114 RestoreVolatileRegisters (&DataInHob->APInfo.VolatileRegisters, FALSE);\r
41be0da5
JF
115}\r
116\r
03a1a925
JF
117/**\r
118 Get the Application Processors state.\r
119\r
120 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
121\r
122 @return The AP status\r
123**/\r
124CPU_STATE\r
125GetApState (\r
053e878b 126 IN CPU_AP_DATA *CpuData\r
03a1a925
JF
127 )\r
128{\r
129 return CpuData->State;\r
130}\r
131\r
132/**\r
133 Set the Application Processors state.\r
134\r
135 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
136 @param[in] State The AP status\r
137**/\r
138VOID\r
139SetApState (\r
053e878b
MK
140 IN CPU_AP_DATA *CpuData,\r
141 IN CPU_STATE State\r
03a1a925
JF
142 )\r
143{\r
144 AcquireSpinLock (&CpuData->ApLock);\r
145 CpuData->State = State;\r
146 ReleaseSpinLock (&CpuData->ApLock);\r
147}\r
3e8ad6bd 148\r
ffab2442 149/**\r
f70174d6 150 Save BSP's local APIC timer setting.\r
ffab2442
JF
151\r
152 @param[in] CpuMpData Pointer to CPU MP Data\r
153**/\r
154VOID\r
155SaveLocalApicTimerSetting (\r
053e878b 156 IN CPU_MP_DATA *CpuMpData\r
ffab2442
JF
157 )\r
158{\r
159 //\r
160 // Record the current local APIC timer setting of BSP\r
161 //\r
162 GetApicTimerState (\r
163 &CpuMpData->DivideValue,\r
164 &CpuMpData->PeriodicMode,\r
165 &CpuMpData->Vector\r
166 );\r
167 CpuMpData->CurrentTimerCount = GetApicTimerCurrentCount ();\r
168 CpuMpData->TimerInterruptState = GetApicTimerInterruptState ();\r
169}\r
170\r
171/**\r
172 Sync local APIC timer setting from BSP to AP.\r
173\r
174 @param[in] CpuMpData Pointer to CPU MP Data\r
175**/\r
176VOID\r
177SyncLocalApicTimerSetting (\r
053e878b 178 IN CPU_MP_DATA *CpuMpData\r
ffab2442
JF
179 )\r
180{\r
181 //\r
182 // Sync local APIC timer setting from BSP to AP\r
183 //\r
184 InitializeApicTimer (\r
185 CpuMpData->DivideValue,\r
186 CpuMpData->CurrentTimerCount,\r
187 CpuMpData->PeriodicMode,\r
188 CpuMpData->Vector\r
189 );\r
190 //\r
191 // Disable AP's local APIC timer interrupt\r
192 //\r
193 DisableApicTimerInterrupt ();\r
194}\r
195\r
68cb9330
JF
196/**\r
197 Save the volatile registers required to be restored following INIT IPI.\r
198\r
199 @param[out] VolatileRegisters Returns buffer saved the volatile resisters\r
200**/\r
201VOID\r
202SaveVolatileRegisters (\r
053e878b 203 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters\r
68cb9330
JF
204 )\r
205{\r
053e878b 206 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
68cb9330
JF
207\r
208 VolatileRegisters->Cr0 = AsmReadCr0 ();\r
209 VolatileRegisters->Cr3 = AsmReadCr3 ();\r
210 VolatileRegisters->Cr4 = AsmReadCr4 ();\r
211\r
212 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
213 if (VersionInfoEdx.Bits.DE != 0) {\r
214 //\r
215 // If processor supports Debugging Extensions feature\r
216 // by CPUID.[EAX=01H]:EDX.BIT2\r
217 //\r
218 VolatileRegisters->Dr0 = AsmReadDr0 ();\r
219 VolatileRegisters->Dr1 = AsmReadDr1 ();\r
220 VolatileRegisters->Dr2 = AsmReadDr2 ();\r
221 VolatileRegisters->Dr3 = AsmReadDr3 ();\r
222 VolatileRegisters->Dr6 = AsmReadDr6 ();\r
223 VolatileRegisters->Dr7 = AsmReadDr7 ();\r
224 }\r
e9415e48
JW
225\r
226 AsmReadGdtr (&VolatileRegisters->Gdtr);\r
227 AsmReadIdtr (&VolatileRegisters->Idtr);\r
228 VolatileRegisters->Tr = AsmReadTr ();\r
68cb9330
JF
229}\r
230\r
231/**\r
232 Restore the volatile registers following INIT IPI.\r
233\r
234 @param[in] VolatileRegisters Pointer to volatile resisters\r
235 @param[in] IsRestoreDr TRUE: Restore DRx if supported\r
236 FALSE: Do not restore DRx\r
237**/\r
238VOID\r
239RestoreVolatileRegisters (\r
053e878b
MK
240 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,\r
241 IN BOOLEAN IsRestoreDr\r
68cb9330
JF
242 )\r
243{\r
053e878b
MK
244 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
245 IA32_TSS_DESCRIPTOR *Tss;\r
68cb9330 246\r
68cb9330
JF
247 AsmWriteCr3 (VolatileRegisters->Cr3);\r
248 AsmWriteCr4 (VolatileRegisters->Cr4);\r
e09b6b59 249 AsmWriteCr0 (VolatileRegisters->Cr0);\r
68cb9330
JF
250\r
251 if (IsRestoreDr) {\r
252 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
253 if (VersionInfoEdx.Bits.DE != 0) {\r
254 //\r
255 // If processor supports Debugging Extensions feature\r
256 // by CPUID.[EAX=01H]:EDX.BIT2\r
257 //\r
258 AsmWriteDr0 (VolatileRegisters->Dr0);\r
259 AsmWriteDr1 (VolatileRegisters->Dr1);\r
260 AsmWriteDr2 (VolatileRegisters->Dr2);\r
261 AsmWriteDr3 (VolatileRegisters->Dr3);\r
262 AsmWriteDr6 (VolatileRegisters->Dr6);\r
263 AsmWriteDr7 (VolatileRegisters->Dr7);\r
264 }\r
265 }\r
e9415e48
JW
266\r
267 AsmWriteGdtr (&VolatileRegisters->Gdtr);\r
268 AsmWriteIdtr (&VolatileRegisters->Idtr);\r
053e878b
MK
269 if ((VolatileRegisters->Tr != 0) &&\r
270 (VolatileRegisters->Tr < VolatileRegisters->Gdtr.Limit))\r
271 {\r
e9415e48
JW
272 Tss = (IA32_TSS_DESCRIPTOR *)(VolatileRegisters->Gdtr.Base +\r
273 VolatileRegisters->Tr);\r
d69ba6a7 274 if (Tss->Bits.P == 1) {\r
e9415e48
JW
275 Tss->Bits.Type &= 0xD; // 1101 - Clear busy bit just in case\r
276 AsmWriteTr (VolatileRegisters->Tr);\r
277 }\r
278 }\r
68cb9330
JF
279}\r
280\r
9ebcf0f4
JF
281/**\r
282 Detect whether Mwait-monitor feature is supported.\r
283\r
284 @retval TRUE Mwait-monitor feature is supported.\r
285 @retval FALSE Mwait-monitor feature is not supported.\r
286**/\r
287BOOLEAN\r
288IsMwaitSupport (\r
289 VOID\r
290 )\r
291{\r
053e878b 292 CPUID_VERSION_INFO_ECX VersionInfoEcx;\r
9ebcf0f4
JF
293\r
294 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);\r
295 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;\r
296}\r
297\r
298/**\r
299 Get AP loop mode.\r
300\r
301 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.\r
302\r
303 @return The AP loop mode.\r
304**/\r
305UINT8\r
306GetApLoopMode (\r
053e878b 307 OUT UINT32 *MonitorFilterSize\r
9ebcf0f4
JF
308 )\r
309{\r
053e878b
MK
310 UINT8 ApLoopMode;\r
311 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;\r
9ebcf0f4
JF
312\r
313 ASSERT (MonitorFilterSize != NULL);\r
314\r
315 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
316 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);\r
317 if (ApLoopMode == ApInMwaitLoop) {\r
318 if (!IsMwaitSupport ()) {\r
319 //\r
320 // If processor does not support MONITOR/MWAIT feature,\r
321 // force AP in Hlt-loop mode\r
322 //\r
323 ApLoopMode = ApInHltLoop;\r
324 }\r
7b7508ad 325\r
06544455
TL
326 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&\r
327 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))\r
328 {\r
7b7508ad 329 //\r
06544455
TL
330 // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop\r
331 // mode in order to use the GHCB protocol for starting APs\r
7b7508ad
TL
332 //\r
333 ApLoopMode = ApInHltLoop;\r
334 }\r
9ebcf0f4
JF
335 }\r
336\r
337 if (ApLoopMode != ApInMwaitLoop) {\r
338 *MonitorFilterSize = sizeof (UINT32);\r
339 } else {\r
340 //\r
341 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes\r
342 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT\r
343 //\r
344 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);\r
345 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;\r
346 }\r
347\r
348 return ApLoopMode;\r
349}\r
b8b04307 350\r
8a2d564b
JF
351/**\r
352 Sort the APIC ID of all processors.\r
353\r
354 This function sorts the APIC ID of all processors so that processor number is\r
355 assigned in the ascending order of APIC ID which eases MP debugging.\r
356\r
357 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
358**/\r
359VOID\r
360SortApicId (\r
053e878b 361 IN CPU_MP_DATA *CpuMpData\r
8a2d564b
JF
362 )\r
363{\r
053e878b
MK
364 UINTN Index1;\r
365 UINTN Index2;\r
366 UINTN Index3;\r
367 UINT32 ApicId;\r
368 CPU_INFO_IN_HOB CpuInfo;\r
369 UINT32 ApCount;\r
370 CPU_INFO_IN_HOB *CpuInfoInHob;\r
371 volatile UINT32 *StartupApSignal;\r
372\r
373 ApCount = CpuMpData->CpuCount - 1;\r
374 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
8a2d564b
JF
375 if (ApCount != 0) {\r
376 for (Index1 = 0; Index1 < ApCount; Index1++) {\r
377 Index3 = Index1;\r
378 //\r
379 // Sort key is the hardware default APIC ID\r
380 //\r
31a1e4da 381 ApicId = CpuInfoInHob[Index1].ApicId;\r
8a2d564b 382 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {\r
31a1e4da 383 if (ApicId > CpuInfoInHob[Index2].ApicId) {\r
8a2d564b 384 Index3 = Index2;\r
31a1e4da 385 ApicId = CpuInfoInHob[Index2].ApicId;\r
8a2d564b
JF
386 }\r
387 }\r
053e878b 388\r
8a2d564b 389 if (Index3 != Index1) {\r
31a1e4da 390 CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof (CPU_INFO_IN_HOB));\r
8a2d564b 391 CopyMem (\r
31a1e4da
JF
392 &CpuInfoInHob[Index3],\r
393 &CpuInfoInHob[Index1],\r
394 sizeof (CPU_INFO_IN_HOB)\r
8a2d564b 395 );\r
31a1e4da 396 CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));\r
bafa76ef
SZ
397\r
398 //\r
399 // Also exchange the StartupApSignal.\r
400 //\r
053e878b 401 StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal;\r
bafa76ef
SZ
402 CpuMpData->CpuData[Index3].StartupApSignal =\r
403 CpuMpData->CpuData[Index1].StartupApSignal;\r
404 CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;\r
8a2d564b
JF
405 }\r
406 }\r
407\r
408 //\r
409 // Get the processor number for the BSP\r
410 //\r
411 ApicId = GetInitialApicId ();\r
412 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {\r
31a1e4da 413 if (CpuInfoInHob[Index1].ApicId == ApicId) {\r
053e878b 414 CpuMpData->BspNumber = (UINT32)Index1;\r
8a2d564b
JF
415 break;\r
416 }\r
417 }\r
8a2d564b
JF
418 }\r
419}\r
420\r
fe627769
JF
421/**\r
422 Enable x2APIC mode on APs.\r
423\r
424 @param[in, out] Buffer Pointer to private data buffer.\r
425**/\r
426VOID\r
427EFIAPI\r
428ApFuncEnableX2Apic (\r
429 IN OUT VOID *Buffer\r
430 )\r
431{\r
432 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
433}\r
434\r
b8b04307
JF
435/**\r
436 Do sync on APs.\r
437\r
438 @param[in, out] Buffer Pointer to private data buffer.\r
439**/\r
440VOID\r
441EFIAPI\r
442ApInitializeSync (\r
443 IN OUT VOID *Buffer\r
444 )\r
445{\r
446 CPU_MP_DATA *CpuMpData;\r
e1ed5573
HW
447 UINTN ProcessorNumber;\r
448 EFI_STATUS Status;\r
b8b04307 449\r
053e878b
MK
450 CpuMpData = (CPU_MP_DATA *)Buffer;\r
451 Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
e1ed5573 452 ASSERT_EFI_ERROR (Status);\r
b8b04307 453 //\r
b8b04307
JF
454 // Load microcode on AP\r
455 //\r
e1ed5573 456 MicrocodeDetect (CpuMpData, ProcessorNumber);\r
cb811673
JF
457 //\r
458 // Sync BSP's MTRR table to AP\r
459 //\r
460 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
b8b04307
JF
461}\r
462\r
463/**\r
464 Find the current Processor number by APIC ID.\r
465\r
367284e7
DB
466 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
467 @param[out] ProcessorNumber Return the pocessor number found\r
b8b04307
JF
468\r
469 @retval EFI_SUCCESS ProcessorNumber is found and returned.\r
470 @retval EFI_NOT_FOUND ProcessorNumber is not found.\r
471**/\r
472EFI_STATUS\r
473GetProcessorNumber (\r
053e878b
MK
474 IN CPU_MP_DATA *CpuMpData,\r
475 OUT UINTN *ProcessorNumber\r
b8b04307
JF
476 )\r
477{\r
053e878b
MK
478 UINTN TotalProcessorNumber;\r
479 UINTN Index;\r
480 CPU_INFO_IN_HOB *CpuInfoInHob;\r
481 UINT32 CurrentApicId;\r
31a1e4da 482\r
053e878b 483 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
b8b04307
JF
484\r
485 TotalProcessorNumber = CpuMpData->CpuCount;\r
053e878b
MK
486 CurrentApicId = GetApicId ();\r
487 for (Index = 0; Index < TotalProcessorNumber; Index++) {\r
e52838d3 488 if (CpuInfoInHob[Index].ApicId == CurrentApicId) {\r
b8b04307
JF
489 *ProcessorNumber = Index;\r
490 return EFI_SUCCESS;\r
491 }\r
492 }\r
e52838d3 493\r
b8b04307
JF
494 return EFI_NOT_FOUND;\r
495}\r
496\r
03434dff
JF
497/**\r
498 This function will get CPU count in the system.\r
499\r
500 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
501\r
502 @return CPU count detected\r
503**/\r
504UINTN\r
505CollectProcessorCount (\r
053e878b 506 IN CPU_MP_DATA *CpuMpData\r
03434dff
JF
507 )\r
508{\r
053e878b
MK
509 UINTN Index;\r
510 CPU_INFO_IN_HOB *CpuInfoInHob;\r
511 BOOLEAN X2Apic;\r
59a119f0 512\r
03434dff
JF
513 //\r
514 // Send 1st broadcast IPI to APs to wakeup APs\r
515 //\r
fe3ca5fd 516 CpuMpData->InitFlag = ApInitConfig;\r
cf4e79e4 517 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE);\r
03434dff 518 CpuMpData->InitFlag = ApInitDone;\r
03434dff 519 //\r
c6be6dab
RN
520 // When InitFlag == ApInitConfig, WakeUpAP () guarantees all APs are checked in.\r
521 // FinishedCount is the number of check-in APs.\r
03434dff 522 //\r
c6be6dab
RN
523 CpuMpData->CpuCount = CpuMpData->FinishedCount + 1;\r
524 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
9c33f16f 525\r
54d1e76f
RN
526 //\r
527 // Enable x2APIC mode if\r
528 // 1. Number of CPU is greater than 255; or\r
529 // 2. There are any logical processors reporting an Initial APIC ID of 255 or greater.\r
530 //\r
fe3ca5fd 531 X2Apic = FALSE;\r
71d8226a
JF
532 if (CpuMpData->CpuCount > 255) {\r
533 //\r
534 // If there are more than 255 processor found, force to enable X2APIC\r
535 //\r
fe3ca5fd 536 X2Apic = TRUE;\r
54d1e76f 537 } else {\r
053e878b 538 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
54d1e76f
RN
539 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
540 if (CpuInfoInHob[Index].InitialApicId >= 0xFF) {\r
fe3ca5fd 541 X2Apic = TRUE;\r
54d1e76f
RN
542 break;\r
543 }\r
544 }\r
71d8226a 545 }\r
54d1e76f 546\r
fe3ca5fd 547 if (X2Apic) {\r
fe627769
JF
548 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));\r
549 //\r
550 // Wakeup all APs to enable x2APIC mode\r
551 //\r
cf4e79e4 552 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL, TRUE);\r
fe627769
JF
553 //\r
554 // Wait for all known APs finished\r
555 //\r
556 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
557 CpuPause ();\r
558 }\r
053e878b 559\r
fe627769
JF
560 //\r
561 // Enable x2APIC on BSP\r
562 //\r
563 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
59a119f0
JF
564 //\r
565 // Set BSP/Aps state to IDLE\r
566 //\r
567 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
568 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
569 }\r
fe627769 570 }\r
053e878b 571\r
fe627769 572 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
8a2d564b
JF
573 //\r
574 // Sort BSP/Aps by CPU APIC ID in ascending order\r
575 //\r
576 SortApicId (CpuMpData);\r
577\r
03434dff
JF
578 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));\r
579\r
580 return CpuMpData->CpuCount;\r
581}\r
582\r
367284e7 583/**\r
03a1a925
JF
584 Initialize CPU AP Data when AP is wakeup at the first time.\r
585\r
586 @param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
587 @param[in] ProcessorNumber The handle number of processor\r
588 @param[in] BistData Processor BIST data\r
367284e7 589 @param[in] ApTopOfStack Top of AP stack\r
03a1a925
JF
590\r
591**/\r
592VOID\r
593InitializeApData (\r
053e878b
MK
594 IN OUT CPU_MP_DATA *CpuMpData,\r
595 IN UINTN ProcessorNumber,\r
596 IN UINT32 BistData,\r
597 IN UINT64 ApTopOfStack\r
03a1a925
JF
598 )\r
599{\r
053e878b
MK
600 CPU_INFO_IN_HOB *CpuInfoInHob;\r
601 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;\r
9ab2b34d 602 AP_STACK_DATA *ApStackData;\r
31a1e4da 603\r
053e878b 604 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
31a1e4da
JF
605 CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
606 CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();\r
607 CpuInfoInHob[ProcessorNumber].Health = BistData;\r
dd3fa0cd 608 CpuInfoInHob[ProcessorNumber].ApTopOfStack = ApTopOfStack;\r
31a1e4da 609\r
9ab2b34d
YX
610 //\r
611 // AP_STACK_DATA is stored at the top of AP Stack\r
612 //\r
613 ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack - sizeof (AP_STACK_DATA));\r
614 ApStackData->MpData = CpuMpData;\r
615\r
03a1a925 616 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
03a1a925 617 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
03a1a925 618\r
4c0f6e34
LD
619 //\r
620 // NOTE: PlatformId is not relevant on AMD platforms.\r
621 //\r
622 if (!StandardSignatureIsAuthenticAMD ()) {\r
053e878b 623 PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
4c0f6e34
LD
624 CpuMpData->CpuData[ProcessorNumber].PlatformId = (UINT8)PlatformIdMsr.Bits.PlatformId;\r
625 }\r
999463c8
HW
626\r
627 AsmCpuid (\r
628 CPUID_VERSION_INFO,\r
629 &CpuMpData->CpuData[ProcessorNumber].ProcessorSignature,\r
630 NULL,\r
631 NULL,\r
632 NULL\r
633 );\r
634\r
053e878b 635 InitializeSpinLock (&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
03a1a925
JF
636 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
637}\r
638\r
b8b04307
JF
639/**\r
640 This function will be called from AP reset code if BSP uses WakeUpAP.\r
641\r
642 @param[in] ExchangeInfo Pointer to the MP exchange info buffer\r
9fcea114 643 @param[in] ApIndex Number of current executing AP\r
b8b04307
JF
644**/\r
645VOID\r
646EFIAPI\r
647ApWakeupFunction (\r
053e878b
MK
648 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
649 IN UINTN ApIndex\r
b8b04307
JF
650 )\r
651{\r
053e878b
MK
652 CPU_MP_DATA *CpuMpData;\r
653 UINTN ProcessorNumber;\r
654 EFI_AP_PROCEDURE Procedure;\r
655 VOID *Parameter;\r
656 UINT32 BistData;\r
657 volatile UINT32 *ApStartupSignalBuffer;\r
658 CPU_INFO_IN_HOB *CpuInfoInHob;\r
659 UINT64 ApTopOfStack;\r
660 UINTN CurrentApicMode;\r
9ab2b34d 661 AP_STACK_DATA *ApStackData;\r
b8b04307
JF
662\r
663 //\r
664 // AP finished assembly code and begin to execute C code\r
665 //\r
666 CpuMpData = ExchangeInfo->CpuMpData;\r
667\r
ffab2442
JF
668 //\r
669 // AP's local APIC settings will be lost after received INIT IPI\r
670 // We need to re-initialize them at here\r
671 //\r
672 ProgramVirtualWireMode ();\r
a2ea6894
RN
673 //\r
674 // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.\r
675 //\r
676 DisableLvtInterrupts ();\r
ffab2442 677 SyncLocalApicTimerSetting (CpuMpData);\r
b8b04307 678\r
c6b0feb3 679 CurrentApicMode = GetApicMode ();\r
b8b04307
JF
680 while (TRUE) {\r
681 if (CpuMpData->InitFlag == ApInitConfig) {\r
37676b9f 682 ProcessorNumber = ApIndex;\r
b8b04307
JF
683 //\r
684 // This is first time AP wakeup, get BIST information from AP stack\r
685 //\r
053e878b 686 ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;\r
9ab2b34d
YX
687 ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack - sizeof (AP_STACK_DATA));\r
688 BistData = (UINT32)ApStackData->Bist;\r
689\r
b8b04307 690 //\r
c563077a
RN
691 // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,\r
692 // to initialize AP in InitConfig path.\r
693 // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs.\r
b8b04307
JF
694 //\r
695 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
845c5be1 696 InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);\r
b8b04307
JF
697 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
698 } else {\r
699 //\r
700 // Execute AP function if AP is ready\r
701 //\r
702 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
703 //\r
704 // Clear AP start-up signal when AP waken up\r
705 //\r
706 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
707 InterlockedCompareExchange32 (\r
053e878b 708 (UINT32 *)ApStartupSignalBuffer,\r
b8b04307
JF
709 WAKEUP_AP_SIGNAL,\r
710 0\r
711 );\r
052aa07d
ED
712\r
713 if (CpuMpData->InitFlag == ApInitReconfig) {\r
199de896 714 //\r
052aa07d
ED
715 // ApInitReconfig happens when:\r
716 // 1. AP is re-enabled after it's disabled, in either PEI or DXE phase.\r
717 // 2. AP is initialized in DXE phase.\r
718 // In either case, use the volatile registers value derived from BSP.\r
719 // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a\r
720 // different IDT shared by all APs.\r
199de896 721 //\r
052aa07d 722 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
053e878b 723 } else {\r
052aa07d
ED
724 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
725 //\r
726 // Restore AP's volatile registers saved before AP is halted\r
727 //\r
728 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
729 } else {\r
730 //\r
731 // The CPU driver might not flush TLB for APs on spot after updating\r
732 // page attributes. AP in mwait loop mode needs to take care of it when\r
733 // woken up.\r
734 //\r
735 CpuFlushTlb ();\r
736 }\r
b8b04307
JF
737 }\r
738\r
739 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
740 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;\r
053e878b 741 Parameter = (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;\r
b8b04307
JF
742 if (Procedure != NULL) {\r
743 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
744 //\r
43c9fdcc 745 // Enable source debugging on AP function\r
7367cc6c 746 //\r
43c9fdcc
JF
747 EnableDebugAgent ();\r
748 //\r
b8b04307
JF
749 // Invoke AP function here\r
750 //\r
751 Procedure (Parameter);\r
053e878b 752 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
41be0da5
JF
753 if (CpuMpData->SwitchBspFlag) {\r
754 //\r
755 // Re-get the processor number due to BSP/AP maybe exchange in AP function\r
756 //\r
757 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
053e878b 758 CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;\r
41be0da5 759 CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;\r
053e878b
MK
760 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
761 CpuInfoInHob[ProcessorNumber].ApTopOfStack = CpuInfoInHob[CpuMpData->NewBspNumber].ApTopOfStack;\r
41be0da5 762 } else {\r
053e878b
MK
763 if ((CpuInfoInHob[ProcessorNumber].ApicId != GetApicId ()) ||\r
764 (CpuInfoInHob[ProcessorNumber].InitialApicId != GetInitialApicId ()))\r
765 {\r
c6b0feb3
JF
766 if (CurrentApicMode != GetApicMode ()) {\r
767 //\r
768 // If APIC mode change happened during AP function execution,\r
769 // we do not support APIC ID value changed.\r
770 //\r
771 ASSERT (FALSE);\r
772 CpuDeadLoop ();\r
773 } else {\r
774 //\r
775 // Re-get the CPU APICID and Initial APICID if they are changed\r
776 //\r
777 CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();\r
778 CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
779 }\r
780 }\r
41be0da5 781 }\r
b8b04307 782 }\r
053e878b 783\r
e048ce88 784 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
b8b04307
JF
785 }\r
786 }\r
787\r
1c5c7bcd
MK
788 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
789 //\r
790 // Save AP volatile registers\r
791 //\r
792 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
793 }\r
794\r
b8b04307
JF
795 //\r
796 // AP finished executing C code\r
797 //\r
053e878b 798 InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount);\r
b8b04307 799\r
1c5c7bcd
MK
800 if (CpuMpData->InitFlag == ApInitConfig) {\r
801 //\r
802 // Delay decrementing the APs executing count when SEV-ES is enabled\r
803 // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly\r
804 // performs another INIT-SIPI-SIPI sequence.\r
805 //\r
06544455 806 if (!CpuMpData->UseSevEsAPMethod) {\r
053e878b 807 InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting);\r
1c5c7bcd
MK
808 }\r
809 }\r
810\r
b8b04307
JF
811 //\r
812 // Place AP is specified loop mode\r
813 //\r
814 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
b8b04307
JF
815 //\r
816 // Place AP in HLT-loop\r
817 //\r
818 while (TRUE) {\r
819 DisableInterrupts ();\r
06544455 820 if (CpuMpData->UseSevEsAPMethod) {\r
e2289d19 821 SevEsPlaceApHlt (CpuMpData);\r
7b7508ad
TL
822 } else {\r
823 CpuSleep ();\r
824 }\r
053e878b 825\r
b8b04307
JF
826 CpuPause ();\r
827 }\r
828 }\r
053e878b 829\r
b8b04307
JF
830 while (TRUE) {\r
831 DisableInterrupts ();\r
832 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
833 //\r
834 // Place AP in MWAIT-loop\r
835 //\r
053e878b 836 AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0);\r
b8b04307
JF
837 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
838 //\r
839 // Check AP start-up signal again.\r
840 // If AP start-up signal is not set, place AP into\r
841 // the specified C-state\r
842 //\r
843 AsmMwait (CpuMpData->ApTargetCState << 4, 0);\r
844 }\r
845 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {\r
846 //\r
847 // Place AP in Run-loop\r
848 //\r
849 CpuPause ();\r
850 } else {\r
851 ASSERT (FALSE);\r
852 }\r
853\r
854 //\r
855 // If AP start-up signal is written, AP is waken up\r
856 // otherwise place AP in loop again\r
857 //\r
858 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
859 break;\r
860 }\r
861 }\r
862 }\r
863}\r
864\r
96f5920d
JF
865/**\r
866 Wait for AP wakeup and write AP start-up signal till AP is waken up.\r
867\r
868 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal\r
869**/\r
870VOID\r
871WaitApWakeup (\r
053e878b 872 IN volatile UINT32 *ApStartupSignalBuffer\r
96f5920d
JF
873 )\r
874{\r
875 //\r
876 // If AP is waken up, StartupApSignal should be cleared.\r
877 // Otherwise, write StartupApSignal again till AP waken up.\r
878 //\r
879 while (InterlockedCompareExchange32 (\r
053e878b
MK
880 (UINT32 *)ApStartupSignalBuffer,\r
881 WAKEUP_AP_SIGNAL,\r
882 WAKEUP_AP_SIGNAL\r
883 ) != 0)\r
884 {\r
96f5920d
JF
885 CpuPause ();\r
886 }\r
887}\r
888\r
283ab943
RN
889/**\r
890 Calculate the size of the reset vector.\r
891\r
892 @param[in] AddressMap The pointer to Address Map structure.\r
893 @param[out] SizeBelow1Mb Return the size of below 1MB memory for AP reset area.\r
894 @param[out] SizeAbove1Mb Return the size of abvoe 1MB memory for AP reset area.\r
895**/\r
896STATIC\r
897VOID\r
898GetApResetVectorSize (\r
899 IN MP_ASSEMBLY_ADDRESS_MAP *AddressMap,\r
900 OUT UINTN *SizeBelow1Mb OPTIONAL,\r
901 OUT UINTN *SizeAbove1Mb OPTIONAL\r
902 )\r
903{\r
904 if (SizeBelow1Mb != NULL) {\r
905 *SizeBelow1Mb = AddressMap->ModeTransitionOffset + sizeof (MP_CPU_EXCHANGE_INFO);\r
906 }\r
907\r
908 if (SizeAbove1Mb != NULL) {\r
909 *SizeAbove1Mb = AddressMap->RendezvousFunnelSize - AddressMap->ModeTransitionOffset;\r
910 }\r
911}\r
912\r
7c3f2a12
JF
913/**\r
914 This function will fill the exchange info structure.\r
915\r
916 @param[in] CpuMpData Pointer to CPU MP Data\r
917\r
918**/\r
919VOID\r
920FillExchangeInfoData (\r
053e878b 921 IN CPU_MP_DATA *CpuMpData\r
7c3f2a12
JF
922 )\r
923{\r
053e878b
MK
924 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
925 UINTN Size;\r
926 IA32_SEGMENT_DESCRIPTOR *Selector;\r
927 IA32_CR4 Cr4;\r
7c3f2a12 928\r
053e878b
MK
929 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
930 ExchangeInfo->StackStart = CpuMpData->Buffer;\r
931 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;\r
932 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;\r
933 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;\r
7c3f2a12 934\r
053e878b
MK
935 ExchangeInfo->CodeSegment = AsmReadCs ();\r
936 ExchangeInfo->DataSegment = AsmReadDs ();\r
7c3f2a12 937\r
053e878b 938 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
7c3f2a12 939\r
053e878b 940 ExchangeInfo->CFunction = (UINTN)ApWakeupFunction;\r
37676b9f 941 ExchangeInfo->ApIndex = 0;\r
0594ec41 942 ExchangeInfo->NumApsExecuting = 0;\r
053e878b
MK
943 ExchangeInfo->InitFlag = (UINTN)CpuMpData->InitFlag;\r
944 ExchangeInfo->CpuInfo = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
7c3f2a12
JF
945 ExchangeInfo->CpuMpData = CpuMpData;\r
946\r
947 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();\r
948\r
3b2928b4
MK
949 ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits;\r
950\r
09f69a87
RN
951 //\r
952 // We can check either CPUID(7).ECX[bit16] or check CR4.LA57[bit12]\r
953 // to determin whether 5-Level Paging is enabled.\r
954 // CPUID(7).ECX[bit16] shows CPU's capability, CR4.LA57[bit12] shows\r
955 // current system setting.\r
956 // Using latter way is simpler because it also eliminates the needs to\r
957 // check whether platform wants to enable it.\r
958 //\r
053e878b
MK
959 Cr4.UintN = AsmReadCr4 ();\r
960 ExchangeInfo->Enable5LevelPaging = (BOOLEAN)(Cr4.Bits.LA57 == 1);\r
09f69a87
RN
961 DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));\r
962\r
9c703bc0
BS
963 ExchangeInfo->SevEsIsEnabled = CpuMpData->SevEsIsEnabled;\r
964 ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;\r
965 ExchangeInfo->GhcbBase = (UINTN)CpuMpData->GhcbBase;\r
7b7508ad 966\r
d4d7c9ad
MR
967 //\r
968 // Populate SEV-ES specific exchange data.\r
969 //\r
970 if (ExchangeInfo->SevSnpIsEnabled) {\r
971 FillExchangeInfoDataSevEs (ExchangeInfo);\r
972 }\r
973\r
7c3f2a12
JF
974 //\r
975 // Get the BSP's data of GDT and IDT\r
976 //\r
053e878b
MK
977 AsmReadGdtr ((IA32_DESCRIPTOR *)&ExchangeInfo->GdtrProfile);\r
978 AsmReadIdtr ((IA32_DESCRIPTOR *)&ExchangeInfo->IdtrProfile);\r
f32bfe6d
JW
979\r
980 //\r
981 // Find a 32-bit code segment\r
982 //\r
983 Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;\r
053e878b 984 Size = ExchangeInfo->GdtrProfile.Limit + 1;\r
f32bfe6d 985 while (Size > 0) {\r
053e878b 986 if ((Selector->Bits.L == 0) && (Selector->Bits.Type >= 8)) {\r
f32bfe6d
JW
987 ExchangeInfo->ModeTransitionSegment =\r
988 (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);\r
989 break;\r
990 }\r
053e878b 991\r
f32bfe6d 992 Selector += 1;\r
053e878b 993 Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);\r
f32bfe6d
JW
994 }\r
995\r
283ab943 996 ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;\r
69dfa8d8
JW
997\r
998 ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +\r
053e878b
MK
999 (UINT32)ExchangeInfo->ModeOffset -\r
1000 (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;\r
69dfa8d8 1001 ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;\r
7c3f2a12
JF
1002}\r
1003\r
6e1987f1
LE
1004/**\r
1005 Helper function that waits until the finished AP count reaches the specified\r
1006 limit, or the specified timeout elapses (whichever comes first).\r
1007\r
1008 @param[in] CpuMpData Pointer to CPU MP Data.\r
1009 @param[in] FinishedApLimit The number of finished APs to wait for.\r
1010 @param[in] TimeLimit The number of microseconds to wait for.\r
1011**/\r
1012VOID\r
1013TimedWaitForApFinish (\r
053e878b
MK
1014 IN CPU_MP_DATA *CpuMpData,\r
1015 IN UINT32 FinishedApLimit,\r
1016 IN UINT32 TimeLimit\r
6e1987f1
LE
1017 );\r
1018\r
a6b3d753
SZ
1019/**\r
1020 Get available system memory below 1MB by specified size.\r
1021\r
1022 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
1023**/\r
1024VOID\r
053e878b
MK
1025BackupAndPrepareWakeupBuffer (\r
1026 IN CPU_MP_DATA *CpuMpData\r
a6b3d753
SZ
1027 )\r
1028{\r
1029 CopyMem (\r
053e878b
MK
1030 (VOID *)CpuMpData->BackupBuffer,\r
1031 (VOID *)CpuMpData->WakeupBuffer,\r
a6b3d753
SZ
1032 CpuMpData->BackupBufferSize\r
1033 );\r
1034 CopyMem (\r
053e878b
MK
1035 (VOID *)CpuMpData->WakeupBuffer,\r
1036 (VOID *)CpuMpData->AddressMap.RendezvousFunnelAddress,\r
283ab943 1037 CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO)\r
a6b3d753
SZ
1038 );\r
1039}\r
1040\r
1041/**\r
1042 Restore wakeup buffer data.\r
1043\r
1044 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
1045**/\r
1046VOID\r
053e878b
MK
1047RestoreWakeupBuffer (\r
1048 IN CPU_MP_DATA *CpuMpData\r
a6b3d753
SZ
1049 )\r
1050{\r
1051 CopyMem (\r
053e878b
MK
1052 (VOID *)CpuMpData->WakeupBuffer,\r
1053 (VOID *)CpuMpData->BackupBuffer,\r
a6b3d753
SZ
1054 CpuMpData->BackupBufferSize\r
1055 );\r
1056}\r
1057\r
1058/**\r
1059 Allocate reset vector buffer.\r
1060\r
1061 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
1062**/\r
1063VOID\r
ccc26975 1064AllocateResetVectorBelow1Mb (\r
053e878b 1065 IN OUT CPU_MP_DATA *CpuMpData\r
a6b3d753
SZ
1066 )\r
1067{\r
053e878b 1068 UINTN ApResetStackSize;\r
a6b3d753 1069\r
053e878b 1070 if (CpuMpData->WakeupBuffer == (UINTN)-1) {\r
ccc26975 1071 CpuMpData->WakeupBuffer = GetWakeupBuffer (CpuMpData->BackupBufferSize);\r
053e878b 1072 CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *)(UINTN)\r
ccc26975
RN
1073 (CpuMpData->WakeupBuffer + CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO));\r
1074 DEBUG ((\r
1075 DEBUG_INFO,\r
1076 "AP Vector: 16-bit = %p/%x, ExchangeInfo = %p/%x\n",\r
1077 CpuMpData->WakeupBuffer,\r
1078 CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO),\r
1079 CpuMpData->MpCpuExchangeInfo,\r
1080 sizeof (MP_CPU_EXCHANGE_INFO)\r
1081 ));\r
7b7508ad 1082 //\r
dbc22a17 1083 // The AP reset stack is only used by SEV-ES guests. Do not allocate it\r
06544455
TL
1084 // if SEV-ES is not enabled. An SEV-SNP guest is also considered\r
1085 // an SEV-ES guest, but uses a different method of AP startup, eliminating\r
1086 // the need for the allocation.\r
7b7508ad 1087 //\r
06544455
TL
1088 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&\r
1089 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))\r
1090 {\r
dbc22a17
TL
1091 //\r
1092 // Stack location is based on ProcessorNumber, so use the total number\r
1093 // of processors for calculating the total stack area.\r
1094 //\r
1095 ApResetStackSize = (AP_RESET_STACK_SIZE *\r
1096 PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
1097\r
1098 //\r
1099 // Invoke GetWakeupBuffer a second time to allocate the stack area\r
1100 // below 1MB. The returned buffer will be page aligned and sized and\r
1101 // below the previously allocated buffer.\r
1102 //\r
1103 CpuMpData->SevEsAPResetStackStart = GetWakeupBuffer (ApResetStackSize);\r
1104\r
1105 //\r
1106 // Check to be sure that the "allocate below" behavior hasn't changed.\r
1107 // This will also catch a failed allocation, as "-1" is returned on\r
1108 // failure.\r
1109 //\r
1110 if (CpuMpData->SevEsAPResetStackStart >= CpuMpData->WakeupBuffer) {\r
1111 DEBUG ((\r
1112 DEBUG_ERROR,\r
1113 "SEV-ES AP reset stack is not below wakeup buffer\n"\r
1114 ));\r
1115\r
1116 ASSERT (FALSE);\r
1117 CpuDeadLoop ();\r
1118 }\r
1119 }\r
a6b3d753 1120 }\r
053e878b 1121\r
a6b3d753
SZ
1122 BackupAndPrepareWakeupBuffer (CpuMpData);\r
1123}\r
1124\r
1125/**\r
1126 Free AP reset vector buffer.\r
1127\r
1128 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
1129**/\r
1130VOID\r
1131FreeResetVector (\r
053e878b 1132 IN CPU_MP_DATA *CpuMpData\r
a6b3d753
SZ
1133 )\r
1134{\r
7b7508ad
TL
1135 //\r
1136 // If SEV-ES is enabled, the reset area is needed for AP parking and\r
1137 // and AP startup in the OS, so the reset area is reserved. Do not\r
1138 // perform the restore as this will overwrite memory which has data\r
1139 // needed by SEV-ES.\r
1140 //\r
06544455 1141 if (!CpuMpData->UseSevEsAPMethod) {\r
7b7508ad
TL
1142 RestoreWakeupBuffer (CpuMpData);\r
1143 }\r
1144}\r
1145\r
96f5920d
JF
1146/**\r
1147 This function will be called by BSP to wakeup AP.\r
1148\r
1149 @param[in] CpuMpData Pointer to CPU MP Data\r
1150 @param[in] Broadcast TRUE: Send broadcast IPI to all APs\r
1151 FALSE: Send IPI to AP by ApicId\r
1152 @param[in] ProcessorNumber The handle number of specified processor\r
1153 @param[in] Procedure The function to be invoked by AP\r
1154 @param[in] ProcedureArgument The argument to be passed into AP function\r
cf4e79e4 1155 @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.\r
96f5920d
JF
1156**/\r
1157VOID\r
1158WakeUpAP (\r
053e878b
MK
1159 IN CPU_MP_DATA *CpuMpData,\r
1160 IN BOOLEAN Broadcast,\r
1161 IN UINTN ProcessorNumber,\r
1162 IN EFI_AP_PROCEDURE Procedure OPTIONAL,\r
1163 IN VOID *ProcedureArgument OPTIONAL,\r
1164 IN BOOLEAN WakeUpDisabledAps\r
96f5920d
JF
1165 )\r
1166{\r
053e878b
MK
1167 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
1168 UINTN Index;\r
1169 CPU_AP_DATA *CpuData;\r
1170 BOOLEAN ResetVectorRequired;\r
1171 CPU_INFO_IN_HOB *CpuInfoInHob;\r
96f5920d
JF
1172\r
1173 CpuMpData->FinishedCount = 0;\r
053e878b 1174 ResetVectorRequired = FALSE;\r
96f5920d 1175\r
58942277 1176 if (CpuMpData->WakeUpByInitSipiSipi ||\r
053e878b
MK
1177 (CpuMpData->InitFlag != ApInitDone))\r
1178 {\r
96f5920d 1179 ResetVectorRequired = TRUE;\r
ccc26975 1180 AllocateResetVectorBelow1Mb (CpuMpData);\r
7b7508ad 1181 AllocateSevEsAPMemory (CpuMpData);\r
96f5920d 1182 FillExchangeInfoData (CpuMpData);\r
ffab2442 1183 SaveLocalApicTimerSetting (CpuMpData);\r
58942277
ED
1184 }\r
1185\r
1186 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
96f5920d
JF
1187 //\r
1188 // Get AP target C-state each time when waking up AP,\r
1189 // for it maybe updated by platform again\r
1190 //\r
1191 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
1192 }\r
1193\r
1194 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
1195\r
1196 if (Broadcast) {\r
1197 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
1198 if (Index != CpuMpData->BspNumber) {\r
1199 CpuData = &CpuMpData->CpuData[Index];\r
cf4e79e4
ED
1200 //\r
1201 // All AP(include disabled AP) will be woke up by INIT-SIPI-SIPI, but\r
e23d9c3e 1202 // the AP procedure will be skipped for disabled AP because AP state\r
cf4e79e4
ED
1203 // is not CpuStateReady.\r
1204 //\r
053e878b 1205 if ((GetApState (CpuData) == CpuStateDisabled) && !WakeUpDisabledAps) {\r
cf4e79e4
ED
1206 continue;\r
1207 }\r
1208\r
053e878b
MK
1209 CpuData->ApFunction = (UINTN)Procedure;\r
1210 CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;\r
96f5920d
JF
1211 SetApState (CpuData, CpuStateReady);\r
1212 if (CpuMpData->InitFlag != ApInitConfig) {\r
053e878b 1213 *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
96f5920d
JF
1214 }\r
1215 }\r
1216 }\r
053e878b 1217\r
96f5920d 1218 if (ResetVectorRequired) {\r
7b7508ad 1219 //\r
06544455 1220 // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by\r
7b7508ad
TL
1221 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address\r
1222 // from the original INIT-SIPI-SIPI.\r
1223 //\r
1224 if (CpuMpData->SevEsIsEnabled) {\r
1225 SetSevEsJumpTable (ExchangeInfo->BufferStart);\r
1226 }\r
1227\r
96f5920d
JF
1228 //\r
1229 // Wakeup all APs\r
06544455
TL
1230 // Must use the INIT-SIPI-SIPI method for initial configuration in\r
1231 // order to obtain the APIC ID.\r
96f5920d 1232 //\r
06544455
TL
1233 if (CpuMpData->SevSnpIsEnabled && (CpuMpData->InitFlag != ApInitConfig)) {\r
1234 SevSnpCreateAP (CpuMpData, -1);\r
1235 } else {\r
1236 SendInitSipiSipiAllExcludingSelf ((UINT32)ExchangeInfo->BufferStart);\r
1237 }\r
96f5920d 1238 }\r
053e878b 1239\r
c1192210 1240 if (CpuMpData->InitFlag == ApInitConfig) {\r
778832bc
LE
1241 if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {\r
1242 //\r
1243 // The AP enumeration algorithm below is suitable only when the\r
1244 // platform can tell us the *exact* boot CPU count in advance.\r
1245 //\r
1246 // The wait below finishes only when the detected AP count reaches\r
1247 // (PcdCpuBootLogicalProcessorNumber - 1), regardless of how long that\r
1248 // takes. If at least one AP fails to check in (meaning a platform\r
1249 // hardware bug), the detection hangs forever, by design. If the actual\r
1250 // boot CPU count in the system is higher than\r
1251 // PcdCpuBootLogicalProcessorNumber (meaning a platform\r
1252 // misconfiguration), then some APs may complete initialization after\r
1253 // the wait finishes, and cause undefined behavior.\r
1254 //\r
1255 TimedWaitForApFinish (\r
1256 CpuMpData,\r
1257 PcdGet32 (PcdCpuBootLogicalProcessorNumber) - 1,\r
1258 MAX_UINT32 // approx. 71 minutes\r
1259 );\r
1260 } else {\r
1261 //\r
1262 // The AP enumeration algorithm below is suitable for two use cases.\r
1263 //\r
1264 // (1) The check-in time for an individual AP is bounded, and APs run\r
1265 // through their initialization routines strongly concurrently. In\r
1266 // particular, the number of concurrently running APs\r
1267 // ("NumApsExecuting") is never expected to fall to zero\r
1268 // *temporarily* -- it is expected to fall to zero only when all\r
1269 // APs have checked-in.\r
1270 //\r
1271 // In this case, the platform is supposed to set\r
1272 // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long\r
1273 // enough for one AP to start initialization). The timeout will be\r
1274 // reached soon, and remaining APs are collected by watching\r
1275 // NumApsExecuting fall to zero. If NumApsExecuting falls to zero\r
1276 // mid-process, while some APs have not completed initialization,\r
1277 // the behavior is undefined.\r
1278 //\r
1279 // (2) The check-in time for an individual AP is unbounded, and/or APs\r
1280 // may complete their initializations widely spread out. In\r
1281 // particular, some APs may finish initialization before some APs\r
1282 // even start.\r
1283 //\r
1284 // In this case, the platform is supposed to set\r
1285 // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP\r
1286 // enumeration will always take that long (except when the boot CPU\r
1287 // count happens to be maximal, that is,\r
1288 // PcdCpuMaxLogicalProcessorNumber). All APs are expected to\r
1289 // check-in before the timeout, and NumApsExecuting is assumed zero\r
1290 // at timeout. APs that miss the time-out may cause undefined\r
1291 // behavior.\r
1292 //\r
1293 TimedWaitForApFinish (\r
1294 CpuMpData,\r
1295 PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,\r
1296 PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)\r
1297 );\r
0594ec41 1298\r
778832bc 1299 while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {\r
053e878b 1300 CpuPause ();\r
778832bc 1301 }\r
0594ec41 1302 }\r
c1192210 1303 } else {\r
96f5920d
JF
1304 //\r
1305 // Wait all APs waken up if this is not the 1st broadcast of SIPI\r
1306 //\r
1307 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
1308 CpuData = &CpuMpData->CpuData[Index];\r
1309 if (Index != CpuMpData->BspNumber) {\r
1310 WaitApWakeup (CpuData->StartupApSignal);\r
1311 }\r
1312 }\r
1313 }\r
1314 } else {\r
053e878b
MK
1315 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1316 CpuData->ApFunction = (UINTN)Procedure;\r
1317 CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;\r
96f5920d
JF
1318 SetApState (CpuData, CpuStateReady);\r
1319 //\r
1320 // Wakeup specified AP\r
1321 //\r
1322 ASSERT (CpuMpData->InitFlag != ApInitConfig);\r
053e878b 1323 *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
96f5920d 1324 if (ResetVectorRequired) {\r
053e878b 1325 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
7b7508ad
TL
1326\r
1327 //\r
06544455 1328 // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by\r
7b7508ad
TL
1329 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address\r
1330 // from the original INIT-SIPI-SIPI.\r
1331 //\r
1332 if (CpuMpData->SevEsIsEnabled) {\r
1333 SetSevEsJumpTable (ExchangeInfo->BufferStart);\r
1334 }\r
1335\r
06544455
TL
1336 if (CpuMpData->SevSnpIsEnabled && (CpuMpData->InitFlag != ApInitConfig)) {\r
1337 SevSnpCreateAP (CpuMpData, (INTN)ProcessorNumber);\r
1338 } else {\r
1339 SendInitSipiSipi (\r
1340 CpuInfoInHob[ProcessorNumber].ApicId,\r
1341 (UINT32)ExchangeInfo->BufferStart\r
1342 );\r
1343 }\r
96f5920d 1344 }\r
053e878b 1345\r
96f5920d
JF
1346 //\r
1347 // Wait specified AP waken up\r
1348 //\r
1349 WaitApWakeup (CpuData->StartupApSignal);\r
1350 }\r
1351\r
1352 if (ResetVectorRequired) {\r
1353 FreeResetVector (CpuMpData);\r
1354 }\r
58942277
ED
1355\r
1356 //\r
1357 // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with\r
1358 // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by\r
1359 // S3SmmInitDone Ppi.\r
1360 //\r
1361 CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);\r
96f5920d
JF
1362}\r
1363\r
08085f08
JF
1364/**\r
1365 Calculate timeout value and return the current performance counter value.\r
1366\r
1367 Calculate the number of performance counter ticks required for a timeout.\r
1368 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
1369 as infinity.\r
1370\r
1371 @param[in] TimeoutInMicroseconds Timeout value in microseconds.\r
1372 @param[out] CurrentTime Returns the current value of the performance counter.\r
1373\r
1374 @return Expected time stamp counter for timeout.\r
1375 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
1376 as infinity.\r
1377\r
1378**/\r
1379UINT64\r
1380CalculateTimeout (\r
1381 IN UINTN TimeoutInMicroseconds,\r
1382 OUT UINT64 *CurrentTime\r
1383 )\r
1384{\r
053e878b
MK
1385 UINT64 TimeoutInSeconds;\r
1386 UINT64 TimestampCounterFreq;\r
48cfb7c0 1387\r
08085f08
JF
1388 //\r
1389 // Read the current value of the performance counter\r
1390 //\r
1391 *CurrentTime = GetPerformanceCounter ();\r
1392\r
1393 //\r
1394 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
1395 // as infinity.\r
1396 //\r
1397 if (TimeoutInMicroseconds == 0) {\r
1398 return 0;\r
1399 }\r
1400\r
1401 //\r
1402 // GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
7367cc6c 1403 // in Hz.\r
48cfb7c0
ED
1404 //\r
1405 TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);\r
1406\r
08085f08 1407 //\r
48cfb7c0
ED
1408 // Check the potential overflow before calculate the number of ticks for the timeout value.\r
1409 //\r
1410 if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {\r
1411 //\r
1412 // Convert microseconds into seconds if direct multiplication overflows\r
1413 //\r
1414 TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);\r
1415 //\r
1416 // Assertion if the final tick count exceeds MAX_UINT64\r
1417 //\r
1418 ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);\r
1419 return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);\r
1420 } else {\r
1421 //\r
1422 // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide\r
1423 // it by 1,000,000, to get the number of ticks for the timeout value.\r
1424 //\r
1425 return DivU64x32 (\r
1426 MultU64x64 (\r
1427 TimestampCounterFreq,\r
1428 TimeoutInMicroseconds\r
1429 ),\r
1430 1000000\r
1431 );\r
1432 }\r
08085f08
JF
1433}\r
1434\r
1435/**\r
1436 Checks whether timeout expires.\r
1437\r
1438 Check whether the number of elapsed performance counter ticks required for\r
1439 a timeout condition has been reached.\r
1440 If Timeout is zero, which means infinity, return value is always FALSE.\r
1441\r
1442 @param[in, out] PreviousTime On input, the value of the performance counter\r
1443 when it was last read.\r
1444 On output, the current value of the performance\r
1445 counter\r
1446 @param[in] TotalTime The total amount of elapsed time in performance\r
1447 counter ticks.\r
1448 @param[in] Timeout The number of performance counter ticks required\r
1449 to reach a timeout condition.\r
1450\r
1451 @retval TRUE A timeout condition has been reached.\r
1452 @retval FALSE A timeout condition has not been reached.\r
1453\r
1454**/\r
1455BOOLEAN\r
1456CheckTimeout (\r
1457 IN OUT UINT64 *PreviousTime,\r
1458 IN UINT64 *TotalTime,\r
1459 IN UINT64 Timeout\r
1460 )\r
1461{\r
1462 UINT64 Start;\r
1463 UINT64 End;\r
1464 UINT64 CurrentTime;\r
1465 INT64 Delta;\r
1466 INT64 Cycle;\r
1467\r
1468 if (Timeout == 0) {\r
1469 return FALSE;\r
1470 }\r
053e878b 1471\r
08085f08
JF
1472 GetPerformanceCounterProperties (&Start, &End);\r
1473 Cycle = End - Start;\r
1474 if (Cycle < 0) {\r
1475 Cycle = -Cycle;\r
1476 }\r
053e878b 1477\r
08085f08 1478 Cycle++;\r
053e878b
MK
1479 CurrentTime = GetPerformanceCounter ();\r
1480 Delta = (INT64)(CurrentTime - *PreviousTime);\r
08085f08
JF
1481 if (Start > End) {\r
1482 Delta = -Delta;\r
1483 }\r
053e878b 1484\r
08085f08
JF
1485 if (Delta < 0) {\r
1486 Delta += Cycle;\r
1487 }\r
053e878b
MK
1488\r
1489 *TotalTime += Delta;\r
08085f08
JF
1490 *PreviousTime = CurrentTime;\r
1491 if (*TotalTime > Timeout) {\r
1492 return TRUE;\r
1493 }\r
053e878b 1494\r
08085f08
JF
1495 return FALSE;\r
1496}\r
1497\r
6e1987f1
LE
1498/**\r
1499 Helper function that waits until the finished AP count reaches the specified\r
1500 limit, or the specified timeout elapses (whichever comes first).\r
1501\r
1502 @param[in] CpuMpData Pointer to CPU MP Data.\r
1503 @param[in] FinishedApLimit The number of finished APs to wait for.\r
1504 @param[in] TimeLimit The number of microseconds to wait for.\r
1505**/\r
1506VOID\r
1507TimedWaitForApFinish (\r
053e878b
MK
1508 IN CPU_MP_DATA *CpuMpData,\r
1509 IN UINT32 FinishedApLimit,\r
1510 IN UINT32 TimeLimit\r
6e1987f1
LE
1511 )\r
1512{\r
1513 //\r
1514 // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0\r
1515 // "infinity", so check for (TimeLimit == 0) explicitly.\r
1516 //\r
1517 if (TimeLimit == 0) {\r
1518 return;\r
1519 }\r
1520\r
053e878b 1521 CpuMpData->TotalTime = 0;\r
6e1987f1
LE
1522 CpuMpData->ExpectedTime = CalculateTimeout (\r
1523 TimeLimit,\r
1524 &CpuMpData->CurrentTime\r
1525 );\r
1526 while (CpuMpData->FinishedCount < FinishedApLimit &&\r
1527 !CheckTimeout (\r
1528 &CpuMpData->CurrentTime,\r
1529 &CpuMpData->TotalTime,\r
1530 CpuMpData->ExpectedTime\r
053e878b
MK
1531 ))\r
1532 {\r
6e1987f1
LE
1533 CpuPause ();\r
1534 }\r
1535\r
1536 if (CpuMpData->FinishedCount >= FinishedApLimit) {\r
1537 DEBUG ((\r
1538 DEBUG_VERBOSE,\r
1539 "%a: reached FinishedApLimit=%u in %Lu microseconds\n",\r
1540 __FUNCTION__,\r
1541 FinishedApLimit,\r
1542 DivU64x64Remainder (\r
1543 MultU64x32 (CpuMpData->TotalTime, 1000000),\r
1544 GetPerformanceCounterProperties (NULL, NULL),\r
1545 NULL\r
1546 )\r
1547 ));\r
1548 }\r
1549}\r
1550\r
08085f08
JF
1551/**\r
1552 Reset an AP to Idle state.\r
1553\r
1554 Any task being executed by the AP will be aborted and the AP\r
1555 will be waiting for a new task in Wait-For-SIPI state.\r
1556\r
1557 @param[in] ProcessorNumber The handle number of processor.\r
1558**/\r
1559VOID\r
1560ResetProcessorToIdleState (\r
053e878b 1561 IN UINTN ProcessorNumber\r
08085f08
JF
1562 )\r
1563{\r
053e878b 1564 CPU_MP_DATA *CpuMpData;\r
08085f08
JF
1565\r
1566 CpuMpData = GetCpuMpData ();\r
1567\r
cb33bde4 1568 CpuMpData->InitFlag = ApInitReconfig;\r
cf4e79e4 1569 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL, TRUE);\r
cb33bde4
JF
1570 while (CpuMpData->FinishedCount < 1) {\r
1571 CpuPause ();\r
1572 }\r
053e878b 1573\r
cb33bde4 1574 CpuMpData->InitFlag = ApInitDone;\r
08085f08
JF
1575\r
1576 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
1577}\r
1578\r
1579/**\r
1580 Searches for the next waiting AP.\r
1581\r
1582 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().\r
1583\r
1584 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.\r
1585\r
1586 @retval EFI_SUCCESS The next waiting AP has been found.\r
1587 @retval EFI_NOT_FOUND No waiting AP exists.\r
1588\r
1589**/\r
1590EFI_STATUS\r
1591GetNextWaitingProcessorNumber (\r
053e878b 1592 OUT UINTN *NextProcessorNumber\r
08085f08
JF
1593 )\r
1594{\r
053e878b
MK
1595 UINTN ProcessorNumber;\r
1596 CPU_MP_DATA *CpuMpData;\r
08085f08
JF
1597\r
1598 CpuMpData = GetCpuMpData ();\r
1599\r
1600 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1601 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1602 *NextProcessorNumber = ProcessorNumber;\r
1603 return EFI_SUCCESS;\r
1604 }\r
1605 }\r
1606\r
1607 return EFI_NOT_FOUND;\r
1608}\r
1609\r
1610/** Checks status of specified AP.\r
1611\r
1612 This function checks whether the specified AP has finished the task assigned\r
1613 by StartupThisAP(), and whether timeout expires.\r
1614\r
1615 @param[in] ProcessorNumber The handle number of processor.\r
1616\r
1617 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().\r
1618 @retval EFI_TIMEOUT The timeout expires.\r
1619 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.\r
1620**/\r
1621EFI_STATUS\r
1622CheckThisAP (\r
053e878b 1623 IN UINTN ProcessorNumber\r
08085f08
JF
1624 )\r
1625{\r
053e878b
MK
1626 CPU_MP_DATA *CpuMpData;\r
1627 CPU_AP_DATA *CpuData;\r
08085f08
JF
1628\r
1629 CpuMpData = GetCpuMpData ();\r
1630 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1631\r
1632 //\r
2a5997f8 1633 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.\r
08085f08 1634 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
2a5997f8 1635 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.\r
08085f08
JF
1636 //\r
1637 //\r
1638 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.\r
1639 //\r
053e878b 1640 if (GetApState (CpuData) == CpuStateFinished) {\r
08085f08
JF
1641 if (CpuData->Finished != NULL) {\r
1642 *(CpuData->Finished) = TRUE;\r
1643 }\r
053e878b 1644\r
e048ce88 1645 SetApState (CpuData, CpuStateIdle);\r
08085f08
JF
1646 return EFI_SUCCESS;\r
1647 } else {\r
1648 //\r
1649 // If timeout expires for StartupThisAP(), report timeout.\r
1650 //\r
1651 if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {\r
1652 if (CpuData->Finished != NULL) {\r
1653 *(CpuData->Finished) = FALSE;\r
1654 }\r
053e878b 1655\r
08085f08
JF
1656 //\r
1657 // Reset failed AP to idle state\r
1658 //\r
1659 ResetProcessorToIdleState (ProcessorNumber);\r
1660\r
1661 return EFI_TIMEOUT;\r
1662 }\r
1663 }\r
053e878b 1664\r
08085f08
JF
1665 return EFI_NOT_READY;\r
1666}\r
1667\r
1668/**\r
1669 Checks status of all APs.\r
1670\r
1671 This function checks whether all APs have finished task assigned by StartupAllAPs(),\r
1672 and whether timeout expires.\r
1673\r
1674 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().\r
1675 @retval EFI_TIMEOUT The timeout expires.\r
1676 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.\r
1677**/\r
1678EFI_STATUS\r
1679CheckAllAPs (\r
1680 VOID\r
1681 )\r
1682{\r
053e878b
MK
1683 UINTN ProcessorNumber;\r
1684 UINTN NextProcessorNumber;\r
1685 UINTN ListIndex;\r
1686 EFI_STATUS Status;\r
1687 CPU_MP_DATA *CpuMpData;\r
1688 CPU_AP_DATA *CpuData;\r
08085f08
JF
1689\r
1690 CpuMpData = GetCpuMpData ();\r
1691\r
1692 NextProcessorNumber = 0;\r
1693\r
1694 //\r
1695 // Go through all APs that are responsible for the StartupAllAPs().\r
1696 //\r
1697 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1698 if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1699 continue;\r
1700 }\r
1701\r
1702 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1703 //\r
2a5997f8 1704 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.\r
08085f08 1705 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
2a5997f8 1706 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.\r
08085f08 1707 //\r
053e878b
MK
1708 if (GetApState (CpuData) == CpuStateFinished) {\r
1709 CpuMpData->RunningCount--;\r
08085f08 1710 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
053e878b 1711 SetApState (CpuData, CpuStateIdle);\r
08085f08
JF
1712\r
1713 //\r
1714 // If in Single Thread mode, then search for the next waiting AP for execution.\r
1715 //\r
1716 if (CpuMpData->SingleThread) {\r
1717 Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);\r
1718\r
1719 if (!EFI_ERROR (Status)) {\r
1720 WakeUpAP (\r
1721 CpuMpData,\r
1722 FALSE,\r
053e878b 1723 (UINT32)NextProcessorNumber,\r
08085f08 1724 CpuMpData->Procedure,\r
cf4e79e4
ED
1725 CpuMpData->ProcArguments,\r
1726 TRUE\r
08085f08 1727 );\r
053e878b 1728 }\r
08085f08
JF
1729 }\r
1730 }\r
1731 }\r
1732\r
1733 //\r
1734 // If all APs finish, return EFI_SUCCESS.\r
1735 //\r
2da3e96c 1736 if (CpuMpData->RunningCount == 0) {\r
08085f08
JF
1737 return EFI_SUCCESS;\r
1738 }\r
1739\r
1740 //\r
1741 // If timeout expires, report timeout.\r
1742 //\r
1743 if (CheckTimeout (\r
053e878b
MK
1744 &CpuMpData->CurrentTime,\r
1745 &CpuMpData->TotalTime,\r
1746 CpuMpData->ExpectedTime\r
1747 )\r
1748 )\r
1749 {\r
08085f08
JF
1750 //\r
1751 // If FailedCpuList is not NULL, record all failed APs in it.\r
1752 //\r
1753 if (CpuMpData->FailedCpuList != NULL) {\r
1754 *CpuMpData->FailedCpuList =\r
053e878b 1755 AllocatePool ((CpuMpData->RunningCount + 1) * sizeof (UINTN));\r
08085f08
JF
1756 ASSERT (*CpuMpData->FailedCpuList != NULL);\r
1757 }\r
053e878b 1758\r
08085f08
JF
1759 ListIndex = 0;\r
1760\r
1761 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1762 //\r
1763 // Check whether this processor is responsible for StartupAllAPs().\r
1764 //\r
1765 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1766 //\r
1767 // Reset failed APs to idle state\r
1768 //\r
1769 ResetProcessorToIdleState (ProcessorNumber);\r
1770 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
1771 if (CpuMpData->FailedCpuList != NULL) {\r
1772 (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;\r
1773 }\r
1774 }\r
1775 }\r
053e878b 1776\r
08085f08
JF
1777 if (CpuMpData->FailedCpuList != NULL) {\r
1778 (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;\r
1779 }\r
053e878b 1780\r
08085f08
JF
1781 return EFI_TIMEOUT;\r
1782 }\r
053e878b 1783\r
08085f08
JF
1784 return EFI_NOT_READY;\r
1785}\r
1786\r
3e8ad6bd
JF
1787/**\r
1788 MP Initialize Library initialization.\r
1789\r
1790 This service will allocate AP reset vector and wakeup all APs to do APs\r
1791 initialization.\r
1792\r
1793 This service must be invoked before all other MP Initialize Library\r
1794 service are invoked.\r
1795\r
1796 @retval EFI_SUCCESS MP initialization succeeds.\r
1797 @retval Others MP initialization fails.\r
1798\r
1799**/\r
1800EFI_STATUS\r
1801EFIAPI\r
1802MpInitLibInitialize (\r
1803 VOID\r
1804 )\r
1805{\r
6a2ee2bb
JF
1806 CPU_MP_DATA *OldCpuMpData;\r
1807 CPU_INFO_IN_HOB *CpuInfoInHob;\r
e59f8f6b
JF
1808 UINT32 MaxLogicalProcessorNumber;\r
1809 UINT32 ApStackSize;\r
f7f85d83 1810 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
c563077a 1811 CPU_VOLATILE_REGISTERS VolatileRegisters;\r
e59f8f6b 1812 UINTN BufferSize;\r
9ebcf0f4 1813 UINT32 MonitorFilterSize;\r
e59f8f6b
JF
1814 VOID *MpBuffer;\r
1815 UINTN Buffer;\r
1816 CPU_MP_DATA *CpuMpData;\r
9ebcf0f4 1817 UINT8 ApLoopMode;\r
e59f8f6b 1818 UINT8 *MonitorBuffer;\r
03a1a925 1819 UINTN Index;\r
283ab943 1820 UINTN ApResetVectorSizeBelow1Mb;\r
ccc26975 1821 UINTN ApResetVectorSizeAbove1Mb;\r
e59f8f6b 1822 UINTN BackupBufferAddr;\r
c563077a 1823 UINTN ApIdtBase;\r
6a2ee2bb
JF
1824\r
1825 OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
1826 if (OldCpuMpData == NULL) {\r
053e878b 1827 MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
6a2ee2bb
JF
1828 } else {\r
1829 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;\r
1830 }\r
053e878b 1831\r
14e8137c 1832 ASSERT (MaxLogicalProcessorNumber != 0);\r
f7f85d83
JF
1833\r
1834 AsmGetAddressMap (&AddressMap);\r
ccc26975
RN
1835 GetApResetVectorSize (&AddressMap, &ApResetVectorSizeBelow1Mb, &ApResetVectorSizeAbove1Mb);\r
1836 ApStackSize = PcdGet32 (PcdCpuApStackSize);\r
9ab2b34d
YX
1837 //\r
1838 // ApStackSize must be power of 2\r
1839 //\r
1840 ASSERT ((ApStackSize & (ApStackSize - 1)) == 0);\r
1841 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
9ebcf0f4 1842\r
c563077a 1843 //\r
e09b6b59 1844 // Save BSP's Control registers for APs.\r
c563077a
RN
1845 //\r
1846 SaveVolatileRegisters (&VolatileRegisters);\r
1847\r
9ab2b34d
YX
1848 BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
1849 //\r
1850 // Allocate extra ApStackSize to let AP stack align on ApStackSize bounday\r
1851 //\r
1852 BufferSize += ApStackSize;\r
e59f8f6b 1853 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
283ab943 1854 BufferSize += ApResetVectorSizeBelow1Mb;\r
c563077a
RN
1855 BufferSize = ALIGN_VALUE (BufferSize, 8);\r
1856 BufferSize += VolatileRegisters.Idtr.Limit + 1;\r
1857 BufferSize += sizeof (CPU_MP_DATA);\r
e59f8f6b
JF
1858 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
1859 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
1860 ASSERT (MpBuffer != NULL);\r
1861 ZeroMem (MpBuffer, BufferSize);\r
9ab2b34d 1862 Buffer = ALIGN_VALUE ((UINTN)MpBuffer, ApStackSize);\r
e59f8f6b 1863\r
c563077a 1864 //\r
9ab2b34d 1865 // The layout of the Buffer is as below (lower address on top):\r
c563077a 1866 //\r
9ab2b34d
YX
1867 // +--------------------+ <-- Buffer (Pointer of CpuMpData is stored in the top of each AP's stack.)\r
1868 // AP Stacks (N) (StackTop = (RSP + ApStackSize) & ~ApStackSize))\r
c563077a
RN
1869 // +--------------------+ <-- MonitorBuffer\r
1870 // AP Monitor Filters (N)\r
1871 // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)\r
1872 // Backup Buffer\r
1873 // +--------------------+\r
1874 // Padding\r
1875 // +--------------------+ <-- ApIdtBase (8-byte boundary)\r
9ab2b34d 1876 // AP IDT All APs share one separate IDT.\r
c563077a
RN
1877 // +--------------------+ <-- CpuMpData\r
1878 // CPU_MP_DATA\r
1879 // +--------------------+ <-- CpuMpData->CpuData\r
1880 // CPU_AP_DATA (N)\r
1881 // +--------------------+ <-- CpuMpData->CpuInfoInHob\r
1882 // CPU_INFO_IN_HOB (N)\r
1883 // +--------------------+\r
1884 //\r
053e878b
MK
1885 MonitorBuffer = (UINT8 *)(Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
1886 BackupBufferAddr = (UINTN)MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
283ab943 1887 ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSizeBelow1Mb, 8);\r
053e878b 1888 CpuMpData = (CPU_MP_DATA *)(ApIdtBase + VolatileRegisters.Idtr.Limit + 1);\r
e59f8f6b
JF
1889 CpuMpData->Buffer = Buffer;\r
1890 CpuMpData->CpuApStackSize = ApStackSize;\r
1891 CpuMpData->BackupBuffer = BackupBufferAddr;\r
283ab943 1892 CpuMpData->BackupBufferSize = ApResetVectorSizeBelow1Mb;\r
053e878b 1893 CpuMpData->WakeupBuffer = (UINTN)-1;\r
e59f8f6b
JF
1894 CpuMpData->CpuCount = 1;\r
1895 CpuMpData->BspNumber = 0;\r
1896 CpuMpData->WaitEvent = NULL;\r
41be0da5 1897 CpuMpData->SwitchBspFlag = FALSE;\r
053e878b
MK
1898 CpuMpData->CpuData = (CPU_AP_DATA *)(CpuMpData + 1);\r
1899 CpuMpData->CpuInfoInHob = (UINT64)(UINTN)(CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
1900 InitializeSpinLock (&CpuMpData->MpLock);\r
06544455
TL
1901 CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);\r
1902 CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevSnp);\r
1903 CpuMpData->SevEsAPBuffer = (UINTN)-1;\r
1904 CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);\r
1905 CpuMpData->UseSevEsAPMethod = CpuMpData->SevEsIsEnabled && !CpuMpData->SevSnpIsEnabled;\r
1906\r
1907 if (CpuMpData->SevSnpIsEnabled) {\r
1908 ASSERT ((PcdGet64 (PcdGhcbHypervisorFeatures) & GHCB_HV_FEATURES_SNP_AP_CREATE) == GHCB_HV_FEATURES_SNP_AP_CREATE);\r
1909 }\r
c563077a
RN
1910\r
1911 //\r
1912 // Make sure no memory usage outside of the allocated buffer.\r
9ab2b34d 1913 // (ApStackSize - (Buffer - (UINTN)MpBuffer)) is the redundant caused by alignment\r
e59f8f6b 1914 //\r
053e878b
MK
1915 ASSERT (\r
1916 (CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==\r
9ab2b34d 1917 (UINTN)MpBuffer + BufferSize - (ApStackSize - Buffer + (UINTN)MpBuffer)\r
053e878b 1918 );\r
c563077a
RN
1919\r
1920 //\r
1921 // Duplicate BSP's IDT to APs.\r
1922 // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1\r
68cb9330 1923 //\r
c563077a
RN
1924 CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);\r
1925 VolatileRegisters.Idtr.Base = ApIdtBase;\r
e09b6b59
JW
1926 //\r
1927 // Don't pass BSP's TR to APs to avoid AP init failure.\r
1928 //\r
1929 VolatileRegisters.Tr = 0;\r
c563077a 1930 CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));\r
68cb9330 1931 //\r
03a1a925
JF
1932 // Set BSP basic information\r
1933 //\r
f2655dcf 1934 InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize);\r
03a1a925 1935 //\r
e59f8f6b
JF
1936 // Save assembly code information\r
1937 //\r
1938 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
1939 //\r
1940 // Finally set AP loop mode\r
1941 //\r
1942 CpuMpData->ApLoopMode = ApLoopMode;\r
1943 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
58942277
ED
1944\r
1945 CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);\r
1946\r
e59f8f6b 1947 //\r
03a1a925
JF
1948 // Set up APs wakeup signal buffer\r
1949 //\r
1950 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
1951 CpuMpData->CpuData[Index].StartupApSignal =\r
1952 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
1953 }\r
053e878b 1954\r
ccc26975
RN
1955 //\r
1956 // Copy all 32-bit code and 64-bit code into memory with type of\r
1957 // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.\r
1958 //\r
1959 CpuMpData->WakeupBufferHigh = AllocateCodeBuffer (ApResetVectorSizeAbove1Mb);\r
1960 CopyMem (\r
1961 (VOID *)CpuMpData->WakeupBufferHigh,\r
1962 CpuMpData->AddressMap.RendezvousFunnelAddress +\r
1963 CpuMpData->AddressMap.ModeTransitionOffset,\r
1964 ApResetVectorSizeAbove1Mb\r
1965 );\r
1966 DEBUG ((DEBUG_INFO, "AP Vector: non-16-bit = %p/%x\n", CpuMpData->WakeupBufferHigh, ApResetVectorSizeAbove1Mb));\r
1967\r
94f63c76 1968 //\r
9d64a9fd
JF
1969 // Enable the local APIC for Virtual Wire Mode.\r
1970 //\r
1971 ProgramVirtualWireMode ();\r
e59f8f6b 1972\r
6a2ee2bb 1973 if (OldCpuMpData == NULL) {\r
14e8137c
JF
1974 if (MaxLogicalProcessorNumber > 1) {\r
1975 //\r
1976 // Wakeup all APs and calculate the processor count in system\r
1977 //\r
1978 CollectProcessorCount (CpuMpData);\r
1979 }\r
6a2ee2bb
JF
1980 } else {\r
1981 //\r
1982 // APs have been wakeup before, just get the CPU Information\r
1983 // from HOB\r
1984 //\r
7b7508ad 1985 OldCpuMpData->NewCpuMpData = CpuMpData;\r
053e878b
MK
1986 CpuMpData->CpuCount = OldCpuMpData->CpuCount;\r
1987 CpuMpData->BspNumber = OldCpuMpData->BspNumber;\r
1988 CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;\r
1989 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
6a2ee2bb 1990 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
053e878b
MK
1991 InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);\r
1992 CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0) ? TRUE : FALSE;\r
6a2ee2bb 1993 CpuMpData->CpuData[Index].ApFunction = 0;\r
6a2ee2bb 1994 }\r
d786a172
HW
1995 }\r
1996\r
348a34d9
HW
1997 if (!GetMicrocodePatchInfoFromHob (\r
1998 &CpuMpData->MicrocodePatchAddress,\r
1999 &CpuMpData->MicrocodePatchRegionSize\r
053e878b
MK
2000 ))\r
2001 {\r
348a34d9
HW
2002 //\r
2003 // The microcode patch information cache HOB does not exist, which means\r
2004 // the microcode patches data has not been loaded into memory yet\r
2005 //\r
2006 ShadowMicrocodeUpdatePatch (CpuMpData);\r
2007 }\r
2008\r
d786a172
HW
2009 //\r
2010 // Detect and apply Microcode on BSP\r
2011 //\r
e1ed5573 2012 MicrocodeDetect (CpuMpData, CpuMpData->BspNumber);\r
d786a172
HW
2013 //\r
2014 // Store BSP's MTRR setting\r
2015 //\r
2016 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
2017\r
2018 //\r
2019 // Wakeup APs to do some AP initialize sync (Microcode & MTRR)\r
2020 //\r
2021 if (CpuMpData->CpuCount > 1) {\r
f07fb43b
ED
2022 if (OldCpuMpData != NULL) {\r
2023 //\r
2024 // Only needs to use this flag for DXE phase to update the wake up\r
2025 // buffer. Wakeup buffer allocated in PEI phase is no longer valid\r
2026 // in DXE.\r
2027 //\r
2028 CpuMpData->InitFlag = ApInitReconfig;\r
2029 }\r
053e878b 2030\r
d786a172 2031 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);\r
18fcb375
HW
2032 //\r
2033 // Wait for all APs finished initialization\r
2034 //\r
d786a172
HW
2035 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
2036 CpuPause ();\r
2037 }\r
053e878b 2038\r
f07fb43b
ED
2039 if (OldCpuMpData != NULL) {\r
2040 CpuMpData->InitFlag = ApInitDone;\r
2041 }\r
053e878b 2042\r
d786a172
HW
2043 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
2044 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
6a2ee2bb
JF
2045 }\r
2046 }\r
93ca4c0f 2047\r
030ba309
RN
2048 //\r
2049 // Dump the microcode revision for each core.\r
2050 //\r
7c2a6033 2051 DEBUG_CODE_BEGIN ();\r
053e878b
MK
2052 UINT32 ThreadId;\r
2053 UINT32 ExpectedMicrocodeRevision;\r
2054\r
2055 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
2056 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
2057 GetProcessorLocationByApicId (CpuInfoInHob[Index].InitialApicId, NULL, NULL, &ThreadId);\r
2058 if (ThreadId == 0) {\r
2059 //\r
2060 // MicrocodeDetect() loads microcode in first thread of each core, so,\r
2061 // CpuMpData->CpuData[Index].MicrocodeEntryAddr is initialized only for first thread of each core.\r
2062 //\r
2063 ExpectedMicrocodeRevision = 0;\r
2064 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {\r
2065 ExpectedMicrocodeRevision = ((CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->CpuData[Index].MicrocodeEntryAddr)->UpdateRevision;\r
030ba309 2066 }\r
053e878b
MK
2067\r
2068 DEBUG ((\r
2069 DEBUG_INFO,\r
2070 "CPU[%04d]: Microcode revision = %08x, expected = %08x\n",\r
2071 Index,\r
2072 CpuMpData->CpuData[Index].MicrocodeRevision,\r
2073 ExpectedMicrocodeRevision\r
2074 ));\r
030ba309 2075 }\r
053e878b
MK
2076 }\r
2077\r
7c2a6033 2078 DEBUG_CODE_END ();\r
93ca4c0f
JF
2079 //\r
2080 // Initialize global data for MP support\r
2081 //\r
2082 InitMpGlobalData (CpuMpData);\r
2083\r
f7f85d83 2084 return EFI_SUCCESS;\r
3e8ad6bd
JF
2085}\r
2086\r
2087/**\r
2088 Gets detailed MP-related information on the requested processor at the\r
2089 instant this call is made. This service may only be called from the BSP.\r
2090\r
2091 @param[in] ProcessorNumber The handle number of processor.\r
2092 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
2093 the requested processor is deposited.\r
2094 @param[out] HealthData Return processor health data.\r
2095\r
2096 @retval EFI_SUCCESS Processor information was returned.\r
2097 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
2098 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
2099 @retval EFI_NOT_FOUND The processor with the handle specified by\r
2100 ProcessorNumber does not exist in the platform.\r
2101 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
2102\r
2103**/\r
2104EFI_STATUS\r
2105EFIAPI\r
2106MpInitLibGetProcessorInfo (\r
2107 IN UINTN ProcessorNumber,\r
2108 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,\r
2109 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL\r
2110 )\r
2111{\r
053e878b
MK
2112 CPU_MP_DATA *CpuMpData;\r
2113 UINTN CallerNumber;\r
2114 CPU_INFO_IN_HOB *CpuInfoInHob;\r
2115 UINTN OriginalProcessorNumber;\r
ad52f25e 2116\r
053e878b
MK
2117 CpuMpData = GetCpuMpData ();\r
2118 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
ad52f25e 2119\r
9099dcbd
RN
2120 //\r
2121 // Lower 24 bits contains the actual processor number.\r
2122 //\r
2123 OriginalProcessorNumber = ProcessorNumber;\r
053e878b 2124 ProcessorNumber &= BIT24 - 1;\r
9099dcbd 2125\r
ad52f25e
JF
2126 //\r
2127 // Check whether caller processor is BSP\r
2128 //\r
2129 MpInitLibWhoAmI (&CallerNumber);\r
2130 if (CallerNumber != CpuMpData->BspNumber) {\r
2131 return EFI_DEVICE_ERROR;\r
2132 }\r
2133\r
2134 if (ProcessorInfoBuffer == NULL) {\r
2135 return EFI_INVALID_PARAMETER;\r
2136 }\r
2137\r
2138 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
2139 return EFI_NOT_FOUND;\r
2140 }\r
2141\r
053e878b 2142 ProcessorInfoBuffer->ProcessorId = (UINT64)CpuInfoInHob[ProcessorNumber].ApicId;\r
ad52f25e
JF
2143 ProcessorInfoBuffer->StatusFlag = 0;\r
2144 if (ProcessorNumber == CpuMpData->BspNumber) {\r
2145 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;\r
2146 }\r
053e878b 2147\r
ad52f25e
JF
2148 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {\r
2149 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;\r
2150 }\r
053e878b 2151\r
ad52f25e
JF
2152 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {\r
2153 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;\r
2154 } else {\r
2155 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;\r
2156 }\r
2157\r
2158 //\r
2159 // Get processor location information\r
2160 //\r
262128e5 2161 GetProcessorLocationByApicId (\r
31a1e4da 2162 CpuInfoInHob[ProcessorNumber].ApicId,\r
73152f19
LD
2163 &ProcessorInfoBuffer->Location.Package,\r
2164 &ProcessorInfoBuffer->Location.Core,\r
2165 &ProcessorInfoBuffer->Location.Thread\r
2166 );\r
ad52f25e 2167\r
9099dcbd
RN
2168 if ((OriginalProcessorNumber & CPU_V2_EXTENDED_TOPOLOGY) != 0) {\r
2169 GetProcessorLocation2ByApicId (\r
2170 CpuInfoInHob[ProcessorNumber].ApicId,\r
2171 &ProcessorInfoBuffer->ExtendedInformation.Location2.Package,\r
2172 &ProcessorInfoBuffer->ExtendedInformation.Location2.Die,\r
2173 &ProcessorInfoBuffer->ExtendedInformation.Location2.Tile,\r
2174 &ProcessorInfoBuffer->ExtendedInformation.Location2.Module,\r
2175 &ProcessorInfoBuffer->ExtendedInformation.Location2.Core,\r
2176 &ProcessorInfoBuffer->ExtendedInformation.Location2.Thread\r
2177 );\r
2178 }\r
2179\r
ad52f25e 2180 if (HealthData != NULL) {\r
31a1e4da 2181 HealthData->Uint32 = CpuInfoInHob[ProcessorNumber].Health;\r
ad52f25e
JF
2182 }\r
2183\r
2184 return EFI_SUCCESS;\r
3e8ad6bd 2185}\r
ad52f25e 2186\r
41be0da5
JF
2187/**\r
2188 Worker function to switch the requested AP to be the BSP from that point onward.\r
2189\r
2190 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.\r
2191 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
2192 enabled AP. Otherwise, it will be disabled.\r
2193\r
2194 @retval EFI_SUCCESS BSP successfully switched.\r
7367cc6c 2195 @retval others Failed to switch BSP.\r
41be0da5
JF
2196\r
2197**/\r
2198EFI_STATUS\r
2199SwitchBSPWorker (\r
053e878b
MK
2200 IN UINTN ProcessorNumber,\r
2201 IN BOOLEAN EnableOldBSP\r
41be0da5
JF
2202 )\r
2203{\r
2204 CPU_MP_DATA *CpuMpData;\r
2205 UINTN CallerNumber;\r
2206 CPU_STATE State;\r
2207 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
a8d75a18 2208 BOOLEAN OldInterruptState;\r
26b43433 2209 BOOLEAN OldTimerInterruptState;\r
a8d75a18 2210\r
26b43433
JF
2211 //\r
2212 // Save and Disable Local APIC timer interrupt\r
2213 //\r
2214 OldTimerInterruptState = GetApicTimerInterruptState ();\r
2215 DisableApicTimerInterrupt ();\r
a8d75a18
JF
2216 //\r
2217 // Before send both BSP and AP to a procedure to exchange their roles,\r
2218 // interrupt must be disabled. This is because during the exchange role\r
2219 // process, 2 CPU may use 1 stack. If interrupt happens, the stack will\r
2220 // be corrupted, since interrupt return address will be pushed to stack\r
2221 // by hardware.\r
2222 //\r
2223 OldInterruptState = SaveAndDisableInterrupts ();\r
2224\r
2225 //\r
2226 // Mask LINT0 & LINT1 for the old BSP\r
2227 //\r
2228 DisableLvtInterrupts ();\r
41be0da5
JF
2229\r
2230 CpuMpData = GetCpuMpData ();\r
2231\r
2232 //\r
2233 // Check whether caller processor is BSP\r
2234 //\r
2235 MpInitLibWhoAmI (&CallerNumber);\r
2236 if (CallerNumber != CpuMpData->BspNumber) {\r
5e72dacc 2237 return EFI_DEVICE_ERROR;\r
41be0da5
JF
2238 }\r
2239\r
2240 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
2241 return EFI_NOT_FOUND;\r
2242 }\r
2243\r
2244 //\r
2245 // Check whether specified AP is disabled\r
2246 //\r
2247 State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);\r
2248 if (State == CpuStateDisabled) {\r
2249 return EFI_INVALID_PARAMETER;\r
2250 }\r
2251\r
2252 //\r
2253 // Check whether ProcessorNumber specifies the current BSP\r
2254 //\r
2255 if (ProcessorNumber == CpuMpData->BspNumber) {\r
2256 return EFI_INVALID_PARAMETER;\r
2257 }\r
2258\r
2259 //\r
2260 // Check whether specified AP is busy\r
2261 //\r
2262 if (State == CpuStateBusy) {\r
2263 return EFI_NOT_READY;\r
2264 }\r
2265\r
2266 CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;\r
2267 CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;\r
2268 CpuMpData->SwitchBspFlag = TRUE;\r
b3775af2 2269 CpuMpData->NewBspNumber = ProcessorNumber;\r
41be0da5
JF
2270\r
2271 //\r
2272 // Clear the BSP bit of MSR_IA32_APIC_BASE\r
2273 //\r
053e878b 2274 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
41be0da5
JF
2275 ApicBaseMsr.Bits.BSP = 0;\r
2276 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
2277\r
2278 //\r
2279 // Need to wakeUp AP (future BSP).\r
2280 //\r
cf4e79e4 2281 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData, TRUE);\r
41be0da5 2282\r
d1abb876
ZL
2283 //\r
2284 // Save and restore volatile registers when switch BSP\r
2285 //\r
2286 SaveVolatileRegisters (&CpuMpData->BSPInfo.VolatileRegisters);\r
41be0da5 2287 AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);\r
d1abb876 2288 RestoreVolatileRegisters (&CpuMpData->BSPInfo.VolatileRegisters, FALSE);\r
41be0da5
JF
2289\r
2290 //\r
2291 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP\r
2292 //\r
053e878b 2293 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
41be0da5
JF
2294 ApicBaseMsr.Bits.BSP = 1;\r
2295 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
9c6961d5 2296 ProgramVirtualWireMode ();\r
41be0da5
JF
2297\r
2298 //\r
2299 // Wait for old BSP finished AP task\r
2300 //\r
e048ce88 2301 while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {\r
41be0da5
JF
2302 CpuPause ();\r
2303 }\r
2304\r
2305 CpuMpData->SwitchBspFlag = FALSE;\r
2306 //\r
2307 // Set old BSP enable state\r
2308 //\r
2309 if (!EnableOldBSP) {\r
2310 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);\r
af8ba51a
JF
2311 } else {\r
2312 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateIdle);\r
41be0da5 2313 }\r
053e878b 2314\r
41be0da5
JF
2315 //\r
2316 // Save new BSP number\r
2317 //\r
053e878b 2318 CpuMpData->BspNumber = (UINT32)ProcessorNumber;\r
41be0da5 2319\r
a8d75a18
JF
2320 //\r
2321 // Restore interrupt state.\r
2322 //\r
2323 SetInterruptState (OldInterruptState);\r
2324\r
26b43433
JF
2325 if (OldTimerInterruptState) {\r
2326 EnableApicTimerInterrupt ();\r
2327 }\r
a8d75a18 2328\r
41be0da5
JF
2329 return EFI_SUCCESS;\r
2330}\r
ad52f25e 2331\r
e37109bc
JF
2332/**\r
2333 Worker function to let the caller enable or disable an AP from this point onward.\r
2334 This service may only be called from the BSP.\r
2335\r
2336 @param[in] ProcessorNumber The handle number of AP.\r
2337 @param[in] EnableAP Specifies the new state for the processor for\r
2338 enabled, FALSE for disabled.\r
2339 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
2340 the new health status of the AP.\r
2341\r
2342 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
2343 @retval others Failed to Enable/Disable AP.\r
2344\r
2345**/\r
2346EFI_STATUS\r
2347EnableDisableApWorker (\r
053e878b
MK
2348 IN UINTN ProcessorNumber,\r
2349 IN BOOLEAN EnableAP,\r
2350 IN UINT32 *HealthFlag OPTIONAL\r
e37109bc
JF
2351 )\r
2352{\r
053e878b
MK
2353 CPU_MP_DATA *CpuMpData;\r
2354 UINTN CallerNumber;\r
e37109bc
JF
2355\r
2356 CpuMpData = GetCpuMpData ();\r
2357\r
2358 //\r
2359 // Check whether caller processor is BSP\r
2360 //\r
2361 MpInitLibWhoAmI (&CallerNumber);\r
2362 if (CallerNumber != CpuMpData->BspNumber) {\r
2363 return EFI_DEVICE_ERROR;\r
2364 }\r
2365\r
2366 if (ProcessorNumber == CpuMpData->BspNumber) {\r
2367 return EFI_INVALID_PARAMETER;\r
2368 }\r
2369\r
2370 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
2371 return EFI_NOT_FOUND;\r
2372 }\r
2373\r
2374 if (!EnableAP) {\r
2375 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);\r
2376 } else {\r
d5fdae96 2377 ResetProcessorToIdleState (ProcessorNumber);\r
e37109bc
JF
2378 }\r
2379\r
2380 if (HealthFlag != NULL) {\r
2381 CpuMpData->CpuData[ProcessorNumber].CpuHealthy =\r
053e878b 2382 (BOOLEAN)((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);\r
e37109bc
JF
2383 }\r
2384\r
2385 return EFI_SUCCESS;\r
2386}\r
2387\r
3e8ad6bd
JF
2388/**\r
2389 This return the handle number for the calling processor. This service may be\r
2390 called from the BSP and APs.\r
2391\r
2392 @param[out] ProcessorNumber Pointer to the handle number of AP.\r
2393 The range is from 0 to the total number of\r
2394 logical processors minus 1. The total number of\r
2395 logical processors can be retrieved by\r
2396 MpInitLibGetNumberOfProcessors().\r
2397\r
2398 @retval EFI_SUCCESS The current processor handle number was returned\r
2399 in ProcessorNumber.\r
2400 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
2401 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
2402\r
2403**/\r
2404EFI_STATUS\r
2405EFIAPI\r
2406MpInitLibWhoAmI (\r
053e878b 2407 OUT UINTN *ProcessorNumber\r
3e8ad6bd
JF
2408 )\r
2409{\r
053e878b 2410 CPU_MP_DATA *CpuMpData;\r
5c9e0997
JF
2411\r
2412 if (ProcessorNumber == NULL) {\r
2413 return EFI_INVALID_PARAMETER;\r
2414 }\r
2415\r
2416 CpuMpData = GetCpuMpData ();\r
2417\r
2418 return GetProcessorNumber (CpuMpData, ProcessorNumber);\r
3e8ad6bd 2419}\r
809213a6 2420\r
3e8ad6bd
JF
2421/**\r
2422 Retrieves the number of logical processor in the platform and the number of\r
2423 those logical processors that are enabled on this boot. This service may only\r
2424 be called from the BSP.\r
2425\r
2426 @param[out] NumberOfProcessors Pointer to the total number of logical\r
2427 processors in the system, including the BSP\r
2428 and disabled APs.\r
2429 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
2430 processors that exist in system, including\r
2431 the BSP.\r
2432\r
2433 @retval EFI_SUCCESS The number of logical processors and enabled\r
2434 logical processors was retrieved.\r
2435 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
2436 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors\r
2437 is NULL.\r
2438 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
2439\r
2440**/\r
2441EFI_STATUS\r
2442EFIAPI\r
2443MpInitLibGetNumberOfProcessors (\r
053e878b
MK
2444 OUT UINTN *NumberOfProcessors OPTIONAL,\r
2445 OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
3e8ad6bd
JF
2446 )\r
2447{\r
053e878b
MK
2448 CPU_MP_DATA *CpuMpData;\r
2449 UINTN CallerNumber;\r
2450 UINTN ProcessorNumber;\r
2451 UINTN EnabledProcessorNumber;\r
2452 UINTN Index;\r
809213a6 2453\r
b5cd30a7
MX
2454 CpuMpData = GetCpuMpData ();\r
2455\r
809213a6
JF
2456 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {\r
2457 return EFI_INVALID_PARAMETER;\r
2458 }\r
2459\r
2460 //\r
2461 // Check whether caller processor is BSP\r
2462 //\r
2463 MpInitLibWhoAmI (&CallerNumber);\r
2464 if (CallerNumber != CpuMpData->BspNumber) {\r
2465 return EFI_DEVICE_ERROR;\r
2466 }\r
2467\r
2468 ProcessorNumber = CpuMpData->CpuCount;\r
2469 EnabledProcessorNumber = 0;\r
2470 for (Index = 0; Index < ProcessorNumber; Index++) {\r
2471 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {\r
053e878b 2472 EnabledProcessorNumber++;\r
809213a6
JF
2473 }\r
2474 }\r
2475\r
2476 if (NumberOfProcessors != NULL) {\r
2477 *NumberOfProcessors = ProcessorNumber;\r
2478 }\r
053e878b 2479\r
809213a6
JF
2480 if (NumberOfEnabledProcessors != NULL) {\r
2481 *NumberOfEnabledProcessors = EnabledProcessorNumber;\r
2482 }\r
2483\r
2484 return EFI_SUCCESS;\r
3e8ad6bd 2485}\r
6a2ee2bb 2486\r
86efe976
JF
2487/**\r
2488 Worker function to execute a caller provided function on all enabled APs.\r
2489\r
2490 @param[in] Procedure A pointer to the function to be run on\r
2491 enabled APs of the system.\r
2492 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
2493 the function specified by Procedure one by\r
2494 one, in ascending order of processor handle\r
2495 number. If FALSE, then all the enabled APs\r
2496 execute the function specified by Procedure\r
2497 simultaneously.\r
ee0c39fa 2498 @param[in] ExcludeBsp Whether let BSP also trig this task.\r
86efe976
JF
2499 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
2500 service.\r
367284e7 2501 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
86efe976
JF
2502 APs to return from Procedure, either for\r
2503 blocking or non-blocking mode.\r
2504 @param[in] ProcedureArgument The parameter passed into Procedure for\r
2505 all APs.\r
2506 @param[out] FailedCpuList If all APs finish successfully, then its\r
2507 content is set to NULL. If not all APs\r
2508 finish before timeout expires, then its\r
2509 content is set to address of the buffer\r
2510 holding handle numbers of the failed APs.\r
2511\r
2512 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
2513 the timeout expired.\r
2514 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
2515 to all enabled APs.\r
2516 @retval others Failed to Startup all APs.\r
2517\r
2518**/\r
2519EFI_STATUS\r
ee0c39fa 2520StartupAllCPUsWorker (\r
053e878b
MK
2521 IN EFI_AP_PROCEDURE Procedure,\r
2522 IN BOOLEAN SingleThread,\r
2523 IN BOOLEAN ExcludeBsp,\r
2524 IN EFI_EVENT WaitEvent OPTIONAL,\r
2525 IN UINTN TimeoutInMicroseconds,\r
2526 IN VOID *ProcedureArgument OPTIONAL,\r
2527 OUT UINTN **FailedCpuList OPTIONAL\r
86efe976
JF
2528 )\r
2529{\r
053e878b
MK
2530 EFI_STATUS Status;\r
2531 CPU_MP_DATA *CpuMpData;\r
2532 UINTN ProcessorCount;\r
2533 UINTN ProcessorNumber;\r
2534 UINTN CallerNumber;\r
2535 CPU_AP_DATA *CpuData;\r
2536 BOOLEAN HasEnabledAp;\r
2537 CPU_STATE ApState;\r
86efe976 2538\r
b5cd30a7
MX
2539 CpuMpData = GetCpuMpData ();\r
2540\r
86efe976
JF
2541 if (FailedCpuList != NULL) {\r
2542 *FailedCpuList = NULL;\r
2543 }\r
2544\r
b5cd30a7 2545 if ((CpuMpData->CpuCount == 1) && ExcludeBsp) {\r
86efe976
JF
2546 return EFI_NOT_STARTED;\r
2547 }\r
2548\r
2549 if (Procedure == NULL) {\r
2550 return EFI_INVALID_PARAMETER;\r
2551 }\r
2552\r
2553 //\r
2554 // Check whether caller processor is BSP\r
2555 //\r
2556 MpInitLibWhoAmI (&CallerNumber);\r
2557 if (CallerNumber != CpuMpData->BspNumber) {\r
2558 return EFI_DEVICE_ERROR;\r
2559 }\r
2560\r
2561 //\r
2562 // Update AP state\r
2563 //\r
2564 CheckAndUpdateApsStatus ();\r
2565\r
2566 ProcessorCount = CpuMpData->CpuCount;\r
2567 HasEnabledAp = FALSE;\r
2568 //\r
2569 // Check whether all enabled APs are idle.\r
2570 // If any enabled AP is not idle, return EFI_NOT_READY.\r
2571 //\r
2572 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
2573 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
2574 if (ProcessorNumber != CpuMpData->BspNumber) {\r
2575 ApState = GetApState (CpuData);\r
2576 if (ApState != CpuStateDisabled) {\r
2577 HasEnabledAp = TRUE;\r
2578 if (ApState != CpuStateIdle) {\r
2579 //\r
2580 // If any enabled APs are busy, return EFI_NOT_READY.\r
2581 //\r
2582 return EFI_NOT_READY;\r
2583 }\r
2584 }\r
2585 }\r
2586 }\r
2587\r
ee0c39fa 2588 if (!HasEnabledAp && ExcludeBsp) {\r
86efe976 2589 //\r
ee0c39fa 2590 // If no enabled AP exists and not include Bsp to do the procedure, return EFI_NOT_STARTED.\r
86efe976
JF
2591 //\r
2592 return EFI_NOT_STARTED;\r
2593 }\r
2594\r
2da3e96c 2595 CpuMpData->RunningCount = 0;\r
86efe976 2596 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
053e878b 2597 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
86efe976
JF
2598 CpuData->Waiting = FALSE;\r
2599 if (ProcessorNumber != CpuMpData->BspNumber) {\r
2600 if (CpuData->State == CpuStateIdle) {\r
2601 //\r
2602 // Mark this processor as responsible for current calling.\r
2603 //\r
2604 CpuData->Waiting = TRUE;\r
2da3e96c 2605 CpuMpData->RunningCount++;\r
86efe976
JF
2606 }\r
2607 }\r
2608 }\r
2609\r
2610 CpuMpData->Procedure = Procedure;\r
2611 CpuMpData->ProcArguments = ProcedureArgument;\r
2612 CpuMpData->SingleThread = SingleThread;\r
2613 CpuMpData->FinishedCount = 0;\r
86efe976
JF
2614 CpuMpData->FailedCpuList = FailedCpuList;\r
2615 CpuMpData->ExpectedTime = CalculateTimeout (\r
2616 TimeoutInMicroseconds,\r
2617 &CpuMpData->CurrentTime\r
2618 );\r
053e878b
MK
2619 CpuMpData->TotalTime = 0;\r
2620 CpuMpData->WaitEvent = WaitEvent;\r
86efe976
JF
2621\r
2622 if (!SingleThread) {\r
cf4e79e4 2623 WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE);\r
86efe976
JF
2624 } else {\r
2625 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
2626 if (ProcessorNumber == CallerNumber) {\r
2627 continue;\r
2628 }\r
053e878b 2629\r
86efe976 2630 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
cf4e79e4 2631 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);\r
86efe976
JF
2632 break;\r
2633 }\r
2634 }\r
2635 }\r
2636\r
ee0c39fa
ED
2637 if (!ExcludeBsp) {\r
2638 //\r
2639 // Start BSP.\r
2640 //\r
2641 Procedure (ProcedureArgument);\r
2642 }\r
2643\r
86efe976
JF
2644 Status = EFI_SUCCESS;\r
2645 if (WaitEvent == NULL) {\r
2646 do {\r
2647 Status = CheckAllAPs ();\r
2648 } while (Status == EFI_NOT_READY);\r
2649 }\r
2650\r
2651 return Status;\r
2652}\r
2653\r
20ae5774
JF
2654/**\r
2655 Worker function to let the caller get one enabled AP to execute a caller-provided\r
2656 function.\r
2657\r
2658 @param[in] Procedure A pointer to the function to be run on\r
2659 enabled APs of the system.\r
2660 @param[in] ProcessorNumber The handle number of the AP.\r
2661 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
2662 service.\r
367284e7 2663 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
20ae5774
JF
2664 APs to return from Procedure, either for\r
2665 blocking or non-blocking mode.\r
2666 @param[in] ProcedureArgument The parameter passed into Procedure for\r
2667 all APs.\r
2668 @param[out] Finished If AP returns from Procedure before the\r
2669 timeout expires, its content is set to TRUE.\r
2670 Otherwise, the value is set to FALSE.\r
2671\r
2672 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
2673 the timeout expires.\r
2674 @retval others Failed to Startup AP.\r
2675\r
2676**/\r
2677EFI_STATUS\r
2678StartupThisAPWorker (\r
053e878b
MK
2679 IN EFI_AP_PROCEDURE Procedure,\r
2680 IN UINTN ProcessorNumber,\r
2681 IN EFI_EVENT WaitEvent OPTIONAL,\r
2682 IN UINTN TimeoutInMicroseconds,\r
2683 IN VOID *ProcedureArgument OPTIONAL,\r
2684 OUT BOOLEAN *Finished OPTIONAL\r
20ae5774
JF
2685 )\r
2686{\r
053e878b
MK
2687 EFI_STATUS Status;\r
2688 CPU_MP_DATA *CpuMpData;\r
2689 CPU_AP_DATA *CpuData;\r
2690 UINTN CallerNumber;\r
20ae5774
JF
2691\r
2692 CpuMpData = GetCpuMpData ();\r
2693\r
2694 if (Finished != NULL) {\r
2695 *Finished = FALSE;\r
2696 }\r
2697\r
2698 //\r
2699 // Check whether caller processor is BSP\r
2700 //\r
2701 MpInitLibWhoAmI (&CallerNumber);\r
2702 if (CallerNumber != CpuMpData->BspNumber) {\r
2703 return EFI_DEVICE_ERROR;\r
2704 }\r
2705\r
2706 //\r
2707 // Check whether processor with the handle specified by ProcessorNumber exists\r
2708 //\r
2709 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
2710 return EFI_NOT_FOUND;\r
2711 }\r
2712\r
2713 //\r
2714 // Check whether specified processor is BSP\r
2715 //\r
2716 if (ProcessorNumber == CpuMpData->BspNumber) {\r
2717 return EFI_INVALID_PARAMETER;\r
2718 }\r
2719\r
2720 //\r
2721 // Check parameter Procedure\r
2722 //\r
2723 if (Procedure == NULL) {\r
2724 return EFI_INVALID_PARAMETER;\r
2725 }\r
2726\r
2727 //\r
2728 // Update AP state\r
2729 //\r
2730 CheckAndUpdateApsStatus ();\r
2731\r
2732 //\r
2733 // Check whether specified AP is disabled\r
2734 //\r
2735 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {\r
2736 return EFI_INVALID_PARAMETER;\r
2737 }\r
2738\r
2739 //\r
2740 // If WaitEvent is not NULL, execute in non-blocking mode.\r
2741 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.\r
2742 // CheckAPsStatus() will check completion and timeout periodically.\r
2743 //\r
053e878b 2744 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
20ae5774
JF
2745 CpuData->WaitEvent = WaitEvent;\r
2746 CpuData->Finished = Finished;\r
2747 CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);\r
2748 CpuData->TotalTime = 0;\r
2749\r
cf4e79e4 2750 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);\r
20ae5774
JF
2751\r
2752 //\r
2753 // If WaitEvent is NULL, execute in blocking mode.\r
2754 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.\r
2755 //\r
2756 Status = EFI_SUCCESS;\r
2757 if (WaitEvent == NULL) {\r
2758 do {\r
2759 Status = CheckThisAP (ProcessorNumber);\r
2760 } while (Status == EFI_NOT_READY);\r
2761 }\r
2762\r
2763 return Status;\r
2764}\r
2765\r
93ca4c0f
JF
2766/**\r
2767 Get pointer to CPU MP Data structure from GUIDed HOB.\r
2768\r
2769 @return The pointer to CPU MP Data structure.\r
2770**/\r
2771CPU_MP_DATA *\r
2772GetCpuMpDataFromGuidedHob (\r
2773 VOID\r
2774 )\r
2775{\r
053e878b
MK
2776 EFI_HOB_GUID_TYPE *GuidHob;\r
2777 VOID *DataInHob;\r
2778 CPU_MP_DATA *CpuMpData;\r
93ca4c0f
JF
2779\r
2780 CpuMpData = NULL;\r
053e878b 2781 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
93ca4c0f
JF
2782 if (GuidHob != NULL) {\r
2783 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
053e878b 2784 CpuMpData = (CPU_MP_DATA *)(*(UINTN *)DataInHob);\r
93ca4c0f 2785 }\r
053e878b 2786\r
93ca4c0f
JF
2787 return CpuMpData;\r
2788}\r
42c37b3b 2789\r
ee0c39fa
ED
2790/**\r
2791 This service executes a caller provided function on all enabled CPUs.\r
2792\r
2793 @param[in] Procedure A pointer to the function to be run on\r
2794 enabled APs of the system. See type\r
2795 EFI_AP_PROCEDURE.\r
2796 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
2797 APs to return from Procedure, either for\r
2798 blocking or non-blocking mode. Zero means\r
2799 infinity. TimeoutInMicroseconds is ignored\r
2800 for BSP.\r
2801 @param[in] ProcedureArgument The parameter passed into Procedure for\r
2802 all APs.\r
2803\r
2804 @retval EFI_SUCCESS In blocking mode, all CPUs have finished before\r
2805 the timeout expired.\r
2806 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
2807 to all enabled CPUs.\r
2808 @retval EFI_DEVICE_ERROR Caller processor is AP.\r
2809 @retval EFI_NOT_READY Any enabled APs are busy.\r
2810 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
2811 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
2812 all enabled APs have finished.\r
2813 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
2814\r
2815**/\r
2816EFI_STATUS\r
2817EFIAPI\r
2818MpInitLibStartupAllCPUs (\r
053e878b
MK
2819 IN EFI_AP_PROCEDURE Procedure,\r
2820 IN UINTN TimeoutInMicroseconds,\r
2821 IN VOID *ProcedureArgument OPTIONAL\r
ee0c39fa
ED
2822 )\r
2823{\r
2824 return StartupAllCPUsWorker (\r
2825 Procedure,\r
2826 FALSE,\r
2827 FALSE,\r
2828 NULL,\r
2829 TimeoutInMicroseconds,\r
2830 ProcedureArgument,\r
2831 NULL\r
2832 );\r
2833}\r
b95908e0
BS
2834\r
2835/**\r
2836 The function check if the specified Attr is set.\r
2837\r
2838 @param[in] CurrentAttr The current attribute.\r
2839 @param[in] Attr The attribute to check.\r
2840\r
2841 @retval TRUE The specified Attr is set.\r
2842 @retval FALSE The specified Attr is not set.\r
2843\r
2844**/\r
2845STATIC\r
2846BOOLEAN\r
2847AmdMemEncryptionAttrCheck (\r
2848 IN UINT64 CurrentAttr,\r
2849 IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr\r
2850 )\r
2851{\r
2852 switch (Attr) {\r
2853 case CCAttrAmdSev:\r
2854 //\r
2855 // SEV is automatically enabled if SEV-ES or SEV-SNP is active.\r
2856 //\r
2857 return CurrentAttr >= CCAttrAmdSev;\r
2858 case CCAttrAmdSevEs:\r
2859 //\r
2860 // SEV-ES is automatically enabled if SEV-SNP is active.\r
2861 //\r
2862 return CurrentAttr >= CCAttrAmdSevEs;\r
2863 case CCAttrAmdSevSnp:\r
2864 return CurrentAttr == CCAttrAmdSevSnp;\r
2865 default:\r
2866 return FALSE;\r
2867 }\r
2868}\r
2869\r
2870/**\r
2871 Check if the specified confidential computing attribute is active.\r
2872\r
2873 @param[in] Attr The attribute to check.\r
2874\r
2875 @retval TRUE The specified Attr is active.\r
2876 @retval FALSE The specified Attr is not active.\r
2877\r
2878**/\r
2879BOOLEAN\r
2880EFIAPI\r
2881ConfidentialComputingGuestHas (\r
2882 IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr\r
2883 )\r
2884{\r
2885 UINT64 CurrentAttr;\r
2886\r
2887 //\r
2888 // Get the current CC attribute.\r
2889 //\r
2890 CurrentAttr = PcdGet64 (PcdConfidentialComputingGuestAttr);\r
2891\r
2892 //\r
2893 // If attr is for the AMD group then call AMD specific checks.\r
2894 //\r
2895 if (((RShiftU64 (CurrentAttr, 8)) & 0xff) == 1) {\r
2896 return AmdMemEncryptionAttrCheck (CurrentAttr, Attr);\r
2897 }\r
2898\r
2899 return (CurrentAttr == Attr);\r
2900}\r