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