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