2 CPU MP Initialize Library common functions.
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
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.
21 DxeIpl may have enabled Execute Disable for BSP,
22 APs need to get the status and sync up the settings.
24 @retval TRUE BSP Execute Disable is enabled.
25 @retval FALSE BSP Execute Disable is not enabled.
28 IsBspExecuteDisableEnabled (
33 CPUID_EXTENDED_CPU_SIG_EDX Edx
;
34 MSR_IA32_EFER_REGISTER EferMsr
;
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
);
43 // Bit 20: Execute Disable Bit available.
45 if (Edx
.Bits
.NX
!= 0) {
46 EferMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_EFER
);
49 // Bit 11: Execute Disable Bit enable.
51 if (EferMsr
.Bits
.NXE
!= 0) {
61 Get CPU Package/Core/Thread location information.
63 @param[in] InitialApicId CPU APIC ID
64 @param[out] Location Pointer to CPU location information
67 ExtractProcessorLocation (
68 IN UINT32 InitialApicId
,
69 OUT EFI_CPU_PHYSICAL_LOCATION
*Location
72 BOOLEAN TopologyLeafSupported
;
75 CPUID_VERSION_INFO_EBX VersionInfoEbx
;
76 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
77 CPUID_CACHE_PARAMS_EAX CacheParamsEax
;
78 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax
;
79 CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx
;
80 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx
;
84 UINT32 MaxLogicProcessorsPerPackage
;
85 UINT32 MaxCoresPerPackage
;
88 // Check if the processor is capable of supporting more than one logical processor.
90 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
91 if (VersionInfoEdx
.Bits
.HTT
== 0) {
94 Location
->Package
= 0;
102 // Assume three-level mapping of APIC ID: Package:Core:SMT.
105 TopologyLeafSupported
= FALSE
;
107 // Get the max index of basic CPUID
109 AsmCpuid (CPUID_SIGNATURE
, &MaxCpuIdIndex
, NULL
, NULL
, NULL
);
112 // If the extended topology enumeration leaf is available, it
113 // is the preferred mechanism for enumerating topology.
115 if (MaxCpuIdIndex
>= CPUID_EXTENDED_TOPOLOGY
) {
117 CPUID_EXTENDED_TOPOLOGY
,
119 &ExtendedTopologyEax
.Uint32
,
120 &ExtendedTopologyEbx
.Uint32
,
121 &ExtendedTopologyEcx
.Uint32
,
125 // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
126 // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
127 // supported on that processor.
129 if (ExtendedTopologyEbx
.Uint32
!= 0) {
130 TopologyLeafSupported
= TRUE
;
133 // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
134 // the SMT sub-field of x2APIC ID.
136 LevelType
= ExtendedTopologyEcx
.Bits
.LevelType
;
137 ASSERT (LevelType
== CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
);
138 ThreadBits
= ExtendedTopologyEax
.Bits
.ApicIdShift
;
141 // Software must not assume any "level type" encoding
142 // value to be related to any sub-leaf index, except sub-leaf 0.
147 CPUID_EXTENDED_TOPOLOGY
,
149 &ExtendedTopologyEax
.Uint32
,
151 &ExtendedTopologyEcx
.Uint32
,
154 LevelType
= ExtendedTopologyEcx
.Bits
.LevelType
;
155 if (LevelType
== CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE
) {
156 CoreBits
= ExtendedTopologyEax
.Bits
.ApicIdShift
- ThreadBits
;
160 } while (LevelType
!= CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID
);
164 if (!TopologyLeafSupported
) {
165 AsmCpuid (CPUID_VERSION_INFO
, NULL
, &VersionInfoEbx
.Uint32
, NULL
, NULL
);
166 MaxLogicProcessorsPerPackage
= VersionInfoEbx
.Bits
.MaximumAddressableIdsForLogicalProcessors
;
167 if (MaxCpuIdIndex
>= CPUID_CACHE_PARAMS
) {
168 AsmCpuidEx (CPUID_CACHE_PARAMS
, 0, &CacheParamsEax
.Uint32
, NULL
, NULL
, NULL
);
169 MaxCoresPerPackage
= CacheParamsEax
.Bits
.MaximumAddressableIdsForLogicalProcessors
+ 1;
172 // Must be a single-core processor.
174 MaxCoresPerPackage
= 1;
177 ThreadBits
= (UINTN
) (HighBitSet32 (MaxLogicProcessorsPerPackage
/ MaxCoresPerPackage
- 1) + 1);
178 CoreBits
= (UINTN
) (HighBitSet32 (MaxCoresPerPackage
- 1) + 1);
181 Location
->Thread
= InitialApicId
& ((1 << ThreadBits
) - 1);
182 Location
->Core
= (InitialApicId
>> ThreadBits
) & ((1 << CoreBits
) - 1);
183 Location
->Package
= (InitialApicId
>> (ThreadBits
+ CoreBits
));
187 Worker function for SwitchBSP().
189 Worker function for SwitchBSP(), assigned to the AP which is intended
192 @param[in] Buffer Pointer to CPU MP Data
200 CPU_MP_DATA
*DataInHob
;
202 DataInHob
= (CPU_MP_DATA
*) Buffer
;
203 AsmExchangeRole (&DataInHob
->APInfo
, &DataInHob
->BSPInfo
);
207 Get the Application Processors state.
209 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
211 @return The AP status
215 IN CPU_AP_DATA
*CpuData
218 return CpuData
->State
;
222 Set the Application Processors state.
224 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
225 @param[in] State The AP status
229 IN CPU_AP_DATA
*CpuData
,
233 AcquireSpinLock (&CpuData
->ApLock
);
234 CpuData
->State
= State
;
235 ReleaseSpinLock (&CpuData
->ApLock
);
239 Save the volatile registers required to be restored following INIT IPI.
241 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
244 SaveVolatileRegisters (
245 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
248 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
250 VolatileRegisters
->Cr0
= AsmReadCr0 ();
251 VolatileRegisters
->Cr3
= AsmReadCr3 ();
252 VolatileRegisters
->Cr4
= AsmReadCr4 ();
254 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
255 if (VersionInfoEdx
.Bits
.DE
!= 0) {
257 // If processor supports Debugging Extensions feature
258 // by CPUID.[EAX=01H]:EDX.BIT2
260 VolatileRegisters
->Dr0
= AsmReadDr0 ();
261 VolatileRegisters
->Dr1
= AsmReadDr1 ();
262 VolatileRegisters
->Dr2
= AsmReadDr2 ();
263 VolatileRegisters
->Dr3
= AsmReadDr3 ();
264 VolatileRegisters
->Dr6
= AsmReadDr6 ();
265 VolatileRegisters
->Dr7
= AsmReadDr7 ();
270 Restore the volatile registers following INIT IPI.
272 @param[in] VolatileRegisters Pointer to volatile resisters
273 @param[in] IsRestoreDr TRUE: Restore DRx if supported
274 FALSE: Do not restore DRx
277 RestoreVolatileRegisters (
278 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
279 IN BOOLEAN IsRestoreDr
282 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
284 AsmWriteCr0 (VolatileRegisters
->Cr0
);
285 AsmWriteCr3 (VolatileRegisters
->Cr3
);
286 AsmWriteCr4 (VolatileRegisters
->Cr4
);
289 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
290 if (VersionInfoEdx
.Bits
.DE
!= 0) {
292 // If processor supports Debugging Extensions feature
293 // by CPUID.[EAX=01H]:EDX.BIT2
295 AsmWriteDr0 (VolatileRegisters
->Dr0
);
296 AsmWriteDr1 (VolatileRegisters
->Dr1
);
297 AsmWriteDr2 (VolatileRegisters
->Dr2
);
298 AsmWriteDr3 (VolatileRegisters
->Dr3
);
299 AsmWriteDr6 (VolatileRegisters
->Dr6
);
300 AsmWriteDr7 (VolatileRegisters
->Dr7
);
306 Detect whether Mwait-monitor feature is supported.
308 @retval TRUE Mwait-monitor feature is supported.
309 @retval FALSE Mwait-monitor feature is not supported.
316 CPUID_VERSION_INFO_ECX VersionInfoEcx
;
318 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &VersionInfoEcx
.Uint32
, NULL
);
319 return (VersionInfoEcx
.Bits
.MONITOR
== 1) ? TRUE
: FALSE
;
325 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
327 @return The AP loop mode.
331 OUT UINT32
*MonitorFilterSize
335 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx
;
337 ASSERT (MonitorFilterSize
!= NULL
);
339 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
340 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
341 if (ApLoopMode
== ApInMwaitLoop
) {
342 if (!IsMwaitSupport ()) {
344 // If processor does not support MONITOR/MWAIT feature,
345 // force AP in Hlt-loop mode
347 ApLoopMode
= ApInHltLoop
;
351 if (ApLoopMode
!= ApInMwaitLoop
) {
352 *MonitorFilterSize
= sizeof (UINT32
);
355 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
356 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
358 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &MonitorMwaitEbx
.Uint32
, NULL
, NULL
);
359 *MonitorFilterSize
= MonitorMwaitEbx
.Bits
.LargestMonitorLineSize
;
366 Sort the APIC ID of all processors.
368 This function sorts the APIC ID of all processors so that processor number is
369 assigned in the ascending order of APIC ID which eases MP debugging.
371 @param[in] CpuMpData Pointer to PEI CPU MP Data
375 IN CPU_MP_DATA
*CpuMpData
384 CPU_INFO_IN_HOB
*CpuInfoInHob
;
386 ApCount
= CpuMpData
->CpuCount
- 1;
389 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
392 // Sort key is the hardware default APIC ID
394 ApicId
= CpuMpData
->CpuData
[Index1
].ApicId
;
395 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
396 if (ApicId
> CpuMpData
->CpuData
[Index2
].ApicId
) {
398 ApicId
= CpuMpData
->CpuData
[Index2
].ApicId
;
401 if (Index3
!= Index1
) {
402 CopyMem (&CpuData
, &CpuMpData
->CpuData
[Index3
], sizeof (CPU_AP_DATA
));
404 &CpuMpData
->CpuData
[Index3
],
405 &CpuMpData
->CpuData
[Index1
],
408 CopyMem (&CpuMpData
->CpuData
[Index1
], &CpuData
, sizeof (CPU_AP_DATA
));
413 // Get the processor number for the BSP
415 ApicId
= GetInitialApicId ();
416 for (Index1
= 0; Index1
< CpuMpData
->CpuCount
; Index1
++) {
417 if (CpuMpData
->CpuData
[Index1
].ApicId
== ApicId
) {
418 CpuMpData
->BspNumber
= (UINT32
) Index1
;
423 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
424 for (Index1
= 0; Index1
< CpuMpData
->CpuCount
; Index1
++) {
425 CpuInfoInHob
[Index1
].InitialApicId
= CpuMpData
->CpuData
[Index1
].InitialApicId
;
426 CpuInfoInHob
[Index1
].ApicId
= CpuMpData
->CpuData
[Index1
].ApicId
;
427 CpuInfoInHob
[Index1
].Health
= CpuMpData
->CpuData
[Index1
].Health
;
433 Enable x2APIC mode on APs.
435 @param[in, out] Buffer Pointer to private data buffer.
443 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
449 @param[in, out] Buffer Pointer to private data buffer.
457 CPU_MP_DATA
*CpuMpData
;
459 CpuMpData
= (CPU_MP_DATA
*) Buffer
;
461 // Sync BSP's MTRR table to AP
463 MtrrSetAllMtrrs (&CpuMpData
->MtrrTable
);
465 // Load microcode on AP
467 MicrocodeDetect (CpuMpData
);
471 Find the current Processor number by APIC ID.
473 @param[in] CpuMpData Pointer to PEI CPU MP Data
474 @param[in] ProcessorNumber Return the pocessor number found
476 @retval EFI_SUCCESS ProcessorNumber is found and returned.
477 @retval EFI_NOT_FOUND ProcessorNumber is not found.
481 IN CPU_MP_DATA
*CpuMpData
,
482 OUT UINTN
*ProcessorNumber
485 UINTN TotalProcessorNumber
;
488 TotalProcessorNumber
= CpuMpData
->CpuCount
;
489 for (Index
= 0; Index
< TotalProcessorNumber
; Index
++) {
490 if (CpuMpData
->CpuData
[Index
].ApicId
== GetApicId ()) {
491 *ProcessorNumber
= Index
;
495 return EFI_NOT_FOUND
;
499 This function will get CPU count in the system.
501 @param[in] CpuMpData Pointer to PEI CPU MP Data
503 @return CPU count detected
506 CollectProcessorCount (
507 IN CPU_MP_DATA
*CpuMpData
511 // Send 1st broadcast IPI to APs to wakeup APs
513 CpuMpData
->InitFlag
= ApInitConfig
;
514 CpuMpData
->X2ApicEnable
= FALSE
;
515 WakeUpAP (CpuMpData
, TRUE
, 0, NULL
, NULL
);
516 CpuMpData
->InitFlag
= ApInitDone
;
517 ASSERT (CpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
519 // Wait for all APs finished the initialization
521 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
525 if (CpuMpData
->X2ApicEnable
) {
526 DEBUG ((DEBUG_INFO
, "Force x2APIC mode!\n"));
528 // Wakeup all APs to enable x2APIC mode
530 WakeUpAP (CpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
);
532 // Wait for all known APs finished
534 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
538 // Enable x2APIC on BSP
540 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
542 DEBUG ((DEBUG_INFO
, "APIC MODE is %d\n", GetApicMode ()));
544 // Sort BSP/Aps by CPU APIC ID in ascending order
546 SortApicId (CpuMpData
);
548 DEBUG ((DEBUG_INFO
, "MpInitLib: Find %d processors in system.\n", CpuMpData
->CpuCount
));
550 return CpuMpData
->CpuCount
;
554 Initialize CPU AP Data when AP is wakeup at the first time.
556 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
557 @param[in] ProcessorNumber The handle number of processor
558 @param[in] BistData Processor BIST data
563 IN OUT CPU_MP_DATA
*CpuMpData
,
564 IN UINTN ProcessorNumber
,
568 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
569 CpuMpData
->CpuData
[ProcessorNumber
].Health
= BistData
;
570 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
= (BistData
== 0) ? TRUE
: FALSE
;
571 CpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetApicId ();
572 CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
573 if (CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
>= 0xFF) {
575 // Set x2APIC mode if there are any logical processor reporting
576 // an Initial APIC ID of 255 or greater.
578 AcquireSpinLock(&CpuMpData
->MpLock
);
579 CpuMpData
->X2ApicEnable
= TRUE
;
580 ReleaseSpinLock(&CpuMpData
->MpLock
);
583 InitializeSpinLock(&CpuMpData
->CpuData
[ProcessorNumber
].ApLock
);
584 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
588 This function will be called from AP reset code if BSP uses WakeUpAP.
590 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
591 @param[in] NumApsExecuting Number of current executing AP
596 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
597 IN UINTN NumApsExecuting
600 CPU_MP_DATA
*CpuMpData
;
601 UINTN ProcessorNumber
;
602 EFI_AP_PROCEDURE Procedure
;
605 volatile UINT32
*ApStartupSignalBuffer
;
608 // AP finished assembly code and begin to execute C code
610 CpuMpData
= ExchangeInfo
->CpuMpData
;
612 ProgramVirtualWireMode ();
615 if (CpuMpData
->InitFlag
== ApInitConfig
) {
619 InterlockedIncrement ((UINT32
*) &CpuMpData
->CpuCount
);
620 ProcessorNumber
= NumApsExecuting
;
622 // This is first time AP wakeup, get BIST information from AP stack
624 BistData
= *(UINT32
*) (CpuMpData
->Buffer
+ ProcessorNumber
* CpuMpData
->CpuApStackSize
- sizeof (UINTN
));
626 // Do some AP initialize sync
628 ApInitializeSync (CpuMpData
);
630 // Sync BSP's Control registers to APs
632 RestoreVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
633 InitializeApData (CpuMpData
, ProcessorNumber
, BistData
);
634 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
637 // Execute AP function if AP is ready
639 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
641 // Clear AP start-up signal when AP waken up
643 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
644 InterlockedCompareExchange32 (
645 (UINT32
*) ApStartupSignalBuffer
,
649 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
651 // Restore AP's volatile registers saved
653 RestoreVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
656 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateReady
) {
657 Procedure
= (EFI_AP_PROCEDURE
)CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
;
658 Parameter
= (VOID
*) CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
;
659 if (Procedure
!= NULL
) {
660 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateBusy
);
662 // Invoke AP function here
664 Procedure (Parameter
);
665 if (CpuMpData
->SwitchBspFlag
) {
667 // Re-get the processor number due to BSP/AP maybe exchange in AP function
669 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
670 CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
= 0;
671 CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
= 0;
674 // Re-get the CPU APICID and Initial APICID
676 CpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetApicId ();
677 CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
680 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateFinished
);
685 // AP finished executing C code
687 InterlockedIncrement ((UINT32
*) &CpuMpData
->FinishedCount
);
690 // Place AP is specified loop mode
692 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
694 // Save AP volatile registers
696 SaveVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
698 // Place AP in HLT-loop
701 DisableInterrupts ();
707 DisableInterrupts ();
708 if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
710 // Place AP in MWAIT-loop
712 AsmMonitor ((UINTN
) ApStartupSignalBuffer
, 0, 0);
713 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
715 // Check AP start-up signal again.
716 // If AP start-up signal is not set, place AP into
717 // the specified C-state
719 AsmMwait (CpuMpData
->ApTargetCState
<< 4, 0);
721 } else if (CpuMpData
->ApLoopMode
== ApInRunLoop
) {
723 // Place AP in Run-loop
731 // If AP start-up signal is written, AP is waken up
732 // otherwise place AP in loop again
734 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
742 Wait for AP wakeup and write AP start-up signal till AP is waken up.
744 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
748 IN
volatile UINT32
*ApStartupSignalBuffer
752 // If AP is waken up, StartupApSignal should be cleared.
753 // Otherwise, write StartupApSignal again till AP waken up.
755 while (InterlockedCompareExchange32 (
756 (UINT32
*) ApStartupSignalBuffer
,
765 This function will fill the exchange info structure.
767 @param[in] CpuMpData Pointer to CPU MP Data
771 FillExchangeInfoData (
772 IN CPU_MP_DATA
*CpuMpData
775 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
777 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
778 ExchangeInfo
->Lock
= 0;
779 ExchangeInfo
->StackStart
= CpuMpData
->Buffer
;
780 ExchangeInfo
->StackSize
= CpuMpData
->CpuApStackSize
;
781 ExchangeInfo
->BufferStart
= CpuMpData
->WakeupBuffer
;
782 ExchangeInfo
->ModeOffset
= CpuMpData
->AddressMap
.ModeEntryOffset
;
784 ExchangeInfo
->CodeSegment
= AsmReadCs ();
785 ExchangeInfo
->DataSegment
= AsmReadDs ();
787 ExchangeInfo
->Cr3
= AsmReadCr3 ();
789 ExchangeInfo
->CFunction
= (UINTN
) ApWakeupFunction
;
790 ExchangeInfo
->NumApsExecuting
= 0;
791 ExchangeInfo
->CpuMpData
= CpuMpData
;
793 ExchangeInfo
->EnableExecuteDisable
= IsBspExecuteDisableEnabled ();
796 // Get the BSP's data of GDT and IDT
798 AsmReadGdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->GdtrProfile
);
799 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
803 This function will be called by BSP to wakeup AP.
805 @param[in] CpuMpData Pointer to CPU MP Data
806 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
807 FALSE: Send IPI to AP by ApicId
808 @param[in] ProcessorNumber The handle number of specified processor
809 @param[in] Procedure The function to be invoked by AP
810 @param[in] ProcedureArgument The argument to be passed into AP function
814 IN CPU_MP_DATA
*CpuMpData
,
815 IN BOOLEAN Broadcast
,
816 IN UINTN ProcessorNumber
,
817 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
818 IN VOID
*ProcedureArgument OPTIONAL
821 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
823 CPU_AP_DATA
*CpuData
;
824 BOOLEAN ResetVectorRequired
;
826 CpuMpData
->FinishedCount
= 0;
827 ResetVectorRequired
= FALSE
;
829 if (CpuMpData
->ApLoopMode
== ApInHltLoop
||
830 CpuMpData
->InitFlag
!= ApInitDone
) {
831 ResetVectorRequired
= TRUE
;
832 AllocateResetVector (CpuMpData
);
833 FillExchangeInfoData (CpuMpData
);
834 } else if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
836 // Get AP target C-state each time when waking up AP,
837 // for it maybe updated by platform again
839 CpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
842 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
845 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
846 if (Index
!= CpuMpData
->BspNumber
) {
847 CpuData
= &CpuMpData
->CpuData
[Index
];
848 CpuData
->ApFunction
= (UINTN
) Procedure
;
849 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
850 SetApState (CpuData
, CpuStateReady
);
851 if (CpuMpData
->InitFlag
!= ApInitConfig
) {
852 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
856 if (ResetVectorRequired
) {
860 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
862 if (CpuMpData
->InitFlag
== ApInitConfig
) {
864 // Wait for all potential APs waken up in one specified period
866 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds
));
869 // Wait all APs waken up if this is not the 1st broadcast of SIPI
871 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
872 CpuData
= &CpuMpData
->CpuData
[Index
];
873 if (Index
!= CpuMpData
->BspNumber
) {
874 WaitApWakeup (CpuData
->StartupApSignal
);
879 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
880 CpuData
->ApFunction
= (UINTN
) Procedure
;
881 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
882 SetApState (CpuData
, CpuStateReady
);
884 // Wakeup specified AP
886 ASSERT (CpuMpData
->InitFlag
!= ApInitConfig
);
887 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
888 if (ResetVectorRequired
) {
891 (UINT32
) ExchangeInfo
->BufferStart
895 // Wait specified AP waken up
897 WaitApWakeup (CpuData
->StartupApSignal
);
900 if (ResetVectorRequired
) {
901 FreeResetVector (CpuMpData
);
906 Calculate timeout value and return the current performance counter value.
908 Calculate the number of performance counter ticks required for a timeout.
909 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
912 @param[in] TimeoutInMicroseconds Timeout value in microseconds.
913 @param[out] CurrentTime Returns the current value of the performance counter.
915 @return Expected time stamp counter for timeout.
916 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
922 IN UINTN TimeoutInMicroseconds
,
923 OUT UINT64
*CurrentTime
927 // Read the current value of the performance counter
929 *CurrentTime
= GetPerformanceCounter ();
932 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
935 if (TimeoutInMicroseconds
== 0) {
940 // GetPerformanceCounterProperties () returns the timestamp counter's frequency
941 // in Hz. So multiply the return value with TimeoutInMicroseconds and then divide
942 // it by 1,000,000, to get the number of ticks for the timeout value.
946 GetPerformanceCounterProperties (NULL
, NULL
),
947 TimeoutInMicroseconds
954 Checks whether timeout expires.
956 Check whether the number of elapsed performance counter ticks required for
957 a timeout condition has been reached.
958 If Timeout is zero, which means infinity, return value is always FALSE.
960 @param[in, out] PreviousTime On input, the value of the performance counter
961 when it was last read.
962 On output, the current value of the performance
964 @param[in] TotalTime The total amount of elapsed time in performance
966 @param[in] Timeout The number of performance counter ticks required
967 to reach a timeout condition.
969 @retval TRUE A timeout condition has been reached.
970 @retval FALSE A timeout condition has not been reached.
975 IN OUT UINT64
*PreviousTime
,
976 IN UINT64
*TotalTime
,
989 GetPerformanceCounterProperties (&Start
, &End
);
995 CurrentTime
= GetPerformanceCounter();
996 Delta
= (INT64
) (CurrentTime
- *PreviousTime
);
1003 *TotalTime
+= Delta
;
1004 *PreviousTime
= CurrentTime
;
1005 if (*TotalTime
> Timeout
) {
1012 Reset an AP to Idle state.
1014 Any task being executed by the AP will be aborted and the AP
1015 will be waiting for a new task in Wait-For-SIPI state.
1017 @param[in] ProcessorNumber The handle number of processor.
1020 ResetProcessorToIdleState (
1021 IN UINTN ProcessorNumber
1024 CPU_MP_DATA
*CpuMpData
;
1026 CpuMpData
= GetCpuMpData ();
1028 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, NULL
, NULL
);
1030 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
1034 Searches for the next waiting AP.
1036 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
1038 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
1040 @retval EFI_SUCCESS The next waiting AP has been found.
1041 @retval EFI_NOT_FOUND No waiting AP exists.
1045 GetNextWaitingProcessorNumber (
1046 OUT UINTN
*NextProcessorNumber
1049 UINTN ProcessorNumber
;
1050 CPU_MP_DATA
*CpuMpData
;
1052 CpuMpData
= GetCpuMpData ();
1054 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1055 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1056 *NextProcessorNumber
= ProcessorNumber
;
1061 return EFI_NOT_FOUND
;
1064 /** Checks status of specified AP.
1066 This function checks whether the specified AP has finished the task assigned
1067 by StartupThisAP(), and whether timeout expires.
1069 @param[in] ProcessorNumber The handle number of processor.
1071 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
1072 @retval EFI_TIMEOUT The timeout expires.
1073 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
1077 IN UINTN ProcessorNumber
1080 CPU_MP_DATA
*CpuMpData
;
1081 CPU_AP_DATA
*CpuData
;
1083 CpuMpData
= GetCpuMpData ();
1084 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1087 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
1088 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1089 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
1092 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
1094 if (GetApState(CpuData
) == CpuStateFinished
) {
1095 if (CpuData
->Finished
!= NULL
) {
1096 *(CpuData
->Finished
) = TRUE
;
1098 SetApState (CpuData
, CpuStateIdle
);
1102 // If timeout expires for StartupThisAP(), report timeout.
1104 if (CheckTimeout (&CpuData
->CurrentTime
, &CpuData
->TotalTime
, CpuData
->ExpectedTime
)) {
1105 if (CpuData
->Finished
!= NULL
) {
1106 *(CpuData
->Finished
) = FALSE
;
1109 // Reset failed AP to idle state
1111 ResetProcessorToIdleState (ProcessorNumber
);
1116 return EFI_NOT_READY
;
1120 Checks status of all APs.
1122 This function checks whether all APs have finished task assigned by StartupAllAPs(),
1123 and whether timeout expires.
1125 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
1126 @retval EFI_TIMEOUT The timeout expires.
1127 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
1134 UINTN ProcessorNumber
;
1135 UINTN NextProcessorNumber
;
1138 CPU_MP_DATA
*CpuMpData
;
1139 CPU_AP_DATA
*CpuData
;
1141 CpuMpData
= GetCpuMpData ();
1143 NextProcessorNumber
= 0;
1146 // Go through all APs that are responsible for the StartupAllAPs().
1148 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1149 if (!CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1153 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1155 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
1156 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1157 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
1159 if (GetApState(CpuData
) == CpuStateFinished
) {
1160 CpuMpData
->RunningCount
++;
1161 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
1162 SetApState(CpuData
, CpuStateIdle
);
1165 // If in Single Thread mode, then search for the next waiting AP for execution.
1167 if (CpuMpData
->SingleThread
) {
1168 Status
= GetNextWaitingProcessorNumber (&NextProcessorNumber
);
1170 if (!EFI_ERROR (Status
)) {
1174 (UINT32
) NextProcessorNumber
,
1175 CpuMpData
->Procedure
,
1176 CpuMpData
->ProcArguments
1184 // If all APs finish, return EFI_SUCCESS.
1186 if (CpuMpData
->RunningCount
== CpuMpData
->StartCount
) {
1191 // If timeout expires, report timeout.
1194 &CpuMpData
->CurrentTime
,
1195 &CpuMpData
->TotalTime
,
1196 CpuMpData
->ExpectedTime
)
1199 // If FailedCpuList is not NULL, record all failed APs in it.
1201 if (CpuMpData
->FailedCpuList
!= NULL
) {
1202 *CpuMpData
->FailedCpuList
=
1203 AllocatePool ((CpuMpData
->StartCount
- CpuMpData
->FinishedCount
+ 1) * sizeof (UINTN
));
1204 ASSERT (*CpuMpData
->FailedCpuList
!= NULL
);
1208 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1210 // Check whether this processor is responsible for StartupAllAPs().
1212 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1214 // Reset failed APs to idle state
1216 ResetProcessorToIdleState (ProcessorNumber
);
1217 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
1218 if (CpuMpData
->FailedCpuList
!= NULL
) {
1219 (*CpuMpData
->FailedCpuList
)[ListIndex
++] = ProcessorNumber
;
1223 if (CpuMpData
->FailedCpuList
!= NULL
) {
1224 (*CpuMpData
->FailedCpuList
)[ListIndex
] = END_OF_CPU_LIST
;
1228 return EFI_NOT_READY
;
1232 MP Initialize Library initialization.
1234 This service will allocate AP reset vector and wakeup all APs to do APs
1237 This service must be invoked before all other MP Initialize Library
1238 service are invoked.
1240 @retval EFI_SUCCESS MP initialization succeeds.
1241 @retval Others MP initialization fails.
1246 MpInitLibInitialize (
1250 CPU_MP_DATA
*OldCpuMpData
;
1251 CPU_INFO_IN_HOB
*CpuInfoInHob
;
1252 UINT32 MaxLogicalProcessorNumber
;
1254 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
1256 UINT32 MonitorFilterSize
;
1259 CPU_MP_DATA
*CpuMpData
;
1261 UINT8
*MonitorBuffer
;
1263 UINTN ApResetVectorSize
;
1264 UINTN BackupBufferAddr
;
1266 OldCpuMpData
= GetCpuMpDataFromGuidedHob ();
1267 if (OldCpuMpData
== NULL
) {
1268 MaxLogicalProcessorNumber
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
1270 MaxLogicalProcessorNumber
= OldCpuMpData
->CpuCount
;
1273 AsmGetAddressMap (&AddressMap
);
1274 ApResetVectorSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
1275 ApStackSize
= PcdGet32(PcdCpuApStackSize
);
1276 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
1278 BufferSize
= ApStackSize
* MaxLogicalProcessorNumber
;
1279 BufferSize
+= MonitorFilterSize
* MaxLogicalProcessorNumber
;
1280 BufferSize
+= sizeof (CPU_MP_DATA
);
1281 BufferSize
+= ApResetVectorSize
;
1282 BufferSize
+= (sizeof (CPU_AP_DATA
) + sizeof (CPU_INFO_IN_HOB
))* MaxLogicalProcessorNumber
;
1283 MpBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (BufferSize
));
1284 ASSERT (MpBuffer
!= NULL
);
1285 ZeroMem (MpBuffer
, BufferSize
);
1286 Buffer
= (UINTN
) MpBuffer
;
1288 MonitorBuffer
= (UINT8
*) (Buffer
+ ApStackSize
* MaxLogicalProcessorNumber
);
1289 BackupBufferAddr
= (UINTN
) MonitorBuffer
+ MonitorFilterSize
* MaxLogicalProcessorNumber
;
1290 CpuMpData
= (CPU_MP_DATA
*) (BackupBufferAddr
+ ApResetVectorSize
);
1291 CpuMpData
->Buffer
= Buffer
;
1292 CpuMpData
->CpuApStackSize
= ApStackSize
;
1293 CpuMpData
->BackupBuffer
= BackupBufferAddr
;
1294 CpuMpData
->BackupBufferSize
= ApResetVectorSize
;
1295 CpuMpData
->EndOfPeiFlag
= FALSE
;
1296 CpuMpData
->WakeupBuffer
= (UINTN
) -1;
1297 CpuMpData
->CpuCount
= 1;
1298 CpuMpData
->BspNumber
= 0;
1299 CpuMpData
->WaitEvent
= NULL
;
1300 CpuMpData
->SwitchBspFlag
= FALSE
;
1301 CpuMpData
->CpuData
= (CPU_AP_DATA
*) (CpuMpData
+ 1);
1302 CpuMpData
->CpuInfoInHob
= (UINT64
) (UINTN
) (CpuMpData
->CpuData
+ MaxLogicalProcessorNumber
);
1303 InitializeSpinLock(&CpuMpData
->MpLock
);
1305 // Save BSP's Control registers to APs
1307 SaveVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
);
1309 // Set BSP basic information
1311 InitializeApData (CpuMpData
, 0, 0);
1313 // Save assembly code information
1315 CopyMem (&CpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
1317 // Finally set AP loop mode
1319 CpuMpData
->ApLoopMode
= ApLoopMode
;
1320 DEBUG ((DEBUG_INFO
, "AP Loop Mode is %d\n", CpuMpData
->ApLoopMode
));
1322 // Set up APs wakeup signal buffer
1324 for (Index
= 0; Index
< MaxLogicalProcessorNumber
; Index
++) {
1325 CpuMpData
->CpuData
[Index
].StartupApSignal
=
1326 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
1329 // Load Microcode on BSP
1331 MicrocodeDetect (CpuMpData
);
1333 // Store BSP's MTRR setting
1335 MtrrGetAllMtrrs (&CpuMpData
->MtrrTable
);
1337 if (OldCpuMpData
== NULL
) {
1339 // Wakeup all APs and calculate the processor count in system
1341 CollectProcessorCount (CpuMpData
);
1344 // APs have been wakeup before, just get the CPU Information
1347 CpuMpData
->CpuCount
= OldCpuMpData
->CpuCount
;
1348 CpuMpData
->BspNumber
= OldCpuMpData
->BspNumber
;
1349 CpuMpData
->InitFlag
= ApInitReconfig
;
1350 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) OldCpuMpData
->CpuInfoInHob
;
1351 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1352 InitializeSpinLock(&CpuMpData
->CpuData
[Index
].ApLock
);
1353 CpuMpData
->CpuData
[Index
].ApicId
= CpuInfoInHob
[Index
].ApicId
;
1354 CpuMpData
->CpuData
[Index
].InitialApicId
= CpuInfoInHob
[Index
].InitialApicId
;
1355 if (CpuMpData
->CpuData
[Index
].InitialApicId
>= 255) {
1356 CpuMpData
->X2ApicEnable
= TRUE
;
1358 CpuMpData
->CpuData
[Index
].Health
= CpuInfoInHob
[Index
].Health
;
1359 CpuMpData
->CpuData
[Index
].CpuHealthy
= (CpuMpData
->CpuData
[Index
].Health
== 0)? TRUE
:FALSE
;
1360 CpuMpData
->CpuData
[Index
].ApFunction
= 0;
1362 &CpuMpData
->CpuData
[Index
].VolatileRegisters
,
1363 &CpuMpData
->CpuData
[0].VolatileRegisters
,
1364 sizeof (CPU_VOLATILE_REGISTERS
)
1368 // Wakeup APs to do some AP initialize sync
1370 WakeUpAP (CpuMpData
, TRUE
, 0, ApInitializeSync
, CpuMpData
);
1372 // Wait for all APs finished initialization
1374 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
1377 CpuMpData
->InitFlag
= ApInitDone
;
1378 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1379 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
1384 // Initialize global data for MP support
1386 InitMpGlobalData (CpuMpData
);
1392 Gets detailed MP-related information on the requested processor at the
1393 instant this call is made. This service may only be called from the BSP.
1395 @param[in] ProcessorNumber The handle number of processor.
1396 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
1397 the requested processor is deposited.
1398 @param[out] HealthData Return processor health data.
1400 @retval EFI_SUCCESS Processor information was returned.
1401 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1402 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
1403 @retval EFI_NOT_FOUND The processor with the handle specified by
1404 ProcessorNumber does not exist in the platform.
1405 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1410 MpInitLibGetProcessorInfo (
1411 IN UINTN ProcessorNumber
,
1412 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
,
1413 OUT EFI_HEALTH_FLAGS
*HealthData OPTIONAL
1416 CPU_MP_DATA
*CpuMpData
;
1419 CpuMpData
= GetCpuMpData ();
1422 // Check whether caller processor is BSP
1424 MpInitLibWhoAmI (&CallerNumber
);
1425 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1426 return EFI_DEVICE_ERROR
;
1429 if (ProcessorInfoBuffer
== NULL
) {
1430 return EFI_INVALID_PARAMETER
;
1433 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1434 return EFI_NOT_FOUND
;
1437 ProcessorInfoBuffer
->ProcessorId
= (UINT64
) CpuMpData
->CpuData
[ProcessorNumber
].ApicId
;
1438 ProcessorInfoBuffer
->StatusFlag
= 0;
1439 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1440 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_AS_BSP_BIT
;
1442 if (CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
) {
1443 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_HEALTH_STATUS_BIT
;
1445 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
1446 ProcessorInfoBuffer
->StatusFlag
&= ~PROCESSOR_ENABLED_BIT
;
1448 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_ENABLED_BIT
;
1452 // Get processor location information
1454 ExtractProcessorLocation (CpuMpData
->CpuData
[ProcessorNumber
].ApicId
, &ProcessorInfoBuffer
->Location
);
1456 if (HealthData
!= NULL
) {
1457 HealthData
->Uint32
= CpuMpData
->CpuData
[ProcessorNumber
].Health
;
1464 Worker function to switch the requested AP to be the BSP from that point onward.
1466 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
1467 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
1468 enabled AP. Otherwise, it will be disabled.
1470 @retval EFI_SUCCESS BSP successfully switched.
1471 @retval others Failed to switch BSP.
1476 IN UINTN ProcessorNumber
,
1477 IN BOOLEAN EnableOldBSP
1480 CPU_MP_DATA
*CpuMpData
;
1483 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
1485 CpuMpData
= GetCpuMpData ();
1488 // Check whether caller processor is BSP
1490 MpInitLibWhoAmI (&CallerNumber
);
1491 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1495 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1496 return EFI_NOT_FOUND
;
1500 // Check whether specified AP is disabled
1502 State
= GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]);
1503 if (State
== CpuStateDisabled
) {
1504 return EFI_INVALID_PARAMETER
;
1508 // Check whether ProcessorNumber specifies the current BSP
1510 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1511 return EFI_INVALID_PARAMETER
;
1515 // Check whether specified AP is busy
1517 if (State
== CpuStateBusy
) {
1518 return EFI_NOT_READY
;
1521 CpuMpData
->BSPInfo
.State
= CPU_SWITCH_STATE_IDLE
;
1522 CpuMpData
->APInfo
.State
= CPU_SWITCH_STATE_IDLE
;
1523 CpuMpData
->SwitchBspFlag
= TRUE
;
1526 // Clear the BSP bit of MSR_IA32_APIC_BASE
1528 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
1529 ApicBaseMsr
.Bits
.BSP
= 0;
1530 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
1533 // Need to wakeUp AP (future BSP).
1535 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, FutureBSPProc
, CpuMpData
);
1537 AsmExchangeRole (&CpuMpData
->BSPInfo
, &CpuMpData
->APInfo
);
1540 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
1542 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
1543 ApicBaseMsr
.Bits
.BSP
= 1;
1544 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
1547 // Wait for old BSP finished AP task
1549 while (GetApState (&CpuMpData
->CpuData
[CallerNumber
]) != CpuStateFinished
) {
1553 CpuMpData
->SwitchBspFlag
= FALSE
;
1555 // Set old BSP enable state
1557 if (!EnableOldBSP
) {
1558 SetApState (&CpuMpData
->CpuData
[CallerNumber
], CpuStateDisabled
);
1561 // Save new BSP number
1563 CpuMpData
->BspNumber
= (UINT32
) ProcessorNumber
;
1569 Worker function to let the caller enable or disable an AP from this point onward.
1570 This service may only be called from the BSP.
1572 @param[in] ProcessorNumber The handle number of AP.
1573 @param[in] EnableAP Specifies the new state for the processor for
1574 enabled, FALSE for disabled.
1575 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
1576 the new health status of the AP.
1578 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
1579 @retval others Failed to Enable/Disable AP.
1583 EnableDisableApWorker (
1584 IN UINTN ProcessorNumber
,
1585 IN BOOLEAN EnableAP
,
1586 IN UINT32
*HealthFlag OPTIONAL
1589 CPU_MP_DATA
*CpuMpData
;
1592 CpuMpData
= GetCpuMpData ();
1595 // Check whether caller processor is BSP
1597 MpInitLibWhoAmI (&CallerNumber
);
1598 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1599 return EFI_DEVICE_ERROR
;
1602 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1603 return EFI_INVALID_PARAMETER
;
1606 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1607 return EFI_NOT_FOUND
;
1611 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateDisabled
);
1613 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
1616 if (HealthFlag
!= NULL
) {
1617 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
=
1618 (BOOLEAN
) ((*HealthFlag
& PROCESSOR_HEALTH_STATUS_BIT
) != 0);
1625 This return the handle number for the calling processor. This service may be
1626 called from the BSP and APs.
1628 @param[out] ProcessorNumber Pointer to the handle number of AP.
1629 The range is from 0 to the total number of
1630 logical processors minus 1. The total number of
1631 logical processors can be retrieved by
1632 MpInitLibGetNumberOfProcessors().
1634 @retval EFI_SUCCESS The current processor handle number was returned
1636 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1637 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1643 OUT UINTN
*ProcessorNumber
1646 CPU_MP_DATA
*CpuMpData
;
1648 if (ProcessorNumber
== NULL
) {
1649 return EFI_INVALID_PARAMETER
;
1652 CpuMpData
= GetCpuMpData ();
1654 return GetProcessorNumber (CpuMpData
, ProcessorNumber
);
1658 Retrieves the number of logical processor in the platform and the number of
1659 those logical processors that are enabled on this boot. This service may only
1660 be called from the BSP.
1662 @param[out] NumberOfProcessors Pointer to the total number of logical
1663 processors in the system, including the BSP
1665 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
1666 processors that exist in system, including
1669 @retval EFI_SUCCESS The number of logical processors and enabled
1670 logical processors was retrieved.
1671 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1672 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
1674 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1679 MpInitLibGetNumberOfProcessors (
1680 OUT UINTN
*NumberOfProcessors
, OPTIONAL
1681 OUT UINTN
*NumberOfEnabledProcessors OPTIONAL
1684 CPU_MP_DATA
*CpuMpData
;
1686 UINTN ProcessorNumber
;
1687 UINTN EnabledProcessorNumber
;
1690 CpuMpData
= GetCpuMpData ();
1692 if ((NumberOfProcessors
== NULL
) && (NumberOfEnabledProcessors
== NULL
)) {
1693 return EFI_INVALID_PARAMETER
;
1697 // Check whether caller processor is BSP
1699 MpInitLibWhoAmI (&CallerNumber
);
1700 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1701 return EFI_DEVICE_ERROR
;
1704 ProcessorNumber
= CpuMpData
->CpuCount
;
1705 EnabledProcessorNumber
= 0;
1706 for (Index
= 0; Index
< ProcessorNumber
; Index
++) {
1707 if (GetApState (&CpuMpData
->CpuData
[Index
]) != CpuStateDisabled
) {
1708 EnabledProcessorNumber
++;
1712 if (NumberOfProcessors
!= NULL
) {
1713 *NumberOfProcessors
= ProcessorNumber
;
1715 if (NumberOfEnabledProcessors
!= NULL
) {
1716 *NumberOfEnabledProcessors
= EnabledProcessorNumber
;
1724 Worker function to execute a caller provided function on all enabled APs.
1726 @param[in] Procedure A pointer to the function to be run on
1727 enabled APs of the system.
1728 @param[in] SingleThread If TRUE, then all the enabled APs execute
1729 the function specified by Procedure one by
1730 one, in ascending order of processor handle
1731 number. If FALSE, then all the enabled APs
1732 execute the function specified by Procedure
1734 @param[in] WaitEvent The event created by the caller with CreateEvent()
1736 @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
1737 APs to return from Procedure, either for
1738 blocking or non-blocking mode.
1739 @param[in] ProcedureArgument The parameter passed into Procedure for
1741 @param[out] FailedCpuList If all APs finish successfully, then its
1742 content is set to NULL. If not all APs
1743 finish before timeout expires, then its
1744 content is set to address of the buffer
1745 holding handle numbers of the failed APs.
1747 @retval EFI_SUCCESS In blocking mode, all APs have finished before
1748 the timeout expired.
1749 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
1751 @retval others Failed to Startup all APs.
1755 StartupAllAPsWorker (
1756 IN EFI_AP_PROCEDURE Procedure
,
1757 IN BOOLEAN SingleThread
,
1758 IN EFI_EVENT WaitEvent OPTIONAL
,
1759 IN UINTN TimeoutInMicroseconds
,
1760 IN VOID
*ProcedureArgument OPTIONAL
,
1761 OUT UINTN
**FailedCpuList OPTIONAL
1765 CPU_MP_DATA
*CpuMpData
;
1766 UINTN ProcessorCount
;
1767 UINTN ProcessorNumber
;
1769 CPU_AP_DATA
*CpuData
;
1770 BOOLEAN HasEnabledAp
;
1773 CpuMpData
= GetCpuMpData ();
1775 if (FailedCpuList
!= NULL
) {
1776 *FailedCpuList
= NULL
;
1779 if (CpuMpData
->CpuCount
== 1) {
1780 return EFI_NOT_STARTED
;
1783 if (Procedure
== NULL
) {
1784 return EFI_INVALID_PARAMETER
;
1788 // Check whether caller processor is BSP
1790 MpInitLibWhoAmI (&CallerNumber
);
1791 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1792 return EFI_DEVICE_ERROR
;
1798 CheckAndUpdateApsStatus ();
1800 ProcessorCount
= CpuMpData
->CpuCount
;
1801 HasEnabledAp
= FALSE
;
1803 // Check whether all enabled APs are idle.
1804 // If any enabled AP is not idle, return EFI_NOT_READY.
1806 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
1807 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1808 if (ProcessorNumber
!= CpuMpData
->BspNumber
) {
1809 ApState
= GetApState (CpuData
);
1810 if (ApState
!= CpuStateDisabled
) {
1811 HasEnabledAp
= TRUE
;
1812 if (ApState
!= CpuStateIdle
) {
1814 // If any enabled APs are busy, return EFI_NOT_READY.
1816 return EFI_NOT_READY
;
1822 if (!HasEnabledAp
) {
1824 // If no enabled AP exists, return EFI_NOT_STARTED.
1826 return EFI_NOT_STARTED
;
1829 CpuMpData
->StartCount
= 0;
1830 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
1831 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1832 CpuData
->Waiting
= FALSE
;
1833 if (ProcessorNumber
!= CpuMpData
->BspNumber
) {
1834 if (CpuData
->State
== CpuStateIdle
) {
1836 // Mark this processor as responsible for current calling.
1838 CpuData
->Waiting
= TRUE
;
1839 CpuMpData
->StartCount
++;
1844 CpuMpData
->Procedure
= Procedure
;
1845 CpuMpData
->ProcArguments
= ProcedureArgument
;
1846 CpuMpData
->SingleThread
= SingleThread
;
1847 CpuMpData
->FinishedCount
= 0;
1848 CpuMpData
->RunningCount
= 0;
1849 CpuMpData
->FailedCpuList
= FailedCpuList
;
1850 CpuMpData
->ExpectedTime
= CalculateTimeout (
1851 TimeoutInMicroseconds
,
1852 &CpuMpData
->CurrentTime
1854 CpuMpData
->TotalTime
= 0;
1855 CpuMpData
->WaitEvent
= WaitEvent
;
1857 if (!SingleThread
) {
1858 WakeUpAP (CpuMpData
, TRUE
, 0, Procedure
, ProcedureArgument
);
1860 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
1861 if (ProcessorNumber
== CallerNumber
) {
1864 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1865 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, Procedure
, ProcedureArgument
);
1871 Status
= EFI_SUCCESS
;
1872 if (WaitEvent
== NULL
) {
1874 Status
= CheckAllAPs ();
1875 } while (Status
== EFI_NOT_READY
);
1882 Worker function to let the caller get one enabled AP to execute a caller-provided
1885 @param[in] Procedure A pointer to the function to be run on
1886 enabled APs of the system.
1887 @param[in] ProcessorNumber The handle number of the AP.
1888 @param[in] WaitEvent The event created by the caller with CreateEvent()
1890 @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
1891 APs to return from Procedure, either for
1892 blocking or non-blocking mode.
1893 @param[in] ProcedureArgument The parameter passed into Procedure for
1895 @param[out] Finished If AP returns from Procedure before the
1896 timeout expires, its content is set to TRUE.
1897 Otherwise, the value is set to FALSE.
1899 @retval EFI_SUCCESS In blocking mode, specified AP finished before
1900 the timeout expires.
1901 @retval others Failed to Startup AP.
1905 StartupThisAPWorker (
1906 IN EFI_AP_PROCEDURE Procedure
,
1907 IN UINTN ProcessorNumber
,
1908 IN EFI_EVENT WaitEvent OPTIONAL
,
1909 IN UINTN TimeoutInMicroseconds
,
1910 IN VOID
*ProcedureArgument OPTIONAL
,
1911 OUT BOOLEAN
*Finished OPTIONAL
1915 CPU_MP_DATA
*CpuMpData
;
1916 CPU_AP_DATA
*CpuData
;
1919 CpuMpData
= GetCpuMpData ();
1921 if (Finished
!= NULL
) {
1926 // Check whether caller processor is BSP
1928 MpInitLibWhoAmI (&CallerNumber
);
1929 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1930 return EFI_DEVICE_ERROR
;
1934 // Check whether processor with the handle specified by ProcessorNumber exists
1936 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1937 return EFI_NOT_FOUND
;
1941 // Check whether specified processor is BSP
1943 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1944 return EFI_INVALID_PARAMETER
;
1948 // Check parameter Procedure
1950 if (Procedure
== NULL
) {
1951 return EFI_INVALID_PARAMETER
;
1957 CheckAndUpdateApsStatus ();
1960 // Check whether specified AP is disabled
1962 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
1963 return EFI_INVALID_PARAMETER
;
1967 // If WaitEvent is not NULL, execute in non-blocking mode.
1968 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
1969 // CheckAPsStatus() will check completion and timeout periodically.
1971 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1972 CpuData
->WaitEvent
= WaitEvent
;
1973 CpuData
->Finished
= Finished
;
1974 CpuData
->ExpectedTime
= CalculateTimeout (TimeoutInMicroseconds
, &CpuData
->CurrentTime
);
1975 CpuData
->TotalTime
= 0;
1977 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, Procedure
, ProcedureArgument
);
1980 // If WaitEvent is NULL, execute in blocking mode.
1981 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
1983 Status
= EFI_SUCCESS
;
1984 if (WaitEvent
== NULL
) {
1986 Status
= CheckThisAP (ProcessorNumber
);
1987 } while (Status
== EFI_NOT_READY
);
1994 Get pointer to CPU MP Data structure from GUIDed HOB.
1996 @return The pointer to CPU MP Data structure.
1999 GetCpuMpDataFromGuidedHob (
2003 EFI_HOB_GUID_TYPE
*GuidHob
;
2005 CPU_MP_DATA
*CpuMpData
;
2008 GuidHob
= GetFirstGuidHob (&mCpuInitMpLibHobGuid
);
2009 if (GuidHob
!= NULL
) {
2010 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
2011 CpuMpData
= (CPU_MP_DATA
*) (*(UINTN
*) DataInHob
);