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