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