]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Send INIT-SIPI-SIPI to get processor count
[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 Do sync on APs.\r
221\r
222 @param[in, out] Buffer Pointer to private data buffer.\r
223**/\r
224VOID\r
225EFIAPI\r
226ApInitializeSync (\r
227 IN OUT VOID *Buffer\r
228 )\r
229{\r
230 CPU_MP_DATA *CpuMpData;\r
231\r
232 CpuMpData = (CPU_MP_DATA *) Buffer;\r
233 //\r
234 // Sync BSP's MTRR table to AP\r
235 //\r
236 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
237 //\r
238 // Load microcode on AP\r
239 //\r
240 MicrocodeDetect (CpuMpData);\r
241}\r
242\r
243/**\r
244 Find the current Processor number by APIC ID.\r
245\r
246 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
247 @param[in] ProcessorNumber Return the pocessor number found\r
248\r
249 @retval EFI_SUCCESS ProcessorNumber is found and returned.\r
250 @retval EFI_NOT_FOUND ProcessorNumber is not found.\r
251**/\r
252EFI_STATUS\r
253GetProcessorNumber (\r
254 IN CPU_MP_DATA *CpuMpData,\r
255 OUT UINTN *ProcessorNumber\r
256 )\r
257{\r
258 UINTN TotalProcessorNumber;\r
259 UINTN Index;\r
260\r
261 TotalProcessorNumber = CpuMpData->CpuCount;\r
262 for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
263 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {\r
264 *ProcessorNumber = Index;\r
265 return EFI_SUCCESS;\r
266 }\r
267 }\r
268 return EFI_NOT_FOUND;\r
269}\r
270\r
271/**\r
272 This function will get CPU count in the system.\r
273\r
274 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
275\r
276 @return CPU count detected\r
277**/\r
278UINTN\r
279CollectProcessorCount (\r
280 IN CPU_MP_DATA *CpuMpData\r
281 )\r
282{\r
283 //\r
284 // Send 1st broadcast IPI to APs to wakeup APs\r
285 //\r
286 CpuMpData->InitFlag = ApInitConfig;\r
287 CpuMpData->X2ApicEnable = FALSE;\r
288 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);\r
289 //\r
290 // Wait for AP task to complete and then exit.\r
291 //\r
292 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));\r
293 CpuMpData->InitFlag = ApInitDone;\r
294 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
295 //\r
296 // Wait for all APs finished the initialization\r
297 //\r
298 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
299 CpuPause ();\r
300 }\r
301\r
302 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));\r
303\r
304 return CpuMpData->CpuCount;\r
305}\r
306\r
307/*\r
308 Initialize CPU AP Data when AP is wakeup at the first time.\r
309\r
310 @param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
311 @param[in] ProcessorNumber The handle number of processor\r
312 @param[in] BistData Processor BIST data\r
313\r
314**/\r
315VOID\r
316InitializeApData (\r
317 IN OUT CPU_MP_DATA *CpuMpData,\r
318 IN UINTN ProcessorNumber,\r
319 IN UINT32 BistData\r
320 )\r
321{\r
322 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
323 CpuMpData->CpuData[ProcessorNumber].Health = BistData;\r
324 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
325 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
326 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
327 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {\r
328 //\r
329 // Set x2APIC mode if there are any logical processor reporting\r
330 // an Initial APIC ID of 255 or greater.\r
331 //\r
332 AcquireSpinLock(&CpuMpData->MpLock);\r
333 CpuMpData->X2ApicEnable = TRUE;\r
334 ReleaseSpinLock(&CpuMpData->MpLock);\r
335 }\r
336\r
337 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
338 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
339}\r
340\r
341/**\r
342 This function will be called from AP reset code if BSP uses WakeUpAP.\r
343\r
344 @param[in] ExchangeInfo Pointer to the MP exchange info buffer\r
345 @param[in] NumApsExecuting Number of current executing AP\r
346**/\r
347VOID\r
348EFIAPI\r
349ApWakeupFunction (\r
350 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
351 IN UINTN NumApsExecuting\r
352 )\r
353{\r
354 CPU_MP_DATA *CpuMpData;\r
355 UINTN ProcessorNumber;\r
356 EFI_AP_PROCEDURE Procedure;\r
357 VOID *Parameter;\r
358 UINT32 BistData;\r
359 volatile UINT32 *ApStartupSignalBuffer;\r
360\r
361 //\r
362 // AP finished assembly code and begin to execute C code\r
363 //\r
364 CpuMpData = ExchangeInfo->CpuMpData;\r
365\r
366 ProgramVirtualWireMode (); \r
367\r
368 while (TRUE) {\r
369 if (CpuMpData->InitFlag == ApInitConfig) {\r
370 //\r
371 // Add CPU number\r
372 //\r
373 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
374 ProcessorNumber = NumApsExecuting;\r
375 //\r
376 // This is first time AP wakeup, get BIST information from AP stack\r
377 //\r
378 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));\r
379 //\r
380 // Do some AP initialize sync\r
381 //\r
382 ApInitializeSync (CpuMpData);\r
383 //\r
384 // Sync BSP's Control registers to APs\r
385 //\r
386 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
387 InitializeApData (CpuMpData, ProcessorNumber, BistData);\r
388 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
389 } else {\r
390 //\r
391 // Execute AP function if AP is ready\r
392 //\r
393 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
394 //\r
395 // Clear AP start-up signal when AP waken up\r
396 //\r
397 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
398 InterlockedCompareExchange32 (\r
399 (UINT32 *) ApStartupSignalBuffer,\r
400 WAKEUP_AP_SIGNAL,\r
401 0\r
402 );\r
403 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
404 //\r
405 // Restore AP's volatile registers saved\r
406 //\r
407 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
408 }\r
409\r
410 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
411 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;\r
412 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;\r
413 if (Procedure != NULL) {\r
414 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
415 //\r
416 // Invoke AP function here\r
417 //\r
418 Procedure (Parameter);\r
419 //\r
420 // Re-get the CPU APICID and Initial APICID\r
421 //\r
422 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
423 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
424 }\r
425 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
426 }\r
427 }\r
428\r
429 //\r
430 // AP finished executing C code\r
431 //\r
432 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
433\r
434 //\r
435 // Place AP is specified loop mode\r
436 //\r
437 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
438 //\r
439 // Save AP volatile registers\r
440 //\r
441 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
442 //\r
443 // Place AP in HLT-loop\r
444 //\r
445 while (TRUE) {\r
446 DisableInterrupts ();\r
447 CpuSleep ();\r
448 CpuPause ();\r
449 }\r
450 }\r
451 while (TRUE) {\r
452 DisableInterrupts ();\r
453 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
454 //\r
455 // Place AP in MWAIT-loop\r
456 //\r
457 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);\r
458 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
459 //\r
460 // Check AP start-up signal again.\r
461 // If AP start-up signal is not set, place AP into\r
462 // the specified C-state\r
463 //\r
464 AsmMwait (CpuMpData->ApTargetCState << 4, 0);\r
465 }\r
466 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {\r
467 //\r
468 // Place AP in Run-loop\r
469 //\r
470 CpuPause ();\r
471 } else {\r
472 ASSERT (FALSE);\r
473 }\r
474\r
475 //\r
476 // If AP start-up signal is written, AP is waken up\r
477 // otherwise place AP in loop again\r
478 //\r
479 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
480 break;\r
481 }\r
482 }\r
483 }\r
484}\r
485\r
486/**\r
487 Wait for AP wakeup and write AP start-up signal till AP is waken up.\r
488\r
489 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal\r
490**/\r
491VOID\r
492WaitApWakeup (\r
493 IN volatile UINT32 *ApStartupSignalBuffer\r
494 )\r
495{\r
496 //\r
497 // If AP is waken up, StartupApSignal should be cleared.\r
498 // Otherwise, write StartupApSignal again till AP waken up.\r
499 //\r
500 while (InterlockedCompareExchange32 (\r
501 (UINT32 *) ApStartupSignalBuffer,\r
502 WAKEUP_AP_SIGNAL,\r
503 WAKEUP_AP_SIGNAL\r
504 ) != 0) {\r
505 CpuPause ();\r
506 }\r
507}\r
508\r
509/**\r
510 This function will fill the exchange info structure.\r
511\r
512 @param[in] CpuMpData Pointer to CPU MP Data\r
513\r
514**/\r
515VOID\r
516FillExchangeInfoData (\r
517 IN CPU_MP_DATA *CpuMpData\r
518 )\r
519{\r
520 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
521\r
522 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
523 ExchangeInfo->Lock = 0;\r
524 ExchangeInfo->StackStart = CpuMpData->Buffer;\r
525 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;\r
526 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;\r
527 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;\r
528\r
529 ExchangeInfo->CodeSegment = AsmReadCs ();\r
530 ExchangeInfo->DataSegment = AsmReadDs ();\r
531\r
532 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
533\r
534 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;\r
535 ExchangeInfo->NumApsExecuting = 0;\r
536 ExchangeInfo->CpuMpData = CpuMpData;\r
537\r
538 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();\r
539\r
540 //\r
541 // Get the BSP's data of GDT and IDT\r
542 //\r
543 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
544 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
545}\r
546\r
547/**\r
548 This function will be called by BSP to wakeup AP.\r
549\r
550 @param[in] CpuMpData Pointer to CPU MP Data\r
551 @param[in] Broadcast TRUE: Send broadcast IPI to all APs\r
552 FALSE: Send IPI to AP by ApicId\r
553 @param[in] ProcessorNumber The handle number of specified processor\r
554 @param[in] Procedure The function to be invoked by AP\r
555 @param[in] ProcedureArgument The argument to be passed into AP function\r
556**/\r
557VOID\r
558WakeUpAP (\r
559 IN CPU_MP_DATA *CpuMpData,\r
560 IN BOOLEAN Broadcast,\r
561 IN UINTN ProcessorNumber,\r
562 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
563 IN VOID *ProcedureArgument OPTIONAL\r
564 )\r
565{\r
566 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
567 UINTN Index;\r
568 CPU_AP_DATA *CpuData;\r
569 BOOLEAN ResetVectorRequired;\r
570\r
571 CpuMpData->FinishedCount = 0;\r
572 ResetVectorRequired = FALSE;\r
573\r
574 if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
575 CpuMpData->InitFlag != ApInitDone) {\r
576 ResetVectorRequired = TRUE;\r
577 AllocateResetVector (CpuMpData);\r
578 FillExchangeInfoData (CpuMpData);\r
579 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
580 //\r
581 // Get AP target C-state each time when waking up AP,\r
582 // for it maybe updated by platform again\r
583 //\r
584 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
585 }\r
586\r
587 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
588\r
589 if (Broadcast) {\r
590 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
591 if (Index != CpuMpData->BspNumber) {\r
592 CpuData = &CpuMpData->CpuData[Index];\r
593 CpuData->ApFunction = (UINTN) Procedure;\r
594 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
595 SetApState (CpuData, CpuStateReady);\r
596 if (CpuMpData->InitFlag != ApInitConfig) {\r
597 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
598 }\r
599 }\r
600 }\r
601 if (ResetVectorRequired) {\r
602 //\r
603 // Wakeup all APs\r
604 //\r
605 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
606 }\r
607 if (CpuMpData->InitFlag != ApInitConfig) {\r
608 //\r
609 // Wait all APs waken up if this is not the 1st broadcast of SIPI\r
610 //\r
611 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
612 CpuData = &CpuMpData->CpuData[Index];\r
613 if (Index != CpuMpData->BspNumber) {\r
614 WaitApWakeup (CpuData->StartupApSignal);\r
615 }\r
616 }\r
617 }\r
618 } else {\r
619 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
620 CpuData->ApFunction = (UINTN) Procedure;\r
621 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
622 SetApState (CpuData, CpuStateReady);\r
623 //\r
624 // Wakeup specified AP\r
625 //\r
626 ASSERT (CpuMpData->InitFlag != ApInitConfig);\r
627 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
628 if (ResetVectorRequired) {\r
629 SendInitSipiSipi (\r
630 CpuData->ApicId,\r
631 (UINT32) ExchangeInfo->BufferStart\r
632 );\r
633 }\r
634 //\r
635 // Wait specified AP waken up\r
636 //\r
637 WaitApWakeup (CpuData->StartupApSignal);\r
638 }\r
639\r
640 if (ResetVectorRequired) {\r
641 FreeResetVector (CpuMpData);\r
642 }\r
643}\r
644\r
645/**\r
646 MP Initialize Library initialization.\r
647\r
648 This service will allocate AP reset vector and wakeup all APs to do APs\r
649 initialization.\r
650\r
651 This service must be invoked before all other MP Initialize Library\r
652 service are invoked.\r
653\r
654 @retval EFI_SUCCESS MP initialization succeeds.\r
655 @retval Others MP initialization fails.\r
656\r
657**/\r
658EFI_STATUS\r
659EFIAPI\r
660MpInitLibInitialize (\r
661 VOID\r
662 )\r
663{\r
664 UINT32 MaxLogicalProcessorNumber;\r
665 UINT32 ApStackSize;\r
666 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
667 UINTN BufferSize;\r
668 UINT32 MonitorFilterSize;\r
669 VOID *MpBuffer;\r
670 UINTN Buffer;\r
671 CPU_MP_DATA *CpuMpData;\r
672 UINT8 ApLoopMode;\r
673 UINT8 *MonitorBuffer;\r
674 UINTN Index;\r
675 UINTN ApResetVectorSize;\r
676 UINTN BackupBufferAddr;\r
677 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
678\r
679 AsmGetAddressMap (&AddressMap);\r
680 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
681 ApStackSize = PcdGet32(PcdCpuApStackSize);\r
682 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
683\r
684 BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
685 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
686 BufferSize += sizeof (CPU_MP_DATA);\r
687 BufferSize += ApResetVectorSize;\r
688 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
689 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
690 ASSERT (MpBuffer != NULL);\r
691 ZeroMem (MpBuffer, BufferSize);\r
692 Buffer = (UINTN) MpBuffer;\r
693\r
694 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
695 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
696 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
697 CpuMpData->Buffer = Buffer;\r
698 CpuMpData->CpuApStackSize = ApStackSize;\r
699 CpuMpData->BackupBuffer = BackupBufferAddr;\r
700 CpuMpData->BackupBufferSize = ApResetVectorSize;\r
701 CpuMpData->EndOfPeiFlag = FALSE;\r
702 CpuMpData->WakeupBuffer = (UINTN) -1;\r
703 CpuMpData->CpuCount = 1;\r
704 CpuMpData->BspNumber = 0;\r
705 CpuMpData->WaitEvent = NULL;\r
706 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
707 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
708 InitializeSpinLock(&CpuMpData->MpLock);\r
709 //\r
710 // Save BSP's Control registers to APs\r
711 //\r
712 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
713 //\r
714 // Set BSP basic information\r
715 //\r
716 InitializeApData (CpuMpData, 0, 0);\r
717 //\r
718 // Save assembly code information\r
719 //\r
720 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
721 //\r
722 // Finally set AP loop mode\r
723 //\r
724 CpuMpData->ApLoopMode = ApLoopMode;\r
725 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
726 //\r
727 // Set up APs wakeup signal buffer\r
728 //\r
729 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
730 CpuMpData->CpuData[Index].StartupApSignal =\r
731 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
732 }\r
733 //\r
734 // Load Microcode on BSP\r
735 //\r
736 MicrocodeDetect (CpuMpData);\r
737 //\r
738 // Store BSP's MTRR setting\r
739 //\r
740 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
741\r
742\r
743 //\r
744 // Wakeup all APs and calculate the processor count in system\r
745 //\r
746 CollectProcessorCount (CpuMpData);\r
747 //\r
748 // Initialize global data for MP support\r
749 //\r
750 InitMpGlobalData (CpuMpData);\r
751\r
752 return EFI_SUCCESS;\r
753}\r
754\r
755/**\r
756 Gets detailed MP-related information on the requested processor at the\r
757 instant this call is made. This service may only be called from the BSP.\r
758\r
759 @param[in] ProcessorNumber The handle number of processor.\r
760 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
761 the requested processor is deposited.\r
762 @param[out] HealthData Return processor health data.\r
763\r
764 @retval EFI_SUCCESS Processor information was returned.\r
765 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
766 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
767 @retval EFI_NOT_FOUND The processor with the handle specified by\r
768 ProcessorNumber does not exist in the platform.\r
769 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
770\r
771**/\r
772EFI_STATUS\r
773EFIAPI\r
774MpInitLibGetProcessorInfo (\r
775 IN UINTN ProcessorNumber,\r
776 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,\r
777 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL\r
778 )\r
779{\r
780 return EFI_UNSUPPORTED;\r
781}\r
782/**\r
783 This return the handle number for the calling processor. This service may be\r
784 called from the BSP and APs.\r
785\r
786 @param[out] ProcessorNumber Pointer to the handle number of AP.\r
787 The range is from 0 to the total number of\r
788 logical processors minus 1. The total number of\r
789 logical processors can be retrieved by\r
790 MpInitLibGetNumberOfProcessors().\r
791\r
792 @retval EFI_SUCCESS The current processor handle number was returned\r
793 in ProcessorNumber.\r
794 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
795 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
796\r
797**/\r
798EFI_STATUS\r
799EFIAPI\r
800MpInitLibWhoAmI (\r
801 OUT UINTN *ProcessorNumber\r
802 )\r
803{\r
804 return EFI_UNSUPPORTED;\r
805}\r
806/**\r
807 Retrieves the number of logical processor in the platform and the number of\r
808 those logical processors that are enabled on this boot. This service may only\r
809 be called from the BSP.\r
810\r
811 @param[out] NumberOfProcessors Pointer to the total number of logical\r
812 processors in the system, including the BSP\r
813 and disabled APs.\r
814 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
815 processors that exist in system, including\r
816 the BSP.\r
817\r
818 @retval EFI_SUCCESS The number of logical processors and enabled\r
819 logical processors was retrieved.\r
820 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
821 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors\r
822 is NULL.\r
823 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
824\r
825**/\r
826EFI_STATUS\r
827EFIAPI\r
828MpInitLibGetNumberOfProcessors (\r
829 OUT UINTN *NumberOfProcessors, OPTIONAL\r
830 OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
831 )\r
832{\r
833 return EFI_UNSUPPORTED;\r
834}\r
835/**\r
836 Get pointer to CPU MP Data structure from GUIDed HOB.\r
837\r
838 @return The pointer to CPU MP Data structure.\r
839**/\r
840CPU_MP_DATA *\r
841GetCpuMpDataFromGuidedHob (\r
842 VOID\r
843 )\r
844{\r
845 EFI_HOB_GUID_TYPE *GuidHob;\r
846 VOID *DataInHob;\r
847 CPU_MP_DATA *CpuMpData;\r
848\r
849 CpuMpData = NULL;\r
850 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
851 if (GuidHob != NULL) {\r
852 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
853 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);\r
854 }\r
855 return CpuMpData;\r
856}\r