UefiCpuPkg/MpInitLib: Skip collect processor count if GUIDed HOB exist
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
CommitLineData
3e8ad6bd
JF
1/** @file\r
2 CPU MP Initialize Library common functions.\r
3\r
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
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
21 DxeIpl may have enabled Execute Disable for BSP,\r
22 APs need to get the status and sync up the settings.\r
23\r
24 @retval TRUE BSP Execute Disable is enabled.\r
25 @retval FALSE BSP Execute Disable is not enabled.\r
26**/\r
27BOOLEAN\r
28IsBspExecuteDisableEnabled (\r
29 VOID\r
30 )\r
31{\r
32 UINT32 Eax;\r
33 CPUID_EXTENDED_CPU_SIG_EDX Edx;\r
34 MSR_IA32_EFER_REGISTER EferMsr;\r
35 BOOLEAN Enabled;\r
36\r
37 Enabled = FALSE;\r
38 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);\r
39 if (Eax >= CPUID_EXTENDED_CPU_SIG) {\r
40 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);\r
41 //\r
42 // CPUID 0x80000001\r
43 // Bit 20: Execute Disable Bit available.\r
44 //\r
45 if (Edx.Bits.NX != 0) {\r
46 EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);\r
47 //\r
48 // MSR 0xC0000080\r
49 // Bit 11: Execute Disable Bit enable.\r
50 //\r
51 if (EferMsr.Bits.NXE != 0) {\r
52 Enabled = TRUE;\r
53 }\r
54 }\r
55 }\r
56\r
57 return Enabled;\r
58}\r
59\r
03a1a925
JF
60/**\r
61 Get the Application Processors state.\r
62\r
63 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
64\r
65 @return The AP status\r
66**/\r
67CPU_STATE\r
68GetApState (\r
69 IN CPU_AP_DATA *CpuData\r
70 )\r
71{\r
72 return CpuData->State;\r
73}\r
74\r
75/**\r
76 Set the Application Processors state.\r
77\r
78 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
79 @param[in] State The AP status\r
80**/\r
81VOID\r
82SetApState (\r
83 IN CPU_AP_DATA *CpuData,\r
84 IN CPU_STATE State\r
85 )\r
86{\r
87 AcquireSpinLock (&CpuData->ApLock);\r
88 CpuData->State = State;\r
89 ReleaseSpinLock (&CpuData->ApLock);\r
90}\r
3e8ad6bd 91\r
68cb9330
JF
92/**\r
93 Save the volatile registers required to be restored following INIT IPI.\r
94\r
95 @param[out] VolatileRegisters Returns buffer saved the volatile resisters\r
96**/\r
97VOID\r
98SaveVolatileRegisters (\r
99 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters\r
100 )\r
101{\r
102 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
103\r
104 VolatileRegisters->Cr0 = AsmReadCr0 ();\r
105 VolatileRegisters->Cr3 = AsmReadCr3 ();\r
106 VolatileRegisters->Cr4 = AsmReadCr4 ();\r
107\r
108 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
109 if (VersionInfoEdx.Bits.DE != 0) {\r
110 //\r
111 // If processor supports Debugging Extensions feature\r
112 // by CPUID.[EAX=01H]:EDX.BIT2\r
113 //\r
114 VolatileRegisters->Dr0 = AsmReadDr0 ();\r
115 VolatileRegisters->Dr1 = AsmReadDr1 ();\r
116 VolatileRegisters->Dr2 = AsmReadDr2 ();\r
117 VolatileRegisters->Dr3 = AsmReadDr3 ();\r
118 VolatileRegisters->Dr6 = AsmReadDr6 ();\r
119 VolatileRegisters->Dr7 = AsmReadDr7 ();\r
120 }\r
121}\r
122\r
123/**\r
124 Restore the volatile registers following INIT IPI.\r
125\r
126 @param[in] VolatileRegisters Pointer to volatile resisters\r
127 @param[in] IsRestoreDr TRUE: Restore DRx if supported\r
128 FALSE: Do not restore DRx\r
129**/\r
130VOID\r
131RestoreVolatileRegisters (\r
132 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,\r
133 IN BOOLEAN IsRestoreDr\r
134 )\r
135{\r
136 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
137\r
138 AsmWriteCr0 (VolatileRegisters->Cr0);\r
139 AsmWriteCr3 (VolatileRegisters->Cr3);\r
140 AsmWriteCr4 (VolatileRegisters->Cr4);\r
141\r
142 if (IsRestoreDr) {\r
143 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
144 if (VersionInfoEdx.Bits.DE != 0) {\r
145 //\r
146 // If processor supports Debugging Extensions feature\r
147 // by CPUID.[EAX=01H]:EDX.BIT2\r
148 //\r
149 AsmWriteDr0 (VolatileRegisters->Dr0);\r
150 AsmWriteDr1 (VolatileRegisters->Dr1);\r
151 AsmWriteDr2 (VolatileRegisters->Dr2);\r
152 AsmWriteDr3 (VolatileRegisters->Dr3);\r
153 AsmWriteDr6 (VolatileRegisters->Dr6);\r
154 AsmWriteDr7 (VolatileRegisters->Dr7);\r
155 }\r
156 }\r
157}\r
158\r
9ebcf0f4
JF
159/**\r
160 Detect whether Mwait-monitor feature is supported.\r
161\r
162 @retval TRUE Mwait-monitor feature is supported.\r
163 @retval FALSE Mwait-monitor feature is not supported.\r
164**/\r
165BOOLEAN\r
166IsMwaitSupport (\r
167 VOID\r
168 )\r
169{\r
170 CPUID_VERSION_INFO_ECX VersionInfoEcx;\r
171\r
172 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);\r
173 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;\r
174}\r
175\r
176/**\r
177 Get AP loop mode.\r
178\r
179 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.\r
180\r
181 @return The AP loop mode.\r
182**/\r
183UINT8\r
184GetApLoopMode (\r
185 OUT UINT32 *MonitorFilterSize\r
186 )\r
187{\r
188 UINT8 ApLoopMode;\r
189 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;\r
190\r
191 ASSERT (MonitorFilterSize != NULL);\r
192\r
193 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
194 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);\r
195 if (ApLoopMode == ApInMwaitLoop) {\r
196 if (!IsMwaitSupport ()) {\r
197 //\r
198 // If processor does not support MONITOR/MWAIT feature,\r
199 // force AP in Hlt-loop mode\r
200 //\r
201 ApLoopMode = ApInHltLoop;\r
202 }\r
203 }\r
204\r
205 if (ApLoopMode != ApInMwaitLoop) {\r
206 *MonitorFilterSize = sizeof (UINT32);\r
207 } else {\r
208 //\r
209 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes\r
210 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT\r
211 //\r
212 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);\r
213 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;\r
214 }\r
215\r
216 return ApLoopMode;\r
217}\r
b8b04307 218\r
8a2d564b
JF
219/**\r
220 Sort the APIC ID of all processors.\r
221\r
222 This function sorts the APIC ID of all processors so that processor number is\r
223 assigned in the ascending order of APIC ID which eases MP debugging.\r
224\r
225 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
226**/\r
227VOID\r
228SortApicId (\r
229 IN CPU_MP_DATA *CpuMpData\r
230 )\r
231{\r
232 UINTN Index1;\r
233 UINTN Index2;\r
234 UINTN Index3;\r
235 UINT32 ApicId;\r
236 CPU_AP_DATA CpuData;\r
237 UINT32 ApCount;\r
238 CPU_INFO_IN_HOB *CpuInfoInHob;\r
239\r
240 ApCount = CpuMpData->CpuCount - 1;\r
241\r
242 if (ApCount != 0) {\r
243 for (Index1 = 0; Index1 < ApCount; Index1++) {\r
244 Index3 = Index1;\r
245 //\r
246 // Sort key is the hardware default APIC ID\r
247 //\r
248 ApicId = CpuMpData->CpuData[Index1].ApicId;\r
249 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {\r
250 if (ApicId > CpuMpData->CpuData[Index2].ApicId) {\r
251 Index3 = Index2;\r
252 ApicId = CpuMpData->CpuData[Index2].ApicId;\r
253 }\r
254 }\r
255 if (Index3 != Index1) {\r
256 CopyMem (&CpuData, &CpuMpData->CpuData[Index3], sizeof (CPU_AP_DATA));\r
257 CopyMem (\r
258 &CpuMpData->CpuData[Index3],\r
259 &CpuMpData->CpuData[Index1],\r
260 sizeof (CPU_AP_DATA)\r
261 );\r
262 CopyMem (&CpuMpData->CpuData[Index1], &CpuData, sizeof (CPU_AP_DATA));\r
263 }\r
264 }\r
265\r
266 //\r
267 // Get the processor number for the BSP\r
268 //\r
269 ApicId = GetInitialApicId ();\r
270 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {\r
271 if (CpuMpData->CpuData[Index1].ApicId == ApicId) {\r
272 CpuMpData->BspNumber = (UINT32) Index1;\r
273 break;\r
274 }\r
275 }\r
276\r
277 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
278 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {\r
279 CpuInfoInHob[Index1].InitialApicId = CpuMpData->CpuData[Index1].InitialApicId;\r
280 CpuInfoInHob[Index1].ApicId = CpuMpData->CpuData[Index1].ApicId;\r
281 CpuInfoInHob[Index1].Health = CpuMpData->CpuData[Index1].Health;\r
282 }\r
283 }\r
284}\r
285\r
fe627769
JF
286/**\r
287 Enable x2APIC mode on APs.\r
288\r
289 @param[in, out] Buffer Pointer to private data buffer.\r
290**/\r
291VOID\r
292EFIAPI\r
293ApFuncEnableX2Apic (\r
294 IN OUT VOID *Buffer\r
295 )\r
296{\r
297 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
298}\r
299\r
b8b04307
JF
300/**\r
301 Do sync on APs.\r
302\r
303 @param[in, out] Buffer Pointer to private data buffer.\r
304**/\r
305VOID\r
306EFIAPI\r
307ApInitializeSync (\r
308 IN OUT VOID *Buffer\r
309 )\r
310{\r
311 CPU_MP_DATA *CpuMpData;\r
312\r
313 CpuMpData = (CPU_MP_DATA *) Buffer;\r
314 //\r
315 // Sync BSP's MTRR table to AP\r
316 //\r
317 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
318 //\r
319 // Load microcode on AP\r
320 //\r
321 MicrocodeDetect (CpuMpData);\r
322}\r
323\r
324/**\r
325 Find the current Processor number by APIC ID.\r
326\r
327 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
328 @param[in] ProcessorNumber Return the pocessor number found\r
329\r
330 @retval EFI_SUCCESS ProcessorNumber is found and returned.\r
331 @retval EFI_NOT_FOUND ProcessorNumber is not found.\r
332**/\r
333EFI_STATUS\r
334GetProcessorNumber (\r
335 IN CPU_MP_DATA *CpuMpData,\r
336 OUT UINTN *ProcessorNumber\r
337 )\r
338{\r
339 UINTN TotalProcessorNumber;\r
340 UINTN Index;\r
341\r
342 TotalProcessorNumber = CpuMpData->CpuCount;\r
343 for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
344 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {\r
345 *ProcessorNumber = Index;\r
346 return EFI_SUCCESS;\r
347 }\r
348 }\r
349 return EFI_NOT_FOUND;\r
350}\r
351\r
03434dff
JF
352/**\r
353 This function will get CPU count in the system.\r
354\r
355 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
356\r
357 @return CPU count detected\r
358**/\r
359UINTN\r
360CollectProcessorCount (\r
361 IN CPU_MP_DATA *CpuMpData\r
362 )\r
363{\r
364 //\r
365 // Send 1st broadcast IPI to APs to wakeup APs\r
366 //\r
367 CpuMpData->InitFlag = ApInitConfig;\r
368 CpuMpData->X2ApicEnable = FALSE;\r
369 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);\r
370 //\r
371 // Wait for AP task to complete and then exit.\r
372 //\r
373 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));\r
374 CpuMpData->InitFlag = ApInitDone;\r
375 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
376 //\r
377 // Wait for all APs finished the initialization\r
378 //\r
379 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
380 CpuPause ();\r
381 }\r
382\r
fe627769
JF
383 if (CpuMpData->X2ApicEnable) {\r
384 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));\r
385 //\r
386 // Wakeup all APs to enable x2APIC mode\r
387 //\r
388 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
389 //\r
390 // Wait for all known APs finished\r
391 //\r
392 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
393 CpuPause ();\r
394 }\r
395 //\r
396 // Enable x2APIC on BSP\r
397 //\r
398 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
399 }\r
400 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
8a2d564b
JF
401 //\r
402 // Sort BSP/Aps by CPU APIC ID in ascending order\r
403 //\r
404 SortApicId (CpuMpData);\r
405\r
03434dff
JF
406 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));\r
407\r
408 return CpuMpData->CpuCount;\r
409}\r
410\r
03a1a925
JF
411/*\r
412 Initialize CPU AP Data when AP is wakeup at the first time.\r
413\r
414 @param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
415 @param[in] ProcessorNumber The handle number of processor\r
416 @param[in] BistData Processor BIST data\r
417\r
418**/\r
419VOID\r
420InitializeApData (\r
421 IN OUT CPU_MP_DATA *CpuMpData,\r
422 IN UINTN ProcessorNumber,\r
423 IN UINT32 BistData\r
424 )\r
425{\r
426 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
427 CpuMpData->CpuData[ProcessorNumber].Health = BistData;\r
428 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
429 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
430 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
431 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {\r
432 //\r
433 // Set x2APIC mode if there are any logical processor reporting\r
434 // an Initial APIC ID of 255 or greater.\r
435 //\r
436 AcquireSpinLock(&CpuMpData->MpLock);\r
437 CpuMpData->X2ApicEnable = TRUE;\r
438 ReleaseSpinLock(&CpuMpData->MpLock);\r
439 }\r
440\r
441 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
442 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
443}\r
444\r
b8b04307
JF
445/**\r
446 This function will be called from AP reset code if BSP uses WakeUpAP.\r
447\r
448 @param[in] ExchangeInfo Pointer to the MP exchange info buffer\r
449 @param[in] NumApsExecuting Number of current executing AP\r
450**/\r
451VOID\r
452EFIAPI\r
453ApWakeupFunction (\r
454 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
455 IN UINTN NumApsExecuting\r
456 )\r
457{\r
458 CPU_MP_DATA *CpuMpData;\r
459 UINTN ProcessorNumber;\r
460 EFI_AP_PROCEDURE Procedure;\r
461 VOID *Parameter;\r
462 UINT32 BistData;\r
463 volatile UINT32 *ApStartupSignalBuffer;\r
464\r
465 //\r
466 // AP finished assembly code and begin to execute C code\r
467 //\r
468 CpuMpData = ExchangeInfo->CpuMpData;\r
469\r
470 ProgramVirtualWireMode (); \r
471\r
472 while (TRUE) {\r
473 if (CpuMpData->InitFlag == ApInitConfig) {\r
474 //\r
475 // Add CPU number\r
476 //\r
477 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
478 ProcessorNumber = NumApsExecuting;\r
479 //\r
480 // This is first time AP wakeup, get BIST information from AP stack\r
481 //\r
482 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));\r
483 //\r
484 // Do some AP initialize sync\r
485 //\r
486 ApInitializeSync (CpuMpData);\r
487 //\r
488 // Sync BSP's Control registers to APs\r
489 //\r
490 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
491 InitializeApData (CpuMpData, ProcessorNumber, BistData);\r
492 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
493 } else {\r
494 //\r
495 // Execute AP function if AP is ready\r
496 //\r
497 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
498 //\r
499 // Clear AP start-up signal when AP waken up\r
500 //\r
501 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
502 InterlockedCompareExchange32 (\r
503 (UINT32 *) ApStartupSignalBuffer,\r
504 WAKEUP_AP_SIGNAL,\r
505 0\r
506 );\r
507 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
508 //\r
509 // Restore AP's volatile registers saved\r
510 //\r
511 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
512 }\r
513\r
514 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
515 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;\r
516 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;\r
517 if (Procedure != NULL) {\r
518 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
519 //\r
520 // Invoke AP function here\r
521 //\r
522 Procedure (Parameter);\r
523 //\r
524 // Re-get the CPU APICID and Initial APICID\r
525 //\r
526 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
527 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
528 }\r
529 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
530 }\r
531 }\r
532\r
533 //\r
534 // AP finished executing C code\r
535 //\r
536 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
537\r
538 //\r
539 // Place AP is specified loop mode\r
540 //\r
541 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
542 //\r
543 // Save AP volatile registers\r
544 //\r
545 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
546 //\r
547 // Place AP in HLT-loop\r
548 //\r
549 while (TRUE) {\r
550 DisableInterrupts ();\r
551 CpuSleep ();\r
552 CpuPause ();\r
553 }\r
554 }\r
555 while (TRUE) {\r
556 DisableInterrupts ();\r
557 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
558 //\r
559 // Place AP in MWAIT-loop\r
560 //\r
561 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);\r
562 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
563 //\r
564 // Check AP start-up signal again.\r
565 // If AP start-up signal is not set, place AP into\r
566 // the specified C-state\r
567 //\r
568 AsmMwait (CpuMpData->ApTargetCState << 4, 0);\r
569 }\r
570 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {\r
571 //\r
572 // Place AP in Run-loop\r
573 //\r
574 CpuPause ();\r
575 } else {\r
576 ASSERT (FALSE);\r
577 }\r
578\r
579 //\r
580 // If AP start-up signal is written, AP is waken up\r
581 // otherwise place AP in loop again\r
582 //\r
583 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
584 break;\r
585 }\r
586 }\r
587 }\r
588}\r
589\r
96f5920d
JF
590/**\r
591 Wait for AP wakeup and write AP start-up signal till AP is waken up.\r
592\r
593 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal\r
594**/\r
595VOID\r
596WaitApWakeup (\r
597 IN volatile UINT32 *ApStartupSignalBuffer\r
598 )\r
599{\r
600 //\r
601 // If AP is waken up, StartupApSignal should be cleared.\r
602 // Otherwise, write StartupApSignal again till AP waken up.\r
603 //\r
604 while (InterlockedCompareExchange32 (\r
605 (UINT32 *) ApStartupSignalBuffer,\r
606 WAKEUP_AP_SIGNAL,\r
607 WAKEUP_AP_SIGNAL\r
608 ) != 0) {\r
609 CpuPause ();\r
610 }\r
611}\r
612\r
7c3f2a12
JF
613/**\r
614 This function will fill the exchange info structure.\r
615\r
616 @param[in] CpuMpData Pointer to CPU MP Data\r
617\r
618**/\r
619VOID\r
620FillExchangeInfoData (\r
621 IN CPU_MP_DATA *CpuMpData\r
622 )\r
623{\r
624 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
625\r
626 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
627 ExchangeInfo->Lock = 0;\r
628 ExchangeInfo->StackStart = CpuMpData->Buffer;\r
629 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;\r
630 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;\r
631 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;\r
632\r
633 ExchangeInfo->CodeSegment = AsmReadCs ();\r
634 ExchangeInfo->DataSegment = AsmReadDs ();\r
635\r
636 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
637\r
638 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;\r
639 ExchangeInfo->NumApsExecuting = 0;\r
640 ExchangeInfo->CpuMpData = CpuMpData;\r
641\r
642 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();\r
643\r
644 //\r
645 // Get the BSP's data of GDT and IDT\r
646 //\r
647 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
648 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
649}\r
650\r
96f5920d
JF
651/**\r
652 This function will be called by BSP to wakeup AP.\r
653\r
654 @param[in] CpuMpData Pointer to CPU MP Data\r
655 @param[in] Broadcast TRUE: Send broadcast IPI to all APs\r
656 FALSE: Send IPI to AP by ApicId\r
657 @param[in] ProcessorNumber The handle number of specified processor\r
658 @param[in] Procedure The function to be invoked by AP\r
659 @param[in] ProcedureArgument The argument to be passed into AP function\r
660**/\r
661VOID\r
662WakeUpAP (\r
663 IN CPU_MP_DATA *CpuMpData,\r
664 IN BOOLEAN Broadcast,\r
665 IN UINTN ProcessorNumber,\r
666 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
667 IN VOID *ProcedureArgument OPTIONAL\r
668 )\r
669{\r
670 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
671 UINTN Index;\r
672 CPU_AP_DATA *CpuData;\r
673 BOOLEAN ResetVectorRequired;\r
674\r
675 CpuMpData->FinishedCount = 0;\r
676 ResetVectorRequired = FALSE;\r
677\r
678 if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
679 CpuMpData->InitFlag != ApInitDone) {\r
680 ResetVectorRequired = TRUE;\r
681 AllocateResetVector (CpuMpData);\r
682 FillExchangeInfoData (CpuMpData);\r
683 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
684 //\r
685 // Get AP target C-state each time when waking up AP,\r
686 // for it maybe updated by platform again\r
687 //\r
688 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
689 }\r
690\r
691 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
692\r
693 if (Broadcast) {\r
694 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
695 if (Index != CpuMpData->BspNumber) {\r
696 CpuData = &CpuMpData->CpuData[Index];\r
697 CpuData->ApFunction = (UINTN) Procedure;\r
698 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
699 SetApState (CpuData, CpuStateReady);\r
700 if (CpuMpData->InitFlag != ApInitConfig) {\r
701 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
702 }\r
703 }\r
704 }\r
705 if (ResetVectorRequired) {\r
706 //\r
707 // Wakeup all APs\r
708 //\r
709 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
710 }\r
711 if (CpuMpData->InitFlag != ApInitConfig) {\r
712 //\r
713 // Wait all APs waken up if this is not the 1st broadcast of SIPI\r
714 //\r
715 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
716 CpuData = &CpuMpData->CpuData[Index];\r
717 if (Index != CpuMpData->BspNumber) {\r
718 WaitApWakeup (CpuData->StartupApSignal);\r
719 }\r
720 }\r
721 }\r
722 } else {\r
723 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
724 CpuData->ApFunction = (UINTN) Procedure;\r
725 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
726 SetApState (CpuData, CpuStateReady);\r
727 //\r
728 // Wakeup specified AP\r
729 //\r
730 ASSERT (CpuMpData->InitFlag != ApInitConfig);\r
731 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
732 if (ResetVectorRequired) {\r
733 SendInitSipiSipi (\r
734 CpuData->ApicId,\r
735 (UINT32) ExchangeInfo->BufferStart\r
736 );\r
737 }\r
738 //\r
739 // Wait specified AP waken up\r
740 //\r
741 WaitApWakeup (CpuData->StartupApSignal);\r
742 }\r
743\r
744 if (ResetVectorRequired) {\r
745 FreeResetVector (CpuMpData);\r
746 }\r
747}\r
748\r
3e8ad6bd
JF
749/**\r
750 MP Initialize Library initialization.\r
751\r
752 This service will allocate AP reset vector and wakeup all APs to do APs\r
753 initialization.\r
754\r
755 This service must be invoked before all other MP Initialize Library\r
756 service are invoked.\r
757\r
758 @retval EFI_SUCCESS MP initialization succeeds.\r
759 @retval Others MP initialization fails.\r
760\r
761**/\r
762EFI_STATUS\r
763EFIAPI\r
764MpInitLibInitialize (\r
765 VOID\r
766 )\r
767{\r
6a2ee2bb
JF
768 CPU_MP_DATA *OldCpuMpData;\r
769 CPU_INFO_IN_HOB *CpuInfoInHob;\r
e59f8f6b
JF
770 UINT32 MaxLogicalProcessorNumber;\r
771 UINT32 ApStackSize;\r
f7f85d83 772 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
e59f8f6b 773 UINTN BufferSize;\r
9ebcf0f4 774 UINT32 MonitorFilterSize;\r
e59f8f6b
JF
775 VOID *MpBuffer;\r
776 UINTN Buffer;\r
777 CPU_MP_DATA *CpuMpData;\r
9ebcf0f4 778 UINT8 ApLoopMode;\r
e59f8f6b 779 UINT8 *MonitorBuffer;\r
03a1a925 780 UINTN Index;\r
f7f85d83 781 UINTN ApResetVectorSize;\r
e59f8f6b 782 UINTN BackupBufferAddr;\r
6a2ee2bb
JF
783\r
784 OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
785 if (OldCpuMpData == NULL) {\r
786 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
787 } else {\r
788 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;\r
789 }\r
f7f85d83
JF
790\r
791 AsmGetAddressMap (&AddressMap);\r
792 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
e59f8f6b 793 ApStackSize = PcdGet32(PcdCpuApStackSize);\r
9ebcf0f4
JF
794 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
795\r
e59f8f6b
JF
796 BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
797 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
798 BufferSize += sizeof (CPU_MP_DATA);\r
799 BufferSize += ApResetVectorSize;\r
800 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
801 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
802 ASSERT (MpBuffer != NULL);\r
803 ZeroMem (MpBuffer, BufferSize);\r
804 Buffer = (UINTN) MpBuffer;\r
805\r
806 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
807 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
808 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
809 CpuMpData->Buffer = Buffer;\r
810 CpuMpData->CpuApStackSize = ApStackSize;\r
811 CpuMpData->BackupBuffer = BackupBufferAddr;\r
812 CpuMpData->BackupBufferSize = ApResetVectorSize;\r
813 CpuMpData->EndOfPeiFlag = FALSE;\r
814 CpuMpData->WakeupBuffer = (UINTN) -1;\r
815 CpuMpData->CpuCount = 1;\r
816 CpuMpData->BspNumber = 0;\r
817 CpuMpData->WaitEvent = NULL;\r
818 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
819 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
820 InitializeSpinLock(&CpuMpData->MpLock);\r
821 //\r
68cb9330
JF
822 // Save BSP's Control registers to APs\r
823 //\r
824 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
825 //\r
03a1a925
JF
826 // Set BSP basic information\r
827 //\r
828 InitializeApData (CpuMpData, 0, 0);\r
829 //\r
e59f8f6b
JF
830 // Save assembly code information\r
831 //\r
832 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
833 //\r
834 // Finally set AP loop mode\r
835 //\r
836 CpuMpData->ApLoopMode = ApLoopMode;\r
837 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
838 //\r
03a1a925
JF
839 // Set up APs wakeup signal buffer\r
840 //\r
841 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
842 CpuMpData->CpuData[Index].StartupApSignal =\r
843 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
844 }\r
94f63c76
JF
845 //\r
846 // Load Microcode on BSP\r
847 //\r
848 MicrocodeDetect (CpuMpData);\r
849 //\r
e59f8f6b
JF
850 // Store BSP's MTRR setting\r
851 //\r
852 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
853\r
6a2ee2bb
JF
854 if (OldCpuMpData == NULL) {\r
855 //\r
856 // Wakeup all APs and calculate the processor count in system\r
857 //\r
858 CollectProcessorCount (CpuMpData);\r
859 } else {\r
860 //\r
861 // APs have been wakeup before, just get the CPU Information\r
862 // from HOB\r
863 //\r
864 CpuMpData->CpuCount = OldCpuMpData->CpuCount;\r
865 CpuMpData->BspNumber = OldCpuMpData->BspNumber;\r
866 CpuMpData->InitFlag = ApInitReconfig;\r
867 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) OldCpuMpData->CpuInfoInHob;\r
868 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
869 InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);\r
870 CpuMpData->CpuData[Index].ApicId = CpuInfoInHob[Index].ApicId;\r
871 CpuMpData->CpuData[Index].InitialApicId = CpuInfoInHob[Index].InitialApicId;\r
872 if (CpuMpData->CpuData[Index].InitialApicId >= 255) {\r
873 CpuMpData->X2ApicEnable = TRUE;\r
874 }\r
875 CpuMpData->CpuData[Index].Health = CpuInfoInHob[Index].Health;\r
876 CpuMpData->CpuData[Index].CpuHealthy = (CpuMpData->CpuData[Index].Health == 0)? TRUE:FALSE;\r
877 CpuMpData->CpuData[Index].ApFunction = 0;\r
878 CopyMem (\r
879 &CpuMpData->CpuData[Index].VolatileRegisters,\r
880 &CpuMpData->CpuData[0].VolatileRegisters,\r
881 sizeof (CPU_VOLATILE_REGISTERS)\r
882 );\r
883 }\r
884 //\r
885 // Wakeup APs to do some AP initialize sync\r
886 //\r
887 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);\r
888 //\r
889 // Wait for all APs finished initialization\r
890 //\r
891 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
892 CpuPause ();\r
893 }\r
894 CpuMpData->InitFlag = ApInitDone;\r
895 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
896 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
897 }\r
898 }\r
93ca4c0f
JF
899\r
900 //\r
901 // Initialize global data for MP support\r
902 //\r
903 InitMpGlobalData (CpuMpData);\r
904\r
f7f85d83 905 return EFI_SUCCESS;\r
3e8ad6bd
JF
906}\r
907\r
908/**\r
909 Gets detailed MP-related information on the requested processor at the\r
910 instant this call is made. This service may only be called from the BSP.\r
911\r
912 @param[in] ProcessorNumber The handle number of processor.\r
913 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
914 the requested processor is deposited.\r
915 @param[out] HealthData Return processor health data.\r
916\r
917 @retval EFI_SUCCESS Processor information was returned.\r
918 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
919 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
920 @retval EFI_NOT_FOUND The processor with the handle specified by\r
921 ProcessorNumber does not exist in the platform.\r
922 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
923\r
924**/\r
925EFI_STATUS\r
926EFIAPI\r
927MpInitLibGetProcessorInfo (\r
928 IN UINTN ProcessorNumber,\r
929 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,\r
930 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL\r
931 )\r
932{\r
933 return EFI_UNSUPPORTED;\r
934}\r
935/**\r
936 This return the handle number for the calling processor. This service may be\r
937 called from the BSP and APs.\r
938\r
939 @param[out] ProcessorNumber Pointer to the handle number of AP.\r
940 The range is from 0 to the total number of\r
941 logical processors minus 1. The total number of\r
942 logical processors can be retrieved by\r
943 MpInitLibGetNumberOfProcessors().\r
944\r
945 @retval EFI_SUCCESS The current processor handle number was returned\r
946 in ProcessorNumber.\r
947 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
948 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
949\r
950**/\r
951EFI_STATUS\r
952EFIAPI\r
953MpInitLibWhoAmI (\r
954 OUT UINTN *ProcessorNumber\r
955 )\r
956{\r
957 return EFI_UNSUPPORTED;\r
958}\r
959/**\r
960 Retrieves the number of logical processor in the platform and the number of\r
961 those logical processors that are enabled on this boot. This service may only\r
962 be called from the BSP.\r
963\r
964 @param[out] NumberOfProcessors Pointer to the total number of logical\r
965 processors in the system, including the BSP\r
966 and disabled APs.\r
967 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
968 processors that exist in system, including\r
969 the BSP.\r
970\r
971 @retval EFI_SUCCESS The number of logical processors and enabled\r
972 logical processors was retrieved.\r
973 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
974 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors\r
975 is NULL.\r
976 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
977\r
978**/\r
979EFI_STATUS\r
980EFIAPI\r
981MpInitLibGetNumberOfProcessors (\r
982 OUT UINTN *NumberOfProcessors, OPTIONAL\r
983 OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
984 )\r
985{\r
986 return EFI_UNSUPPORTED;\r
987}\r
6a2ee2bb 988\r
93ca4c0f
JF
989/**\r
990 Get pointer to CPU MP Data structure from GUIDed HOB.\r
991\r
992 @return The pointer to CPU MP Data structure.\r
993**/\r
994CPU_MP_DATA *\r
995GetCpuMpDataFromGuidedHob (\r
996 VOID\r
997 )\r
998{\r
999 EFI_HOB_GUID_TYPE *GuidHob;\r
1000 VOID *DataInHob;\r
1001 CPU_MP_DATA *CpuMpData;\r
1002\r
1003 CpuMpData = NULL;\r
1004 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
1005 if (GuidHob != NULL) {\r
1006 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
1007 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);\r
1008 }\r
1009 return CpuMpData;\r
1010}\r