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
);
517 // Wait for AP task to complete and then exit.
519 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds
));
520 CpuMpData
->InitFlag
= ApInitDone
;
521 ASSERT (CpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
523 // Wait for all APs finished the initialization
525 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
529 if (CpuMpData
->X2ApicEnable
) {
530 DEBUG ((DEBUG_INFO
, "Force x2APIC mode!\n"));
532 // Wakeup all APs to enable x2APIC mode
534 WakeUpAP (CpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
);
536 // Wait for all known APs finished
538 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
542 // Enable x2APIC on BSP
544 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
546 DEBUG ((DEBUG_INFO
, "APIC MODE is %d\n", GetApicMode ()));
548 // Sort BSP/Aps by CPU APIC ID in ascending order
550 SortApicId (CpuMpData
);
552 DEBUG ((DEBUG_INFO
, "MpInitLib: Find %d processors in system.\n", CpuMpData
->CpuCount
));
554 return CpuMpData
->CpuCount
;
558 Initialize CPU AP Data when AP is wakeup at the first time.
560 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
561 @param[in] ProcessorNumber The handle number of processor
562 @param[in] BistData Processor BIST data
567 IN OUT CPU_MP_DATA
*CpuMpData
,
568 IN UINTN ProcessorNumber
,
572 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
573 CpuMpData
->CpuData
[ProcessorNumber
].Health
= BistData
;
574 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
= (BistData
== 0) ? TRUE
: FALSE
;
575 CpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetApicId ();
576 CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
577 if (CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
>= 0xFF) {
579 // Set x2APIC mode if there are any logical processor reporting
580 // an Initial APIC ID of 255 or greater.
582 AcquireSpinLock(&CpuMpData
->MpLock
);
583 CpuMpData
->X2ApicEnable
= TRUE
;
584 ReleaseSpinLock(&CpuMpData
->MpLock
);
587 InitializeSpinLock(&CpuMpData
->CpuData
[ProcessorNumber
].ApLock
);
588 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
592 This function will be called from AP reset code if BSP uses WakeUpAP.
594 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
595 @param[in] NumApsExecuting Number of current executing AP
600 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
601 IN UINTN NumApsExecuting
604 CPU_MP_DATA
*CpuMpData
;
605 UINTN ProcessorNumber
;
606 EFI_AP_PROCEDURE Procedure
;
609 volatile UINT32
*ApStartupSignalBuffer
;
612 // AP finished assembly code and begin to execute C code
614 CpuMpData
= ExchangeInfo
->CpuMpData
;
616 ProgramVirtualWireMode ();
619 if (CpuMpData
->InitFlag
== ApInitConfig
) {
623 InterlockedIncrement ((UINT32
*) &CpuMpData
->CpuCount
);
624 ProcessorNumber
= NumApsExecuting
;
626 // This is first time AP wakeup, get BIST information from AP stack
628 BistData
= *(UINT32
*) (CpuMpData
->Buffer
+ ProcessorNumber
* CpuMpData
->CpuApStackSize
- sizeof (UINTN
));
630 // Do some AP initialize sync
632 ApInitializeSync (CpuMpData
);
634 // Sync BSP's Control registers to APs
636 RestoreVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
637 InitializeApData (CpuMpData
, ProcessorNumber
, BistData
);
638 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
641 // Execute AP function if AP is ready
643 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
645 // Clear AP start-up signal when AP waken up
647 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
648 InterlockedCompareExchange32 (
649 (UINT32
*) ApStartupSignalBuffer
,
653 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
655 // Restore AP's volatile registers saved
657 RestoreVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
660 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateReady
) {
661 Procedure
= (EFI_AP_PROCEDURE
)CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
;
662 Parameter
= (VOID
*) CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
;
663 if (Procedure
!= NULL
) {
664 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateBusy
);
666 // Invoke AP function here
668 Procedure (Parameter
);
669 if (CpuMpData
->SwitchBspFlag
) {
671 // Re-get the processor number due to BSP/AP maybe exchange in AP function
673 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
674 CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
= 0;
675 CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
= 0;
678 // Re-get the CPU APICID and Initial APICID
680 CpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetApicId ();
681 CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
684 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateFinished
);
689 // AP finished executing C code
691 InterlockedIncrement ((UINT32
*) &CpuMpData
->FinishedCount
);
694 // Place AP is specified loop mode
696 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
698 // Save AP volatile registers
700 SaveVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
702 // Place AP in HLT-loop
705 DisableInterrupts ();
711 DisableInterrupts ();
712 if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
714 // Place AP in MWAIT-loop
716 AsmMonitor ((UINTN
) ApStartupSignalBuffer
, 0, 0);
717 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
719 // Check AP start-up signal again.
720 // If AP start-up signal is not set, place AP into
721 // the specified C-state
723 AsmMwait (CpuMpData
->ApTargetCState
<< 4, 0);
725 } else if (CpuMpData
->ApLoopMode
== ApInRunLoop
) {
727 // Place AP in Run-loop
735 // If AP start-up signal is written, AP is waken up
736 // otherwise place AP in loop again
738 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
746 Wait for AP wakeup and write AP start-up signal till AP is waken up.
748 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
752 IN
volatile UINT32
*ApStartupSignalBuffer
756 // If AP is waken up, StartupApSignal should be cleared.
757 // Otherwise, write StartupApSignal again till AP waken up.
759 while (InterlockedCompareExchange32 (
760 (UINT32
*) ApStartupSignalBuffer
,
769 This function will fill the exchange info structure.
771 @param[in] CpuMpData Pointer to CPU MP Data
775 FillExchangeInfoData (
776 IN CPU_MP_DATA
*CpuMpData
779 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
781 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
782 ExchangeInfo
->Lock
= 0;
783 ExchangeInfo
->StackStart
= CpuMpData
->Buffer
;
784 ExchangeInfo
->StackSize
= CpuMpData
->CpuApStackSize
;
785 ExchangeInfo
->BufferStart
= CpuMpData
->WakeupBuffer
;
786 ExchangeInfo
->ModeOffset
= CpuMpData
->AddressMap
.ModeEntryOffset
;
788 ExchangeInfo
->CodeSegment
= AsmReadCs ();
789 ExchangeInfo
->DataSegment
= AsmReadDs ();
791 ExchangeInfo
->Cr3
= AsmReadCr3 ();
793 ExchangeInfo
->CFunction
= (UINTN
) ApWakeupFunction
;
794 ExchangeInfo
->NumApsExecuting
= 0;
795 ExchangeInfo
->CpuMpData
= CpuMpData
;
797 ExchangeInfo
->EnableExecuteDisable
= IsBspExecuteDisableEnabled ();
800 // Get the BSP's data of GDT and IDT
802 AsmReadGdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->GdtrProfile
);
803 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
807 This function will be called by BSP to wakeup AP.
809 @param[in] CpuMpData Pointer to CPU MP Data
810 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
811 FALSE: Send IPI to AP by ApicId
812 @param[in] ProcessorNumber The handle number of specified processor
813 @param[in] Procedure The function to be invoked by AP
814 @param[in] ProcedureArgument The argument to be passed into AP function
818 IN CPU_MP_DATA
*CpuMpData
,
819 IN BOOLEAN Broadcast
,
820 IN UINTN ProcessorNumber
,
821 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
822 IN VOID
*ProcedureArgument OPTIONAL
825 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
827 CPU_AP_DATA
*CpuData
;
828 BOOLEAN ResetVectorRequired
;
830 CpuMpData
->FinishedCount
= 0;
831 ResetVectorRequired
= FALSE
;
833 if (CpuMpData
->ApLoopMode
== ApInHltLoop
||
834 CpuMpData
->InitFlag
!= ApInitDone
) {
835 ResetVectorRequired
= TRUE
;
836 AllocateResetVector (CpuMpData
);
837 FillExchangeInfoData (CpuMpData
);
838 } else if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
840 // Get AP target C-state each time when waking up AP,
841 // for it maybe updated by platform again
843 CpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
846 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
849 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
850 if (Index
!= CpuMpData
->BspNumber
) {
851 CpuData
= &CpuMpData
->CpuData
[Index
];
852 CpuData
->ApFunction
= (UINTN
) Procedure
;
853 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
854 SetApState (CpuData
, CpuStateReady
);
855 if (CpuMpData
->InitFlag
!= ApInitConfig
) {
856 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
860 if (ResetVectorRequired
) {
864 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
866 if (CpuMpData
->InitFlag
!= ApInitConfig
) {
868 // Wait all APs waken up if this is not the 1st broadcast of SIPI
870 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
871 CpuData
= &CpuMpData
->CpuData
[Index
];
872 if (Index
!= CpuMpData
->BspNumber
) {
873 WaitApWakeup (CpuData
->StartupApSignal
);
878 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
879 CpuData
->ApFunction
= (UINTN
) Procedure
;
880 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
881 SetApState (CpuData
, CpuStateReady
);
883 // Wakeup specified AP
885 ASSERT (CpuMpData
->InitFlag
!= ApInitConfig
);
886 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
887 if (ResetVectorRequired
) {
890 (UINT32
) ExchangeInfo
->BufferStart
894 // Wait specified AP waken up
896 WaitApWakeup (CpuData
->StartupApSignal
);
899 if (ResetVectorRequired
) {
900 FreeResetVector (CpuMpData
);
905 MP Initialize Library initialization.
907 This service will allocate AP reset vector and wakeup all APs to do APs
910 This service must be invoked before all other MP Initialize Library
913 @retval EFI_SUCCESS MP initialization succeeds.
914 @retval Others MP initialization fails.
919 MpInitLibInitialize (
923 CPU_MP_DATA
*OldCpuMpData
;
924 CPU_INFO_IN_HOB
*CpuInfoInHob
;
925 UINT32 MaxLogicalProcessorNumber
;
927 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
929 UINT32 MonitorFilterSize
;
932 CPU_MP_DATA
*CpuMpData
;
934 UINT8
*MonitorBuffer
;
936 UINTN ApResetVectorSize
;
937 UINTN BackupBufferAddr
;
939 OldCpuMpData
= GetCpuMpDataFromGuidedHob ();
940 if (OldCpuMpData
== NULL
) {
941 MaxLogicalProcessorNumber
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
943 MaxLogicalProcessorNumber
= OldCpuMpData
->CpuCount
;
946 AsmGetAddressMap (&AddressMap
);
947 ApResetVectorSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
948 ApStackSize
= PcdGet32(PcdCpuApStackSize
);
949 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
951 BufferSize
= ApStackSize
* MaxLogicalProcessorNumber
;
952 BufferSize
+= MonitorFilterSize
* MaxLogicalProcessorNumber
;
953 BufferSize
+= sizeof (CPU_MP_DATA
);
954 BufferSize
+= ApResetVectorSize
;
955 BufferSize
+= (sizeof (CPU_AP_DATA
) + sizeof (CPU_INFO_IN_HOB
))* MaxLogicalProcessorNumber
;
956 MpBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (BufferSize
));
957 ASSERT (MpBuffer
!= NULL
);
958 ZeroMem (MpBuffer
, BufferSize
);
959 Buffer
= (UINTN
) MpBuffer
;
961 MonitorBuffer
= (UINT8
*) (Buffer
+ ApStackSize
* MaxLogicalProcessorNumber
);
962 BackupBufferAddr
= (UINTN
) MonitorBuffer
+ MonitorFilterSize
* MaxLogicalProcessorNumber
;
963 CpuMpData
= (CPU_MP_DATA
*) (BackupBufferAddr
+ ApResetVectorSize
);
964 CpuMpData
->Buffer
= Buffer
;
965 CpuMpData
->CpuApStackSize
= ApStackSize
;
966 CpuMpData
->BackupBuffer
= BackupBufferAddr
;
967 CpuMpData
->BackupBufferSize
= ApResetVectorSize
;
968 CpuMpData
->EndOfPeiFlag
= FALSE
;
969 CpuMpData
->WakeupBuffer
= (UINTN
) -1;
970 CpuMpData
->CpuCount
= 1;
971 CpuMpData
->BspNumber
= 0;
972 CpuMpData
->WaitEvent
= NULL
;
973 CpuMpData
->SwitchBspFlag
= FALSE
;
974 CpuMpData
->CpuData
= (CPU_AP_DATA
*) (CpuMpData
+ 1);
975 CpuMpData
->CpuInfoInHob
= (UINT64
) (UINTN
) (CpuMpData
->CpuData
+ MaxLogicalProcessorNumber
);
976 InitializeSpinLock(&CpuMpData
->MpLock
);
978 // Save BSP's Control registers to APs
980 SaveVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
);
982 // Set BSP basic information
984 InitializeApData (CpuMpData
, 0, 0);
986 // Save assembly code information
988 CopyMem (&CpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
990 // Finally set AP loop mode
992 CpuMpData
->ApLoopMode
= ApLoopMode
;
993 DEBUG ((DEBUG_INFO
, "AP Loop Mode is %d\n", CpuMpData
->ApLoopMode
));
995 // Set up APs wakeup signal buffer
997 for (Index
= 0; Index
< MaxLogicalProcessorNumber
; Index
++) {
998 CpuMpData
->CpuData
[Index
].StartupApSignal
=
999 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
1002 // Load Microcode on BSP
1004 MicrocodeDetect (CpuMpData
);
1006 // Store BSP's MTRR setting
1008 MtrrGetAllMtrrs (&CpuMpData
->MtrrTable
);
1010 if (OldCpuMpData
== NULL
) {
1012 // Wakeup all APs and calculate the processor count in system
1014 CollectProcessorCount (CpuMpData
);
1017 // APs have been wakeup before, just get the CPU Information
1020 CpuMpData
->CpuCount
= OldCpuMpData
->CpuCount
;
1021 CpuMpData
->BspNumber
= OldCpuMpData
->BspNumber
;
1022 CpuMpData
->InitFlag
= ApInitReconfig
;
1023 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) OldCpuMpData
->CpuInfoInHob
;
1024 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1025 InitializeSpinLock(&CpuMpData
->CpuData
[Index
].ApLock
);
1026 CpuMpData
->CpuData
[Index
].ApicId
= CpuInfoInHob
[Index
].ApicId
;
1027 CpuMpData
->CpuData
[Index
].InitialApicId
= CpuInfoInHob
[Index
].InitialApicId
;
1028 if (CpuMpData
->CpuData
[Index
].InitialApicId
>= 255) {
1029 CpuMpData
->X2ApicEnable
= TRUE
;
1031 CpuMpData
->CpuData
[Index
].Health
= CpuInfoInHob
[Index
].Health
;
1032 CpuMpData
->CpuData
[Index
].CpuHealthy
= (CpuMpData
->CpuData
[Index
].Health
== 0)? TRUE
:FALSE
;
1033 CpuMpData
->CpuData
[Index
].ApFunction
= 0;
1035 &CpuMpData
->CpuData
[Index
].VolatileRegisters
,
1036 &CpuMpData
->CpuData
[0].VolatileRegisters
,
1037 sizeof (CPU_VOLATILE_REGISTERS
)
1041 // Wakeup APs to do some AP initialize sync
1043 WakeUpAP (CpuMpData
, TRUE
, 0, ApInitializeSync
, CpuMpData
);
1045 // Wait for all APs finished initialization
1047 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
1050 CpuMpData
->InitFlag
= ApInitDone
;
1051 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1052 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
1057 // Initialize global data for MP support
1059 InitMpGlobalData (CpuMpData
);
1065 Gets detailed MP-related information on the requested processor at the
1066 instant this call is made. This service may only be called from the BSP.
1068 @param[in] ProcessorNumber The handle number of processor.
1069 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
1070 the requested processor is deposited.
1071 @param[out] HealthData Return processor health data.
1073 @retval EFI_SUCCESS Processor information was returned.
1074 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1075 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
1076 @retval EFI_NOT_FOUND The processor with the handle specified by
1077 ProcessorNumber does not exist in the platform.
1078 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1083 MpInitLibGetProcessorInfo (
1084 IN UINTN ProcessorNumber
,
1085 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
,
1086 OUT EFI_HEALTH_FLAGS
*HealthData OPTIONAL
1089 CPU_MP_DATA
*CpuMpData
;
1092 CpuMpData
= GetCpuMpData ();
1095 // Check whether caller processor is BSP
1097 MpInitLibWhoAmI (&CallerNumber
);
1098 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1099 return EFI_DEVICE_ERROR
;
1102 if (ProcessorInfoBuffer
== NULL
) {
1103 return EFI_INVALID_PARAMETER
;
1106 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1107 return EFI_NOT_FOUND
;
1110 ProcessorInfoBuffer
->ProcessorId
= (UINT64
) CpuMpData
->CpuData
[ProcessorNumber
].ApicId
;
1111 ProcessorInfoBuffer
->StatusFlag
= 0;
1112 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1113 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_AS_BSP_BIT
;
1115 if (CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
) {
1116 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_HEALTH_STATUS_BIT
;
1118 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
1119 ProcessorInfoBuffer
->StatusFlag
&= ~PROCESSOR_ENABLED_BIT
;
1121 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_ENABLED_BIT
;
1125 // Get processor location information
1127 ExtractProcessorLocation (CpuMpData
->CpuData
[ProcessorNumber
].ApicId
, &ProcessorInfoBuffer
->Location
);
1129 if (HealthData
!= NULL
) {
1130 HealthData
->Uint32
= CpuMpData
->CpuData
[ProcessorNumber
].Health
;
1137 Worker function to switch the requested AP to be the BSP from that point onward.
1139 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
1140 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
1141 enabled AP. Otherwise, it will be disabled.
1143 @retval EFI_SUCCESS BSP successfully switched.
1144 @retval others Failed to switch BSP.
1149 IN UINTN ProcessorNumber
,
1150 IN BOOLEAN EnableOldBSP
1153 CPU_MP_DATA
*CpuMpData
;
1156 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
1158 CpuMpData
= GetCpuMpData ();
1161 // Check whether caller processor is BSP
1163 MpInitLibWhoAmI (&CallerNumber
);
1164 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1168 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1169 return EFI_NOT_FOUND
;
1173 // Check whether specified AP is disabled
1175 State
= GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]);
1176 if (State
== CpuStateDisabled
) {
1177 return EFI_INVALID_PARAMETER
;
1181 // Check whether ProcessorNumber specifies the current BSP
1183 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1184 return EFI_INVALID_PARAMETER
;
1188 // Check whether specified AP is busy
1190 if (State
== CpuStateBusy
) {
1191 return EFI_NOT_READY
;
1194 CpuMpData
->BSPInfo
.State
= CPU_SWITCH_STATE_IDLE
;
1195 CpuMpData
->APInfo
.State
= CPU_SWITCH_STATE_IDLE
;
1196 CpuMpData
->SwitchBspFlag
= TRUE
;
1199 // Clear the BSP bit of MSR_IA32_APIC_BASE
1201 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
1202 ApicBaseMsr
.Bits
.BSP
= 0;
1203 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
1206 // Need to wakeUp AP (future BSP).
1208 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, FutureBSPProc
, CpuMpData
);
1210 AsmExchangeRole (&CpuMpData
->BSPInfo
, &CpuMpData
->APInfo
);
1213 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
1215 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
1216 ApicBaseMsr
.Bits
.BSP
= 1;
1217 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
1220 // Wait for old BSP finished AP task
1222 while (GetApState (&CpuMpData
->CpuData
[CallerNumber
]) != CpuStateFinished
) {
1226 CpuMpData
->SwitchBspFlag
= FALSE
;
1228 // Set old BSP enable state
1230 if (!EnableOldBSP
) {
1231 SetApState (&CpuMpData
->CpuData
[CallerNumber
], CpuStateDisabled
);
1234 // Save new BSP number
1236 CpuMpData
->BspNumber
= (UINT32
) ProcessorNumber
;
1242 This return the handle number for the calling processor. This service may be
1243 called from the BSP and APs.
1245 @param[out] ProcessorNumber Pointer to the handle number of AP.
1246 The range is from 0 to the total number of
1247 logical processors minus 1. The total number of
1248 logical processors can be retrieved by
1249 MpInitLibGetNumberOfProcessors().
1251 @retval EFI_SUCCESS The current processor handle number was returned
1253 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1254 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1260 OUT UINTN
*ProcessorNumber
1263 CPU_MP_DATA
*CpuMpData
;
1265 if (ProcessorNumber
== NULL
) {
1266 return EFI_INVALID_PARAMETER
;
1269 CpuMpData
= GetCpuMpData ();
1271 return GetProcessorNumber (CpuMpData
, ProcessorNumber
);
1275 Retrieves the number of logical processor in the platform and the number of
1276 those logical processors that are enabled on this boot. This service may only
1277 be called from the BSP.
1279 @param[out] NumberOfProcessors Pointer to the total number of logical
1280 processors in the system, including the BSP
1282 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
1283 processors that exist in system, including
1286 @retval EFI_SUCCESS The number of logical processors and enabled
1287 logical processors was retrieved.
1288 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1289 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
1291 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1296 MpInitLibGetNumberOfProcessors (
1297 OUT UINTN
*NumberOfProcessors
, OPTIONAL
1298 OUT UINTN
*NumberOfEnabledProcessors OPTIONAL
1301 CPU_MP_DATA
*CpuMpData
;
1303 UINTN ProcessorNumber
;
1304 UINTN EnabledProcessorNumber
;
1307 CpuMpData
= GetCpuMpData ();
1309 if ((NumberOfProcessors
== NULL
) && (NumberOfEnabledProcessors
== NULL
)) {
1310 return EFI_INVALID_PARAMETER
;
1314 // Check whether caller processor is BSP
1316 MpInitLibWhoAmI (&CallerNumber
);
1317 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1318 return EFI_DEVICE_ERROR
;
1321 ProcessorNumber
= CpuMpData
->CpuCount
;
1322 EnabledProcessorNumber
= 0;
1323 for (Index
= 0; Index
< ProcessorNumber
; Index
++) {
1324 if (GetApState (&CpuMpData
->CpuData
[Index
]) != CpuStateDisabled
) {
1325 EnabledProcessorNumber
++;
1329 if (NumberOfProcessors
!= NULL
) {
1330 *NumberOfProcessors
= ProcessorNumber
;
1332 if (NumberOfEnabledProcessors
!= NULL
) {
1333 *NumberOfEnabledProcessors
= EnabledProcessorNumber
;
1341 Get pointer to CPU MP Data structure from GUIDed HOB.
1343 @return The pointer to CPU MP Data structure.
1346 GetCpuMpDataFromGuidedHob (
1350 EFI_HOB_GUID_TYPE
*GuidHob
;
1352 CPU_MP_DATA
*CpuMpData
;
1355 GuidHob
= GetFirstGuidHob (&mCpuInitMpLibHobGuid
);
1356 if (GuidHob
!= NULL
) {
1357 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
1358 CpuMpData
= (CPU_MP_DATA
*) (*(UINTN
*) DataInHob
);