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