2 CPU MP Initialize Library common functions.
4 Copyright (c) 2016 - 2018, 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
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.
17 EFI_GUID mCpuInitMpLibHobGuid
= CPU_INIT_MP_LIB_HOB_GUID
;
20 The function will check if BSP Execute Disable is enabled.
22 DxeIpl may have enabled Execute Disable for BSP, APs need to
23 get the status and sync up the settings.
24 If BSP's CR0.Paging is not set, BSP execute Disble feature is
27 @retval TRUE BSP Execute Disable is enabled.
28 @retval FALSE BSP Execute Disable is not enabled.
31 IsBspExecuteDisableEnabled (
36 CPUID_EXTENDED_CPU_SIG_EDX Edx
;
37 MSR_IA32_EFER_REGISTER EferMsr
;
42 Cr0
.UintN
= AsmReadCr0 ();
43 if (Cr0
.Bits
.PG
!= 0) {
45 // If CR0 Paging bit is set
47 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &Eax
, NULL
, NULL
, NULL
);
48 if (Eax
>= CPUID_EXTENDED_CPU_SIG
) {
49 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
52 // Bit 20: Execute Disable Bit available.
54 if (Edx
.Bits
.NX
!= 0) {
55 EferMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_EFER
);
58 // Bit 11: Execute Disable Bit enable.
60 if (EferMsr
.Bits
.NXE
!= 0) {
71 Worker function for SwitchBSP().
73 Worker function for SwitchBSP(), assigned to the AP which is intended
76 @param[in] Buffer Pointer to CPU MP Data
84 CPU_MP_DATA
*DataInHob
;
86 DataInHob
= (CPU_MP_DATA
*) Buffer
;
87 AsmExchangeRole (&DataInHob
->APInfo
, &DataInHob
->BSPInfo
);
91 Get the Application Processors state.
93 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
99 IN CPU_AP_DATA
*CpuData
102 return CpuData
->State
;
106 Set the Application Processors state.
108 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
109 @param[in] State The AP status
113 IN CPU_AP_DATA
*CpuData
,
117 AcquireSpinLock (&CpuData
->ApLock
);
118 CpuData
->State
= State
;
119 ReleaseSpinLock (&CpuData
->ApLock
);
123 Save BSP's local APIC timer setting.
125 @param[in] CpuMpData Pointer to CPU MP Data
128 SaveLocalApicTimerSetting (
129 IN CPU_MP_DATA
*CpuMpData
133 // Record the current local APIC timer setting of BSP
136 &CpuMpData
->DivideValue
,
137 &CpuMpData
->PeriodicMode
,
140 CpuMpData
->CurrentTimerCount
= GetApicTimerCurrentCount ();
141 CpuMpData
->TimerInterruptState
= GetApicTimerInterruptState ();
145 Sync local APIC timer setting from BSP to AP.
147 @param[in] CpuMpData Pointer to CPU MP Data
150 SyncLocalApicTimerSetting (
151 IN CPU_MP_DATA
*CpuMpData
155 // Sync local APIC timer setting from BSP to AP
157 InitializeApicTimer (
158 CpuMpData
->DivideValue
,
159 CpuMpData
->CurrentTimerCount
,
160 CpuMpData
->PeriodicMode
,
164 // Disable AP's local APIC timer interrupt
166 DisableApicTimerInterrupt ();
170 Save the volatile registers required to be restored following INIT IPI.
172 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
175 SaveVolatileRegisters (
176 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
179 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
181 VolatileRegisters
->Cr0
= AsmReadCr0 ();
182 VolatileRegisters
->Cr3
= AsmReadCr3 ();
183 VolatileRegisters
->Cr4
= AsmReadCr4 ();
185 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
186 if (VersionInfoEdx
.Bits
.DE
!= 0) {
188 // If processor supports Debugging Extensions feature
189 // by CPUID.[EAX=01H]:EDX.BIT2
191 VolatileRegisters
->Dr0
= AsmReadDr0 ();
192 VolatileRegisters
->Dr1
= AsmReadDr1 ();
193 VolatileRegisters
->Dr2
= AsmReadDr2 ();
194 VolatileRegisters
->Dr3
= AsmReadDr3 ();
195 VolatileRegisters
->Dr6
= AsmReadDr6 ();
196 VolatileRegisters
->Dr7
= AsmReadDr7 ();
199 AsmReadGdtr (&VolatileRegisters
->Gdtr
);
200 AsmReadIdtr (&VolatileRegisters
->Idtr
);
201 VolatileRegisters
->Tr
= AsmReadTr ();
205 Restore the volatile registers following INIT IPI.
207 @param[in] VolatileRegisters Pointer to volatile resisters
208 @param[in] IsRestoreDr TRUE: Restore DRx if supported
209 FALSE: Do not restore DRx
212 RestoreVolatileRegisters (
213 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
214 IN BOOLEAN IsRestoreDr
217 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
218 IA32_TSS_DESCRIPTOR
*Tss
;
220 AsmWriteCr0 (VolatileRegisters
->Cr0
);
221 AsmWriteCr3 (VolatileRegisters
->Cr3
);
222 AsmWriteCr4 (VolatileRegisters
->Cr4
);
225 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
226 if (VersionInfoEdx
.Bits
.DE
!= 0) {
228 // If processor supports Debugging Extensions feature
229 // by CPUID.[EAX=01H]:EDX.BIT2
231 AsmWriteDr0 (VolatileRegisters
->Dr0
);
232 AsmWriteDr1 (VolatileRegisters
->Dr1
);
233 AsmWriteDr2 (VolatileRegisters
->Dr2
);
234 AsmWriteDr3 (VolatileRegisters
->Dr3
);
235 AsmWriteDr6 (VolatileRegisters
->Dr6
);
236 AsmWriteDr7 (VolatileRegisters
->Dr7
);
240 AsmWriteGdtr (&VolatileRegisters
->Gdtr
);
241 AsmWriteIdtr (&VolatileRegisters
->Idtr
);
242 if (VolatileRegisters
->Tr
!= 0 &&
243 VolatileRegisters
->Tr
< VolatileRegisters
->Gdtr
.Limit
) {
244 Tss
= (IA32_TSS_DESCRIPTOR
*)(VolatileRegisters
->Gdtr
.Base
+
245 VolatileRegisters
->Tr
);
246 if (Tss
->Bits
.P
== 1) {
247 Tss
->Bits
.Type
&= 0xD; // 1101 - Clear busy bit just in case
248 AsmWriteTr (VolatileRegisters
->Tr
);
254 Detect whether Mwait-monitor feature is supported.
256 @retval TRUE Mwait-monitor feature is supported.
257 @retval FALSE Mwait-monitor feature is not supported.
264 CPUID_VERSION_INFO_ECX VersionInfoEcx
;
266 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &VersionInfoEcx
.Uint32
, NULL
);
267 return (VersionInfoEcx
.Bits
.MONITOR
== 1) ? TRUE
: FALSE
;
273 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
275 @return The AP loop mode.
279 OUT UINT32
*MonitorFilterSize
283 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx
;
285 ASSERT (MonitorFilterSize
!= NULL
);
287 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
288 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
289 if (ApLoopMode
== ApInMwaitLoop
) {
290 if (!IsMwaitSupport ()) {
292 // If processor does not support MONITOR/MWAIT feature,
293 // force AP in Hlt-loop mode
295 ApLoopMode
= ApInHltLoop
;
299 if (ApLoopMode
!= ApInMwaitLoop
) {
300 *MonitorFilterSize
= sizeof (UINT32
);
303 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
304 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
306 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &MonitorMwaitEbx
.Uint32
, NULL
, NULL
);
307 *MonitorFilterSize
= MonitorMwaitEbx
.Bits
.LargestMonitorLineSize
;
314 Sort the APIC ID of all processors.
316 This function sorts the APIC ID of all processors so that processor number is
317 assigned in the ascending order of APIC ID which eases MP debugging.
319 @param[in] CpuMpData Pointer to PEI CPU MP Data
323 IN CPU_MP_DATA
*CpuMpData
330 CPU_INFO_IN_HOB CpuInfo
;
332 CPU_INFO_IN_HOB
*CpuInfoInHob
;
334 ApCount
= CpuMpData
->CpuCount
- 1;
335 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
337 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
340 // Sort key is the hardware default APIC ID
342 ApicId
= CpuInfoInHob
[Index1
].ApicId
;
343 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
344 if (ApicId
> CpuInfoInHob
[Index2
].ApicId
) {
346 ApicId
= CpuInfoInHob
[Index2
].ApicId
;
349 if (Index3
!= Index1
) {
350 CopyMem (&CpuInfo
, &CpuInfoInHob
[Index3
], sizeof (CPU_INFO_IN_HOB
));
352 &CpuInfoInHob
[Index3
],
353 &CpuInfoInHob
[Index1
],
354 sizeof (CPU_INFO_IN_HOB
)
356 CopyMem (&CpuInfoInHob
[Index1
], &CpuInfo
, sizeof (CPU_INFO_IN_HOB
));
361 // Get the processor number for the BSP
363 ApicId
= GetInitialApicId ();
364 for (Index1
= 0; Index1
< CpuMpData
->CpuCount
; Index1
++) {
365 if (CpuInfoInHob
[Index1
].ApicId
== ApicId
) {
366 CpuMpData
->BspNumber
= (UINT32
) Index1
;
374 Enable x2APIC mode on APs.
376 @param[in, out] Buffer Pointer to private data buffer.
384 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
390 @param[in, out] Buffer Pointer to private data buffer.
398 CPU_MP_DATA
*CpuMpData
;
400 CpuMpData
= (CPU_MP_DATA
*) Buffer
;
402 // Load microcode on AP
404 MicrocodeDetect (CpuMpData
);
406 // Sync BSP's MTRR table to AP
408 MtrrSetAllMtrrs (&CpuMpData
->MtrrTable
);
412 Find the current Processor number by APIC ID.
414 @param[in] CpuMpData Pointer to PEI CPU MP Data
415 @param[out] ProcessorNumber Return the pocessor number found
417 @retval EFI_SUCCESS ProcessorNumber is found and returned.
418 @retval EFI_NOT_FOUND ProcessorNumber is not found.
422 IN CPU_MP_DATA
*CpuMpData
,
423 OUT UINTN
*ProcessorNumber
426 UINTN TotalProcessorNumber
;
428 CPU_INFO_IN_HOB
*CpuInfoInHob
;
430 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
432 TotalProcessorNumber
= CpuMpData
->CpuCount
;
433 for (Index
= 0; Index
< TotalProcessorNumber
; Index
++) {
434 if (CpuInfoInHob
[Index
].ApicId
== GetApicId ()) {
435 *ProcessorNumber
= Index
;
439 return EFI_NOT_FOUND
;
443 This function will get CPU count in the system.
445 @param[in] CpuMpData Pointer to PEI CPU MP Data
447 @return CPU count detected
450 CollectProcessorCount (
451 IN CPU_MP_DATA
*CpuMpData
457 // Send 1st broadcast IPI to APs to wakeup APs
459 CpuMpData
->InitFlag
= ApInitConfig
;
460 CpuMpData
->X2ApicEnable
= FALSE
;
461 WakeUpAP (CpuMpData
, TRUE
, 0, NULL
, NULL
);
462 CpuMpData
->InitFlag
= ApInitDone
;
463 ASSERT (CpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
465 // Wait for all APs finished the initialization
467 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
471 if (CpuMpData
->CpuCount
> 255) {
473 // If there are more than 255 processor found, force to enable X2APIC
475 CpuMpData
->X2ApicEnable
= TRUE
;
477 if (CpuMpData
->X2ApicEnable
) {
478 DEBUG ((DEBUG_INFO
, "Force x2APIC mode!\n"));
480 // Wakeup all APs to enable x2APIC mode
482 WakeUpAP (CpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
);
484 // Wait for all known APs finished
486 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
490 // Enable x2APIC on BSP
492 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
494 // Set BSP/Aps state to IDLE
496 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
497 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
500 DEBUG ((DEBUG_INFO
, "APIC MODE is %d\n", GetApicMode ()));
502 // Sort BSP/Aps by CPU APIC ID in ascending order
504 SortApicId (CpuMpData
);
506 DEBUG ((DEBUG_INFO
, "MpInitLib: Find %d processors in system.\n", CpuMpData
->CpuCount
));
508 return CpuMpData
->CpuCount
;
512 Initialize CPU AP Data when AP is wakeup at the first time.
514 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
515 @param[in] ProcessorNumber The handle number of processor
516 @param[in] BistData Processor BIST data
517 @param[in] ApTopOfStack Top of AP stack
522 IN OUT CPU_MP_DATA
*CpuMpData
,
523 IN UINTN ProcessorNumber
,
525 IN UINT64 ApTopOfStack
528 CPU_INFO_IN_HOB
*CpuInfoInHob
;
530 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
531 CpuInfoInHob
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
532 CpuInfoInHob
[ProcessorNumber
].ApicId
= GetApicId ();
533 CpuInfoInHob
[ProcessorNumber
].Health
= BistData
;
534 CpuInfoInHob
[ProcessorNumber
].ApTopOfStack
= ApTopOfStack
;
536 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
537 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
= (BistData
== 0) ? TRUE
: FALSE
;
538 if (CpuInfoInHob
[ProcessorNumber
].InitialApicId
>= 0xFF) {
540 // Set x2APIC mode if there are any logical processor reporting
541 // an Initial APIC ID of 255 or greater.
543 AcquireSpinLock(&CpuMpData
->MpLock
);
544 CpuMpData
->X2ApicEnable
= TRUE
;
545 ReleaseSpinLock(&CpuMpData
->MpLock
);
548 InitializeSpinLock(&CpuMpData
->CpuData
[ProcessorNumber
].ApLock
);
549 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
553 This function will be called from AP reset code if BSP uses WakeUpAP.
555 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
556 @param[in] ApIndex Number of current executing AP
561 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
565 CPU_MP_DATA
*CpuMpData
;
566 UINTN ProcessorNumber
;
567 EFI_AP_PROCEDURE Procedure
;
570 volatile UINT32
*ApStartupSignalBuffer
;
571 CPU_INFO_IN_HOB
*CpuInfoInHob
;
573 UINTN CurrentApicMode
;
576 // AP finished assembly code and begin to execute C code
578 CpuMpData
= ExchangeInfo
->CpuMpData
;
581 // AP's local APIC settings will be lost after received INIT IPI
582 // We need to re-initialize them at here
584 ProgramVirtualWireMode ();
586 // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.
588 DisableLvtInterrupts ();
589 SyncLocalApicTimerSetting (CpuMpData
);
591 CurrentApicMode
= GetApicMode ();
593 if (CpuMpData
->InitFlag
== ApInitConfig
) {
597 InterlockedIncrement ((UINT32
*) &CpuMpData
->CpuCount
);
598 ProcessorNumber
= ApIndex
;
600 // This is first time AP wakeup, get BIST information from AP stack
602 ApTopOfStack
= CpuMpData
->Buffer
+ (ProcessorNumber
+ 1) * CpuMpData
->CpuApStackSize
;
603 BistData
= *(UINT32
*) ((UINTN
) ApTopOfStack
- sizeof (UINTN
));
605 // Do some AP initialize sync
607 ApInitializeSync (CpuMpData
);
609 // Sync BSP's Control registers to APs
611 RestoreVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
612 InitializeApData (CpuMpData
, ProcessorNumber
, BistData
, ApTopOfStack
);
613 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
616 // Execute AP function if AP is ready
618 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
620 // Clear AP start-up signal when AP waken up
622 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
623 InterlockedCompareExchange32 (
624 (UINT32
*) ApStartupSignalBuffer
,
628 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
630 // Restore AP's volatile registers saved
632 RestoreVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
635 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateReady
) {
636 Procedure
= (EFI_AP_PROCEDURE
)CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
;
637 Parameter
= (VOID
*) CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
;
638 if (Procedure
!= NULL
) {
639 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateBusy
);
641 // Enable source debugging on AP function
645 // Invoke AP function here
647 Procedure (Parameter
);
648 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
649 if (CpuMpData
->SwitchBspFlag
) {
651 // Re-get the processor number due to BSP/AP maybe exchange in AP function
653 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
654 CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
= 0;
655 CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
= 0;
656 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
657 CpuInfoInHob
[ProcessorNumber
].ApTopOfStack
= CpuInfoInHob
[CpuMpData
->NewBspNumber
].ApTopOfStack
;
659 if (CpuInfoInHob
[ProcessorNumber
].ApicId
!= GetApicId () ||
660 CpuInfoInHob
[ProcessorNumber
].InitialApicId
!= GetInitialApicId ()) {
661 if (CurrentApicMode
!= GetApicMode ()) {
663 // If APIC mode change happened during AP function execution,
664 // we do not support APIC ID value changed.
670 // Re-get the CPU APICID and Initial APICID if they are changed
672 CpuInfoInHob
[ProcessorNumber
].ApicId
= GetApicId ();
673 CpuInfoInHob
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
678 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateFinished
);
683 // AP finished executing C code
685 InterlockedIncrement ((UINT32
*) &CpuMpData
->FinishedCount
);
686 InterlockedDecrement ((UINT32
*) &CpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
);
689 // Place AP is specified loop mode
691 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
693 // Save AP volatile registers
695 SaveVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
697 // Place AP in HLT-loop
700 DisableInterrupts ();
706 DisableInterrupts ();
707 if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
709 // Place AP in MWAIT-loop
711 AsmMonitor ((UINTN
) ApStartupSignalBuffer
, 0, 0);
712 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
714 // Check AP start-up signal again.
715 // If AP start-up signal is not set, place AP into
716 // the specified C-state
718 AsmMwait (CpuMpData
->ApTargetCState
<< 4, 0);
720 } else if (CpuMpData
->ApLoopMode
== ApInRunLoop
) {
722 // Place AP in Run-loop
730 // If AP start-up signal is written, AP is waken up
731 // otherwise place AP in loop again
733 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
741 Wait for AP wakeup and write AP start-up signal till AP is waken up.
743 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
747 IN
volatile UINT32
*ApStartupSignalBuffer
751 // If AP is waken up, StartupApSignal should be cleared.
752 // Otherwise, write StartupApSignal again till AP waken up.
754 while (InterlockedCompareExchange32 (
755 (UINT32
*) ApStartupSignalBuffer
,
764 This function will fill the exchange info structure.
766 @param[in] CpuMpData Pointer to CPU MP Data
770 FillExchangeInfoData (
771 IN CPU_MP_DATA
*CpuMpData
774 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
776 IA32_SEGMENT_DESCRIPTOR
*Selector
;
778 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
779 ExchangeInfo
->Lock
= 0;
780 ExchangeInfo
->StackStart
= CpuMpData
->Buffer
;
781 ExchangeInfo
->StackSize
= CpuMpData
->CpuApStackSize
;
782 ExchangeInfo
->BufferStart
= CpuMpData
->WakeupBuffer
;
783 ExchangeInfo
->ModeOffset
= CpuMpData
->AddressMap
.ModeEntryOffset
;
785 ExchangeInfo
->CodeSegment
= AsmReadCs ();
786 ExchangeInfo
->DataSegment
= AsmReadDs ();
788 ExchangeInfo
->Cr3
= AsmReadCr3 ();
790 ExchangeInfo
->CFunction
= (UINTN
) ApWakeupFunction
;
791 ExchangeInfo
->ApIndex
= 0;
792 ExchangeInfo
->NumApsExecuting
= 0;
793 ExchangeInfo
->InitFlag
= (UINTN
) CpuMpData
->InitFlag
;
794 ExchangeInfo
->CpuInfo
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
795 ExchangeInfo
->CpuMpData
= CpuMpData
;
797 ExchangeInfo
->EnableExecuteDisable
= IsBspExecuteDisableEnabled ();
799 ExchangeInfo
->InitializeFloatingPointUnitsAddress
= (UINTN
)InitializeFloatingPointUnits
;
802 // Get the BSP's data of GDT and IDT
804 AsmReadGdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->GdtrProfile
);
805 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
808 // Find a 32-bit code segment
810 Selector
= (IA32_SEGMENT_DESCRIPTOR
*)ExchangeInfo
->GdtrProfile
.Base
;
811 Size
= ExchangeInfo
->GdtrProfile
.Limit
+ 1;
813 if (Selector
->Bits
.L
== 0 && Selector
->Bits
.Type
>= 8) {
814 ExchangeInfo
->ModeTransitionSegment
=
815 (UINT16
)((UINTN
)Selector
- ExchangeInfo
->GdtrProfile
.Base
);
819 Size
-= sizeof (IA32_SEGMENT_DESCRIPTOR
);
823 // Copy all 32-bit code and 64-bit code into memory with type of
824 // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
826 if (CpuMpData
->WakeupBufferHigh
!= 0) {
827 Size
= CpuMpData
->AddressMap
.RendezvousFunnelSize
-
828 CpuMpData
->AddressMap
.ModeTransitionOffset
;
830 (VOID
*)CpuMpData
->WakeupBufferHigh
,
831 CpuMpData
->AddressMap
.RendezvousFunnelAddress
+
832 CpuMpData
->AddressMap
.ModeTransitionOffset
,
836 ExchangeInfo
->ModeTransitionMemory
= (UINT32
)CpuMpData
->WakeupBufferHigh
;
837 ExchangeInfo
->ModeHighMemory
= (UINT32
)CpuMpData
->WakeupBufferHigh
+
838 (UINT32
)ExchangeInfo
->ModeOffset
-
839 (UINT32
)CpuMpData
->AddressMap
.ModeTransitionOffset
;
840 ExchangeInfo
->ModeHighSegment
= (UINT16
)ExchangeInfo
->CodeSegment
;
842 ExchangeInfo
->ModeTransitionMemory
= (UINT32
)
843 (ExchangeInfo
->BufferStart
+ CpuMpData
->AddressMap
.ModeTransitionOffset
);
848 Helper function that waits until the finished AP count reaches the specified
849 limit, or the specified timeout elapses (whichever comes first).
851 @param[in] CpuMpData Pointer to CPU MP Data.
852 @param[in] FinishedApLimit The number of finished APs to wait for.
853 @param[in] TimeLimit The number of microseconds to wait for.
856 TimedWaitForApFinish (
857 IN CPU_MP_DATA
*CpuMpData
,
858 IN UINT32 FinishedApLimit
,
863 Get available system memory below 1MB by specified size.
865 @param[in] CpuMpData The pointer to CPU MP Data structure.
868 BackupAndPrepareWakeupBuffer(
869 IN CPU_MP_DATA
*CpuMpData
873 (VOID
*) CpuMpData
->BackupBuffer
,
874 (VOID
*) CpuMpData
->WakeupBuffer
,
875 CpuMpData
->BackupBufferSize
878 (VOID
*) CpuMpData
->WakeupBuffer
,
879 (VOID
*) CpuMpData
->AddressMap
.RendezvousFunnelAddress
,
880 CpuMpData
->AddressMap
.RendezvousFunnelSize
885 Restore wakeup buffer data.
887 @param[in] CpuMpData The pointer to CPU MP Data structure.
891 IN CPU_MP_DATA
*CpuMpData
895 (VOID
*) CpuMpData
->WakeupBuffer
,
896 (VOID
*) CpuMpData
->BackupBuffer
,
897 CpuMpData
->BackupBufferSize
902 Allocate reset vector buffer.
904 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
907 AllocateResetVector (
908 IN OUT CPU_MP_DATA
*CpuMpData
911 UINTN ApResetVectorSize
;
913 if (CpuMpData
->WakeupBuffer
== (UINTN
) -1) {
914 ApResetVectorSize
= CpuMpData
->AddressMap
.RendezvousFunnelSize
+
915 sizeof (MP_CPU_EXCHANGE_INFO
);
917 CpuMpData
->WakeupBuffer
= GetWakeupBuffer (ApResetVectorSize
);
918 CpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
)
919 (CpuMpData
->WakeupBuffer
+ CpuMpData
->AddressMap
.RendezvousFunnelSize
);
920 CpuMpData
->WakeupBufferHigh
= GetModeTransitionBuffer (
921 CpuMpData
->AddressMap
.RendezvousFunnelSize
-
922 CpuMpData
->AddressMap
.ModeTransitionOffset
925 BackupAndPrepareWakeupBuffer (CpuMpData
);
929 Free AP reset vector buffer.
931 @param[in] CpuMpData The pointer to CPU MP Data structure.
935 IN CPU_MP_DATA
*CpuMpData
938 RestoreWakeupBuffer (CpuMpData
);
942 This function will be called by BSP to wakeup AP.
944 @param[in] CpuMpData Pointer to CPU MP Data
945 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
946 FALSE: Send IPI to AP by ApicId
947 @param[in] ProcessorNumber The handle number of specified processor
948 @param[in] Procedure The function to be invoked by AP
949 @param[in] ProcedureArgument The argument to be passed into AP function
953 IN CPU_MP_DATA
*CpuMpData
,
954 IN BOOLEAN Broadcast
,
955 IN UINTN ProcessorNumber
,
956 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
957 IN VOID
*ProcedureArgument OPTIONAL
960 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
962 CPU_AP_DATA
*CpuData
;
963 BOOLEAN ResetVectorRequired
;
964 CPU_INFO_IN_HOB
*CpuInfoInHob
;
966 CpuMpData
->FinishedCount
= 0;
967 ResetVectorRequired
= FALSE
;
969 if (CpuMpData
->ApLoopMode
== ApInHltLoop
||
970 CpuMpData
->InitFlag
!= ApInitDone
) {
971 ResetVectorRequired
= TRUE
;
972 AllocateResetVector (CpuMpData
);
973 FillExchangeInfoData (CpuMpData
);
974 SaveLocalApicTimerSetting (CpuMpData
);
975 } else if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
977 // Get AP target C-state each time when waking up AP,
978 // for it maybe updated by platform again
980 CpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
983 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
986 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
987 if (Index
!= CpuMpData
->BspNumber
) {
988 CpuData
= &CpuMpData
->CpuData
[Index
];
989 CpuData
->ApFunction
= (UINTN
) Procedure
;
990 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
991 SetApState (CpuData
, CpuStateReady
);
992 if (CpuMpData
->InitFlag
!= ApInitConfig
) {
993 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
997 if (ResetVectorRequired
) {
1001 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
1003 if (CpuMpData
->InitFlag
== ApInitConfig
) {
1005 // Here support two methods to collect AP count through adjust
1006 // PcdCpuApInitTimeOutInMicroSeconds values.
1008 // one way is set a value to just let the first AP to start the
1009 // initialization, then through the later while loop to wait all Aps
1010 // finsh the initialization.
1011 // The other way is set a value to let all APs finished the initialzation.
1012 // In this case, the later while loop is useless.
1014 TimedWaitForApFinish (
1016 PcdGet32 (PcdCpuMaxLogicalProcessorNumber
) - 1,
1017 PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
)
1020 while (CpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
!= 0) {
1025 // Wait all APs waken up if this is not the 1st broadcast of SIPI
1027 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1028 CpuData
= &CpuMpData
->CpuData
[Index
];
1029 if (Index
!= CpuMpData
->BspNumber
) {
1030 WaitApWakeup (CpuData
->StartupApSignal
);
1035 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1036 CpuData
->ApFunction
= (UINTN
) Procedure
;
1037 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
1038 SetApState (CpuData
, CpuStateReady
);
1040 // Wakeup specified AP
1042 ASSERT (CpuMpData
->InitFlag
!= ApInitConfig
);
1043 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
1044 if (ResetVectorRequired
) {
1045 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
1047 CpuInfoInHob
[ProcessorNumber
].ApicId
,
1048 (UINT32
) ExchangeInfo
->BufferStart
1052 // Wait specified AP waken up
1054 WaitApWakeup (CpuData
->StartupApSignal
);
1057 if (ResetVectorRequired
) {
1058 FreeResetVector (CpuMpData
);
1063 Calculate timeout value and return the current performance counter value.
1065 Calculate the number of performance counter ticks required for a timeout.
1066 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1069 @param[in] TimeoutInMicroseconds Timeout value in microseconds.
1070 @param[out] CurrentTime Returns the current value of the performance counter.
1072 @return Expected time stamp counter for timeout.
1073 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1079 IN UINTN TimeoutInMicroseconds
,
1080 OUT UINT64
*CurrentTime
1083 UINT64 TimeoutInSeconds
;
1084 UINT64 TimestampCounterFreq
;
1087 // Read the current value of the performance counter
1089 *CurrentTime
= GetPerformanceCounter ();
1092 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1095 if (TimeoutInMicroseconds
== 0) {
1100 // GetPerformanceCounterProperties () returns the timestamp counter's frequency
1103 TimestampCounterFreq
= GetPerformanceCounterProperties (NULL
, NULL
);
1106 // Check the potential overflow before calculate the number of ticks for the timeout value.
1108 if (DivU64x64Remainder (MAX_UINT64
, TimeoutInMicroseconds
, NULL
) < TimestampCounterFreq
) {
1110 // Convert microseconds into seconds if direct multiplication overflows
1112 TimeoutInSeconds
= DivU64x32 (TimeoutInMicroseconds
, 1000000);
1114 // Assertion if the final tick count exceeds MAX_UINT64
1116 ASSERT (DivU64x64Remainder (MAX_UINT64
, TimeoutInSeconds
, NULL
) >= TimestampCounterFreq
);
1117 return MultU64x64 (TimestampCounterFreq
, TimeoutInSeconds
);
1120 // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
1121 // it by 1,000,000, to get the number of ticks for the timeout value.
1125 TimestampCounterFreq
,
1126 TimeoutInMicroseconds
1134 Checks whether timeout expires.
1136 Check whether the number of elapsed performance counter ticks required for
1137 a timeout condition has been reached.
1138 If Timeout is zero, which means infinity, return value is always FALSE.
1140 @param[in, out] PreviousTime On input, the value of the performance counter
1141 when it was last read.
1142 On output, the current value of the performance
1144 @param[in] TotalTime The total amount of elapsed time in performance
1146 @param[in] Timeout The number of performance counter ticks required
1147 to reach a timeout condition.
1149 @retval TRUE A timeout condition has been reached.
1150 @retval FALSE A timeout condition has not been reached.
1155 IN OUT UINT64
*PreviousTime
,
1156 IN UINT64
*TotalTime
,
1169 GetPerformanceCounterProperties (&Start
, &End
);
1170 Cycle
= End
- Start
;
1175 CurrentTime
= GetPerformanceCounter();
1176 Delta
= (INT64
) (CurrentTime
- *PreviousTime
);
1183 *TotalTime
+= Delta
;
1184 *PreviousTime
= CurrentTime
;
1185 if (*TotalTime
> Timeout
) {
1192 Helper function that waits until the finished AP count reaches the specified
1193 limit, or the specified timeout elapses (whichever comes first).
1195 @param[in] CpuMpData Pointer to CPU MP Data.
1196 @param[in] FinishedApLimit The number of finished APs to wait for.
1197 @param[in] TimeLimit The number of microseconds to wait for.
1200 TimedWaitForApFinish (
1201 IN CPU_MP_DATA
*CpuMpData
,
1202 IN UINT32 FinishedApLimit
,
1207 // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
1208 // "infinity", so check for (TimeLimit == 0) explicitly.
1210 if (TimeLimit
== 0) {
1214 CpuMpData
->TotalTime
= 0;
1215 CpuMpData
->ExpectedTime
= CalculateTimeout (
1217 &CpuMpData
->CurrentTime
1219 while (CpuMpData
->FinishedCount
< FinishedApLimit
&&
1221 &CpuMpData
->CurrentTime
,
1222 &CpuMpData
->TotalTime
,
1223 CpuMpData
->ExpectedTime
1228 if (CpuMpData
->FinishedCount
>= FinishedApLimit
) {
1231 "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
1234 DivU64x64Remainder (
1235 MultU64x32 (CpuMpData
->TotalTime
, 1000000),
1236 GetPerformanceCounterProperties (NULL
, NULL
),
1244 Reset an AP to Idle state.
1246 Any task being executed by the AP will be aborted and the AP
1247 will be waiting for a new task in Wait-For-SIPI state.
1249 @param[in] ProcessorNumber The handle number of processor.
1252 ResetProcessorToIdleState (
1253 IN UINTN ProcessorNumber
1256 CPU_MP_DATA
*CpuMpData
;
1258 CpuMpData
= GetCpuMpData ();
1260 CpuMpData
->InitFlag
= ApInitReconfig
;
1261 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, NULL
, NULL
);
1262 while (CpuMpData
->FinishedCount
< 1) {
1265 CpuMpData
->InitFlag
= ApInitDone
;
1267 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
1271 Searches for the next waiting AP.
1273 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
1275 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
1277 @retval EFI_SUCCESS The next waiting AP has been found.
1278 @retval EFI_NOT_FOUND No waiting AP exists.
1282 GetNextWaitingProcessorNumber (
1283 OUT UINTN
*NextProcessorNumber
1286 UINTN ProcessorNumber
;
1287 CPU_MP_DATA
*CpuMpData
;
1289 CpuMpData
= GetCpuMpData ();
1291 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1292 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1293 *NextProcessorNumber
= ProcessorNumber
;
1298 return EFI_NOT_FOUND
;
1301 /** Checks status of specified AP.
1303 This function checks whether the specified AP has finished the task assigned
1304 by StartupThisAP(), and whether timeout expires.
1306 @param[in] ProcessorNumber The handle number of processor.
1308 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
1309 @retval EFI_TIMEOUT The timeout expires.
1310 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
1314 IN UINTN ProcessorNumber
1317 CPU_MP_DATA
*CpuMpData
;
1318 CPU_AP_DATA
*CpuData
;
1320 CpuMpData
= GetCpuMpData ();
1321 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1324 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
1325 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1326 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
1329 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
1331 if (GetApState(CpuData
) == CpuStateFinished
) {
1332 if (CpuData
->Finished
!= NULL
) {
1333 *(CpuData
->Finished
) = TRUE
;
1335 SetApState (CpuData
, CpuStateIdle
);
1339 // If timeout expires for StartupThisAP(), report timeout.
1341 if (CheckTimeout (&CpuData
->CurrentTime
, &CpuData
->TotalTime
, CpuData
->ExpectedTime
)) {
1342 if (CpuData
->Finished
!= NULL
) {
1343 *(CpuData
->Finished
) = FALSE
;
1346 // Reset failed AP to idle state
1348 ResetProcessorToIdleState (ProcessorNumber
);
1353 return EFI_NOT_READY
;
1357 Checks status of all APs.
1359 This function checks whether all APs have finished task assigned by StartupAllAPs(),
1360 and whether timeout expires.
1362 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
1363 @retval EFI_TIMEOUT The timeout expires.
1364 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
1371 UINTN ProcessorNumber
;
1372 UINTN NextProcessorNumber
;
1375 CPU_MP_DATA
*CpuMpData
;
1376 CPU_AP_DATA
*CpuData
;
1378 CpuMpData
= GetCpuMpData ();
1380 NextProcessorNumber
= 0;
1383 // Go through all APs that are responsible for the StartupAllAPs().
1385 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1386 if (!CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1390 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1392 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
1393 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1394 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
1396 if (GetApState(CpuData
) == CpuStateFinished
) {
1397 CpuMpData
->RunningCount
++;
1398 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
1399 SetApState(CpuData
, CpuStateIdle
);
1402 // If in Single Thread mode, then search for the next waiting AP for execution.
1404 if (CpuMpData
->SingleThread
) {
1405 Status
= GetNextWaitingProcessorNumber (&NextProcessorNumber
);
1407 if (!EFI_ERROR (Status
)) {
1411 (UINT32
) NextProcessorNumber
,
1412 CpuMpData
->Procedure
,
1413 CpuMpData
->ProcArguments
1421 // If all APs finish, return EFI_SUCCESS.
1423 if (CpuMpData
->RunningCount
== CpuMpData
->StartCount
) {
1428 // If timeout expires, report timeout.
1431 &CpuMpData
->CurrentTime
,
1432 &CpuMpData
->TotalTime
,
1433 CpuMpData
->ExpectedTime
)
1436 // If FailedCpuList is not NULL, record all failed APs in it.
1438 if (CpuMpData
->FailedCpuList
!= NULL
) {
1439 *CpuMpData
->FailedCpuList
=
1440 AllocatePool ((CpuMpData
->StartCount
- CpuMpData
->FinishedCount
+ 1) * sizeof (UINTN
));
1441 ASSERT (*CpuMpData
->FailedCpuList
!= NULL
);
1445 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1447 // Check whether this processor is responsible for StartupAllAPs().
1449 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1451 // Reset failed APs to idle state
1453 ResetProcessorToIdleState (ProcessorNumber
);
1454 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
1455 if (CpuMpData
->FailedCpuList
!= NULL
) {
1456 (*CpuMpData
->FailedCpuList
)[ListIndex
++] = ProcessorNumber
;
1460 if (CpuMpData
->FailedCpuList
!= NULL
) {
1461 (*CpuMpData
->FailedCpuList
)[ListIndex
] = END_OF_CPU_LIST
;
1465 return EFI_NOT_READY
;
1469 MP Initialize Library initialization.
1471 This service will allocate AP reset vector and wakeup all APs to do APs
1474 This service must be invoked before all other MP Initialize Library
1475 service are invoked.
1477 @retval EFI_SUCCESS MP initialization succeeds.
1478 @retval Others MP initialization fails.
1483 MpInitLibInitialize (
1487 CPU_MP_DATA
*OldCpuMpData
;
1488 CPU_INFO_IN_HOB
*CpuInfoInHob
;
1489 UINT32 MaxLogicalProcessorNumber
;
1491 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
1493 UINT32 MonitorFilterSize
;
1496 CPU_MP_DATA
*CpuMpData
;
1498 UINT8
*MonitorBuffer
;
1500 UINTN ApResetVectorSize
;
1501 UINTN BackupBufferAddr
;
1503 OldCpuMpData
= GetCpuMpDataFromGuidedHob ();
1504 if (OldCpuMpData
== NULL
) {
1505 MaxLogicalProcessorNumber
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
1507 MaxLogicalProcessorNumber
= OldCpuMpData
->CpuCount
;
1509 ASSERT (MaxLogicalProcessorNumber
!= 0);
1511 AsmGetAddressMap (&AddressMap
);
1512 ApResetVectorSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
1513 ApStackSize
= PcdGet32(PcdCpuApStackSize
);
1514 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
1516 BufferSize
= ApStackSize
* MaxLogicalProcessorNumber
;
1517 BufferSize
+= MonitorFilterSize
* MaxLogicalProcessorNumber
;
1518 BufferSize
+= sizeof (CPU_MP_DATA
);
1519 BufferSize
+= ApResetVectorSize
;
1520 BufferSize
+= (sizeof (CPU_AP_DATA
) + sizeof (CPU_INFO_IN_HOB
))* MaxLogicalProcessorNumber
;
1521 MpBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (BufferSize
));
1522 ASSERT (MpBuffer
!= NULL
);
1523 ZeroMem (MpBuffer
, BufferSize
);
1524 Buffer
= (UINTN
) MpBuffer
;
1526 MonitorBuffer
= (UINT8
*) (Buffer
+ ApStackSize
* MaxLogicalProcessorNumber
);
1527 BackupBufferAddr
= (UINTN
) MonitorBuffer
+ MonitorFilterSize
* MaxLogicalProcessorNumber
;
1528 CpuMpData
= (CPU_MP_DATA
*) (BackupBufferAddr
+ ApResetVectorSize
);
1529 CpuMpData
->Buffer
= Buffer
;
1530 CpuMpData
->CpuApStackSize
= ApStackSize
;
1531 CpuMpData
->BackupBuffer
= BackupBufferAddr
;
1532 CpuMpData
->BackupBufferSize
= ApResetVectorSize
;
1533 CpuMpData
->WakeupBuffer
= (UINTN
) -1;
1534 CpuMpData
->CpuCount
= 1;
1535 CpuMpData
->BspNumber
= 0;
1536 CpuMpData
->WaitEvent
= NULL
;
1537 CpuMpData
->SwitchBspFlag
= FALSE
;
1538 CpuMpData
->CpuData
= (CPU_AP_DATA
*) (CpuMpData
+ 1);
1539 CpuMpData
->CpuInfoInHob
= (UINT64
) (UINTN
) (CpuMpData
->CpuData
+ MaxLogicalProcessorNumber
);
1540 CpuMpData
->MicrocodePatchAddress
= PcdGet64 (PcdCpuMicrocodePatchAddress
);
1541 CpuMpData
->MicrocodePatchRegionSize
= PcdGet64 (PcdCpuMicrocodePatchRegionSize
);
1542 InitializeSpinLock(&CpuMpData
->MpLock
);
1544 // Save BSP's Control registers to APs
1546 SaveVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
);
1548 // Set BSP basic information
1550 InitializeApData (CpuMpData
, 0, 0, CpuMpData
->Buffer
+ ApStackSize
);
1552 // Save assembly code information
1554 CopyMem (&CpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
1556 // Finally set AP loop mode
1558 CpuMpData
->ApLoopMode
= ApLoopMode
;
1559 DEBUG ((DEBUG_INFO
, "AP Loop Mode is %d\n", CpuMpData
->ApLoopMode
));
1561 // Set up APs wakeup signal buffer
1563 for (Index
= 0; Index
< MaxLogicalProcessorNumber
; Index
++) {
1564 CpuMpData
->CpuData
[Index
].StartupApSignal
=
1565 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
1568 // Load Microcode on BSP
1570 MicrocodeDetect (CpuMpData
);
1572 // Store BSP's MTRR setting
1574 MtrrGetAllMtrrs (&CpuMpData
->MtrrTable
);
1576 // Enable the local APIC for Virtual Wire Mode.
1578 ProgramVirtualWireMode ();
1580 if (OldCpuMpData
== NULL
) {
1581 if (MaxLogicalProcessorNumber
> 1) {
1583 // Wakeup all APs and calculate the processor count in system
1585 CollectProcessorCount (CpuMpData
);
1589 // APs have been wakeup before, just get the CPU Information
1592 CpuMpData
->CpuCount
= OldCpuMpData
->CpuCount
;
1593 CpuMpData
->BspNumber
= OldCpuMpData
->BspNumber
;
1594 CpuMpData
->InitFlag
= ApInitReconfig
;
1595 CpuMpData
->CpuInfoInHob
= OldCpuMpData
->CpuInfoInHob
;
1596 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
1597 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1598 InitializeSpinLock(&CpuMpData
->CpuData
[Index
].ApLock
);
1599 if (CpuInfoInHob
[Index
].InitialApicId
>= 255 || Index
> 254) {
1600 CpuMpData
->X2ApicEnable
= TRUE
;
1602 CpuMpData
->CpuData
[Index
].CpuHealthy
= (CpuInfoInHob
[Index
].Health
== 0)? TRUE
:FALSE
;
1603 CpuMpData
->CpuData
[Index
].ApFunction
= 0;
1605 &CpuMpData
->CpuData
[Index
].VolatileRegisters
,
1606 &CpuMpData
->CpuData
[0].VolatileRegisters
,
1607 sizeof (CPU_VOLATILE_REGISTERS
)
1610 if (MaxLogicalProcessorNumber
> 1) {
1612 // Wakeup APs to do some AP initialize sync
1614 WakeUpAP (CpuMpData
, TRUE
, 0, ApInitializeSync
, CpuMpData
);
1616 // Wait for all APs finished initialization
1618 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
1621 CpuMpData
->InitFlag
= ApInitDone
;
1622 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1623 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
1629 // Initialize global data for MP support
1631 InitMpGlobalData (CpuMpData
);
1637 Gets detailed MP-related information on the requested processor at the
1638 instant this call is made. This service may only be called from the BSP.
1640 @param[in] ProcessorNumber The handle number of processor.
1641 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
1642 the requested processor is deposited.
1643 @param[out] HealthData Return processor health data.
1645 @retval EFI_SUCCESS Processor information was returned.
1646 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1647 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
1648 @retval EFI_NOT_FOUND The processor with the handle specified by
1649 ProcessorNumber does not exist in the platform.
1650 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1655 MpInitLibGetProcessorInfo (
1656 IN UINTN ProcessorNumber
,
1657 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
,
1658 OUT EFI_HEALTH_FLAGS
*HealthData OPTIONAL
1661 CPU_MP_DATA
*CpuMpData
;
1663 CPU_INFO_IN_HOB
*CpuInfoInHob
;
1665 CpuMpData
= GetCpuMpData ();
1666 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
1669 // Check whether caller processor is BSP
1671 MpInitLibWhoAmI (&CallerNumber
);
1672 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1673 return EFI_DEVICE_ERROR
;
1676 if (ProcessorInfoBuffer
== NULL
) {
1677 return EFI_INVALID_PARAMETER
;
1680 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1681 return EFI_NOT_FOUND
;
1684 ProcessorInfoBuffer
->ProcessorId
= (UINT64
) CpuInfoInHob
[ProcessorNumber
].ApicId
;
1685 ProcessorInfoBuffer
->StatusFlag
= 0;
1686 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1687 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_AS_BSP_BIT
;
1689 if (CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
) {
1690 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_HEALTH_STATUS_BIT
;
1692 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
1693 ProcessorInfoBuffer
->StatusFlag
&= ~PROCESSOR_ENABLED_BIT
;
1695 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_ENABLED_BIT
;
1699 // Get processor location information
1701 GetProcessorLocationByApicId (
1702 CpuInfoInHob
[ProcessorNumber
].ApicId
,
1703 &ProcessorInfoBuffer
->Location
.Package
,
1704 &ProcessorInfoBuffer
->Location
.Core
,
1705 &ProcessorInfoBuffer
->Location
.Thread
1708 if (HealthData
!= NULL
) {
1709 HealthData
->Uint32
= CpuInfoInHob
[ProcessorNumber
].Health
;
1716 Worker function to switch the requested AP to be the BSP from that point onward.
1718 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
1719 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
1720 enabled AP. Otherwise, it will be disabled.
1722 @retval EFI_SUCCESS BSP successfully switched.
1723 @retval others Failed to switch BSP.
1728 IN UINTN ProcessorNumber
,
1729 IN BOOLEAN EnableOldBSP
1732 CPU_MP_DATA
*CpuMpData
;
1735 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
1736 BOOLEAN OldInterruptState
;
1737 BOOLEAN OldTimerInterruptState
;
1740 // Save and Disable Local APIC timer interrupt
1742 OldTimerInterruptState
= GetApicTimerInterruptState ();
1743 DisableApicTimerInterrupt ();
1745 // Before send both BSP and AP to a procedure to exchange their roles,
1746 // interrupt must be disabled. This is because during the exchange role
1747 // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
1748 // be corrupted, since interrupt return address will be pushed to stack
1751 OldInterruptState
= SaveAndDisableInterrupts ();
1754 // Mask LINT0 & LINT1 for the old BSP
1756 DisableLvtInterrupts ();
1758 CpuMpData
= GetCpuMpData ();
1761 // Check whether caller processor is BSP
1763 MpInitLibWhoAmI (&CallerNumber
);
1764 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1765 return EFI_DEVICE_ERROR
;
1768 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1769 return EFI_NOT_FOUND
;
1773 // Check whether specified AP is disabled
1775 State
= GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]);
1776 if (State
== CpuStateDisabled
) {
1777 return EFI_INVALID_PARAMETER
;
1781 // Check whether ProcessorNumber specifies the current BSP
1783 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1784 return EFI_INVALID_PARAMETER
;
1788 // Check whether specified AP is busy
1790 if (State
== CpuStateBusy
) {
1791 return EFI_NOT_READY
;
1794 CpuMpData
->BSPInfo
.State
= CPU_SWITCH_STATE_IDLE
;
1795 CpuMpData
->APInfo
.State
= CPU_SWITCH_STATE_IDLE
;
1796 CpuMpData
->SwitchBspFlag
= TRUE
;
1797 CpuMpData
->NewBspNumber
= ProcessorNumber
;
1800 // Clear the BSP bit of MSR_IA32_APIC_BASE
1802 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
1803 ApicBaseMsr
.Bits
.BSP
= 0;
1804 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
1807 // Need to wakeUp AP (future BSP).
1809 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, FutureBSPProc
, CpuMpData
);
1811 AsmExchangeRole (&CpuMpData
->BSPInfo
, &CpuMpData
->APInfo
);
1814 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
1816 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
1817 ApicBaseMsr
.Bits
.BSP
= 1;
1818 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
1819 ProgramVirtualWireMode ();
1822 // Wait for old BSP finished AP task
1824 while (GetApState (&CpuMpData
->CpuData
[CallerNumber
]) != CpuStateFinished
) {
1828 CpuMpData
->SwitchBspFlag
= FALSE
;
1830 // Set old BSP enable state
1832 if (!EnableOldBSP
) {
1833 SetApState (&CpuMpData
->CpuData
[CallerNumber
], CpuStateDisabled
);
1835 SetApState (&CpuMpData
->CpuData
[CallerNumber
], CpuStateIdle
);
1838 // Save new BSP number
1840 CpuMpData
->BspNumber
= (UINT32
) ProcessorNumber
;
1843 // Restore interrupt state.
1845 SetInterruptState (OldInterruptState
);
1847 if (OldTimerInterruptState
) {
1848 EnableApicTimerInterrupt ();
1855 Worker function to let the caller enable or disable an AP from this point onward.
1856 This service may only be called from the BSP.
1858 @param[in] ProcessorNumber The handle number of AP.
1859 @param[in] EnableAP Specifies the new state for the processor for
1860 enabled, FALSE for disabled.
1861 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
1862 the new health status of the AP.
1864 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
1865 @retval others Failed to Enable/Disable AP.
1869 EnableDisableApWorker (
1870 IN UINTN ProcessorNumber
,
1871 IN BOOLEAN EnableAP
,
1872 IN UINT32
*HealthFlag OPTIONAL
1875 CPU_MP_DATA
*CpuMpData
;
1878 CpuMpData
= GetCpuMpData ();
1881 // Check whether caller processor is BSP
1883 MpInitLibWhoAmI (&CallerNumber
);
1884 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1885 return EFI_DEVICE_ERROR
;
1888 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1889 return EFI_INVALID_PARAMETER
;
1892 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1893 return EFI_NOT_FOUND
;
1897 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateDisabled
);
1899 ResetProcessorToIdleState (ProcessorNumber
);
1902 if (HealthFlag
!= NULL
) {
1903 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
=
1904 (BOOLEAN
) ((*HealthFlag
& PROCESSOR_HEALTH_STATUS_BIT
) != 0);
1911 This return the handle number for the calling processor. This service may be
1912 called from the BSP and APs.
1914 @param[out] ProcessorNumber Pointer to the handle number of AP.
1915 The range is from 0 to the total number of
1916 logical processors minus 1. The total number of
1917 logical processors can be retrieved by
1918 MpInitLibGetNumberOfProcessors().
1920 @retval EFI_SUCCESS The current processor handle number was returned
1922 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1923 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1929 OUT UINTN
*ProcessorNumber
1932 CPU_MP_DATA
*CpuMpData
;
1934 if (ProcessorNumber
== NULL
) {
1935 return EFI_INVALID_PARAMETER
;
1938 CpuMpData
= GetCpuMpData ();
1940 return GetProcessorNumber (CpuMpData
, ProcessorNumber
);
1944 Retrieves the number of logical processor in the platform and the number of
1945 those logical processors that are enabled on this boot. This service may only
1946 be called from the BSP.
1948 @param[out] NumberOfProcessors Pointer to the total number of logical
1949 processors in the system, including the BSP
1951 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
1952 processors that exist in system, including
1955 @retval EFI_SUCCESS The number of logical processors and enabled
1956 logical processors was retrieved.
1957 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1958 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
1960 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1965 MpInitLibGetNumberOfProcessors (
1966 OUT UINTN
*NumberOfProcessors
, OPTIONAL
1967 OUT UINTN
*NumberOfEnabledProcessors OPTIONAL
1970 CPU_MP_DATA
*CpuMpData
;
1972 UINTN ProcessorNumber
;
1973 UINTN EnabledProcessorNumber
;
1976 CpuMpData
= GetCpuMpData ();
1978 if ((NumberOfProcessors
== NULL
) && (NumberOfEnabledProcessors
== NULL
)) {
1979 return EFI_INVALID_PARAMETER
;
1983 // Check whether caller processor is BSP
1985 MpInitLibWhoAmI (&CallerNumber
);
1986 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1987 return EFI_DEVICE_ERROR
;
1990 ProcessorNumber
= CpuMpData
->CpuCount
;
1991 EnabledProcessorNumber
= 0;
1992 for (Index
= 0; Index
< ProcessorNumber
; Index
++) {
1993 if (GetApState (&CpuMpData
->CpuData
[Index
]) != CpuStateDisabled
) {
1994 EnabledProcessorNumber
++;
1998 if (NumberOfProcessors
!= NULL
) {
1999 *NumberOfProcessors
= ProcessorNumber
;
2001 if (NumberOfEnabledProcessors
!= NULL
) {
2002 *NumberOfEnabledProcessors
= EnabledProcessorNumber
;
2010 Worker function to execute a caller provided function on all enabled APs.
2012 @param[in] Procedure A pointer to the function to be run on
2013 enabled APs of the system.
2014 @param[in] SingleThread If TRUE, then all the enabled APs execute
2015 the function specified by Procedure one by
2016 one, in ascending order of processor handle
2017 number. If FALSE, then all the enabled APs
2018 execute the function specified by Procedure
2020 @param[in] WaitEvent The event created by the caller with CreateEvent()
2022 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2023 APs to return from Procedure, either for
2024 blocking or non-blocking mode.
2025 @param[in] ProcedureArgument The parameter passed into Procedure for
2027 @param[out] FailedCpuList If all APs finish successfully, then its
2028 content is set to NULL. If not all APs
2029 finish before timeout expires, then its
2030 content is set to address of the buffer
2031 holding handle numbers of the failed APs.
2033 @retval EFI_SUCCESS In blocking mode, all APs have finished before
2034 the timeout expired.
2035 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2037 @retval others Failed to Startup all APs.
2041 StartupAllAPsWorker (
2042 IN EFI_AP_PROCEDURE Procedure
,
2043 IN BOOLEAN SingleThread
,
2044 IN EFI_EVENT WaitEvent OPTIONAL
,
2045 IN UINTN TimeoutInMicroseconds
,
2046 IN VOID
*ProcedureArgument OPTIONAL
,
2047 OUT UINTN
**FailedCpuList OPTIONAL
2051 CPU_MP_DATA
*CpuMpData
;
2052 UINTN ProcessorCount
;
2053 UINTN ProcessorNumber
;
2055 CPU_AP_DATA
*CpuData
;
2056 BOOLEAN HasEnabledAp
;
2059 CpuMpData
= GetCpuMpData ();
2061 if (FailedCpuList
!= NULL
) {
2062 *FailedCpuList
= NULL
;
2065 if (CpuMpData
->CpuCount
== 1) {
2066 return EFI_NOT_STARTED
;
2069 if (Procedure
== NULL
) {
2070 return EFI_INVALID_PARAMETER
;
2074 // Check whether caller processor is BSP
2076 MpInitLibWhoAmI (&CallerNumber
);
2077 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2078 return EFI_DEVICE_ERROR
;
2084 CheckAndUpdateApsStatus ();
2086 ProcessorCount
= CpuMpData
->CpuCount
;
2087 HasEnabledAp
= FALSE
;
2089 // Check whether all enabled APs are idle.
2090 // If any enabled AP is not idle, return EFI_NOT_READY.
2092 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2093 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2094 if (ProcessorNumber
!= CpuMpData
->BspNumber
) {
2095 ApState
= GetApState (CpuData
);
2096 if (ApState
!= CpuStateDisabled
) {
2097 HasEnabledAp
= TRUE
;
2098 if (ApState
!= CpuStateIdle
) {
2100 // If any enabled APs are busy, return EFI_NOT_READY.
2102 return EFI_NOT_READY
;
2108 if (!HasEnabledAp
) {
2110 // If no enabled AP exists, return EFI_NOT_STARTED.
2112 return EFI_NOT_STARTED
;
2115 CpuMpData
->StartCount
= 0;
2116 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2117 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2118 CpuData
->Waiting
= FALSE
;
2119 if (ProcessorNumber
!= CpuMpData
->BspNumber
) {
2120 if (CpuData
->State
== CpuStateIdle
) {
2122 // Mark this processor as responsible for current calling.
2124 CpuData
->Waiting
= TRUE
;
2125 CpuMpData
->StartCount
++;
2130 CpuMpData
->Procedure
= Procedure
;
2131 CpuMpData
->ProcArguments
= ProcedureArgument
;
2132 CpuMpData
->SingleThread
= SingleThread
;
2133 CpuMpData
->FinishedCount
= 0;
2134 CpuMpData
->RunningCount
= 0;
2135 CpuMpData
->FailedCpuList
= FailedCpuList
;
2136 CpuMpData
->ExpectedTime
= CalculateTimeout (
2137 TimeoutInMicroseconds
,
2138 &CpuMpData
->CurrentTime
2140 CpuMpData
->TotalTime
= 0;
2141 CpuMpData
->WaitEvent
= WaitEvent
;
2143 if (!SingleThread
) {
2144 WakeUpAP (CpuMpData
, TRUE
, 0, Procedure
, ProcedureArgument
);
2146 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2147 if (ProcessorNumber
== CallerNumber
) {
2150 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
2151 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, Procedure
, ProcedureArgument
);
2157 Status
= EFI_SUCCESS
;
2158 if (WaitEvent
== NULL
) {
2160 Status
= CheckAllAPs ();
2161 } while (Status
== EFI_NOT_READY
);
2168 Worker function to let the caller get one enabled AP to execute a caller-provided
2171 @param[in] Procedure A pointer to the function to be run on
2172 enabled APs of the system.
2173 @param[in] ProcessorNumber The handle number of the AP.
2174 @param[in] WaitEvent The event created by the caller with CreateEvent()
2176 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2177 APs to return from Procedure, either for
2178 blocking or non-blocking mode.
2179 @param[in] ProcedureArgument The parameter passed into Procedure for
2181 @param[out] Finished If AP returns from Procedure before the
2182 timeout expires, its content is set to TRUE.
2183 Otherwise, the value is set to FALSE.
2185 @retval EFI_SUCCESS In blocking mode, specified AP finished before
2186 the timeout expires.
2187 @retval others Failed to Startup AP.
2191 StartupThisAPWorker (
2192 IN EFI_AP_PROCEDURE Procedure
,
2193 IN UINTN ProcessorNumber
,
2194 IN EFI_EVENT WaitEvent OPTIONAL
,
2195 IN UINTN TimeoutInMicroseconds
,
2196 IN VOID
*ProcedureArgument OPTIONAL
,
2197 OUT BOOLEAN
*Finished OPTIONAL
2201 CPU_MP_DATA
*CpuMpData
;
2202 CPU_AP_DATA
*CpuData
;
2205 CpuMpData
= GetCpuMpData ();
2207 if (Finished
!= NULL
) {
2212 // Check whether caller processor is BSP
2214 MpInitLibWhoAmI (&CallerNumber
);
2215 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2216 return EFI_DEVICE_ERROR
;
2220 // Check whether processor with the handle specified by ProcessorNumber exists
2222 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
2223 return EFI_NOT_FOUND
;
2227 // Check whether specified processor is BSP
2229 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
2230 return EFI_INVALID_PARAMETER
;
2234 // Check parameter Procedure
2236 if (Procedure
== NULL
) {
2237 return EFI_INVALID_PARAMETER
;
2243 CheckAndUpdateApsStatus ();
2246 // Check whether specified AP is disabled
2248 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
2249 return EFI_INVALID_PARAMETER
;
2253 // If WaitEvent is not NULL, execute in non-blocking mode.
2254 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
2255 // CheckAPsStatus() will check completion and timeout periodically.
2257 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2258 CpuData
->WaitEvent
= WaitEvent
;
2259 CpuData
->Finished
= Finished
;
2260 CpuData
->ExpectedTime
= CalculateTimeout (TimeoutInMicroseconds
, &CpuData
->CurrentTime
);
2261 CpuData
->TotalTime
= 0;
2263 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, Procedure
, ProcedureArgument
);
2266 // If WaitEvent is NULL, execute in blocking mode.
2267 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
2269 Status
= EFI_SUCCESS
;
2270 if (WaitEvent
== NULL
) {
2272 Status
= CheckThisAP (ProcessorNumber
);
2273 } while (Status
== EFI_NOT_READY
);
2280 Get pointer to CPU MP Data structure from GUIDed HOB.
2282 @return The pointer to CPU MP Data structure.
2285 GetCpuMpDataFromGuidedHob (
2289 EFI_HOB_GUID_TYPE
*GuidHob
;
2291 CPU_MP_DATA
*CpuMpData
;
2294 GuidHob
= GetFirstGuidHob (&mCpuInitMpLibHobGuid
);
2295 if (GuidHob
!= NULL
) {
2296 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
2297 CpuMpData
= (CPU_MP_DATA
*) (*(UINTN
*) DataInHob
);