]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Sort processor by ascending order of APIC ID
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
... / ...
CommitLineData
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
17EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;\r
18\r
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
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
91\r
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
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
218\r
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
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
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
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
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
401 //\r
402 // Sort BSP/Aps by CPU APIC ID in ascending order\r
403 //\r
404 SortApicId (CpuMpData);\r
405\r
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
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
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
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
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
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
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
768 UINT32 MaxLogicalProcessorNumber;\r
769 UINT32 ApStackSize;\r
770 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
771 UINTN BufferSize;\r
772 UINT32 MonitorFilterSize;\r
773 VOID *MpBuffer;\r
774 UINTN Buffer;\r
775 CPU_MP_DATA *CpuMpData;\r
776 UINT8 ApLoopMode;\r
777 UINT8 *MonitorBuffer;\r
778 UINTN Index;\r
779 UINTN ApResetVectorSize;\r
780 UINTN BackupBufferAddr;\r
781 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
782\r
783 AsmGetAddressMap (&AddressMap);\r
784 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
785 ApStackSize = PcdGet32(PcdCpuApStackSize);\r
786 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
787\r
788 BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
789 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
790 BufferSize += sizeof (CPU_MP_DATA);\r
791 BufferSize += ApResetVectorSize;\r
792 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
793 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
794 ASSERT (MpBuffer != NULL);\r
795 ZeroMem (MpBuffer, BufferSize);\r
796 Buffer = (UINTN) MpBuffer;\r
797\r
798 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
799 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
800 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
801 CpuMpData->Buffer = Buffer;\r
802 CpuMpData->CpuApStackSize = ApStackSize;\r
803 CpuMpData->BackupBuffer = BackupBufferAddr;\r
804 CpuMpData->BackupBufferSize = ApResetVectorSize;\r
805 CpuMpData->EndOfPeiFlag = FALSE;\r
806 CpuMpData->WakeupBuffer = (UINTN) -1;\r
807 CpuMpData->CpuCount = 1;\r
808 CpuMpData->BspNumber = 0;\r
809 CpuMpData->WaitEvent = NULL;\r
810 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
811 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
812 InitializeSpinLock(&CpuMpData->MpLock);\r
813 //\r
814 // Save BSP's Control registers to APs\r
815 //\r
816 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
817 //\r
818 // Set BSP basic information\r
819 //\r
820 InitializeApData (CpuMpData, 0, 0);\r
821 //\r
822 // Save assembly code information\r
823 //\r
824 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
825 //\r
826 // Finally set AP loop mode\r
827 //\r
828 CpuMpData->ApLoopMode = ApLoopMode;\r
829 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
830 //\r
831 // Set up APs wakeup signal buffer\r
832 //\r
833 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
834 CpuMpData->CpuData[Index].StartupApSignal =\r
835 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
836 }\r
837 //\r
838 // Load Microcode on BSP\r
839 //\r
840 MicrocodeDetect (CpuMpData);\r
841 //\r
842 // Store BSP's MTRR setting\r
843 //\r
844 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
845\r
846\r
847 //\r
848 // Wakeup all APs and calculate the processor count in system\r
849 //\r
850 CollectProcessorCount (CpuMpData);\r
851 //\r
852 // Initialize global data for MP support\r
853 //\r
854 InitMpGlobalData (CpuMpData);\r
855\r
856 return EFI_SUCCESS;\r
857}\r
858\r
859/**\r
860 Gets detailed MP-related information on the requested processor at the\r
861 instant this call is made. This service may only be called from the BSP.\r
862\r
863 @param[in] ProcessorNumber The handle number of processor.\r
864 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
865 the requested processor is deposited.\r
866 @param[out] HealthData Return processor health data.\r
867\r
868 @retval EFI_SUCCESS Processor information was returned.\r
869 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
870 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
871 @retval EFI_NOT_FOUND The processor with the handle specified by\r
872 ProcessorNumber does not exist in the platform.\r
873 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
874\r
875**/\r
876EFI_STATUS\r
877EFIAPI\r
878MpInitLibGetProcessorInfo (\r
879 IN UINTN ProcessorNumber,\r
880 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,\r
881 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL\r
882 )\r
883{\r
884 return EFI_UNSUPPORTED;\r
885}\r
886/**\r
887 This return the handle number for the calling processor. This service may be\r
888 called from the BSP and APs.\r
889\r
890 @param[out] ProcessorNumber Pointer to the handle number of AP.\r
891 The range is from 0 to the total number of\r
892 logical processors minus 1. The total number of\r
893 logical processors can be retrieved by\r
894 MpInitLibGetNumberOfProcessors().\r
895\r
896 @retval EFI_SUCCESS The current processor handle number was returned\r
897 in ProcessorNumber.\r
898 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
899 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
900\r
901**/\r
902EFI_STATUS\r
903EFIAPI\r
904MpInitLibWhoAmI (\r
905 OUT UINTN *ProcessorNumber\r
906 )\r
907{\r
908 return EFI_UNSUPPORTED;\r
909}\r
910/**\r
911 Retrieves the number of logical processor in the platform and the number of\r
912 those logical processors that are enabled on this boot. This service may only\r
913 be called from the BSP.\r
914\r
915 @param[out] NumberOfProcessors Pointer to the total number of logical\r
916 processors in the system, including the BSP\r
917 and disabled APs.\r
918 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
919 processors that exist in system, including\r
920 the BSP.\r
921\r
922 @retval EFI_SUCCESS The number of logical processors and enabled\r
923 logical processors was retrieved.\r
924 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
925 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors\r
926 is NULL.\r
927 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
928\r
929**/\r
930EFI_STATUS\r
931EFIAPI\r
932MpInitLibGetNumberOfProcessors (\r
933 OUT UINTN *NumberOfProcessors, OPTIONAL\r
934 OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
935 )\r
936{\r
937 return EFI_UNSUPPORTED;\r
938}\r
939/**\r
940 Get pointer to CPU MP Data structure from GUIDed HOB.\r
941\r
942 @return The pointer to CPU MP Data structure.\r
943**/\r
944CPU_MP_DATA *\r
945GetCpuMpDataFromGuidedHob (\r
946 VOID\r
947 )\r
948{\r
949 EFI_HOB_GUID_TYPE *GuidHob;\r
950 VOID *DataInHob;\r
951 CPU_MP_DATA *CpuMpData;\r
952\r
953 CpuMpData = NULL;\r
954 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
955 if (GuidHob != NULL) {\r
956 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
957 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);\r
958 }\r
959 return CpuMpData;\r
960}\r