]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: fix AP init issue in 64-bit PEI
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
CommitLineData
3e8ad6bd
JF
1/** @file\r
2 CPU MP Initialize Library common functions.\r
3\r
a2ea6894 4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
3e8ad6bd
JF
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "MpLib.h"\r
16\r
93ca4c0f
JF
17EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;\r
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
JF
219\r
220 AsmWriteCr0 (VolatileRegisters->Cr0);\r
221 AsmWriteCr3 (VolatileRegisters->Cr3);\r
222 AsmWriteCr4 (VolatileRegisters->Cr4);\r
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
297 }\r
298\r
299 if (ApLoopMode != ApInMwaitLoop) {\r
300 *MonitorFilterSize = sizeof (UINT32);\r
301 } else {\r
302 //\r
303 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes\r
304 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT\r
305 //\r
306 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);\r
307 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;\r
308 }\r
309\r
310 return ApLoopMode;\r
311}\r
b8b04307 312\r
8a2d564b
JF
313/**\r
314 Sort the APIC ID of all processors.\r
315\r
316 This function sorts the APIC ID of all processors so that processor number is\r
317 assigned in the ascending order of APIC ID which eases MP debugging.\r
318\r
319 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
320**/\r
321VOID\r
322SortApicId (\r
323 IN CPU_MP_DATA *CpuMpData\r
324 )\r
325{\r
326 UINTN Index1;\r
327 UINTN Index2;\r
328 UINTN Index3;\r
329 UINT32 ApicId;\r
31a1e4da 330 CPU_INFO_IN_HOB CpuInfo;\r
8a2d564b
JF
331 UINT32 ApCount;\r
332 CPU_INFO_IN_HOB *CpuInfoInHob;\r
bafa76ef 333 volatile UINT32 *StartupApSignal;\r
8a2d564b
JF
334\r
335 ApCount = CpuMpData->CpuCount - 1;\r
31a1e4da 336 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
8a2d564b
JF
337 if (ApCount != 0) {\r
338 for (Index1 = 0; Index1 < ApCount; Index1++) {\r
339 Index3 = Index1;\r
340 //\r
341 // Sort key is the hardware default APIC ID\r
342 //\r
31a1e4da 343 ApicId = CpuInfoInHob[Index1].ApicId;\r
8a2d564b 344 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {\r
31a1e4da 345 if (ApicId > CpuInfoInHob[Index2].ApicId) {\r
8a2d564b 346 Index3 = Index2;\r
31a1e4da 347 ApicId = CpuInfoInHob[Index2].ApicId;\r
8a2d564b
JF
348 }\r
349 }\r
350 if (Index3 != Index1) {\r
31a1e4da 351 CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof (CPU_INFO_IN_HOB));\r
8a2d564b 352 CopyMem (\r
31a1e4da
JF
353 &CpuInfoInHob[Index3],\r
354 &CpuInfoInHob[Index1],\r
355 sizeof (CPU_INFO_IN_HOB)\r
8a2d564b 356 );\r
31a1e4da 357 CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));\r
bafa76ef
SZ
358\r
359 //\r
360 // Also exchange the StartupApSignal.\r
361 //\r
362 StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal;\r
363 CpuMpData->CpuData[Index3].StartupApSignal =\r
364 CpuMpData->CpuData[Index1].StartupApSignal;\r
365 CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;\r
8a2d564b
JF
366 }\r
367 }\r
368\r
369 //\r
370 // Get the processor number for the BSP\r
371 //\r
372 ApicId = GetInitialApicId ();\r
373 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {\r
31a1e4da 374 if (CpuInfoInHob[Index1].ApicId == ApicId) {\r
8a2d564b
JF
375 CpuMpData->BspNumber = (UINT32) Index1;\r
376 break;\r
377 }\r
378 }\r
8a2d564b
JF
379 }\r
380}\r
381\r
fe627769
JF
382/**\r
383 Enable x2APIC mode on APs.\r
384\r
385 @param[in, out] Buffer Pointer to private data buffer.\r
386**/\r
387VOID\r
388EFIAPI\r
389ApFuncEnableX2Apic (\r
390 IN OUT VOID *Buffer\r
391 )\r
392{\r
393 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
394}\r
395\r
b8b04307
JF
396/**\r
397 Do sync on APs.\r
398\r
399 @param[in, out] Buffer Pointer to private data buffer.\r
400**/\r
401VOID\r
402EFIAPI\r
403ApInitializeSync (\r
404 IN OUT VOID *Buffer\r
405 )\r
406{\r
407 CPU_MP_DATA *CpuMpData;\r
408\r
409 CpuMpData = (CPU_MP_DATA *) Buffer;\r
410 //\r
b8b04307
JF
411 // Load microcode on AP\r
412 //\r
413 MicrocodeDetect (CpuMpData);\r
cb811673
JF
414 //\r
415 // Sync BSP's MTRR table to AP\r
416 //\r
417 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
b8b04307
JF
418}\r
419\r
420/**\r
421 Find the current Processor number by APIC ID.\r
422\r
367284e7
DB
423 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
424 @param[out] ProcessorNumber Return the pocessor number found\r
b8b04307
JF
425\r
426 @retval EFI_SUCCESS ProcessorNumber is found and returned.\r
427 @retval EFI_NOT_FOUND ProcessorNumber is not found.\r
428**/\r
429EFI_STATUS\r
430GetProcessorNumber (\r
431 IN CPU_MP_DATA *CpuMpData,\r
432 OUT UINTN *ProcessorNumber\r
433 )\r
434{\r
435 UINTN TotalProcessorNumber;\r
436 UINTN Index;\r
31a1e4da
JF
437 CPU_INFO_IN_HOB *CpuInfoInHob;\r
438\r
439 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
b8b04307
JF
440\r
441 TotalProcessorNumber = CpuMpData->CpuCount;\r
442 for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
31a1e4da 443 if (CpuInfoInHob[Index].ApicId == GetApicId ()) {\r
b8b04307
JF
444 *ProcessorNumber = Index;\r
445 return EFI_SUCCESS;\r
446 }\r
447 }\r
448 return EFI_NOT_FOUND;\r
449}\r
450\r
03434dff
JF
451/**\r
452 This function will get CPU count in the system.\r
453\r
454 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
455\r
456 @return CPU count detected\r
457**/\r
458UINTN\r
459CollectProcessorCount (\r
460 IN CPU_MP_DATA *CpuMpData\r
461 )\r
462{\r
59a119f0
JF
463 UINTN Index;\r
464\r
03434dff
JF
465 //\r
466 // Send 1st broadcast IPI to APs to wakeup APs\r
467 //\r
468 CpuMpData->InitFlag = ApInitConfig;\r
469 CpuMpData->X2ApicEnable = FALSE;\r
470 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);\r
03434dff
JF
471 CpuMpData->InitFlag = ApInitDone;\r
472 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
473 //\r
474 // Wait for all APs finished the initialization\r
475 //\r
476 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
477 CpuPause ();\r
478 }\r
479\r
71d8226a
JF
480 if (CpuMpData->CpuCount > 255) {\r
481 //\r
482 // If there are more than 255 processor found, force to enable X2APIC\r
483 //\r
484 CpuMpData->X2ApicEnable = TRUE;\r
485 }\r
fe627769
JF
486 if (CpuMpData->X2ApicEnable) {\r
487 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));\r
488 //\r
489 // Wakeup all APs to enable x2APIC mode\r
490 //\r
491 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
492 //\r
493 // Wait for all known APs finished\r
494 //\r
495 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
496 CpuPause ();\r
497 }\r
498 //\r
499 // Enable x2APIC on BSP\r
500 //\r
501 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
59a119f0
JF
502 //\r
503 // Set BSP/Aps state to IDLE\r
504 //\r
505 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
506 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
507 }\r
fe627769
JF
508 }\r
509 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
8a2d564b
JF
510 //\r
511 // Sort BSP/Aps by CPU APIC ID in ascending order\r
512 //\r
513 SortApicId (CpuMpData);\r
514\r
03434dff
JF
515 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));\r
516\r
517 return CpuMpData->CpuCount;\r
518}\r
519\r
367284e7 520/**\r
03a1a925
JF
521 Initialize CPU AP Data when AP is wakeup at the first time.\r
522\r
523 @param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
524 @param[in] ProcessorNumber The handle number of processor\r
525 @param[in] BistData Processor BIST data\r
367284e7 526 @param[in] ApTopOfStack Top of AP stack\r
03a1a925
JF
527\r
528**/\r
529VOID\r
530InitializeApData (\r
531 IN OUT CPU_MP_DATA *CpuMpData,\r
532 IN UINTN ProcessorNumber,\r
845c5be1 533 IN UINT32 BistData,\r
dd3fa0cd 534 IN UINT64 ApTopOfStack\r
03a1a925
JF
535 )\r
536{\r
31a1e4da
JF
537 CPU_INFO_IN_HOB *CpuInfoInHob;\r
538\r
539 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
540 CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
541 CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();\r
542 CpuInfoInHob[ProcessorNumber].Health = BistData;\r
dd3fa0cd 543 CpuInfoInHob[ProcessorNumber].ApTopOfStack = ApTopOfStack;\r
31a1e4da 544\r
03a1a925 545 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
03a1a925 546 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
31a1e4da 547 if (CpuInfoInHob[ProcessorNumber].InitialApicId >= 0xFF) {\r
03a1a925
JF
548 //\r
549 // Set x2APIC mode if there are any logical processor reporting\r
550 // an Initial APIC ID of 255 or greater.\r
551 //\r
552 AcquireSpinLock(&CpuMpData->MpLock);\r
553 CpuMpData->X2ApicEnable = TRUE;\r
554 ReleaseSpinLock(&CpuMpData->MpLock);\r
555 }\r
556\r
557 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
558 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
559}\r
560\r
b8b04307
JF
561/**\r
562 This function will be called from AP reset code if BSP uses WakeUpAP.\r
563\r
564 @param[in] ExchangeInfo Pointer to the MP exchange info buffer\r
9fcea114 565 @param[in] ApIndex Number of current executing AP\r
b8b04307
JF
566**/\r
567VOID\r
568EFIAPI\r
569ApWakeupFunction (\r
570 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
37676b9f 571 IN UINTN ApIndex\r
b8b04307
JF
572 )\r
573{\r
574 CPU_MP_DATA *CpuMpData;\r
575 UINTN ProcessorNumber;\r
576 EFI_AP_PROCEDURE Procedure;\r
577 VOID *Parameter;\r
578 UINT32 BistData;\r
579 volatile UINT32 *ApStartupSignalBuffer;\r
31a1e4da 580 CPU_INFO_IN_HOB *CpuInfoInHob;\r
dd3fa0cd 581 UINT64 ApTopOfStack;\r
c6b0feb3 582 UINTN CurrentApicMode;\r
b8b04307
JF
583\r
584 //\r
585 // AP finished assembly code and begin to execute C code\r
586 //\r
587 CpuMpData = ExchangeInfo->CpuMpData;\r
588\r
ffab2442
JF
589 //\r
590 // AP's local APIC settings will be lost after received INIT IPI\r
591 // We need to re-initialize them at here\r
592 //\r
593 ProgramVirtualWireMode ();\r
a2ea6894
RN
594 //\r
595 // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.\r
596 //\r
597 DisableLvtInterrupts ();\r
ffab2442 598 SyncLocalApicTimerSetting (CpuMpData);\r
b8b04307 599\r
c6b0feb3 600 CurrentApicMode = GetApicMode ();\r
b8b04307
JF
601 while (TRUE) {\r
602 if (CpuMpData->InitFlag == ApInitConfig) {\r
603 //\r
604 // Add CPU number\r
605 //\r
606 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
37676b9f 607 ProcessorNumber = ApIndex;\r
b8b04307
JF
608 //\r
609 // This is first time AP wakeup, get BIST information from AP stack\r
610 //\r
845c5be1 611 ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;\r
dd3fa0cd 612 BistData = *(UINT32 *) ((UINTN) ApTopOfStack - sizeof (UINTN));\r
b8b04307
JF
613 //\r
614 // Do some AP initialize sync\r
615 //\r
616 ApInitializeSync (CpuMpData);\r
617 //\r
618 // Sync BSP's Control registers to APs\r
619 //\r
620 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
845c5be1 621 InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);\r
b8b04307
JF
622 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
623 } else {\r
624 //\r
625 // Execute AP function if AP is ready\r
626 //\r
627 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
628 //\r
629 // Clear AP start-up signal when AP waken up\r
630 //\r
631 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
632 InterlockedCompareExchange32 (\r
633 (UINT32 *) ApStartupSignalBuffer,\r
634 WAKEUP_AP_SIGNAL,\r
635 0\r
636 );\r
637 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
638 //\r
639 // Restore AP's volatile registers saved\r
640 //\r
641 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
642 }\r
643\r
644 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
645 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;\r
646 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;\r
647 if (Procedure != NULL) {\r
648 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
649 //\r
43c9fdcc
JF
650 // Enable source debugging on AP function\r
651 // \r
652 EnableDebugAgent ();\r
653 //\r
b8b04307
JF
654 // Invoke AP function here\r
655 //\r
656 Procedure (Parameter);\r
31a1e4da 657 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
41be0da5
JF
658 if (CpuMpData->SwitchBspFlag) {\r
659 //\r
660 // Re-get the processor number due to BSP/AP maybe exchange in AP function\r
661 //\r
662 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
663 CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;\r
664 CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;\r
b3775af2
JF
665 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
666 CpuInfoInHob[ProcessorNumber].ApTopOfStack = CpuInfoInHob[CpuMpData->NewBspNumber].ApTopOfStack;\r
41be0da5 667 } else {\r
c6b0feb3
JF
668 if (CpuInfoInHob[ProcessorNumber].ApicId != GetApicId () ||\r
669 CpuInfoInHob[ProcessorNumber].InitialApicId != GetInitialApicId ()) {\r
670 if (CurrentApicMode != GetApicMode ()) {\r
671 //\r
672 // If APIC mode change happened during AP function execution,\r
673 // we do not support APIC ID value changed.\r
674 //\r
675 ASSERT (FALSE);\r
676 CpuDeadLoop ();\r
677 } else {\r
678 //\r
679 // Re-get the CPU APICID and Initial APICID if they are changed\r
680 //\r
681 CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();\r
682 CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
683 }\r
684 }\r
41be0da5 685 }\r
b8b04307
JF
686 }\r
687 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
688 }\r
689 }\r
690\r
691 //\r
692 // AP finished executing C code\r
693 //\r
694 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
0594ec41 695 InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting);\r
b8b04307
JF
696\r
697 //\r
698 // Place AP is specified loop mode\r
699 //\r
700 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
701 //\r
702 // Save AP volatile registers\r
703 //\r
704 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
705 //\r
706 // Place AP in HLT-loop\r
707 //\r
708 while (TRUE) {\r
709 DisableInterrupts ();\r
710 CpuSleep ();\r
711 CpuPause ();\r
712 }\r
713 }\r
714 while (TRUE) {\r
715 DisableInterrupts ();\r
716 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
717 //\r
718 // Place AP in MWAIT-loop\r
719 //\r
720 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);\r
721 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
722 //\r
723 // Check AP start-up signal again.\r
724 // If AP start-up signal is not set, place AP into\r
725 // the specified C-state\r
726 //\r
727 AsmMwait (CpuMpData->ApTargetCState << 4, 0);\r
728 }\r
729 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {\r
730 //\r
731 // Place AP in Run-loop\r
732 //\r
733 CpuPause ();\r
734 } else {\r
735 ASSERT (FALSE);\r
736 }\r
737\r
738 //\r
739 // If AP start-up signal is written, AP is waken up\r
740 // otherwise place AP in loop again\r
741 //\r
742 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
743 break;\r
744 }\r
745 }\r
746 }\r
747}\r
748\r
96f5920d
JF
749/**\r
750 Wait for AP wakeup and write AP start-up signal till AP is waken up.\r
751\r
752 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal\r
753**/\r
754VOID\r
755WaitApWakeup (\r
756 IN volatile UINT32 *ApStartupSignalBuffer\r
757 )\r
758{\r
759 //\r
760 // If AP is waken up, StartupApSignal should be cleared.\r
761 // Otherwise, write StartupApSignal again till AP waken up.\r
762 //\r
763 while (InterlockedCompareExchange32 (\r
764 (UINT32 *) ApStartupSignalBuffer,\r
765 WAKEUP_AP_SIGNAL,\r
766 WAKEUP_AP_SIGNAL\r
767 ) != 0) {\r
768 CpuPause ();\r
769 }\r
770}\r
771\r
7c3f2a12
JF
772/**\r
773 This function will fill the exchange info structure.\r
774\r
775 @param[in] CpuMpData Pointer to CPU MP Data\r
776\r
777**/\r
778VOID\r
779FillExchangeInfoData (\r
780 IN CPU_MP_DATA *CpuMpData\r
781 )\r
782{\r
783 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
f32bfe6d
JW
784 UINTN Size;\r
785 IA32_SEGMENT_DESCRIPTOR *Selector;\r
7c3f2a12
JF
786\r
787 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
788 ExchangeInfo->Lock = 0;\r
789 ExchangeInfo->StackStart = CpuMpData->Buffer;\r
790 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;\r
791 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;\r
792 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;\r
793\r
794 ExchangeInfo->CodeSegment = AsmReadCs ();\r
795 ExchangeInfo->DataSegment = AsmReadDs ();\r
796\r
797 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
798\r
799 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;\r
37676b9f 800 ExchangeInfo->ApIndex = 0;\r
0594ec41 801 ExchangeInfo->NumApsExecuting = 0;\r
46d4b885
JF
802 ExchangeInfo->InitFlag = (UINTN) CpuMpData->InitFlag;\r
803 ExchangeInfo->CpuInfo = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
7c3f2a12
JF
804 ExchangeInfo->CpuMpData = CpuMpData;\r
805\r
806 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();\r
807\r
3b2928b4
MK
808 ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits;\r
809\r
7c3f2a12
JF
810 //\r
811 // Get the BSP's data of GDT and IDT\r
812 //\r
813 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
814 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
f32bfe6d
JW
815\r
816 //\r
817 // Find a 32-bit code segment\r
818 //\r
819 Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;\r
820 Size = ExchangeInfo->GdtrProfile.Limit + 1;\r
821 while (Size > 0) {\r
822 if (Selector->Bits.L == 0 && Selector->Bits.Type >= 8) {\r
823 ExchangeInfo->ModeTransitionSegment =\r
824 (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);\r
825 break;\r
826 }\r
827 Selector += 1;\r
828 Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);\r
829 }\r
830\r
831 //\r
832 // Copy all 32-bit code and 64-bit code into memory with type of\r
833 // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.\r
834 //\r
66833b2a 835 if (CpuMpData->WakeupBufferHigh != 0) {\r
f32bfe6d
JW
836 Size = CpuMpData->AddressMap.RendezvousFunnelSize -\r
837 CpuMpData->AddressMap.ModeTransitionOffset;\r
838 CopyMem (\r
66833b2a 839 (VOID *)CpuMpData->WakeupBufferHigh,\r
f32bfe6d
JW
840 CpuMpData->AddressMap.RendezvousFunnelAddress +\r
841 CpuMpData->AddressMap.ModeTransitionOffset,\r
842 Size\r
843 );\r
844\r
66833b2a 845 ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;\r
f32bfe6d
JW
846 } else {\r
847 ExchangeInfo->ModeTransitionMemory = (UINT32)\r
848 (ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset);\r
849 }\r
69dfa8d8
JW
850\r
851 ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +\r
852 (UINT32)ExchangeInfo->ModeOffset -\r
853 (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;\r
854 ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;\r
7c3f2a12
JF
855}\r
856\r
6e1987f1
LE
857/**\r
858 Helper function that waits until the finished AP count reaches the specified\r
859 limit, or the specified timeout elapses (whichever comes first).\r
860\r
861 @param[in] CpuMpData Pointer to CPU MP Data.\r
862 @param[in] FinishedApLimit The number of finished APs to wait for.\r
863 @param[in] TimeLimit The number of microseconds to wait for.\r
864**/\r
865VOID\r
866TimedWaitForApFinish (\r
867 IN CPU_MP_DATA *CpuMpData,\r
868 IN UINT32 FinishedApLimit,\r
869 IN UINT32 TimeLimit\r
870 );\r
871\r
a6b3d753
SZ
872/**\r
873 Get available system memory below 1MB by specified size.\r
874\r
875 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
876**/\r
877VOID\r
878BackupAndPrepareWakeupBuffer(\r
879 IN CPU_MP_DATA *CpuMpData\r
880 )\r
881{\r
882 CopyMem (\r
883 (VOID *) CpuMpData->BackupBuffer,\r
884 (VOID *) CpuMpData->WakeupBuffer,\r
885 CpuMpData->BackupBufferSize\r
886 );\r
887 CopyMem (\r
888 (VOID *) CpuMpData->WakeupBuffer,\r
889 (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,\r
890 CpuMpData->AddressMap.RendezvousFunnelSize\r
891 );\r
892}\r
893\r
894/**\r
895 Restore wakeup buffer data.\r
896\r
897 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
898**/\r
899VOID\r
900RestoreWakeupBuffer(\r
901 IN CPU_MP_DATA *CpuMpData\r
902 )\r
903{\r
904 CopyMem (\r
905 (VOID *) CpuMpData->WakeupBuffer,\r
906 (VOID *) CpuMpData->BackupBuffer,\r
907 CpuMpData->BackupBufferSize\r
908 );\r
909}\r
910\r
911/**\r
912 Allocate reset vector buffer.\r
913\r
914 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
915**/\r
916VOID\r
917AllocateResetVector (\r
918 IN OUT CPU_MP_DATA *CpuMpData\r
919 )\r
920{\r
921 UINTN ApResetVectorSize;\r
922\r
923 if (CpuMpData->WakeupBuffer == (UINTN) -1) {\r
924 ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +\r
925 sizeof (MP_CPU_EXCHANGE_INFO);\r
926\r
927 CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);\r
928 CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
929 (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);\r
66833b2a
JW
930 CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer (\r
931 CpuMpData->AddressMap.RendezvousFunnelSize -\r
932 CpuMpData->AddressMap.ModeTransitionOffset\r
933 );\r
a6b3d753
SZ
934 }\r
935 BackupAndPrepareWakeupBuffer (CpuMpData);\r
936}\r
937\r
938/**\r
939 Free AP reset vector buffer.\r
940\r
941 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
942**/\r
943VOID\r
944FreeResetVector (\r
945 IN CPU_MP_DATA *CpuMpData\r
946 )\r
947{\r
948 RestoreWakeupBuffer (CpuMpData);\r
949}\r
950\r
96f5920d
JF
951/**\r
952 This function will be called by BSP to wakeup AP.\r
953\r
954 @param[in] CpuMpData Pointer to CPU MP Data\r
955 @param[in] Broadcast TRUE: Send broadcast IPI to all APs\r
956 FALSE: Send IPI to AP by ApicId\r
957 @param[in] ProcessorNumber The handle number of specified processor\r
958 @param[in] Procedure The function to be invoked by AP\r
959 @param[in] ProcedureArgument The argument to be passed into AP function\r
960**/\r
961VOID\r
962WakeUpAP (\r
963 IN CPU_MP_DATA *CpuMpData,\r
964 IN BOOLEAN Broadcast,\r
965 IN UINTN ProcessorNumber,\r
966 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
967 IN VOID *ProcedureArgument OPTIONAL\r
968 )\r
969{\r
970 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
971 UINTN Index;\r
972 CPU_AP_DATA *CpuData;\r
973 BOOLEAN ResetVectorRequired;\r
31a1e4da 974 CPU_INFO_IN_HOB *CpuInfoInHob;\r
96f5920d
JF
975\r
976 CpuMpData->FinishedCount = 0;\r
977 ResetVectorRequired = FALSE;\r
978\r
979 if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
980 CpuMpData->InitFlag != ApInitDone) {\r
981 ResetVectorRequired = TRUE;\r
982 AllocateResetVector (CpuMpData);\r
983 FillExchangeInfoData (CpuMpData);\r
ffab2442 984 SaveLocalApicTimerSetting (CpuMpData);\r
96f5920d
JF
985 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
986 //\r
987 // Get AP target C-state each time when waking up AP,\r
988 // for it maybe updated by platform again\r
989 //\r
990 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
991 }\r
992\r
993 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
994\r
995 if (Broadcast) {\r
996 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
997 if (Index != CpuMpData->BspNumber) {\r
998 CpuData = &CpuMpData->CpuData[Index];\r
999 CpuData->ApFunction = (UINTN) Procedure;\r
1000 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
1001 SetApState (CpuData, CpuStateReady);\r
1002 if (CpuMpData->InitFlag != ApInitConfig) {\r
1003 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
1004 }\r
1005 }\r
1006 }\r
1007 if (ResetVectorRequired) {\r
1008 //\r
1009 // Wakeup all APs\r
1010 //\r
1011 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
1012 }\r
c1192210
JF
1013 if (CpuMpData->InitFlag == ApInitConfig) {\r
1014 //\r
86121874
ED
1015 // Here support two methods to collect AP count through adjust\r
1016 // PcdCpuApInitTimeOutInMicroSeconds values.\r
1017 //\r
1018 // one way is set a value to just let the first AP to start the\r
1019 // initialization, then through the later while loop to wait all Aps\r
1020 // finsh the initialization.\r
1021 // The other way is set a value to let all APs finished the initialzation.\r
1022 // In this case, the later while loop is useless.\r
1023 //\r
1024 TimedWaitForApFinish (\r
1025 CpuMpData,\r
1026 PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,\r
1027 PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)\r
1028 );\r
0594ec41
ED
1029\r
1030 while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {\r
1031 CpuPause();\r
1032 }\r
c1192210 1033 } else {\r
96f5920d
JF
1034 //\r
1035 // Wait all APs waken up if this is not the 1st broadcast of SIPI\r
1036 //\r
1037 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
1038 CpuData = &CpuMpData->CpuData[Index];\r
1039 if (Index != CpuMpData->BspNumber) {\r
1040 WaitApWakeup (CpuData->StartupApSignal);\r
1041 }\r
1042 }\r
1043 }\r
1044 } else {\r
1045 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1046 CpuData->ApFunction = (UINTN) Procedure;\r
1047 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
1048 SetApState (CpuData, CpuStateReady);\r
1049 //\r
1050 // Wakeup specified AP\r
1051 //\r
1052 ASSERT (CpuMpData->InitFlag != ApInitConfig);\r
1053 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
1054 if (ResetVectorRequired) {\r
31a1e4da 1055 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
96f5920d 1056 SendInitSipiSipi (\r
31a1e4da 1057 CpuInfoInHob[ProcessorNumber].ApicId,\r
96f5920d
JF
1058 (UINT32) ExchangeInfo->BufferStart\r
1059 );\r
1060 }\r
1061 //\r
1062 // Wait specified AP waken up\r
1063 //\r
1064 WaitApWakeup (CpuData->StartupApSignal);\r
1065 }\r
1066\r
1067 if (ResetVectorRequired) {\r
1068 FreeResetVector (CpuMpData);\r
1069 }\r
1070}\r
1071\r
08085f08
JF
1072/**\r
1073 Calculate timeout value and return the current performance counter value.\r
1074\r
1075 Calculate the number of performance counter ticks required for a timeout.\r
1076 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
1077 as infinity.\r
1078\r
1079 @param[in] TimeoutInMicroseconds Timeout value in microseconds.\r
1080 @param[out] CurrentTime Returns the current value of the performance counter.\r
1081\r
1082 @return Expected time stamp counter for timeout.\r
1083 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
1084 as infinity.\r
1085\r
1086**/\r
1087UINT64\r
1088CalculateTimeout (\r
1089 IN UINTN TimeoutInMicroseconds,\r
1090 OUT UINT64 *CurrentTime\r
1091 )\r
1092{\r
48cfb7c0
ED
1093 UINT64 TimeoutInSeconds;\r
1094 UINT64 TimestampCounterFreq;\r
1095\r
08085f08
JF
1096 //\r
1097 // Read the current value of the performance counter\r
1098 //\r
1099 *CurrentTime = GetPerformanceCounter ();\r
1100\r
1101 //\r
1102 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
1103 // as infinity.\r
1104 //\r
1105 if (TimeoutInMicroseconds == 0) {\r
1106 return 0;\r
1107 }\r
1108\r
1109 //\r
1110 // GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
48cfb7c0
ED
1111 // in Hz. \r
1112 //\r
1113 TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);\r
1114\r
08085f08 1115 //\r
48cfb7c0
ED
1116 // Check the potential overflow before calculate the number of ticks for the timeout value.\r
1117 //\r
1118 if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {\r
1119 //\r
1120 // Convert microseconds into seconds if direct multiplication overflows\r
1121 //\r
1122 TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);\r
1123 //\r
1124 // Assertion if the final tick count exceeds MAX_UINT64\r
1125 //\r
1126 ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);\r
1127 return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);\r
1128 } else {\r
1129 //\r
1130 // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide\r
1131 // it by 1,000,000, to get the number of ticks for the timeout value.\r
1132 //\r
1133 return DivU64x32 (\r
1134 MultU64x64 (\r
1135 TimestampCounterFreq,\r
1136 TimeoutInMicroseconds\r
1137 ),\r
1138 1000000\r
1139 );\r
1140 }\r
08085f08
JF
1141}\r
1142\r
1143/**\r
1144 Checks whether timeout expires.\r
1145\r
1146 Check whether the number of elapsed performance counter ticks required for\r
1147 a timeout condition has been reached.\r
1148 If Timeout is zero, which means infinity, return value is always FALSE.\r
1149\r
1150 @param[in, out] PreviousTime On input, the value of the performance counter\r
1151 when it was last read.\r
1152 On output, the current value of the performance\r
1153 counter\r
1154 @param[in] TotalTime The total amount of elapsed time in performance\r
1155 counter ticks.\r
1156 @param[in] Timeout The number of performance counter ticks required\r
1157 to reach a timeout condition.\r
1158\r
1159 @retval TRUE A timeout condition has been reached.\r
1160 @retval FALSE A timeout condition has not been reached.\r
1161\r
1162**/\r
1163BOOLEAN\r
1164CheckTimeout (\r
1165 IN OUT UINT64 *PreviousTime,\r
1166 IN UINT64 *TotalTime,\r
1167 IN UINT64 Timeout\r
1168 )\r
1169{\r
1170 UINT64 Start;\r
1171 UINT64 End;\r
1172 UINT64 CurrentTime;\r
1173 INT64 Delta;\r
1174 INT64 Cycle;\r
1175\r
1176 if (Timeout == 0) {\r
1177 return FALSE;\r
1178 }\r
1179 GetPerformanceCounterProperties (&Start, &End);\r
1180 Cycle = End - Start;\r
1181 if (Cycle < 0) {\r
1182 Cycle = -Cycle;\r
1183 }\r
1184 Cycle++;\r
1185 CurrentTime = GetPerformanceCounter();\r
1186 Delta = (INT64) (CurrentTime - *PreviousTime);\r
1187 if (Start > End) {\r
1188 Delta = -Delta;\r
1189 }\r
1190 if (Delta < 0) {\r
1191 Delta += Cycle;\r
1192 }\r
1193 *TotalTime += Delta;\r
1194 *PreviousTime = CurrentTime;\r
1195 if (*TotalTime > Timeout) {\r
1196 return TRUE;\r
1197 }\r
1198 return FALSE;\r
1199}\r
1200\r
6e1987f1
LE
1201/**\r
1202 Helper function that waits until the finished AP count reaches the specified\r
1203 limit, or the specified timeout elapses (whichever comes first).\r
1204\r
1205 @param[in] CpuMpData Pointer to CPU MP Data.\r
1206 @param[in] FinishedApLimit The number of finished APs to wait for.\r
1207 @param[in] TimeLimit The number of microseconds to wait for.\r
1208**/\r
1209VOID\r
1210TimedWaitForApFinish (\r
1211 IN CPU_MP_DATA *CpuMpData,\r
1212 IN UINT32 FinishedApLimit,\r
1213 IN UINT32 TimeLimit\r
1214 )\r
1215{\r
1216 //\r
1217 // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0\r
1218 // "infinity", so check for (TimeLimit == 0) explicitly.\r
1219 //\r
1220 if (TimeLimit == 0) {\r
1221 return;\r
1222 }\r
1223\r
1224 CpuMpData->TotalTime = 0;\r
1225 CpuMpData->ExpectedTime = CalculateTimeout (\r
1226 TimeLimit,\r
1227 &CpuMpData->CurrentTime\r
1228 );\r
1229 while (CpuMpData->FinishedCount < FinishedApLimit &&\r
1230 !CheckTimeout (\r
1231 &CpuMpData->CurrentTime,\r
1232 &CpuMpData->TotalTime,\r
1233 CpuMpData->ExpectedTime\r
1234 )) {\r
1235 CpuPause ();\r
1236 }\r
1237\r
1238 if (CpuMpData->FinishedCount >= FinishedApLimit) {\r
1239 DEBUG ((\r
1240 DEBUG_VERBOSE,\r
1241 "%a: reached FinishedApLimit=%u in %Lu microseconds\n",\r
1242 __FUNCTION__,\r
1243 FinishedApLimit,\r
1244 DivU64x64Remainder (\r
1245 MultU64x32 (CpuMpData->TotalTime, 1000000),\r
1246 GetPerformanceCounterProperties (NULL, NULL),\r
1247 NULL\r
1248 )\r
1249 ));\r
1250 }\r
1251}\r
1252\r
08085f08
JF
1253/**\r
1254 Reset an AP to Idle state.\r
1255\r
1256 Any task being executed by the AP will be aborted and the AP\r
1257 will be waiting for a new task in Wait-For-SIPI state.\r
1258\r
1259 @param[in] ProcessorNumber The handle number of processor.\r
1260**/\r
1261VOID\r
1262ResetProcessorToIdleState (\r
1263 IN UINTN ProcessorNumber\r
1264 )\r
1265{\r
1266 CPU_MP_DATA *CpuMpData;\r
1267\r
1268 CpuMpData = GetCpuMpData ();\r
1269\r
cb33bde4 1270 CpuMpData->InitFlag = ApInitReconfig;\r
08085f08 1271 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL);\r
cb33bde4
JF
1272 while (CpuMpData->FinishedCount < 1) {\r
1273 CpuPause ();\r
1274 }\r
1275 CpuMpData->InitFlag = ApInitDone;\r
08085f08
JF
1276\r
1277 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
1278}\r
1279\r
1280/**\r
1281 Searches for the next waiting AP.\r
1282\r
1283 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().\r
1284\r
1285 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.\r
1286\r
1287 @retval EFI_SUCCESS The next waiting AP has been found.\r
1288 @retval EFI_NOT_FOUND No waiting AP exists.\r
1289\r
1290**/\r
1291EFI_STATUS\r
1292GetNextWaitingProcessorNumber (\r
1293 OUT UINTN *NextProcessorNumber\r
1294 )\r
1295{\r
1296 UINTN ProcessorNumber;\r
1297 CPU_MP_DATA *CpuMpData;\r
1298\r
1299 CpuMpData = GetCpuMpData ();\r
1300\r
1301 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1302 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1303 *NextProcessorNumber = ProcessorNumber;\r
1304 return EFI_SUCCESS;\r
1305 }\r
1306 }\r
1307\r
1308 return EFI_NOT_FOUND;\r
1309}\r
1310\r
1311/** Checks status of specified AP.\r
1312\r
1313 This function checks whether the specified AP has finished the task assigned\r
1314 by StartupThisAP(), and whether timeout expires.\r
1315\r
1316 @param[in] ProcessorNumber The handle number of processor.\r
1317\r
1318 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().\r
1319 @retval EFI_TIMEOUT The timeout expires.\r
1320 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.\r
1321**/\r
1322EFI_STATUS\r
1323CheckThisAP (\r
1324 IN UINTN ProcessorNumber\r
1325 )\r
1326{\r
1327 CPU_MP_DATA *CpuMpData;\r
1328 CPU_AP_DATA *CpuData;\r
1329\r
1330 CpuMpData = GetCpuMpData ();\r
1331 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1332\r
1333 //\r
1334 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
1335 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
1336 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
1337 //\r
1338 //\r
1339 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.\r
1340 //\r
1341 if (GetApState(CpuData) == CpuStateFinished) {\r
1342 if (CpuData->Finished != NULL) {\r
1343 *(CpuData->Finished) = TRUE;\r
1344 }\r
1345 SetApState (CpuData, CpuStateIdle);\r
1346 return EFI_SUCCESS;\r
1347 } else {\r
1348 //\r
1349 // If timeout expires for StartupThisAP(), report timeout.\r
1350 //\r
1351 if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {\r
1352 if (CpuData->Finished != NULL) {\r
1353 *(CpuData->Finished) = FALSE;\r
1354 }\r
1355 //\r
1356 // Reset failed AP to idle state\r
1357 //\r
1358 ResetProcessorToIdleState (ProcessorNumber);\r
1359\r
1360 return EFI_TIMEOUT;\r
1361 }\r
1362 }\r
1363 return EFI_NOT_READY;\r
1364}\r
1365\r
1366/**\r
1367 Checks status of all APs.\r
1368\r
1369 This function checks whether all APs have finished task assigned by StartupAllAPs(),\r
1370 and whether timeout expires.\r
1371\r
1372 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().\r
1373 @retval EFI_TIMEOUT The timeout expires.\r
1374 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.\r
1375**/\r
1376EFI_STATUS\r
1377CheckAllAPs (\r
1378 VOID\r
1379 )\r
1380{\r
1381 UINTN ProcessorNumber;\r
1382 UINTN NextProcessorNumber;\r
1383 UINTN ListIndex;\r
1384 EFI_STATUS Status;\r
1385 CPU_MP_DATA *CpuMpData;\r
1386 CPU_AP_DATA *CpuData;\r
1387\r
1388 CpuMpData = GetCpuMpData ();\r
1389\r
1390 NextProcessorNumber = 0;\r
1391\r
1392 //\r
1393 // Go through all APs that are responsible for the StartupAllAPs().\r
1394 //\r
1395 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1396 if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1397 continue;\r
1398 }\r
1399\r
1400 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1401 //\r
1402 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
1403 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
1404 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
1405 //\r
1406 if (GetApState(CpuData) == CpuStateFinished) {\r
1407 CpuMpData->RunningCount ++;\r
1408 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
1409 SetApState(CpuData, CpuStateIdle);\r
1410\r
1411 //\r
1412 // If in Single Thread mode, then search for the next waiting AP for execution.\r
1413 //\r
1414 if (CpuMpData->SingleThread) {\r
1415 Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);\r
1416\r
1417 if (!EFI_ERROR (Status)) {\r
1418 WakeUpAP (\r
1419 CpuMpData,\r
1420 FALSE,\r
1421 (UINT32) NextProcessorNumber,\r
1422 CpuMpData->Procedure,\r
1423 CpuMpData->ProcArguments\r
1424 );\r
1425 }\r
1426 }\r
1427 }\r
1428 }\r
1429\r
1430 //\r
1431 // If all APs finish, return EFI_SUCCESS.\r
1432 //\r
1433 if (CpuMpData->RunningCount == CpuMpData->StartCount) {\r
1434 return EFI_SUCCESS;\r
1435 }\r
1436\r
1437 //\r
1438 // If timeout expires, report timeout.\r
1439 //\r
1440 if (CheckTimeout (\r
1441 &CpuMpData->CurrentTime,\r
1442 &CpuMpData->TotalTime,\r
1443 CpuMpData->ExpectedTime)\r
1444 ) {\r
1445 //\r
1446 // If FailedCpuList is not NULL, record all failed APs in it.\r
1447 //\r
1448 if (CpuMpData->FailedCpuList != NULL) {\r
1449 *CpuMpData->FailedCpuList =\r
1450 AllocatePool ((CpuMpData->StartCount - CpuMpData->FinishedCount + 1) * sizeof (UINTN));\r
1451 ASSERT (*CpuMpData->FailedCpuList != NULL);\r
1452 }\r
1453 ListIndex = 0;\r
1454\r
1455 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1456 //\r
1457 // Check whether this processor is responsible for StartupAllAPs().\r
1458 //\r
1459 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1460 //\r
1461 // Reset failed APs to idle state\r
1462 //\r
1463 ResetProcessorToIdleState (ProcessorNumber);\r
1464 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
1465 if (CpuMpData->FailedCpuList != NULL) {\r
1466 (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;\r
1467 }\r
1468 }\r
1469 }\r
1470 if (CpuMpData->FailedCpuList != NULL) {\r
1471 (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;\r
1472 }\r
1473 return EFI_TIMEOUT;\r
1474 }\r
1475 return EFI_NOT_READY;\r
1476}\r
1477\r
3e8ad6bd
JF
1478/**\r
1479 MP Initialize Library initialization.\r
1480\r
1481 This service will allocate AP reset vector and wakeup all APs to do APs\r
1482 initialization.\r
1483\r
1484 This service must be invoked before all other MP Initialize Library\r
1485 service are invoked.\r
1486\r
1487 @retval EFI_SUCCESS MP initialization succeeds.\r
1488 @retval Others MP initialization fails.\r
1489\r
1490**/\r
1491EFI_STATUS\r
1492EFIAPI\r
1493MpInitLibInitialize (\r
1494 VOID\r
1495 )\r
1496{\r
6a2ee2bb
JF
1497 CPU_MP_DATA *OldCpuMpData;\r
1498 CPU_INFO_IN_HOB *CpuInfoInHob;\r
e59f8f6b
JF
1499 UINT32 MaxLogicalProcessorNumber;\r
1500 UINT32 ApStackSize;\r
f7f85d83 1501 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
e59f8f6b 1502 UINTN BufferSize;\r
9ebcf0f4 1503 UINT32 MonitorFilterSize;\r
e59f8f6b
JF
1504 VOID *MpBuffer;\r
1505 UINTN Buffer;\r
1506 CPU_MP_DATA *CpuMpData;\r
9ebcf0f4 1507 UINT8 ApLoopMode;\r
e59f8f6b 1508 UINT8 *MonitorBuffer;\r
03a1a925 1509 UINTN Index;\r
f7f85d83 1510 UINTN ApResetVectorSize;\r
e59f8f6b 1511 UINTN BackupBufferAddr;\r
6a2ee2bb
JF
1512\r
1513 OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
1514 if (OldCpuMpData == NULL) {\r
1515 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
1516 } else {\r
1517 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;\r
1518 }\r
14e8137c 1519 ASSERT (MaxLogicalProcessorNumber != 0);\r
f7f85d83
JF
1520\r
1521 AsmGetAddressMap (&AddressMap);\r
1522 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
e59f8f6b 1523 ApStackSize = PcdGet32(PcdCpuApStackSize);\r
9ebcf0f4
JF
1524 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
1525\r
e59f8f6b
JF
1526 BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
1527 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
1528 BufferSize += sizeof (CPU_MP_DATA);\r
1529 BufferSize += ApResetVectorSize;\r
1530 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
1531 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
1532 ASSERT (MpBuffer != NULL);\r
1533 ZeroMem (MpBuffer, BufferSize);\r
1534 Buffer = (UINTN) MpBuffer;\r
1535\r
1536 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
1537 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
1538 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
1539 CpuMpData->Buffer = Buffer;\r
1540 CpuMpData->CpuApStackSize = ApStackSize;\r
1541 CpuMpData->BackupBuffer = BackupBufferAddr;\r
1542 CpuMpData->BackupBufferSize = ApResetVectorSize;\r
e59f8f6b
JF
1543 CpuMpData->WakeupBuffer = (UINTN) -1;\r
1544 CpuMpData->CpuCount = 1;\r
1545 CpuMpData->BspNumber = 0;\r
1546 CpuMpData->WaitEvent = NULL;\r
41be0da5 1547 CpuMpData->SwitchBspFlag = FALSE;\r
e59f8f6b
JF
1548 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
1549 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
1e3f7a37
ED
1550 CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
1551 CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
e59f8f6b
JF
1552 InitializeSpinLock(&CpuMpData->MpLock);\r
1553 //\r
68cb9330
JF
1554 // Save BSP's Control registers to APs\r
1555 //\r
1556 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
1557 //\r
03a1a925
JF
1558 // Set BSP basic information\r
1559 //\r
f2655dcf 1560 InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize);\r
03a1a925 1561 //\r
e59f8f6b
JF
1562 // Save assembly code information\r
1563 //\r
1564 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
1565 //\r
1566 // Finally set AP loop mode\r
1567 //\r
1568 CpuMpData->ApLoopMode = ApLoopMode;\r
1569 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
1570 //\r
03a1a925
JF
1571 // Set up APs wakeup signal buffer\r
1572 //\r
1573 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
1574 CpuMpData->CpuData[Index].StartupApSignal =\r
1575 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
1576 }\r
94f63c76
JF
1577 //\r
1578 // Load Microcode on BSP\r
1579 //\r
1580 MicrocodeDetect (CpuMpData);\r
1581 //\r
e59f8f6b
JF
1582 // Store BSP's MTRR setting\r
1583 //\r
1584 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
9d64a9fd
JF
1585 //\r
1586 // Enable the local APIC for Virtual Wire Mode.\r
1587 //\r
1588 ProgramVirtualWireMode ();\r
e59f8f6b 1589\r
6a2ee2bb 1590 if (OldCpuMpData == NULL) {\r
14e8137c
JF
1591 if (MaxLogicalProcessorNumber > 1) {\r
1592 //\r
1593 // Wakeup all APs and calculate the processor count in system\r
1594 //\r
1595 CollectProcessorCount (CpuMpData);\r
1596 }\r
6a2ee2bb
JF
1597 } else {\r
1598 //\r
1599 // APs have been wakeup before, just get the CPU Information\r
1600 // from HOB\r
1601 //\r
1602 CpuMpData->CpuCount = OldCpuMpData->CpuCount;\r
1603 CpuMpData->BspNumber = OldCpuMpData->BspNumber;\r
1604 CpuMpData->InitFlag = ApInitReconfig;\r
31a1e4da
JF
1605 CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;\r
1606 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
6a2ee2bb
JF
1607 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
1608 InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);\r
71d8226a 1609 if (CpuInfoInHob[Index].InitialApicId >= 255 || Index > 254) {\r
6a2ee2bb
JF
1610 CpuMpData->X2ApicEnable = TRUE;\r
1611 }\r
31a1e4da 1612 CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE;\r
6a2ee2bb
JF
1613 CpuMpData->CpuData[Index].ApFunction = 0;\r
1614 CopyMem (\r
1615 &CpuMpData->CpuData[Index].VolatileRegisters,\r
1616 &CpuMpData->CpuData[0].VolatileRegisters,\r
1617 sizeof (CPU_VOLATILE_REGISTERS)\r
1618 );\r
1619 }\r
14e8137c
JF
1620 if (MaxLogicalProcessorNumber > 1) {\r
1621 //\r
1622 // Wakeup APs to do some AP initialize sync\r
1623 //\r
1624 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);\r
1625 //\r
1626 // Wait for all APs finished initialization\r
1627 //\r
1628 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
1629 CpuPause ();\r
1630 }\r
1631 CpuMpData->InitFlag = ApInitDone;\r
1632 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
1633 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
1634 }\r
6a2ee2bb
JF
1635 }\r
1636 }\r
93ca4c0f
JF
1637\r
1638 //\r
1639 // Initialize global data for MP support\r
1640 //\r
1641 InitMpGlobalData (CpuMpData);\r
1642\r
f7f85d83 1643 return EFI_SUCCESS;\r
3e8ad6bd
JF
1644}\r
1645\r
1646/**\r
1647 Gets detailed MP-related information on the requested processor at the\r
1648 instant this call is made. This service may only be called from the BSP.\r
1649\r
1650 @param[in] ProcessorNumber The handle number of processor.\r
1651 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
1652 the requested processor is deposited.\r
1653 @param[out] HealthData Return processor health data.\r
1654\r
1655 @retval EFI_SUCCESS Processor information was returned.\r
1656 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
1657 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
1658 @retval EFI_NOT_FOUND The processor with the handle specified by\r
1659 ProcessorNumber does not exist in the platform.\r
1660 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1661\r
1662**/\r
1663EFI_STATUS\r
1664EFIAPI\r
1665MpInitLibGetProcessorInfo (\r
1666 IN UINTN ProcessorNumber,\r
1667 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,\r
1668 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL\r
1669 )\r
1670{\r
ad52f25e
JF
1671 CPU_MP_DATA *CpuMpData;\r
1672 UINTN CallerNumber;\r
31a1e4da 1673 CPU_INFO_IN_HOB *CpuInfoInHob;\r
ad52f25e
JF
1674\r
1675 CpuMpData = GetCpuMpData ();\r
31a1e4da 1676 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
ad52f25e
JF
1677\r
1678 //\r
1679 // Check whether caller processor is BSP\r
1680 //\r
1681 MpInitLibWhoAmI (&CallerNumber);\r
1682 if (CallerNumber != CpuMpData->BspNumber) {\r
1683 return EFI_DEVICE_ERROR;\r
1684 }\r
1685\r
1686 if (ProcessorInfoBuffer == NULL) {\r
1687 return EFI_INVALID_PARAMETER;\r
1688 }\r
1689\r
1690 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
1691 return EFI_NOT_FOUND;\r
1692 }\r
1693\r
31a1e4da 1694 ProcessorInfoBuffer->ProcessorId = (UINT64) CpuInfoInHob[ProcessorNumber].ApicId;\r
ad52f25e
JF
1695 ProcessorInfoBuffer->StatusFlag = 0;\r
1696 if (ProcessorNumber == CpuMpData->BspNumber) {\r
1697 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;\r
1698 }\r
1699 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {\r
1700 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;\r
1701 }\r
1702 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {\r
1703 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;\r
1704 } else {\r
1705 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;\r
1706 }\r
1707\r
1708 //\r
1709 // Get processor location information\r
1710 //\r
262128e5 1711 GetProcessorLocationByApicId (\r
31a1e4da 1712 CpuInfoInHob[ProcessorNumber].ApicId,\r
73152f19
LD
1713 &ProcessorInfoBuffer->Location.Package,\r
1714 &ProcessorInfoBuffer->Location.Core,\r
1715 &ProcessorInfoBuffer->Location.Thread\r
1716 );\r
ad52f25e
JF
1717\r
1718 if (HealthData != NULL) {\r
31a1e4da 1719 HealthData->Uint32 = CpuInfoInHob[ProcessorNumber].Health;\r
ad52f25e
JF
1720 }\r
1721\r
1722 return EFI_SUCCESS;\r
3e8ad6bd 1723}\r
ad52f25e 1724\r
41be0da5
JF
1725/**\r
1726 Worker function to switch the requested AP to be the BSP from that point onward.\r
1727\r
1728 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.\r
1729 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
1730 enabled AP. Otherwise, it will be disabled.\r
1731\r
1732 @retval EFI_SUCCESS BSP successfully switched.\r
1733 @retval others Failed to switch BSP. \r
1734\r
1735**/\r
1736EFI_STATUS\r
1737SwitchBSPWorker (\r
1738 IN UINTN ProcessorNumber,\r
1739 IN BOOLEAN EnableOldBSP\r
1740 )\r
1741{\r
1742 CPU_MP_DATA *CpuMpData;\r
1743 UINTN CallerNumber;\r
1744 CPU_STATE State;\r
1745 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
a8d75a18 1746 BOOLEAN OldInterruptState;\r
26b43433 1747 BOOLEAN OldTimerInterruptState;\r
a8d75a18 1748\r
26b43433
JF
1749 //\r
1750 // Save and Disable Local APIC timer interrupt\r
1751 //\r
1752 OldTimerInterruptState = GetApicTimerInterruptState ();\r
1753 DisableApicTimerInterrupt ();\r
a8d75a18
JF
1754 //\r
1755 // Before send both BSP and AP to a procedure to exchange their roles,\r
1756 // interrupt must be disabled. This is because during the exchange role\r
1757 // process, 2 CPU may use 1 stack. If interrupt happens, the stack will\r
1758 // be corrupted, since interrupt return address will be pushed to stack\r
1759 // by hardware.\r
1760 //\r
1761 OldInterruptState = SaveAndDisableInterrupts ();\r
1762\r
1763 //\r
1764 // Mask LINT0 & LINT1 for the old BSP\r
1765 //\r
1766 DisableLvtInterrupts ();\r
41be0da5
JF
1767\r
1768 CpuMpData = GetCpuMpData ();\r
1769\r
1770 //\r
1771 // Check whether caller processor is BSP\r
1772 //\r
1773 MpInitLibWhoAmI (&CallerNumber);\r
1774 if (CallerNumber != CpuMpData->BspNumber) {\r
5e72dacc 1775 return EFI_DEVICE_ERROR;\r
41be0da5
JF
1776 }\r
1777\r
1778 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
1779 return EFI_NOT_FOUND;\r
1780 }\r
1781\r
1782 //\r
1783 // Check whether specified AP is disabled\r
1784 //\r
1785 State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);\r
1786 if (State == CpuStateDisabled) {\r
1787 return EFI_INVALID_PARAMETER;\r
1788 }\r
1789\r
1790 //\r
1791 // Check whether ProcessorNumber specifies the current BSP\r
1792 //\r
1793 if (ProcessorNumber == CpuMpData->BspNumber) {\r
1794 return EFI_INVALID_PARAMETER;\r
1795 }\r
1796\r
1797 //\r
1798 // Check whether specified AP is busy\r
1799 //\r
1800 if (State == CpuStateBusy) {\r
1801 return EFI_NOT_READY;\r
1802 }\r
1803\r
1804 CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;\r
1805 CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;\r
1806 CpuMpData->SwitchBspFlag = TRUE;\r
b3775af2 1807 CpuMpData->NewBspNumber = ProcessorNumber;\r
41be0da5
JF
1808\r
1809 //\r
1810 // Clear the BSP bit of MSR_IA32_APIC_BASE\r
1811 //\r
1812 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
1813 ApicBaseMsr.Bits.BSP = 0;\r
1814 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
1815\r
1816 //\r
1817 // Need to wakeUp AP (future BSP).\r
1818 //\r
1819 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData);\r
1820\r
1821 AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);\r
1822\r
1823 //\r
1824 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP\r
1825 //\r
1826 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
1827 ApicBaseMsr.Bits.BSP = 1;\r
1828 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
9c6961d5 1829 ProgramVirtualWireMode ();\r
41be0da5
JF
1830\r
1831 //\r
1832 // Wait for old BSP finished AP task\r
1833 //\r
1834 while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {\r
1835 CpuPause ();\r
1836 }\r
1837\r
1838 CpuMpData->SwitchBspFlag = FALSE;\r
1839 //\r
1840 // Set old BSP enable state\r
1841 //\r
1842 if (!EnableOldBSP) {\r
1843 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);\r
af8ba51a
JF
1844 } else {\r
1845 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateIdle);\r
41be0da5
JF
1846 }\r
1847 //\r
1848 // Save new BSP number\r
1849 //\r
1850 CpuMpData->BspNumber = (UINT32) ProcessorNumber;\r
1851\r
a8d75a18
JF
1852 //\r
1853 // Restore interrupt state.\r
1854 //\r
1855 SetInterruptState (OldInterruptState);\r
1856\r
26b43433
JF
1857 if (OldTimerInterruptState) {\r
1858 EnableApicTimerInterrupt ();\r
1859 }\r
a8d75a18 1860\r
41be0da5
JF
1861 return EFI_SUCCESS;\r
1862}\r
ad52f25e 1863\r
e37109bc
JF
1864/**\r
1865 Worker function to let the caller enable or disable an AP from this point onward.\r
1866 This service may only be called from the BSP.\r
1867\r
1868 @param[in] ProcessorNumber The handle number of AP.\r
1869 @param[in] EnableAP Specifies the new state for the processor for\r
1870 enabled, FALSE for disabled.\r
1871 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
1872 the new health status of the AP.\r
1873\r
1874 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
1875 @retval others Failed to Enable/Disable AP.\r
1876\r
1877**/\r
1878EFI_STATUS\r
1879EnableDisableApWorker (\r
1880 IN UINTN ProcessorNumber,\r
1881 IN BOOLEAN EnableAP,\r
1882 IN UINT32 *HealthFlag OPTIONAL\r
1883 )\r
1884{\r
1885 CPU_MP_DATA *CpuMpData;\r
1886 UINTN CallerNumber;\r
1887\r
1888 CpuMpData = GetCpuMpData ();\r
1889\r
1890 //\r
1891 // Check whether caller processor is BSP\r
1892 //\r
1893 MpInitLibWhoAmI (&CallerNumber);\r
1894 if (CallerNumber != CpuMpData->BspNumber) {\r
1895 return EFI_DEVICE_ERROR;\r
1896 }\r
1897\r
1898 if (ProcessorNumber == CpuMpData->BspNumber) {\r
1899 return EFI_INVALID_PARAMETER;\r
1900 }\r
1901\r
1902 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
1903 return EFI_NOT_FOUND;\r
1904 }\r
1905\r
1906 if (!EnableAP) {\r
1907 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);\r
1908 } else {\r
d5fdae96 1909 ResetProcessorToIdleState (ProcessorNumber);\r
e37109bc
JF
1910 }\r
1911\r
1912 if (HealthFlag != NULL) {\r
1913 CpuMpData->CpuData[ProcessorNumber].CpuHealthy =\r
1914 (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);\r
1915 }\r
1916\r
1917 return EFI_SUCCESS;\r
1918}\r
1919\r
3e8ad6bd
JF
1920/**\r
1921 This return the handle number for the calling processor. This service may be\r
1922 called from the BSP and APs.\r
1923\r
1924 @param[out] ProcessorNumber Pointer to the handle number of AP.\r
1925 The range is from 0 to the total number of\r
1926 logical processors minus 1. The total number of\r
1927 logical processors can be retrieved by\r
1928 MpInitLibGetNumberOfProcessors().\r
1929\r
1930 @retval EFI_SUCCESS The current processor handle number was returned\r
1931 in ProcessorNumber.\r
1932 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
1933 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1934\r
1935**/\r
1936EFI_STATUS\r
1937EFIAPI\r
1938MpInitLibWhoAmI (\r
1939 OUT UINTN *ProcessorNumber\r
1940 )\r
1941{\r
5c9e0997
JF
1942 CPU_MP_DATA *CpuMpData;\r
1943\r
1944 if (ProcessorNumber == NULL) {\r
1945 return EFI_INVALID_PARAMETER;\r
1946 }\r
1947\r
1948 CpuMpData = GetCpuMpData ();\r
1949\r
1950 return GetProcessorNumber (CpuMpData, ProcessorNumber);\r
3e8ad6bd 1951}\r
809213a6 1952\r
3e8ad6bd
JF
1953/**\r
1954 Retrieves the number of logical processor in the platform and the number of\r
1955 those logical processors that are enabled on this boot. This service may only\r
1956 be called from the BSP.\r
1957\r
1958 @param[out] NumberOfProcessors Pointer to the total number of logical\r
1959 processors in the system, including the BSP\r
1960 and disabled APs.\r
1961 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
1962 processors that exist in system, including\r
1963 the BSP.\r
1964\r
1965 @retval EFI_SUCCESS The number of logical processors and enabled\r
1966 logical processors was retrieved.\r
1967 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
1968 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors\r
1969 is NULL.\r
1970 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1971\r
1972**/\r
1973EFI_STATUS\r
1974EFIAPI\r
1975MpInitLibGetNumberOfProcessors (\r
1976 OUT UINTN *NumberOfProcessors, OPTIONAL\r
1977 OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
1978 )\r
1979{\r
809213a6
JF
1980 CPU_MP_DATA *CpuMpData;\r
1981 UINTN CallerNumber;\r
1982 UINTN ProcessorNumber;\r
1983 UINTN EnabledProcessorNumber;\r
1984 UINTN Index;\r
1985\r
1986 CpuMpData = GetCpuMpData ();\r
1987\r
1988 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {\r
1989 return EFI_INVALID_PARAMETER;\r
1990 }\r
1991\r
1992 //\r
1993 // Check whether caller processor is BSP\r
1994 //\r
1995 MpInitLibWhoAmI (&CallerNumber);\r
1996 if (CallerNumber != CpuMpData->BspNumber) {\r
1997 return EFI_DEVICE_ERROR;\r
1998 }\r
1999\r
2000 ProcessorNumber = CpuMpData->CpuCount;\r
2001 EnabledProcessorNumber = 0;\r
2002 for (Index = 0; Index < ProcessorNumber; Index++) {\r
2003 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {\r
2004 EnabledProcessorNumber ++;\r
2005 }\r
2006 }\r
2007\r
2008 if (NumberOfProcessors != NULL) {\r
2009 *NumberOfProcessors = ProcessorNumber;\r
2010 }\r
2011 if (NumberOfEnabledProcessors != NULL) {\r
2012 *NumberOfEnabledProcessors = EnabledProcessorNumber;\r
2013 }\r
2014\r
2015 return EFI_SUCCESS;\r
3e8ad6bd 2016}\r
6a2ee2bb 2017\r
809213a6 2018\r
86efe976
JF
2019/**\r
2020 Worker function to execute a caller provided function on all enabled APs.\r
2021\r
2022 @param[in] Procedure A pointer to the function to be run on\r
2023 enabled APs of the system.\r
2024 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
2025 the function specified by Procedure one by\r
2026 one, in ascending order of processor handle\r
2027 number. If FALSE, then all the enabled APs\r
2028 execute the function specified by Procedure\r
2029 simultaneously.\r
2030 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
2031 service.\r
367284e7 2032 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
86efe976
JF
2033 APs to return from Procedure, either for\r
2034 blocking or non-blocking mode.\r
2035 @param[in] ProcedureArgument The parameter passed into Procedure for\r
2036 all APs.\r
2037 @param[out] FailedCpuList If all APs finish successfully, then its\r
2038 content is set to NULL. If not all APs\r
2039 finish before timeout expires, then its\r
2040 content is set to address of the buffer\r
2041 holding handle numbers of the failed APs.\r
2042\r
2043 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
2044 the timeout expired.\r
2045 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
2046 to all enabled APs.\r
2047 @retval others Failed to Startup all APs.\r
2048\r
2049**/\r
2050EFI_STATUS\r
2051StartupAllAPsWorker (\r
2052 IN EFI_AP_PROCEDURE Procedure,\r
2053 IN BOOLEAN SingleThread,\r
2054 IN EFI_EVENT WaitEvent OPTIONAL,\r
2055 IN UINTN TimeoutInMicroseconds,\r
2056 IN VOID *ProcedureArgument OPTIONAL,\r
2057 OUT UINTN **FailedCpuList OPTIONAL\r
2058 )\r
2059{\r
2060 EFI_STATUS Status;\r
2061 CPU_MP_DATA *CpuMpData;\r
2062 UINTN ProcessorCount;\r
2063 UINTN ProcessorNumber;\r
2064 UINTN CallerNumber;\r
2065 CPU_AP_DATA *CpuData;\r
2066 BOOLEAN HasEnabledAp;\r
2067 CPU_STATE ApState;\r
2068\r
2069 CpuMpData = GetCpuMpData ();\r
2070\r
2071 if (FailedCpuList != NULL) {\r
2072 *FailedCpuList = NULL;\r
2073 }\r
2074\r
2075 if (CpuMpData->CpuCount == 1) {\r
2076 return EFI_NOT_STARTED;\r
2077 }\r
2078\r
2079 if (Procedure == NULL) {\r
2080 return EFI_INVALID_PARAMETER;\r
2081 }\r
2082\r
2083 //\r
2084 // Check whether caller processor is BSP\r
2085 //\r
2086 MpInitLibWhoAmI (&CallerNumber);\r
2087 if (CallerNumber != CpuMpData->BspNumber) {\r
2088 return EFI_DEVICE_ERROR;\r
2089 }\r
2090\r
2091 //\r
2092 // Update AP state\r
2093 //\r
2094 CheckAndUpdateApsStatus ();\r
2095\r
2096 ProcessorCount = CpuMpData->CpuCount;\r
2097 HasEnabledAp = FALSE;\r
2098 //\r
2099 // Check whether all enabled APs are idle.\r
2100 // If any enabled AP is not idle, return EFI_NOT_READY.\r
2101 //\r
2102 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
2103 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
2104 if (ProcessorNumber != CpuMpData->BspNumber) {\r
2105 ApState = GetApState (CpuData);\r
2106 if (ApState != CpuStateDisabled) {\r
2107 HasEnabledAp = TRUE;\r
2108 if (ApState != CpuStateIdle) {\r
2109 //\r
2110 // If any enabled APs are busy, return EFI_NOT_READY.\r
2111 //\r
2112 return EFI_NOT_READY;\r
2113 }\r
2114 }\r
2115 }\r
2116 }\r
2117\r
2118 if (!HasEnabledAp) {\r
2119 //\r
2120 // If no enabled AP exists, return EFI_NOT_STARTED.\r
2121 //\r
2122 return EFI_NOT_STARTED;\r
2123 }\r
2124\r
2125 CpuMpData->StartCount = 0;\r
2126 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
2127 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
2128 CpuData->Waiting = FALSE;\r
2129 if (ProcessorNumber != CpuMpData->BspNumber) {\r
2130 if (CpuData->State == CpuStateIdle) {\r
2131 //\r
2132 // Mark this processor as responsible for current calling.\r
2133 //\r
2134 CpuData->Waiting = TRUE;\r
2135 CpuMpData->StartCount++;\r
2136 }\r
2137 }\r
2138 }\r
2139\r
2140 CpuMpData->Procedure = Procedure;\r
2141 CpuMpData->ProcArguments = ProcedureArgument;\r
2142 CpuMpData->SingleThread = SingleThread;\r
2143 CpuMpData->FinishedCount = 0;\r
2144 CpuMpData->RunningCount = 0;\r
2145 CpuMpData->FailedCpuList = FailedCpuList;\r
2146 CpuMpData->ExpectedTime = CalculateTimeout (\r
2147 TimeoutInMicroseconds,\r
2148 &CpuMpData->CurrentTime\r
2149 );\r
2150 CpuMpData->TotalTime = 0;\r
2151 CpuMpData->WaitEvent = WaitEvent;\r
2152\r
2153 if (!SingleThread) {\r
2154 WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument);\r
2155 } else {\r
2156 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
2157 if (ProcessorNumber == CallerNumber) {\r
2158 continue;\r
2159 }\r
2160 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
2161 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);\r
2162 break;\r
2163 }\r
2164 }\r
2165 }\r
2166\r
2167 Status = EFI_SUCCESS;\r
2168 if (WaitEvent == NULL) {\r
2169 do {\r
2170 Status = CheckAllAPs ();\r
2171 } while (Status == EFI_NOT_READY);\r
2172 }\r
2173\r
2174 return Status;\r
2175}\r
2176\r
20ae5774
JF
2177/**\r
2178 Worker function to let the caller get one enabled AP to execute a caller-provided\r
2179 function.\r
2180\r
2181 @param[in] Procedure A pointer to the function to be run on\r
2182 enabled APs of the system.\r
2183 @param[in] ProcessorNumber The handle number of the AP.\r
2184 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
2185 service.\r
367284e7 2186 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
20ae5774
JF
2187 APs to return from Procedure, either for\r
2188 blocking or non-blocking mode.\r
2189 @param[in] ProcedureArgument The parameter passed into Procedure for\r
2190 all APs.\r
2191 @param[out] Finished If AP returns from Procedure before the\r
2192 timeout expires, its content is set to TRUE.\r
2193 Otherwise, the value is set to FALSE.\r
2194\r
2195 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
2196 the timeout expires.\r
2197 @retval others Failed to Startup AP.\r
2198\r
2199**/\r
2200EFI_STATUS\r
2201StartupThisAPWorker (\r
2202 IN EFI_AP_PROCEDURE Procedure,\r
2203 IN UINTN ProcessorNumber,\r
2204 IN EFI_EVENT WaitEvent OPTIONAL,\r
2205 IN UINTN TimeoutInMicroseconds,\r
2206 IN VOID *ProcedureArgument OPTIONAL,\r
2207 OUT BOOLEAN *Finished OPTIONAL\r
2208 )\r
2209{\r
2210 EFI_STATUS Status;\r
2211 CPU_MP_DATA *CpuMpData;\r
2212 CPU_AP_DATA *CpuData;\r
2213 UINTN CallerNumber;\r
2214\r
2215 CpuMpData = GetCpuMpData ();\r
2216\r
2217 if (Finished != NULL) {\r
2218 *Finished = FALSE;\r
2219 }\r
2220\r
2221 //\r
2222 // Check whether caller processor is BSP\r
2223 //\r
2224 MpInitLibWhoAmI (&CallerNumber);\r
2225 if (CallerNumber != CpuMpData->BspNumber) {\r
2226 return EFI_DEVICE_ERROR;\r
2227 }\r
2228\r
2229 //\r
2230 // Check whether processor with the handle specified by ProcessorNumber exists\r
2231 //\r
2232 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
2233 return EFI_NOT_FOUND;\r
2234 }\r
2235\r
2236 //\r
2237 // Check whether specified processor is BSP\r
2238 //\r
2239 if (ProcessorNumber == CpuMpData->BspNumber) {\r
2240 return EFI_INVALID_PARAMETER;\r
2241 }\r
2242\r
2243 //\r
2244 // Check parameter Procedure\r
2245 //\r
2246 if (Procedure == NULL) {\r
2247 return EFI_INVALID_PARAMETER;\r
2248 }\r
2249\r
2250 //\r
2251 // Update AP state\r
2252 //\r
2253 CheckAndUpdateApsStatus ();\r
2254\r
2255 //\r
2256 // Check whether specified AP is disabled\r
2257 //\r
2258 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {\r
2259 return EFI_INVALID_PARAMETER;\r
2260 }\r
2261\r
2262 //\r
2263 // If WaitEvent is not NULL, execute in non-blocking mode.\r
2264 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.\r
2265 // CheckAPsStatus() will check completion and timeout periodically.\r
2266 //\r
2267 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
2268 CpuData->WaitEvent = WaitEvent;\r
2269 CpuData->Finished = Finished;\r
2270 CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);\r
2271 CpuData->TotalTime = 0;\r
2272\r
2273 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);\r
2274\r
2275 //\r
2276 // If WaitEvent is NULL, execute in blocking mode.\r
2277 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.\r
2278 //\r
2279 Status = EFI_SUCCESS;\r
2280 if (WaitEvent == NULL) {\r
2281 do {\r
2282 Status = CheckThisAP (ProcessorNumber);\r
2283 } while (Status == EFI_NOT_READY);\r
2284 }\r
2285\r
2286 return Status;\r
2287}\r
2288\r
93ca4c0f
JF
2289/**\r
2290 Get pointer to CPU MP Data structure from GUIDed HOB.\r
2291\r
2292 @return The pointer to CPU MP Data structure.\r
2293**/\r
2294CPU_MP_DATA *\r
2295GetCpuMpDataFromGuidedHob (\r
2296 VOID\r
2297 )\r
2298{\r
2299 EFI_HOB_GUID_TYPE *GuidHob;\r
2300 VOID *DataInHob;\r
2301 CPU_MP_DATA *CpuMpData;\r
2302\r
2303 CpuMpData = NULL;\r
2304 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
2305 if (GuidHob != NULL) {\r
2306 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
2307 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);\r
2308 }\r
2309 return CpuMpData;\r
2310}\r
42c37b3b 2311\r