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