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 Get the Application Processors state.
189 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
191 @return The AP status
195 IN CPU_AP_DATA
*CpuData
198 return CpuData
->State
;
202 Set the Application Processors state.
204 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
205 @param[in] State The AP status
209 IN CPU_AP_DATA
*CpuData
,
213 AcquireSpinLock (&CpuData
->ApLock
);
214 CpuData
->State
= State
;
215 ReleaseSpinLock (&CpuData
->ApLock
);
219 Save the volatile registers required to be restored following INIT IPI.
221 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
224 SaveVolatileRegisters (
225 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
228 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
230 VolatileRegisters
->Cr0
= AsmReadCr0 ();
231 VolatileRegisters
->Cr3
= AsmReadCr3 ();
232 VolatileRegisters
->Cr4
= AsmReadCr4 ();
234 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
235 if (VersionInfoEdx
.Bits
.DE
!= 0) {
237 // If processor supports Debugging Extensions feature
238 // by CPUID.[EAX=01H]:EDX.BIT2
240 VolatileRegisters
->Dr0
= AsmReadDr0 ();
241 VolatileRegisters
->Dr1
= AsmReadDr1 ();
242 VolatileRegisters
->Dr2
= AsmReadDr2 ();
243 VolatileRegisters
->Dr3
= AsmReadDr3 ();
244 VolatileRegisters
->Dr6
= AsmReadDr6 ();
245 VolatileRegisters
->Dr7
= AsmReadDr7 ();
250 Restore the volatile registers following INIT IPI.
252 @param[in] VolatileRegisters Pointer to volatile resisters
253 @param[in] IsRestoreDr TRUE: Restore DRx if supported
254 FALSE: Do not restore DRx
257 RestoreVolatileRegisters (
258 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
259 IN BOOLEAN IsRestoreDr
262 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
264 AsmWriteCr0 (VolatileRegisters
->Cr0
);
265 AsmWriteCr3 (VolatileRegisters
->Cr3
);
266 AsmWriteCr4 (VolatileRegisters
->Cr4
);
269 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
270 if (VersionInfoEdx
.Bits
.DE
!= 0) {
272 // If processor supports Debugging Extensions feature
273 // by CPUID.[EAX=01H]:EDX.BIT2
275 AsmWriteDr0 (VolatileRegisters
->Dr0
);
276 AsmWriteDr1 (VolatileRegisters
->Dr1
);
277 AsmWriteDr2 (VolatileRegisters
->Dr2
);
278 AsmWriteDr3 (VolatileRegisters
->Dr3
);
279 AsmWriteDr6 (VolatileRegisters
->Dr6
);
280 AsmWriteDr7 (VolatileRegisters
->Dr7
);
286 Detect whether Mwait-monitor feature is supported.
288 @retval TRUE Mwait-monitor feature is supported.
289 @retval FALSE Mwait-monitor feature is not supported.
296 CPUID_VERSION_INFO_ECX VersionInfoEcx
;
298 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &VersionInfoEcx
.Uint32
, NULL
);
299 return (VersionInfoEcx
.Bits
.MONITOR
== 1) ? TRUE
: FALSE
;
305 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
307 @return The AP loop mode.
311 OUT UINT32
*MonitorFilterSize
315 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx
;
317 ASSERT (MonitorFilterSize
!= NULL
);
319 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
320 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
321 if (ApLoopMode
== ApInMwaitLoop
) {
322 if (!IsMwaitSupport ()) {
324 // If processor does not support MONITOR/MWAIT feature,
325 // force AP in Hlt-loop mode
327 ApLoopMode
= ApInHltLoop
;
331 if (ApLoopMode
!= ApInMwaitLoop
) {
332 *MonitorFilterSize
= sizeof (UINT32
);
335 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
336 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
338 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &MonitorMwaitEbx
.Uint32
, NULL
, NULL
);
339 *MonitorFilterSize
= MonitorMwaitEbx
.Bits
.LargestMonitorLineSize
;
346 Sort the APIC ID of all processors.
348 This function sorts the APIC ID of all processors so that processor number is
349 assigned in the ascending order of APIC ID which eases MP debugging.
351 @param[in] CpuMpData Pointer to PEI CPU MP Data
355 IN CPU_MP_DATA
*CpuMpData
364 CPU_INFO_IN_HOB
*CpuInfoInHob
;
366 ApCount
= CpuMpData
->CpuCount
- 1;
369 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
372 // Sort key is the hardware default APIC ID
374 ApicId
= CpuMpData
->CpuData
[Index1
].ApicId
;
375 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
376 if (ApicId
> CpuMpData
->CpuData
[Index2
].ApicId
) {
378 ApicId
= CpuMpData
->CpuData
[Index2
].ApicId
;
381 if (Index3
!= Index1
) {
382 CopyMem (&CpuData
, &CpuMpData
->CpuData
[Index3
], sizeof (CPU_AP_DATA
));
384 &CpuMpData
->CpuData
[Index3
],
385 &CpuMpData
->CpuData
[Index1
],
388 CopyMem (&CpuMpData
->CpuData
[Index1
], &CpuData
, sizeof (CPU_AP_DATA
));
393 // Get the processor number for the BSP
395 ApicId
= GetInitialApicId ();
396 for (Index1
= 0; Index1
< CpuMpData
->CpuCount
; Index1
++) {
397 if (CpuMpData
->CpuData
[Index1
].ApicId
== ApicId
) {
398 CpuMpData
->BspNumber
= (UINT32
) Index1
;
403 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
404 for (Index1
= 0; Index1
< CpuMpData
->CpuCount
; Index1
++) {
405 CpuInfoInHob
[Index1
].InitialApicId
= CpuMpData
->CpuData
[Index1
].InitialApicId
;
406 CpuInfoInHob
[Index1
].ApicId
= CpuMpData
->CpuData
[Index1
].ApicId
;
407 CpuInfoInHob
[Index1
].Health
= CpuMpData
->CpuData
[Index1
].Health
;
413 Enable x2APIC mode on APs.
415 @param[in, out] Buffer Pointer to private data buffer.
423 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
429 @param[in, out] Buffer Pointer to private data buffer.
437 CPU_MP_DATA
*CpuMpData
;
439 CpuMpData
= (CPU_MP_DATA
*) Buffer
;
441 // Sync BSP's MTRR table to AP
443 MtrrSetAllMtrrs (&CpuMpData
->MtrrTable
);
445 // Load microcode on AP
447 MicrocodeDetect (CpuMpData
);
451 Find the current Processor number by APIC ID.
453 @param[in] CpuMpData Pointer to PEI CPU MP Data
454 @param[in] ProcessorNumber Return the pocessor number found
456 @retval EFI_SUCCESS ProcessorNumber is found and returned.
457 @retval EFI_NOT_FOUND ProcessorNumber is not found.
461 IN CPU_MP_DATA
*CpuMpData
,
462 OUT UINTN
*ProcessorNumber
465 UINTN TotalProcessorNumber
;
468 TotalProcessorNumber
= CpuMpData
->CpuCount
;
469 for (Index
= 0; Index
< TotalProcessorNumber
; Index
++) {
470 if (CpuMpData
->CpuData
[Index
].ApicId
== GetApicId ()) {
471 *ProcessorNumber
= Index
;
475 return EFI_NOT_FOUND
;
479 This function will get CPU count in the system.
481 @param[in] CpuMpData Pointer to PEI CPU MP Data
483 @return CPU count detected
486 CollectProcessorCount (
487 IN CPU_MP_DATA
*CpuMpData
491 // Send 1st broadcast IPI to APs to wakeup APs
493 CpuMpData
->InitFlag
= ApInitConfig
;
494 CpuMpData
->X2ApicEnable
= FALSE
;
495 WakeUpAP (CpuMpData
, TRUE
, 0, NULL
, NULL
);
497 // Wait for AP task to complete and then exit.
499 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds
));
500 CpuMpData
->InitFlag
= ApInitDone
;
501 ASSERT (CpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
503 // Wait for all APs finished the initialization
505 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
509 if (CpuMpData
->X2ApicEnable
) {
510 DEBUG ((DEBUG_INFO
, "Force x2APIC mode!\n"));
512 // Wakeup all APs to enable x2APIC mode
514 WakeUpAP (CpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
);
516 // Wait for all known APs finished
518 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
522 // Enable x2APIC on BSP
524 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
526 DEBUG ((DEBUG_INFO
, "APIC MODE is %d\n", GetApicMode ()));
528 // Sort BSP/Aps by CPU APIC ID in ascending order
530 SortApicId (CpuMpData
);
532 DEBUG ((DEBUG_INFO
, "MpInitLib: Find %d processors in system.\n", CpuMpData
->CpuCount
));
534 return CpuMpData
->CpuCount
;
538 Initialize CPU AP Data when AP is wakeup at the first time.
540 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
541 @param[in] ProcessorNumber The handle number of processor
542 @param[in] BistData Processor BIST data
547 IN OUT CPU_MP_DATA
*CpuMpData
,
548 IN UINTN ProcessorNumber
,
552 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
553 CpuMpData
->CpuData
[ProcessorNumber
].Health
= BistData
;
554 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
= (BistData
== 0) ? TRUE
: FALSE
;
555 CpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetApicId ();
556 CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
557 if (CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
>= 0xFF) {
559 // Set x2APIC mode if there are any logical processor reporting
560 // an Initial APIC ID of 255 or greater.
562 AcquireSpinLock(&CpuMpData
->MpLock
);
563 CpuMpData
->X2ApicEnable
= TRUE
;
564 ReleaseSpinLock(&CpuMpData
->MpLock
);
567 InitializeSpinLock(&CpuMpData
->CpuData
[ProcessorNumber
].ApLock
);
568 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
572 This function will be called from AP reset code if BSP uses WakeUpAP.
574 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
575 @param[in] NumApsExecuting Number of current executing AP
580 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
581 IN UINTN NumApsExecuting
584 CPU_MP_DATA
*CpuMpData
;
585 UINTN ProcessorNumber
;
586 EFI_AP_PROCEDURE Procedure
;
589 volatile UINT32
*ApStartupSignalBuffer
;
592 // AP finished assembly code and begin to execute C code
594 CpuMpData
= ExchangeInfo
->CpuMpData
;
596 ProgramVirtualWireMode ();
599 if (CpuMpData
->InitFlag
== ApInitConfig
) {
603 InterlockedIncrement ((UINT32
*) &CpuMpData
->CpuCount
);
604 ProcessorNumber
= NumApsExecuting
;
606 // This is first time AP wakeup, get BIST information from AP stack
608 BistData
= *(UINT32
*) (CpuMpData
->Buffer
+ ProcessorNumber
* CpuMpData
->CpuApStackSize
- sizeof (UINTN
));
610 // Do some AP initialize sync
612 ApInitializeSync (CpuMpData
);
614 // Sync BSP's Control registers to APs
616 RestoreVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
617 InitializeApData (CpuMpData
, ProcessorNumber
, BistData
);
618 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
621 // Execute AP function if AP is ready
623 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
625 // Clear AP start-up signal when AP waken up
627 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
628 InterlockedCompareExchange32 (
629 (UINT32
*) ApStartupSignalBuffer
,
633 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
635 // Restore AP's volatile registers saved
637 RestoreVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
640 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateReady
) {
641 Procedure
= (EFI_AP_PROCEDURE
)CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
;
642 Parameter
= (VOID
*) CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
;
643 if (Procedure
!= NULL
) {
644 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateBusy
);
646 // Invoke AP function here
648 Procedure (Parameter
);
650 // Re-get the CPU APICID and Initial APICID
652 CpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetApicId ();
653 CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
655 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateFinished
);
660 // AP finished executing C code
662 InterlockedIncrement ((UINT32
*) &CpuMpData
->FinishedCount
);
665 // Place AP is specified loop mode
667 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
669 // Save AP volatile registers
671 SaveVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
673 // Place AP in HLT-loop
676 DisableInterrupts ();
682 DisableInterrupts ();
683 if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
685 // Place AP in MWAIT-loop
687 AsmMonitor ((UINTN
) ApStartupSignalBuffer
, 0, 0);
688 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
690 // Check AP start-up signal again.
691 // If AP start-up signal is not set, place AP into
692 // the specified C-state
694 AsmMwait (CpuMpData
->ApTargetCState
<< 4, 0);
696 } else if (CpuMpData
->ApLoopMode
== ApInRunLoop
) {
698 // Place AP in Run-loop
706 // If AP start-up signal is written, AP is waken up
707 // otherwise place AP in loop again
709 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
717 Wait for AP wakeup and write AP start-up signal till AP is waken up.
719 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
723 IN
volatile UINT32
*ApStartupSignalBuffer
727 // If AP is waken up, StartupApSignal should be cleared.
728 // Otherwise, write StartupApSignal again till AP waken up.
730 while (InterlockedCompareExchange32 (
731 (UINT32
*) ApStartupSignalBuffer
,
740 This function will fill the exchange info structure.
742 @param[in] CpuMpData Pointer to CPU MP Data
746 FillExchangeInfoData (
747 IN CPU_MP_DATA
*CpuMpData
750 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
752 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
753 ExchangeInfo
->Lock
= 0;
754 ExchangeInfo
->StackStart
= CpuMpData
->Buffer
;
755 ExchangeInfo
->StackSize
= CpuMpData
->CpuApStackSize
;
756 ExchangeInfo
->BufferStart
= CpuMpData
->WakeupBuffer
;
757 ExchangeInfo
->ModeOffset
= CpuMpData
->AddressMap
.ModeEntryOffset
;
759 ExchangeInfo
->CodeSegment
= AsmReadCs ();
760 ExchangeInfo
->DataSegment
= AsmReadDs ();
762 ExchangeInfo
->Cr3
= AsmReadCr3 ();
764 ExchangeInfo
->CFunction
= (UINTN
) ApWakeupFunction
;
765 ExchangeInfo
->NumApsExecuting
= 0;
766 ExchangeInfo
->CpuMpData
= CpuMpData
;
768 ExchangeInfo
->EnableExecuteDisable
= IsBspExecuteDisableEnabled ();
771 // Get the BSP's data of GDT and IDT
773 AsmReadGdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->GdtrProfile
);
774 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
778 This function will be called by BSP to wakeup AP.
780 @param[in] CpuMpData Pointer to CPU MP Data
781 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
782 FALSE: Send IPI to AP by ApicId
783 @param[in] ProcessorNumber The handle number of specified processor
784 @param[in] Procedure The function to be invoked by AP
785 @param[in] ProcedureArgument The argument to be passed into AP function
789 IN CPU_MP_DATA
*CpuMpData
,
790 IN BOOLEAN Broadcast
,
791 IN UINTN ProcessorNumber
,
792 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
793 IN VOID
*ProcedureArgument OPTIONAL
796 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
798 CPU_AP_DATA
*CpuData
;
799 BOOLEAN ResetVectorRequired
;
801 CpuMpData
->FinishedCount
= 0;
802 ResetVectorRequired
= FALSE
;
804 if (CpuMpData
->ApLoopMode
== ApInHltLoop
||
805 CpuMpData
->InitFlag
!= ApInitDone
) {
806 ResetVectorRequired
= TRUE
;
807 AllocateResetVector (CpuMpData
);
808 FillExchangeInfoData (CpuMpData
);
809 } else if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
811 // Get AP target C-state each time when waking up AP,
812 // for it maybe updated by platform again
814 CpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
817 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
820 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
821 if (Index
!= CpuMpData
->BspNumber
) {
822 CpuData
= &CpuMpData
->CpuData
[Index
];
823 CpuData
->ApFunction
= (UINTN
) Procedure
;
824 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
825 SetApState (CpuData
, CpuStateReady
);
826 if (CpuMpData
->InitFlag
!= ApInitConfig
) {
827 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
831 if (ResetVectorRequired
) {
835 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
837 if (CpuMpData
->InitFlag
!= ApInitConfig
) {
839 // Wait all APs waken up if this is not the 1st broadcast of SIPI
841 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
842 CpuData
= &CpuMpData
->CpuData
[Index
];
843 if (Index
!= CpuMpData
->BspNumber
) {
844 WaitApWakeup (CpuData
->StartupApSignal
);
849 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
850 CpuData
->ApFunction
= (UINTN
) Procedure
;
851 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
852 SetApState (CpuData
, CpuStateReady
);
854 // Wakeup specified AP
856 ASSERT (CpuMpData
->InitFlag
!= ApInitConfig
);
857 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
858 if (ResetVectorRequired
) {
861 (UINT32
) ExchangeInfo
->BufferStart
865 // Wait specified AP waken up
867 WaitApWakeup (CpuData
->StartupApSignal
);
870 if (ResetVectorRequired
) {
871 FreeResetVector (CpuMpData
);
876 MP Initialize Library initialization.
878 This service will allocate AP reset vector and wakeup all APs to do APs
881 This service must be invoked before all other MP Initialize Library
884 @retval EFI_SUCCESS MP initialization succeeds.
885 @retval Others MP initialization fails.
890 MpInitLibInitialize (
894 CPU_MP_DATA
*OldCpuMpData
;
895 CPU_INFO_IN_HOB
*CpuInfoInHob
;
896 UINT32 MaxLogicalProcessorNumber
;
898 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
900 UINT32 MonitorFilterSize
;
903 CPU_MP_DATA
*CpuMpData
;
905 UINT8
*MonitorBuffer
;
907 UINTN ApResetVectorSize
;
908 UINTN BackupBufferAddr
;
910 OldCpuMpData
= GetCpuMpDataFromGuidedHob ();
911 if (OldCpuMpData
== NULL
) {
912 MaxLogicalProcessorNumber
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
914 MaxLogicalProcessorNumber
= OldCpuMpData
->CpuCount
;
917 AsmGetAddressMap (&AddressMap
);
918 ApResetVectorSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
919 ApStackSize
= PcdGet32(PcdCpuApStackSize
);
920 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
922 BufferSize
= ApStackSize
* MaxLogicalProcessorNumber
;
923 BufferSize
+= MonitorFilterSize
* MaxLogicalProcessorNumber
;
924 BufferSize
+= sizeof (CPU_MP_DATA
);
925 BufferSize
+= ApResetVectorSize
;
926 BufferSize
+= (sizeof (CPU_AP_DATA
) + sizeof (CPU_INFO_IN_HOB
))* MaxLogicalProcessorNumber
;
927 MpBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (BufferSize
));
928 ASSERT (MpBuffer
!= NULL
);
929 ZeroMem (MpBuffer
, BufferSize
);
930 Buffer
= (UINTN
) MpBuffer
;
932 MonitorBuffer
= (UINT8
*) (Buffer
+ ApStackSize
* MaxLogicalProcessorNumber
);
933 BackupBufferAddr
= (UINTN
) MonitorBuffer
+ MonitorFilterSize
* MaxLogicalProcessorNumber
;
934 CpuMpData
= (CPU_MP_DATA
*) (BackupBufferAddr
+ ApResetVectorSize
);
935 CpuMpData
->Buffer
= Buffer
;
936 CpuMpData
->CpuApStackSize
= ApStackSize
;
937 CpuMpData
->BackupBuffer
= BackupBufferAddr
;
938 CpuMpData
->BackupBufferSize
= ApResetVectorSize
;
939 CpuMpData
->EndOfPeiFlag
= FALSE
;
940 CpuMpData
->WakeupBuffer
= (UINTN
) -1;
941 CpuMpData
->CpuCount
= 1;
942 CpuMpData
->BspNumber
= 0;
943 CpuMpData
->WaitEvent
= NULL
;
944 CpuMpData
->CpuData
= (CPU_AP_DATA
*) (CpuMpData
+ 1);
945 CpuMpData
->CpuInfoInHob
= (UINT64
) (UINTN
) (CpuMpData
->CpuData
+ MaxLogicalProcessorNumber
);
946 InitializeSpinLock(&CpuMpData
->MpLock
);
948 // Save BSP's Control registers to APs
950 SaveVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
);
952 // Set BSP basic information
954 InitializeApData (CpuMpData
, 0, 0);
956 // Save assembly code information
958 CopyMem (&CpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
960 // Finally set AP loop mode
962 CpuMpData
->ApLoopMode
= ApLoopMode
;
963 DEBUG ((DEBUG_INFO
, "AP Loop Mode is %d\n", CpuMpData
->ApLoopMode
));
965 // Set up APs wakeup signal buffer
967 for (Index
= 0; Index
< MaxLogicalProcessorNumber
; Index
++) {
968 CpuMpData
->CpuData
[Index
].StartupApSignal
=
969 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
972 // Load Microcode on BSP
974 MicrocodeDetect (CpuMpData
);
976 // Store BSP's MTRR setting
978 MtrrGetAllMtrrs (&CpuMpData
->MtrrTable
);
980 if (OldCpuMpData
== NULL
) {
982 // Wakeup all APs and calculate the processor count in system
984 CollectProcessorCount (CpuMpData
);
987 // APs have been wakeup before, just get the CPU Information
990 CpuMpData
->CpuCount
= OldCpuMpData
->CpuCount
;
991 CpuMpData
->BspNumber
= OldCpuMpData
->BspNumber
;
992 CpuMpData
->InitFlag
= ApInitReconfig
;
993 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) OldCpuMpData
->CpuInfoInHob
;
994 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
995 InitializeSpinLock(&CpuMpData
->CpuData
[Index
].ApLock
);
996 CpuMpData
->CpuData
[Index
].ApicId
= CpuInfoInHob
[Index
].ApicId
;
997 CpuMpData
->CpuData
[Index
].InitialApicId
= CpuInfoInHob
[Index
].InitialApicId
;
998 if (CpuMpData
->CpuData
[Index
].InitialApicId
>= 255) {
999 CpuMpData
->X2ApicEnable
= TRUE
;
1001 CpuMpData
->CpuData
[Index
].Health
= CpuInfoInHob
[Index
].Health
;
1002 CpuMpData
->CpuData
[Index
].CpuHealthy
= (CpuMpData
->CpuData
[Index
].Health
== 0)? TRUE
:FALSE
;
1003 CpuMpData
->CpuData
[Index
].ApFunction
= 0;
1005 &CpuMpData
->CpuData
[Index
].VolatileRegisters
,
1006 &CpuMpData
->CpuData
[0].VolatileRegisters
,
1007 sizeof (CPU_VOLATILE_REGISTERS
)
1011 // Wakeup APs to do some AP initialize sync
1013 WakeUpAP (CpuMpData
, TRUE
, 0, ApInitializeSync
, CpuMpData
);
1015 // Wait for all APs finished initialization
1017 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
1020 CpuMpData
->InitFlag
= ApInitDone
;
1021 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1022 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
1027 // Initialize global data for MP support
1029 InitMpGlobalData (CpuMpData
);
1035 Gets detailed MP-related information on the requested processor at the
1036 instant this call is made. This service may only be called from the BSP.
1038 @param[in] ProcessorNumber The handle number of processor.
1039 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
1040 the requested processor is deposited.
1041 @param[out] HealthData Return processor health data.
1043 @retval EFI_SUCCESS Processor information was returned.
1044 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1045 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
1046 @retval EFI_NOT_FOUND The processor with the handle specified by
1047 ProcessorNumber does not exist in the platform.
1048 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1053 MpInitLibGetProcessorInfo (
1054 IN UINTN ProcessorNumber
,
1055 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
,
1056 OUT EFI_HEALTH_FLAGS
*HealthData OPTIONAL
1059 CPU_MP_DATA
*CpuMpData
;
1062 CpuMpData
= GetCpuMpData ();
1065 // Check whether caller processor is BSP
1067 MpInitLibWhoAmI (&CallerNumber
);
1068 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1069 return EFI_DEVICE_ERROR
;
1072 if (ProcessorInfoBuffer
== NULL
) {
1073 return EFI_INVALID_PARAMETER
;
1076 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1077 return EFI_NOT_FOUND
;
1080 ProcessorInfoBuffer
->ProcessorId
= (UINT64
) CpuMpData
->CpuData
[ProcessorNumber
].ApicId
;
1081 ProcessorInfoBuffer
->StatusFlag
= 0;
1082 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1083 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_AS_BSP_BIT
;
1085 if (CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
) {
1086 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_HEALTH_STATUS_BIT
;
1088 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
1089 ProcessorInfoBuffer
->StatusFlag
&= ~PROCESSOR_ENABLED_BIT
;
1091 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_ENABLED_BIT
;
1095 // Get processor location information
1097 ExtractProcessorLocation (CpuMpData
->CpuData
[ProcessorNumber
].ApicId
, &ProcessorInfoBuffer
->Location
);
1099 if (HealthData
!= NULL
) {
1100 HealthData
->Uint32
= CpuMpData
->CpuData
[ProcessorNumber
].Health
;
1108 This return the handle number for the calling processor. This service may be
1109 called from the BSP and APs.
1111 @param[out] ProcessorNumber Pointer to the handle number of AP.
1112 The range is from 0 to the total number of
1113 logical processors minus 1. The total number of
1114 logical processors can be retrieved by
1115 MpInitLibGetNumberOfProcessors().
1117 @retval EFI_SUCCESS The current processor handle number was returned
1119 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1120 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1126 OUT UINTN
*ProcessorNumber
1129 return EFI_UNSUPPORTED
;
1133 Retrieves the number of logical processor in the platform and the number of
1134 those logical processors that are enabled on this boot. This service may only
1135 be called from the BSP.
1137 @param[out] NumberOfProcessors Pointer to the total number of logical
1138 processors in the system, including the BSP
1140 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
1141 processors that exist in system, including
1144 @retval EFI_SUCCESS The number of logical processors and enabled
1145 logical processors was retrieved.
1146 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1147 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
1149 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1154 MpInitLibGetNumberOfProcessors (
1155 OUT UINTN
*NumberOfProcessors
, OPTIONAL
1156 OUT UINTN
*NumberOfEnabledProcessors OPTIONAL
1159 CPU_MP_DATA
*CpuMpData
;
1161 UINTN ProcessorNumber
;
1162 UINTN EnabledProcessorNumber
;
1165 CpuMpData
= GetCpuMpData ();
1167 if ((NumberOfProcessors
== NULL
) && (NumberOfEnabledProcessors
== NULL
)) {
1168 return EFI_INVALID_PARAMETER
;
1172 // Check whether caller processor is BSP
1174 MpInitLibWhoAmI (&CallerNumber
);
1175 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1176 return EFI_DEVICE_ERROR
;
1179 ProcessorNumber
= CpuMpData
->CpuCount
;
1180 EnabledProcessorNumber
= 0;
1181 for (Index
= 0; Index
< ProcessorNumber
; Index
++) {
1182 if (GetApState (&CpuMpData
->CpuData
[Index
]) != CpuStateDisabled
) {
1183 EnabledProcessorNumber
++;
1187 if (NumberOfProcessors
!= NULL
) {
1188 *NumberOfProcessors
= ProcessorNumber
;
1190 if (NumberOfEnabledProcessors
!= NULL
) {
1191 *NumberOfEnabledProcessors
= EnabledProcessorNumber
;
1199 Get pointer to CPU MP Data structure from GUIDed HOB.
1201 @return The pointer to CPU MP Data structure.
1204 GetCpuMpDataFromGuidedHob (
1208 EFI_HOB_GUID_TYPE
*GuidHob
;
1210 CPU_MP_DATA
*CpuMpData
;
1213 GuidHob
= GetFirstGuidHob (&mCpuInitMpLibHobGuid
);
1214 if (GuidHob
!= NULL
) {
1215 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
1216 CpuMpData
= (CPU_MP_DATA
*) (*(UINTN
*) DataInHob
);