2 CPU MP Initialize Library common functions.
4 Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/VmgExitLib.h>
13 #include <Register/Amd/Fam17Msr.h>
14 #include <Register/Amd/Ghcb.h>
16 EFI_GUID mCpuInitMpLibHobGuid
= CPU_INIT_MP_LIB_HOB_GUID
;
19 The function will check if BSP Execute Disable is enabled.
21 DxeIpl may have enabled Execute Disable for BSP, APs need to
22 get the status and sync up the settings.
23 If BSP's CR0.Paging is not set, BSP execute Disble feature is
26 @retval TRUE BSP Execute Disable is enabled.
27 @retval FALSE BSP Execute Disable is not enabled.
30 IsBspExecuteDisableEnabled (
35 CPUID_EXTENDED_CPU_SIG_EDX Edx
;
36 MSR_IA32_EFER_REGISTER EferMsr
;
41 Cr0
.UintN
= AsmReadCr0 ();
42 if (Cr0
.Bits
.PG
!= 0) {
44 // If CR0 Paging bit is set
46 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &Eax
, NULL
, NULL
, NULL
);
47 if (Eax
>= CPUID_EXTENDED_CPU_SIG
) {
48 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
51 // Bit 20: Execute Disable Bit available.
53 if (Edx
.Bits
.NX
!= 0) {
54 EferMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_EFER
);
57 // Bit 11: Execute Disable Bit enable.
59 if (EferMsr
.Bits
.NXE
!= 0) {
70 Worker function for SwitchBSP().
72 Worker function for SwitchBSP(), assigned to the AP which is intended
75 @param[in] Buffer Pointer to CPU MP Data
83 CPU_MP_DATA
*DataInHob
;
85 DataInHob
= (CPU_MP_DATA
*)Buffer
;
86 AsmExchangeRole (&DataInHob
->APInfo
, &DataInHob
->BSPInfo
);
90 Get the Application Processors state.
92 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
98 IN CPU_AP_DATA
*CpuData
101 return CpuData
->State
;
105 Set the Application Processors state.
107 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
108 @param[in] State The AP status
112 IN CPU_AP_DATA
*CpuData
,
116 AcquireSpinLock (&CpuData
->ApLock
);
117 CpuData
->State
= State
;
118 ReleaseSpinLock (&CpuData
->ApLock
);
122 Save BSP's local APIC timer setting.
124 @param[in] CpuMpData Pointer to CPU MP Data
127 SaveLocalApicTimerSetting (
128 IN CPU_MP_DATA
*CpuMpData
132 // Record the current local APIC timer setting of BSP
135 &CpuMpData
->DivideValue
,
136 &CpuMpData
->PeriodicMode
,
139 CpuMpData
->CurrentTimerCount
= GetApicTimerCurrentCount ();
140 CpuMpData
->TimerInterruptState
= GetApicTimerInterruptState ();
144 Sync local APIC timer setting from BSP to AP.
146 @param[in] CpuMpData Pointer to CPU MP Data
149 SyncLocalApicTimerSetting (
150 IN CPU_MP_DATA
*CpuMpData
154 // Sync local APIC timer setting from BSP to AP
156 InitializeApicTimer (
157 CpuMpData
->DivideValue
,
158 CpuMpData
->CurrentTimerCount
,
159 CpuMpData
->PeriodicMode
,
163 // Disable AP's local APIC timer interrupt
165 DisableApicTimerInterrupt ();
169 Save the volatile registers required to be restored following INIT IPI.
171 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
174 SaveVolatileRegisters (
175 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
178 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
180 VolatileRegisters
->Cr0
= AsmReadCr0 ();
181 VolatileRegisters
->Cr3
= AsmReadCr3 ();
182 VolatileRegisters
->Cr4
= AsmReadCr4 ();
184 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
185 if (VersionInfoEdx
.Bits
.DE
!= 0) {
187 // If processor supports Debugging Extensions feature
188 // by CPUID.[EAX=01H]:EDX.BIT2
190 VolatileRegisters
->Dr0
= AsmReadDr0 ();
191 VolatileRegisters
->Dr1
= AsmReadDr1 ();
192 VolatileRegisters
->Dr2
= AsmReadDr2 ();
193 VolatileRegisters
->Dr3
= AsmReadDr3 ();
194 VolatileRegisters
->Dr6
= AsmReadDr6 ();
195 VolatileRegisters
->Dr7
= AsmReadDr7 ();
198 AsmReadGdtr (&VolatileRegisters
->Gdtr
);
199 AsmReadIdtr (&VolatileRegisters
->Idtr
);
200 VolatileRegisters
->Tr
= AsmReadTr ();
204 Restore the volatile registers following INIT IPI.
206 @param[in] VolatileRegisters Pointer to volatile resisters
207 @param[in] IsRestoreDr TRUE: Restore DRx if supported
208 FALSE: Do not restore DRx
211 RestoreVolatileRegisters (
212 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
213 IN BOOLEAN IsRestoreDr
216 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
217 IA32_TSS_DESCRIPTOR
*Tss
;
219 AsmWriteCr3 (VolatileRegisters
->Cr3
);
220 AsmWriteCr4 (VolatileRegisters
->Cr4
);
221 AsmWriteCr0 (VolatileRegisters
->Cr0
);
224 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
225 if (VersionInfoEdx
.Bits
.DE
!= 0) {
227 // If processor supports Debugging Extensions feature
228 // by CPUID.[EAX=01H]:EDX.BIT2
230 AsmWriteDr0 (VolatileRegisters
->Dr0
);
231 AsmWriteDr1 (VolatileRegisters
->Dr1
);
232 AsmWriteDr2 (VolatileRegisters
->Dr2
);
233 AsmWriteDr3 (VolatileRegisters
->Dr3
);
234 AsmWriteDr6 (VolatileRegisters
->Dr6
);
235 AsmWriteDr7 (VolatileRegisters
->Dr7
);
239 AsmWriteGdtr (&VolatileRegisters
->Gdtr
);
240 AsmWriteIdtr (&VolatileRegisters
->Idtr
);
241 if ((VolatileRegisters
->Tr
!= 0) &&
242 (VolatileRegisters
->Tr
< VolatileRegisters
->Gdtr
.Limit
))
244 Tss
= (IA32_TSS_DESCRIPTOR
*)(VolatileRegisters
->Gdtr
.Base
+
245 VolatileRegisters
->Tr
);
246 if (Tss
->Bits
.P
== 1) {
247 Tss
->Bits
.Type
&= 0xD; // 1101 - Clear busy bit just in case
248 AsmWriteTr (VolatileRegisters
->Tr
);
254 Detect whether Mwait-monitor feature is supported.
256 @retval TRUE Mwait-monitor feature is supported.
257 @retval FALSE Mwait-monitor feature is not supported.
264 CPUID_VERSION_INFO_ECX VersionInfoEcx
;
266 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &VersionInfoEcx
.Uint32
, NULL
);
267 return (VersionInfoEcx
.Bits
.MONITOR
== 1) ? TRUE
: FALSE
;
273 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
275 @return The AP loop mode.
279 OUT UINT32
*MonitorFilterSize
283 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx
;
285 ASSERT (MonitorFilterSize
!= NULL
);
287 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
288 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
289 if (ApLoopMode
== ApInMwaitLoop
) {
290 if (!IsMwaitSupport ()) {
292 // If processor does not support MONITOR/MWAIT feature,
293 // force AP in Hlt-loop mode
295 ApLoopMode
= ApInHltLoop
;
298 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
) &&
299 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp
))
302 // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop
303 // mode in order to use the GHCB protocol for starting APs
305 ApLoopMode
= ApInHltLoop
;
309 if (ApLoopMode
!= ApInMwaitLoop
) {
310 *MonitorFilterSize
= sizeof (UINT32
);
313 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
314 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
316 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &MonitorMwaitEbx
.Uint32
, NULL
, NULL
);
317 *MonitorFilterSize
= MonitorMwaitEbx
.Bits
.LargestMonitorLineSize
;
324 Sort the APIC ID of all processors.
326 This function sorts the APIC ID of all processors so that processor number is
327 assigned in the ascending order of APIC ID which eases MP debugging.
329 @param[in] CpuMpData Pointer to PEI CPU MP Data
333 IN CPU_MP_DATA
*CpuMpData
340 CPU_INFO_IN_HOB CpuInfo
;
342 CPU_INFO_IN_HOB
*CpuInfoInHob
;
343 volatile UINT32
*StartupApSignal
;
345 ApCount
= CpuMpData
->CpuCount
- 1;
346 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
348 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
351 // Sort key is the hardware default APIC ID
353 ApicId
= CpuInfoInHob
[Index1
].ApicId
;
354 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
355 if (ApicId
> CpuInfoInHob
[Index2
].ApicId
) {
357 ApicId
= CpuInfoInHob
[Index2
].ApicId
;
361 if (Index3
!= Index1
) {
362 CopyMem (&CpuInfo
, &CpuInfoInHob
[Index3
], sizeof (CPU_INFO_IN_HOB
));
364 &CpuInfoInHob
[Index3
],
365 &CpuInfoInHob
[Index1
],
366 sizeof (CPU_INFO_IN_HOB
)
368 CopyMem (&CpuInfoInHob
[Index1
], &CpuInfo
, sizeof (CPU_INFO_IN_HOB
));
371 // Also exchange the StartupApSignal.
373 StartupApSignal
= CpuMpData
->CpuData
[Index3
].StartupApSignal
;
374 CpuMpData
->CpuData
[Index3
].StartupApSignal
=
375 CpuMpData
->CpuData
[Index1
].StartupApSignal
;
376 CpuMpData
->CpuData
[Index1
].StartupApSignal
= StartupApSignal
;
381 // Get the processor number for the BSP
383 ApicId
= GetInitialApicId ();
384 for (Index1
= 0; Index1
< CpuMpData
->CpuCount
; Index1
++) {
385 if (CpuInfoInHob
[Index1
].ApicId
== ApicId
) {
386 CpuMpData
->BspNumber
= (UINT32
)Index1
;
394 Enable x2APIC mode on APs.
396 @param[in, out] Buffer Pointer to private data buffer.
404 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
410 @param[in, out] Buffer Pointer to private data buffer.
418 CPU_MP_DATA
*CpuMpData
;
419 UINTN ProcessorNumber
;
422 CpuMpData
= (CPU_MP_DATA
*)Buffer
;
423 Status
= GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
424 ASSERT_EFI_ERROR (Status
);
426 // Load microcode on AP
428 MicrocodeDetect (CpuMpData
, ProcessorNumber
);
430 // Sync BSP's MTRR table to AP
432 MtrrSetAllMtrrs (&CpuMpData
->MtrrTable
);
436 Find the current Processor number by APIC ID.
438 @param[in] CpuMpData Pointer to PEI CPU MP Data
439 @param[out] ProcessorNumber Return the pocessor number found
441 @retval EFI_SUCCESS ProcessorNumber is found and returned.
442 @retval EFI_NOT_FOUND ProcessorNumber is not found.
446 IN CPU_MP_DATA
*CpuMpData
,
447 OUT UINTN
*ProcessorNumber
450 UINTN TotalProcessorNumber
;
452 CPU_INFO_IN_HOB
*CpuInfoInHob
;
453 UINT32 CurrentApicId
;
455 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
457 TotalProcessorNumber
= CpuMpData
->CpuCount
;
458 CurrentApicId
= GetApicId ();
459 for (Index
= 0; Index
< TotalProcessorNumber
; Index
++) {
460 if (CpuInfoInHob
[Index
].ApicId
== CurrentApicId
) {
461 *ProcessorNumber
= Index
;
466 return EFI_NOT_FOUND
;
470 This function will get CPU count in the system.
472 @param[in] CpuMpData Pointer to PEI CPU MP Data
474 @return CPU count detected
477 CollectProcessorCount (
478 IN CPU_MP_DATA
*CpuMpData
482 CPU_INFO_IN_HOB
*CpuInfoInHob
;
486 // Send 1st broadcast IPI to APs to wakeup APs
488 CpuMpData
->InitFlag
= ApInitConfig
;
489 WakeUpAP (CpuMpData
, TRUE
, 0, NULL
, NULL
, TRUE
);
490 CpuMpData
->InitFlag
= ApInitDone
;
492 // When InitFlag == ApInitConfig, WakeUpAP () guarantees all APs are checked in.
493 // FinishedCount is the number of check-in APs.
495 CpuMpData
->CpuCount
= CpuMpData
->FinishedCount
+ 1;
496 ASSERT (CpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
499 // Enable x2APIC mode if
500 // 1. Number of CPU is greater than 255; or
501 // 2. There are any logical processors reporting an Initial APIC ID of 255 or greater.
504 if (CpuMpData
->CpuCount
> 255) {
506 // If there are more than 255 processor found, force to enable X2APIC
510 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
511 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
512 if (CpuInfoInHob
[Index
].InitialApicId
>= 0xFF) {
520 DEBUG ((DEBUG_INFO
, "Force x2APIC mode!\n"));
522 // Wakeup all APs to enable x2APIC mode
524 WakeUpAP (CpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
, TRUE
);
526 // Wait for all known APs finished
528 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
533 // Enable x2APIC on BSP
535 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
537 // Set BSP/Aps state to IDLE
539 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
540 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
544 DEBUG ((DEBUG_INFO
, "APIC MODE is %d\n", GetApicMode ()));
546 // Sort BSP/Aps by CPU APIC ID in ascending order
548 SortApicId (CpuMpData
);
550 DEBUG ((DEBUG_INFO
, "MpInitLib: Find %d processors in system.\n", CpuMpData
->CpuCount
));
552 return CpuMpData
->CpuCount
;
556 Initialize CPU AP Data when AP is wakeup at the first time.
558 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
559 @param[in] ProcessorNumber The handle number of processor
560 @param[in] BistData Processor BIST data
561 @param[in] ApTopOfStack Top of AP stack
566 IN OUT CPU_MP_DATA
*CpuMpData
,
567 IN UINTN ProcessorNumber
,
569 IN UINT64 ApTopOfStack
572 CPU_INFO_IN_HOB
*CpuInfoInHob
;
573 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr
;
575 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
576 CpuInfoInHob
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
577 CpuInfoInHob
[ProcessorNumber
].ApicId
= GetApicId ();
578 CpuInfoInHob
[ProcessorNumber
].Health
= BistData
;
579 CpuInfoInHob
[ProcessorNumber
].ApTopOfStack
= ApTopOfStack
;
581 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
582 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
= (BistData
== 0) ? TRUE
: FALSE
;
585 // NOTE: PlatformId is not relevant on AMD platforms.
587 if (!StandardSignatureIsAuthenticAMD ()) {
588 PlatformIdMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_PLATFORM_ID
);
589 CpuMpData
->CpuData
[ProcessorNumber
].PlatformId
= (UINT8
)PlatformIdMsr
.Bits
.PlatformId
;
594 &CpuMpData
->CpuData
[ProcessorNumber
].ProcessorSignature
,
600 InitializeSpinLock (&CpuMpData
->CpuData
[ProcessorNumber
].ApLock
);
601 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
605 This function will be called from AP reset code if BSP uses WakeUpAP.
607 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
608 @param[in] ApIndex Number of current executing AP
613 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
617 CPU_MP_DATA
*CpuMpData
;
618 UINTN ProcessorNumber
;
619 EFI_AP_PROCEDURE Procedure
;
622 volatile UINT32
*ApStartupSignalBuffer
;
623 CPU_INFO_IN_HOB
*CpuInfoInHob
;
625 UINTN CurrentApicMode
;
628 // AP finished assembly code and begin to execute C code
630 CpuMpData
= ExchangeInfo
->CpuMpData
;
633 // AP's local APIC settings will be lost after received INIT IPI
634 // We need to re-initialize them at here
636 ProgramVirtualWireMode ();
638 // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.
640 DisableLvtInterrupts ();
641 SyncLocalApicTimerSetting (CpuMpData
);
643 CurrentApicMode
= GetApicMode ();
645 if (CpuMpData
->InitFlag
== ApInitConfig
) {
646 ProcessorNumber
= ApIndex
;
648 // This is first time AP wakeup, get BIST information from AP stack
650 ApTopOfStack
= CpuMpData
->Buffer
+ (ProcessorNumber
+ 1) * CpuMpData
->CpuApStackSize
;
651 BistData
= *(UINT32
*)((UINTN
)ApTopOfStack
- sizeof (UINTN
));
653 // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,
654 // to initialize AP in InitConfig path.
655 // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs.
657 RestoreVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
658 InitializeApData (CpuMpData
, ProcessorNumber
, BistData
, ApTopOfStack
);
659 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
662 // Execute AP function if AP is ready
664 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
666 // Clear AP start-up signal when AP waken up
668 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
669 InterlockedCompareExchange32 (
670 (UINT32
*)ApStartupSignalBuffer
,
675 if (CpuMpData
->InitFlag
== ApInitReconfig
) {
677 // ApInitReconfig happens when:
678 // 1. AP is re-enabled after it's disabled, in either PEI or DXE phase.
679 // 2. AP is initialized in DXE phase.
680 // In either case, use the volatile registers value derived from BSP.
681 // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a
682 // different IDT shared by all APs.
684 RestoreVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
686 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
688 // Restore AP's volatile registers saved before AP is halted
690 RestoreVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
693 // The CPU driver might not flush TLB for APs on spot after updating
694 // page attributes. AP in mwait loop mode needs to take care of it when
701 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateReady
) {
702 Procedure
= (EFI_AP_PROCEDURE
)CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
;
703 Parameter
= (VOID
*)CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
;
704 if (Procedure
!= NULL
) {
705 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateBusy
);
707 // Enable source debugging on AP function
711 // Invoke AP function here
713 Procedure (Parameter
);
714 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
715 if (CpuMpData
->SwitchBspFlag
) {
717 // Re-get the processor number due to BSP/AP maybe exchange in AP function
719 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
720 CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
= 0;
721 CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
= 0;
722 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
723 CpuInfoInHob
[ProcessorNumber
].ApTopOfStack
= CpuInfoInHob
[CpuMpData
->NewBspNumber
].ApTopOfStack
;
725 if ((CpuInfoInHob
[ProcessorNumber
].ApicId
!= GetApicId ()) ||
726 (CpuInfoInHob
[ProcessorNumber
].InitialApicId
!= GetInitialApicId ()))
728 if (CurrentApicMode
!= GetApicMode ()) {
730 // If APIC mode change happened during AP function execution,
731 // we do not support APIC ID value changed.
737 // Re-get the CPU APICID and Initial APICID if they are changed
739 CpuInfoInHob
[ProcessorNumber
].ApicId
= GetApicId ();
740 CpuInfoInHob
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
746 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateFinished
);
750 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
752 // Save AP volatile registers
754 SaveVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
758 // AP finished executing C code
760 InterlockedIncrement ((UINT32
*)&CpuMpData
->FinishedCount
);
762 if (CpuMpData
->InitFlag
== ApInitConfig
) {
764 // Delay decrementing the APs executing count when SEV-ES is enabled
765 // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly
766 // performs another INIT-SIPI-SIPI sequence.
768 if (!CpuMpData
->UseSevEsAPMethod
) {
769 InterlockedDecrement ((UINT32
*)&CpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
);
774 // Place AP is specified loop mode
776 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
778 // Place AP in HLT-loop
781 DisableInterrupts ();
782 if (CpuMpData
->UseSevEsAPMethod
) {
783 SevEsPlaceApHlt (CpuMpData
);
793 DisableInterrupts ();
794 if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
796 // Place AP in MWAIT-loop
798 AsmMonitor ((UINTN
)ApStartupSignalBuffer
, 0, 0);
799 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
801 // Check AP start-up signal again.
802 // If AP start-up signal is not set, place AP into
803 // the specified C-state
805 AsmMwait (CpuMpData
->ApTargetCState
<< 4, 0);
807 } else if (CpuMpData
->ApLoopMode
== ApInRunLoop
) {
809 // Place AP in Run-loop
817 // If AP start-up signal is written, AP is waken up
818 // otherwise place AP in loop again
820 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
828 Wait for AP wakeup and write AP start-up signal till AP is waken up.
830 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
834 IN
volatile UINT32
*ApStartupSignalBuffer
838 // If AP is waken up, StartupApSignal should be cleared.
839 // Otherwise, write StartupApSignal again till AP waken up.
841 while (InterlockedCompareExchange32 (
842 (UINT32
*)ApStartupSignalBuffer
,
852 Calculate the size of the reset vector.
854 @param[in] AddressMap The pointer to Address Map structure.
855 @param[out] SizeBelow1Mb Return the size of below 1MB memory for AP reset area.
856 @param[out] SizeAbove1Mb Return the size of abvoe 1MB memory for AP reset area.
860 GetApResetVectorSize (
861 IN MP_ASSEMBLY_ADDRESS_MAP
*AddressMap
,
862 OUT UINTN
*SizeBelow1Mb OPTIONAL
,
863 OUT UINTN
*SizeAbove1Mb OPTIONAL
866 if (SizeBelow1Mb
!= NULL
) {
867 *SizeBelow1Mb
= AddressMap
->ModeTransitionOffset
+ sizeof (MP_CPU_EXCHANGE_INFO
);
870 if (SizeAbove1Mb
!= NULL
) {
871 *SizeAbove1Mb
= AddressMap
->RendezvousFunnelSize
- AddressMap
->ModeTransitionOffset
;
876 This function will fill the exchange info structure.
878 @param[in] CpuMpData Pointer to CPU MP Data
882 FillExchangeInfoData (
883 IN CPU_MP_DATA
*CpuMpData
886 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
888 IA32_SEGMENT_DESCRIPTOR
*Selector
;
891 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
892 ExchangeInfo
->StackStart
= CpuMpData
->Buffer
;
893 ExchangeInfo
->StackSize
= CpuMpData
->CpuApStackSize
;
894 ExchangeInfo
->BufferStart
= CpuMpData
->WakeupBuffer
;
895 ExchangeInfo
->ModeOffset
= CpuMpData
->AddressMap
.ModeEntryOffset
;
897 ExchangeInfo
->CodeSegment
= AsmReadCs ();
898 ExchangeInfo
->DataSegment
= AsmReadDs ();
900 ExchangeInfo
->Cr3
= AsmReadCr3 ();
902 ExchangeInfo
->CFunction
= (UINTN
)ApWakeupFunction
;
903 ExchangeInfo
->ApIndex
= 0;
904 ExchangeInfo
->NumApsExecuting
= 0;
905 ExchangeInfo
->InitFlag
= (UINTN
)CpuMpData
->InitFlag
;
906 ExchangeInfo
->CpuInfo
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
907 ExchangeInfo
->CpuMpData
= CpuMpData
;
909 ExchangeInfo
->EnableExecuteDisable
= IsBspExecuteDisableEnabled ();
911 ExchangeInfo
->InitializeFloatingPointUnitsAddress
= (UINTN
)InitializeFloatingPointUnits
;
914 // We can check either CPUID(7).ECX[bit16] or check CR4.LA57[bit12]
915 // to determin whether 5-Level Paging is enabled.
916 // CPUID(7).ECX[bit16] shows CPU's capability, CR4.LA57[bit12] shows
917 // current system setting.
918 // Using latter way is simpler because it also eliminates the needs to
919 // check whether platform wants to enable it.
921 Cr4
.UintN
= AsmReadCr4 ();
922 ExchangeInfo
->Enable5LevelPaging
= (BOOLEAN
)(Cr4
.Bits
.LA57
== 1);
923 DEBUG ((DEBUG_INFO
, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName
, ExchangeInfo
->Enable5LevelPaging
));
925 ExchangeInfo
->SevEsIsEnabled
= CpuMpData
->SevEsIsEnabled
;
926 ExchangeInfo
->SevSnpIsEnabled
= CpuMpData
->SevSnpIsEnabled
;
927 ExchangeInfo
->GhcbBase
= (UINTN
)CpuMpData
->GhcbBase
;
930 // Populate SEV-ES specific exchange data.
932 if (ExchangeInfo
->SevSnpIsEnabled
) {
933 FillExchangeInfoDataSevEs (ExchangeInfo
);
937 // Get the BSP's data of GDT and IDT
939 AsmReadGdtr ((IA32_DESCRIPTOR
*)&ExchangeInfo
->GdtrProfile
);
940 AsmReadIdtr ((IA32_DESCRIPTOR
*)&ExchangeInfo
->IdtrProfile
);
943 // Find a 32-bit code segment
945 Selector
= (IA32_SEGMENT_DESCRIPTOR
*)ExchangeInfo
->GdtrProfile
.Base
;
946 Size
= ExchangeInfo
->GdtrProfile
.Limit
+ 1;
948 if ((Selector
->Bits
.L
== 0) && (Selector
->Bits
.Type
>= 8)) {
949 ExchangeInfo
->ModeTransitionSegment
=
950 (UINT16
)((UINTN
)Selector
- ExchangeInfo
->GdtrProfile
.Base
);
955 Size
-= sizeof (IA32_SEGMENT_DESCRIPTOR
);
959 // Copy all 32-bit code and 64-bit code into memory with type of
960 // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
962 GetApResetVectorSize (&CpuMpData
->AddressMap
, NULL
, &Size
);
964 (VOID
*)CpuMpData
->WakeupBufferHigh
,
965 CpuMpData
->AddressMap
.RendezvousFunnelAddress
+
966 CpuMpData
->AddressMap
.ModeTransitionOffset
,
970 ExchangeInfo
->ModeTransitionMemory
= (UINT32
)CpuMpData
->WakeupBufferHigh
;
972 ExchangeInfo
->ModeHighMemory
= ExchangeInfo
->ModeTransitionMemory
+
973 (UINT32
)ExchangeInfo
->ModeOffset
-
974 (UINT32
)CpuMpData
->AddressMap
.ModeTransitionOffset
;
975 ExchangeInfo
->ModeHighSegment
= (UINT16
)ExchangeInfo
->CodeSegment
;
979 Helper function that waits until the finished AP count reaches the specified
980 limit, or the specified timeout elapses (whichever comes first).
982 @param[in] CpuMpData Pointer to CPU MP Data.
983 @param[in] FinishedApLimit The number of finished APs to wait for.
984 @param[in] TimeLimit The number of microseconds to wait for.
987 TimedWaitForApFinish (
988 IN CPU_MP_DATA
*CpuMpData
,
989 IN UINT32 FinishedApLimit
,
994 Get available system memory below 1MB by specified size.
996 @param[in] CpuMpData The pointer to CPU MP Data structure.
999 BackupAndPrepareWakeupBuffer (
1000 IN CPU_MP_DATA
*CpuMpData
1004 (VOID
*)CpuMpData
->BackupBuffer
,
1005 (VOID
*)CpuMpData
->WakeupBuffer
,
1006 CpuMpData
->BackupBufferSize
1009 (VOID
*)CpuMpData
->WakeupBuffer
,
1010 (VOID
*)CpuMpData
->AddressMap
.RendezvousFunnelAddress
,
1011 CpuMpData
->BackupBufferSize
- sizeof (MP_CPU_EXCHANGE_INFO
)
1016 Restore wakeup buffer data.
1018 @param[in] CpuMpData The pointer to CPU MP Data structure.
1021 RestoreWakeupBuffer (
1022 IN CPU_MP_DATA
*CpuMpData
1026 (VOID
*)CpuMpData
->WakeupBuffer
,
1027 (VOID
*)CpuMpData
->BackupBuffer
,
1028 CpuMpData
->BackupBufferSize
1033 Allocate reset vector buffer.
1035 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
1038 AllocateResetVector (
1039 IN OUT CPU_MP_DATA
*CpuMpData
1042 UINTN ApResetVectorSizeBelow1Mb
;
1043 UINTN ApResetVectorSizeAbove1Mb
;
1044 UINTN ApResetStackSize
;
1046 if (CpuMpData
->WakeupBuffer
== (UINTN
)-1) {
1047 GetApResetVectorSize (&CpuMpData
->AddressMap
, &ApResetVectorSizeBelow1Mb
, &ApResetVectorSizeAbove1Mb
);
1049 CpuMpData
->WakeupBuffer
= GetWakeupBuffer (ApResetVectorSizeBelow1Mb
);
1050 CpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*)(UINTN
)
1051 (CpuMpData
->WakeupBuffer
+ ApResetVectorSizeBelow1Mb
- sizeof (MP_CPU_EXCHANGE_INFO
));
1052 CpuMpData
->WakeupBufferHigh
= AllocateCodeBuffer (ApResetVectorSizeAbove1Mb
);
1054 // The AP reset stack is only used by SEV-ES guests. Do not allocate it
1055 // if SEV-ES is not enabled. An SEV-SNP guest is also considered
1056 // an SEV-ES guest, but uses a different method of AP startup, eliminating
1057 // the need for the allocation.
1059 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
) &&
1060 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp
))
1063 // Stack location is based on ProcessorNumber, so use the total number
1064 // of processors for calculating the total stack area.
1066 ApResetStackSize
= (AP_RESET_STACK_SIZE
*
1067 PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
1070 // Invoke GetWakeupBuffer a second time to allocate the stack area
1071 // below 1MB. The returned buffer will be page aligned and sized and
1072 // below the previously allocated buffer.
1074 CpuMpData
->SevEsAPResetStackStart
= GetWakeupBuffer (ApResetStackSize
);
1077 // Check to be sure that the "allocate below" behavior hasn't changed.
1078 // This will also catch a failed allocation, as "-1" is returned on
1081 if (CpuMpData
->SevEsAPResetStackStart
>= CpuMpData
->WakeupBuffer
) {
1084 "SEV-ES AP reset stack is not below wakeup buffer\n"
1093 BackupAndPrepareWakeupBuffer (CpuMpData
);
1097 Free AP reset vector buffer.
1099 @param[in] CpuMpData The pointer to CPU MP Data structure.
1103 IN CPU_MP_DATA
*CpuMpData
1107 // If SEV-ES is enabled, the reset area is needed for AP parking and
1108 // and AP startup in the OS, so the reset area is reserved. Do not
1109 // perform the restore as this will overwrite memory which has data
1110 // needed by SEV-ES.
1112 if (!CpuMpData
->UseSevEsAPMethod
) {
1113 RestoreWakeupBuffer (CpuMpData
);
1118 This function will be called by BSP to wakeup AP.
1120 @param[in] CpuMpData Pointer to CPU MP Data
1121 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
1122 FALSE: Send IPI to AP by ApicId
1123 @param[in] ProcessorNumber The handle number of specified processor
1124 @param[in] Procedure The function to be invoked by AP
1125 @param[in] ProcedureArgument The argument to be passed into AP function
1126 @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.
1130 IN CPU_MP_DATA
*CpuMpData
,
1131 IN BOOLEAN Broadcast
,
1132 IN UINTN ProcessorNumber
,
1133 IN EFI_AP_PROCEDURE Procedure OPTIONAL
,
1134 IN VOID
*ProcedureArgument OPTIONAL
,
1135 IN BOOLEAN WakeUpDisabledAps
1138 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
1140 CPU_AP_DATA
*CpuData
;
1141 BOOLEAN ResetVectorRequired
;
1142 CPU_INFO_IN_HOB
*CpuInfoInHob
;
1144 CpuMpData
->FinishedCount
= 0;
1145 ResetVectorRequired
= FALSE
;
1147 if (CpuMpData
->WakeUpByInitSipiSipi
||
1148 (CpuMpData
->InitFlag
!= ApInitDone
))
1150 ResetVectorRequired
= TRUE
;
1151 AllocateResetVector (CpuMpData
);
1152 AllocateSevEsAPMemory (CpuMpData
);
1153 FillExchangeInfoData (CpuMpData
);
1154 SaveLocalApicTimerSetting (CpuMpData
);
1157 if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
1159 // Get AP target C-state each time when waking up AP,
1160 // for it maybe updated by platform again
1162 CpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
1165 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
1168 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1169 if (Index
!= CpuMpData
->BspNumber
) {
1170 CpuData
= &CpuMpData
->CpuData
[Index
];
1172 // All AP(include disabled AP) will be woke up by INIT-SIPI-SIPI, but
1173 // the AP procedure will be skipped for disabled AP because AP state
1174 // is not CpuStateReady.
1176 if ((GetApState (CpuData
) == CpuStateDisabled
) && !WakeUpDisabledAps
) {
1180 CpuData
->ApFunction
= (UINTN
)Procedure
;
1181 CpuData
->ApFunctionArgument
= (UINTN
)ProcedureArgument
;
1182 SetApState (CpuData
, CpuStateReady
);
1183 if (CpuMpData
->InitFlag
!= ApInitConfig
) {
1184 *(UINT32
*)CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
1189 if (ResetVectorRequired
) {
1191 // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
1192 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
1193 // from the original INIT-SIPI-SIPI.
1195 if (CpuMpData
->SevEsIsEnabled
) {
1196 SetSevEsJumpTable (ExchangeInfo
->BufferStart
);
1201 // Must use the INIT-SIPI-SIPI method for initial configuration in
1202 // order to obtain the APIC ID.
1204 if (CpuMpData
->SevSnpIsEnabled
&& (CpuMpData
->InitFlag
!= ApInitConfig
)) {
1205 SevSnpCreateAP (CpuMpData
, -1);
1207 SendInitSipiSipiAllExcludingSelf ((UINT32
)ExchangeInfo
->BufferStart
);
1211 if (CpuMpData
->InitFlag
== ApInitConfig
) {
1212 if (PcdGet32 (PcdCpuBootLogicalProcessorNumber
) > 0) {
1214 // The AP enumeration algorithm below is suitable only when the
1215 // platform can tell us the *exact* boot CPU count in advance.
1217 // The wait below finishes only when the detected AP count reaches
1218 // (PcdCpuBootLogicalProcessorNumber - 1), regardless of how long that
1219 // takes. If at least one AP fails to check in (meaning a platform
1220 // hardware bug), the detection hangs forever, by design. If the actual
1221 // boot CPU count in the system is higher than
1222 // PcdCpuBootLogicalProcessorNumber (meaning a platform
1223 // misconfiguration), then some APs may complete initialization after
1224 // the wait finishes, and cause undefined behavior.
1226 TimedWaitForApFinish (
1228 PcdGet32 (PcdCpuBootLogicalProcessorNumber
) - 1,
1229 MAX_UINT32
// approx. 71 minutes
1233 // The AP enumeration algorithm below is suitable for two use cases.
1235 // (1) The check-in time for an individual AP is bounded, and APs run
1236 // through their initialization routines strongly concurrently. In
1237 // particular, the number of concurrently running APs
1238 // ("NumApsExecuting") is never expected to fall to zero
1239 // *temporarily* -- it is expected to fall to zero only when all
1240 // APs have checked-in.
1242 // In this case, the platform is supposed to set
1243 // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long
1244 // enough for one AP to start initialization). The timeout will be
1245 // reached soon, and remaining APs are collected by watching
1246 // NumApsExecuting fall to zero. If NumApsExecuting falls to zero
1247 // mid-process, while some APs have not completed initialization,
1248 // the behavior is undefined.
1250 // (2) The check-in time for an individual AP is unbounded, and/or APs
1251 // may complete their initializations widely spread out. In
1252 // particular, some APs may finish initialization before some APs
1255 // In this case, the platform is supposed to set
1256 // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP
1257 // enumeration will always take that long (except when the boot CPU
1258 // count happens to be maximal, that is,
1259 // PcdCpuMaxLogicalProcessorNumber). All APs are expected to
1260 // check-in before the timeout, and NumApsExecuting is assumed zero
1261 // at timeout. APs that miss the time-out may cause undefined
1264 TimedWaitForApFinish (
1266 PcdGet32 (PcdCpuMaxLogicalProcessorNumber
) - 1,
1267 PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
)
1270 while (CpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
!= 0) {
1276 // Wait all APs waken up if this is not the 1st broadcast of SIPI
1278 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1279 CpuData
= &CpuMpData
->CpuData
[Index
];
1280 if (Index
!= CpuMpData
->BspNumber
) {
1281 WaitApWakeup (CpuData
->StartupApSignal
);
1286 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1287 CpuData
->ApFunction
= (UINTN
)Procedure
;
1288 CpuData
->ApFunctionArgument
= (UINTN
)ProcedureArgument
;
1289 SetApState (CpuData
, CpuStateReady
);
1291 // Wakeup specified AP
1293 ASSERT (CpuMpData
->InitFlag
!= ApInitConfig
);
1294 *(UINT32
*)CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
1295 if (ResetVectorRequired
) {
1296 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
1299 // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
1300 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
1301 // from the original INIT-SIPI-SIPI.
1303 if (CpuMpData
->SevEsIsEnabled
) {
1304 SetSevEsJumpTable (ExchangeInfo
->BufferStart
);
1307 if (CpuMpData
->SevSnpIsEnabled
&& (CpuMpData
->InitFlag
!= ApInitConfig
)) {
1308 SevSnpCreateAP (CpuMpData
, (INTN
)ProcessorNumber
);
1311 CpuInfoInHob
[ProcessorNumber
].ApicId
,
1312 (UINT32
)ExchangeInfo
->BufferStart
1318 // Wait specified AP waken up
1320 WaitApWakeup (CpuData
->StartupApSignal
);
1323 if (ResetVectorRequired
) {
1324 FreeResetVector (CpuMpData
);
1328 // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with
1329 // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by
1330 // S3SmmInitDone Ppi.
1332 CpuMpData
->WakeUpByInitSipiSipi
= (CpuMpData
->ApLoopMode
== ApInHltLoop
);
1336 Calculate timeout value and return the current performance counter value.
1338 Calculate the number of performance counter ticks required for a timeout.
1339 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1342 @param[in] TimeoutInMicroseconds Timeout value in microseconds.
1343 @param[out] CurrentTime Returns the current value of the performance counter.
1345 @return Expected time stamp counter for timeout.
1346 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1352 IN UINTN TimeoutInMicroseconds
,
1353 OUT UINT64
*CurrentTime
1356 UINT64 TimeoutInSeconds
;
1357 UINT64 TimestampCounterFreq
;
1360 // Read the current value of the performance counter
1362 *CurrentTime
= GetPerformanceCounter ();
1365 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1368 if (TimeoutInMicroseconds
== 0) {
1373 // GetPerformanceCounterProperties () returns the timestamp counter's frequency
1376 TimestampCounterFreq
= GetPerformanceCounterProperties (NULL
, NULL
);
1379 // Check the potential overflow before calculate the number of ticks for the timeout value.
1381 if (DivU64x64Remainder (MAX_UINT64
, TimeoutInMicroseconds
, NULL
) < TimestampCounterFreq
) {
1383 // Convert microseconds into seconds if direct multiplication overflows
1385 TimeoutInSeconds
= DivU64x32 (TimeoutInMicroseconds
, 1000000);
1387 // Assertion if the final tick count exceeds MAX_UINT64
1389 ASSERT (DivU64x64Remainder (MAX_UINT64
, TimeoutInSeconds
, NULL
) >= TimestampCounterFreq
);
1390 return MultU64x64 (TimestampCounterFreq
, TimeoutInSeconds
);
1393 // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
1394 // it by 1,000,000, to get the number of ticks for the timeout value.
1398 TimestampCounterFreq
,
1399 TimeoutInMicroseconds
1407 Checks whether timeout expires.
1409 Check whether the number of elapsed performance counter ticks required for
1410 a timeout condition has been reached.
1411 If Timeout is zero, which means infinity, return value is always FALSE.
1413 @param[in, out] PreviousTime On input, the value of the performance counter
1414 when it was last read.
1415 On output, the current value of the performance
1417 @param[in] TotalTime The total amount of elapsed time in performance
1419 @param[in] Timeout The number of performance counter ticks required
1420 to reach a timeout condition.
1422 @retval TRUE A timeout condition has been reached.
1423 @retval FALSE A timeout condition has not been reached.
1428 IN OUT UINT64
*PreviousTime
,
1429 IN UINT64
*TotalTime
,
1443 GetPerformanceCounterProperties (&Start
, &End
);
1444 Cycle
= End
- Start
;
1450 CurrentTime
= GetPerformanceCounter ();
1451 Delta
= (INT64
)(CurrentTime
- *PreviousTime
);
1460 *TotalTime
+= Delta
;
1461 *PreviousTime
= CurrentTime
;
1462 if (*TotalTime
> Timeout
) {
1470 Helper function that waits until the finished AP count reaches the specified
1471 limit, or the specified timeout elapses (whichever comes first).
1473 @param[in] CpuMpData Pointer to CPU MP Data.
1474 @param[in] FinishedApLimit The number of finished APs to wait for.
1475 @param[in] TimeLimit The number of microseconds to wait for.
1478 TimedWaitForApFinish (
1479 IN CPU_MP_DATA
*CpuMpData
,
1480 IN UINT32 FinishedApLimit
,
1485 // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
1486 // "infinity", so check for (TimeLimit == 0) explicitly.
1488 if (TimeLimit
== 0) {
1492 CpuMpData
->TotalTime
= 0;
1493 CpuMpData
->ExpectedTime
= CalculateTimeout (
1495 &CpuMpData
->CurrentTime
1497 while (CpuMpData
->FinishedCount
< FinishedApLimit
&&
1499 &CpuMpData
->CurrentTime
,
1500 &CpuMpData
->TotalTime
,
1501 CpuMpData
->ExpectedTime
1507 if (CpuMpData
->FinishedCount
>= FinishedApLimit
) {
1510 "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
1513 DivU64x64Remainder (
1514 MultU64x32 (CpuMpData
->TotalTime
, 1000000),
1515 GetPerformanceCounterProperties (NULL
, NULL
),
1523 Reset an AP to Idle state.
1525 Any task being executed by the AP will be aborted and the AP
1526 will be waiting for a new task in Wait-For-SIPI state.
1528 @param[in] ProcessorNumber The handle number of processor.
1531 ResetProcessorToIdleState (
1532 IN UINTN ProcessorNumber
1535 CPU_MP_DATA
*CpuMpData
;
1537 CpuMpData
= GetCpuMpData ();
1539 CpuMpData
->InitFlag
= ApInitReconfig
;
1540 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, NULL
, NULL
, TRUE
);
1541 while (CpuMpData
->FinishedCount
< 1) {
1545 CpuMpData
->InitFlag
= ApInitDone
;
1547 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
1551 Searches for the next waiting AP.
1553 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
1555 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
1557 @retval EFI_SUCCESS The next waiting AP has been found.
1558 @retval EFI_NOT_FOUND No waiting AP exists.
1562 GetNextWaitingProcessorNumber (
1563 OUT UINTN
*NextProcessorNumber
1566 UINTN ProcessorNumber
;
1567 CPU_MP_DATA
*CpuMpData
;
1569 CpuMpData
= GetCpuMpData ();
1571 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1572 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1573 *NextProcessorNumber
= ProcessorNumber
;
1578 return EFI_NOT_FOUND
;
1581 /** Checks status of specified AP.
1583 This function checks whether the specified AP has finished the task assigned
1584 by StartupThisAP(), and whether timeout expires.
1586 @param[in] ProcessorNumber The handle number of processor.
1588 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
1589 @retval EFI_TIMEOUT The timeout expires.
1590 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
1594 IN UINTN ProcessorNumber
1597 CPU_MP_DATA
*CpuMpData
;
1598 CPU_AP_DATA
*CpuData
;
1600 CpuMpData
= GetCpuMpData ();
1601 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1604 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
1605 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1606 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
1609 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
1611 if (GetApState (CpuData
) == CpuStateFinished
) {
1612 if (CpuData
->Finished
!= NULL
) {
1613 *(CpuData
->Finished
) = TRUE
;
1616 SetApState (CpuData
, CpuStateIdle
);
1620 // If timeout expires for StartupThisAP(), report timeout.
1622 if (CheckTimeout (&CpuData
->CurrentTime
, &CpuData
->TotalTime
, CpuData
->ExpectedTime
)) {
1623 if (CpuData
->Finished
!= NULL
) {
1624 *(CpuData
->Finished
) = FALSE
;
1628 // Reset failed AP to idle state
1630 ResetProcessorToIdleState (ProcessorNumber
);
1636 return EFI_NOT_READY
;
1640 Checks status of all APs.
1642 This function checks whether all APs have finished task assigned by StartupAllAPs(),
1643 and whether timeout expires.
1645 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
1646 @retval EFI_TIMEOUT The timeout expires.
1647 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
1654 UINTN ProcessorNumber
;
1655 UINTN NextProcessorNumber
;
1658 CPU_MP_DATA
*CpuMpData
;
1659 CPU_AP_DATA
*CpuData
;
1661 CpuMpData
= GetCpuMpData ();
1663 NextProcessorNumber
= 0;
1666 // Go through all APs that are responsible for the StartupAllAPs().
1668 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1669 if (!CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1673 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1675 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
1676 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1677 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
1679 if (GetApState (CpuData
) == CpuStateFinished
) {
1680 CpuMpData
->RunningCount
--;
1681 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
1682 SetApState (CpuData
, CpuStateIdle
);
1685 // If in Single Thread mode, then search for the next waiting AP for execution.
1687 if (CpuMpData
->SingleThread
) {
1688 Status
= GetNextWaitingProcessorNumber (&NextProcessorNumber
);
1690 if (!EFI_ERROR (Status
)) {
1694 (UINT32
)NextProcessorNumber
,
1695 CpuMpData
->Procedure
,
1696 CpuMpData
->ProcArguments
,
1705 // If all APs finish, return EFI_SUCCESS.
1707 if (CpuMpData
->RunningCount
== 0) {
1712 // If timeout expires, report timeout.
1715 &CpuMpData
->CurrentTime
,
1716 &CpuMpData
->TotalTime
,
1717 CpuMpData
->ExpectedTime
1722 // If FailedCpuList is not NULL, record all failed APs in it.
1724 if (CpuMpData
->FailedCpuList
!= NULL
) {
1725 *CpuMpData
->FailedCpuList
=
1726 AllocatePool ((CpuMpData
->RunningCount
+ 1) * sizeof (UINTN
));
1727 ASSERT (*CpuMpData
->FailedCpuList
!= NULL
);
1732 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1734 // Check whether this processor is responsible for StartupAllAPs().
1736 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1738 // Reset failed APs to idle state
1740 ResetProcessorToIdleState (ProcessorNumber
);
1741 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
1742 if (CpuMpData
->FailedCpuList
!= NULL
) {
1743 (*CpuMpData
->FailedCpuList
)[ListIndex
++] = ProcessorNumber
;
1748 if (CpuMpData
->FailedCpuList
!= NULL
) {
1749 (*CpuMpData
->FailedCpuList
)[ListIndex
] = END_OF_CPU_LIST
;
1755 return EFI_NOT_READY
;
1759 MP Initialize Library initialization.
1761 This service will allocate AP reset vector and wakeup all APs to do APs
1764 This service must be invoked before all other MP Initialize Library
1765 service are invoked.
1767 @retval EFI_SUCCESS MP initialization succeeds.
1768 @retval Others MP initialization fails.
1773 MpInitLibInitialize (
1777 CPU_MP_DATA
*OldCpuMpData
;
1778 CPU_INFO_IN_HOB
*CpuInfoInHob
;
1779 UINT32 MaxLogicalProcessorNumber
;
1781 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
1782 CPU_VOLATILE_REGISTERS VolatileRegisters
;
1784 UINT32 MonitorFilterSize
;
1787 CPU_MP_DATA
*CpuMpData
;
1789 UINT8
*MonitorBuffer
;
1791 UINTN ApResetVectorSizeBelow1Mb
;
1792 UINTN BackupBufferAddr
;
1795 OldCpuMpData
= GetCpuMpDataFromGuidedHob ();
1796 if (OldCpuMpData
== NULL
) {
1797 MaxLogicalProcessorNumber
= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
);
1799 MaxLogicalProcessorNumber
= OldCpuMpData
->CpuCount
;
1802 ASSERT (MaxLogicalProcessorNumber
!= 0);
1804 AsmGetAddressMap (&AddressMap
);
1805 GetApResetVectorSize (&AddressMap
, &ApResetVectorSizeBelow1Mb
, NULL
);
1806 ApStackSize
= PcdGet32 (PcdCpuApStackSize
);
1807 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
1810 // Save BSP's Control registers for APs.
1812 SaveVolatileRegisters (&VolatileRegisters
);
1814 BufferSize
= ApStackSize
* MaxLogicalProcessorNumber
;
1815 BufferSize
+= MonitorFilterSize
* MaxLogicalProcessorNumber
;
1816 BufferSize
+= ApResetVectorSizeBelow1Mb
;
1817 BufferSize
= ALIGN_VALUE (BufferSize
, 8);
1818 BufferSize
+= VolatileRegisters
.Idtr
.Limit
+ 1;
1819 BufferSize
+= sizeof (CPU_MP_DATA
);
1820 BufferSize
+= (sizeof (CPU_AP_DATA
) + sizeof (CPU_INFO_IN_HOB
))* MaxLogicalProcessorNumber
;
1821 MpBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (BufferSize
));
1822 ASSERT (MpBuffer
!= NULL
);
1823 ZeroMem (MpBuffer
, BufferSize
);
1824 Buffer
= (UINTN
)MpBuffer
;
1827 // The layout of the Buffer is as below:
1829 // +--------------------+ <-- Buffer
1831 // +--------------------+ <-- MonitorBuffer
1832 // AP Monitor Filters (N)
1833 // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)
1835 // +--------------------+
1837 // +--------------------+ <-- ApIdtBase (8-byte boundary)
1838 // AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.
1839 // +--------------------+ <-- CpuMpData
1841 // +--------------------+ <-- CpuMpData->CpuData
1843 // +--------------------+ <-- CpuMpData->CpuInfoInHob
1844 // CPU_INFO_IN_HOB (N)
1845 // +--------------------+
1847 MonitorBuffer
= (UINT8
*)(Buffer
+ ApStackSize
* MaxLogicalProcessorNumber
);
1848 BackupBufferAddr
= (UINTN
)MonitorBuffer
+ MonitorFilterSize
* MaxLogicalProcessorNumber
;
1849 ApIdtBase
= ALIGN_VALUE (BackupBufferAddr
+ ApResetVectorSizeBelow1Mb
, 8);
1850 CpuMpData
= (CPU_MP_DATA
*)(ApIdtBase
+ VolatileRegisters
.Idtr
.Limit
+ 1);
1851 CpuMpData
->Buffer
= Buffer
;
1852 CpuMpData
->CpuApStackSize
= ApStackSize
;
1853 CpuMpData
->BackupBuffer
= BackupBufferAddr
;
1854 CpuMpData
->BackupBufferSize
= ApResetVectorSizeBelow1Mb
;
1855 CpuMpData
->WakeupBuffer
= (UINTN
)-1;
1856 CpuMpData
->CpuCount
= 1;
1857 CpuMpData
->BspNumber
= 0;
1858 CpuMpData
->WaitEvent
= NULL
;
1859 CpuMpData
->SwitchBspFlag
= FALSE
;
1860 CpuMpData
->CpuData
= (CPU_AP_DATA
*)(CpuMpData
+ 1);
1861 CpuMpData
->CpuInfoInHob
= (UINT64
)(UINTN
)(CpuMpData
->CpuData
+ MaxLogicalProcessorNumber
);
1862 InitializeSpinLock (&CpuMpData
->MpLock
);
1863 CpuMpData
->SevEsIsEnabled
= ConfidentialComputingGuestHas (CCAttrAmdSevEs
);
1864 CpuMpData
->SevSnpIsEnabled
= ConfidentialComputingGuestHas (CCAttrAmdSevSnp
);
1865 CpuMpData
->SevEsAPBuffer
= (UINTN
)-1;
1866 CpuMpData
->GhcbBase
= PcdGet64 (PcdGhcbBase
);
1867 CpuMpData
->UseSevEsAPMethod
= CpuMpData
->SevEsIsEnabled
&& !CpuMpData
->SevSnpIsEnabled
;
1869 if (CpuMpData
->SevSnpIsEnabled
) {
1870 ASSERT ((PcdGet64 (PcdGhcbHypervisorFeatures
) & GHCB_HV_FEATURES_SNP_AP_CREATE
) == GHCB_HV_FEATURES_SNP_AP_CREATE
);
1874 // Make sure no memory usage outside of the allocated buffer.
1877 (CpuMpData
->CpuInfoInHob
+ sizeof (CPU_INFO_IN_HOB
) * MaxLogicalProcessorNumber
) ==
1882 // Duplicate BSP's IDT to APs.
1883 // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1
1885 CopyMem ((VOID
*)ApIdtBase
, (VOID
*)VolatileRegisters
.Idtr
.Base
, VolatileRegisters
.Idtr
.Limit
+ 1);
1886 VolatileRegisters
.Idtr
.Base
= ApIdtBase
;
1888 // Don't pass BSP's TR to APs to avoid AP init failure.
1890 VolatileRegisters
.Tr
= 0;
1891 CopyMem (&CpuMpData
->CpuData
[0].VolatileRegisters
, &VolatileRegisters
, sizeof (VolatileRegisters
));
1893 // Set BSP basic information
1895 InitializeApData (CpuMpData
, 0, 0, CpuMpData
->Buffer
+ ApStackSize
);
1897 // Save assembly code information
1899 CopyMem (&CpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
1901 // Finally set AP loop mode
1903 CpuMpData
->ApLoopMode
= ApLoopMode
;
1904 DEBUG ((DEBUG_INFO
, "AP Loop Mode is %d\n", CpuMpData
->ApLoopMode
));
1906 CpuMpData
->WakeUpByInitSipiSipi
= (CpuMpData
->ApLoopMode
== ApInHltLoop
);
1909 // Set up APs wakeup signal buffer
1911 for (Index
= 0; Index
< MaxLogicalProcessorNumber
; Index
++) {
1912 CpuMpData
->CpuData
[Index
].StartupApSignal
=
1913 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
1917 // Enable the local APIC for Virtual Wire Mode.
1919 ProgramVirtualWireMode ();
1921 if (OldCpuMpData
== NULL
) {
1922 if (MaxLogicalProcessorNumber
> 1) {
1924 // Wakeup all APs and calculate the processor count in system
1926 CollectProcessorCount (CpuMpData
);
1930 // APs have been wakeup before, just get the CPU Information
1933 OldCpuMpData
->NewCpuMpData
= CpuMpData
;
1934 CpuMpData
->CpuCount
= OldCpuMpData
->CpuCount
;
1935 CpuMpData
->BspNumber
= OldCpuMpData
->BspNumber
;
1936 CpuMpData
->CpuInfoInHob
= OldCpuMpData
->CpuInfoInHob
;
1937 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
1938 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1939 InitializeSpinLock (&CpuMpData
->CpuData
[Index
].ApLock
);
1940 CpuMpData
->CpuData
[Index
].CpuHealthy
= (CpuInfoInHob
[Index
].Health
== 0) ? TRUE
: FALSE
;
1941 CpuMpData
->CpuData
[Index
].ApFunction
= 0;
1945 if (!GetMicrocodePatchInfoFromHob (
1946 &CpuMpData
->MicrocodePatchAddress
,
1947 &CpuMpData
->MicrocodePatchRegionSize
1951 // The microcode patch information cache HOB does not exist, which means
1952 // the microcode patches data has not been loaded into memory yet
1954 ShadowMicrocodeUpdatePatch (CpuMpData
);
1958 // Detect and apply Microcode on BSP
1960 MicrocodeDetect (CpuMpData
, CpuMpData
->BspNumber
);
1962 // Store BSP's MTRR setting
1964 MtrrGetAllMtrrs (&CpuMpData
->MtrrTable
);
1967 // Wakeup APs to do some AP initialize sync (Microcode & MTRR)
1969 if (CpuMpData
->CpuCount
> 1) {
1970 if (OldCpuMpData
!= NULL
) {
1972 // Only needs to use this flag for DXE phase to update the wake up
1973 // buffer. Wakeup buffer allocated in PEI phase is no longer valid
1976 CpuMpData
->InitFlag
= ApInitReconfig
;
1979 WakeUpAP (CpuMpData
, TRUE
, 0, ApInitializeSync
, CpuMpData
, TRUE
);
1981 // Wait for all APs finished initialization
1983 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
1987 if (OldCpuMpData
!= NULL
) {
1988 CpuMpData
->InitFlag
= ApInitDone
;
1991 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1992 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
1997 // Dump the microcode revision for each core.
1999 DEBUG_CODE_BEGIN ();
2001 UINT32 ExpectedMicrocodeRevision
;
2003 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
2004 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
2005 GetProcessorLocationByApicId (CpuInfoInHob
[Index
].InitialApicId
, NULL
, NULL
, &ThreadId
);
2006 if (ThreadId
== 0) {
2008 // MicrocodeDetect() loads microcode in first thread of each core, so,
2009 // CpuMpData->CpuData[Index].MicrocodeEntryAddr is initialized only for first thread of each core.
2011 ExpectedMicrocodeRevision
= 0;
2012 if (CpuMpData
->CpuData
[Index
].MicrocodeEntryAddr
!= 0) {
2013 ExpectedMicrocodeRevision
= ((CPU_MICROCODE_HEADER
*)(UINTN
)CpuMpData
->CpuData
[Index
].MicrocodeEntryAddr
)->UpdateRevision
;
2018 "CPU[%04d]: Microcode revision = %08x, expected = %08x\n",
2020 CpuMpData
->CpuData
[Index
].MicrocodeRevision
,
2021 ExpectedMicrocodeRevision
2028 // Initialize global data for MP support
2030 InitMpGlobalData (CpuMpData
);
2036 Gets detailed MP-related information on the requested processor at the
2037 instant this call is made. This service may only be called from the BSP.
2039 @param[in] ProcessorNumber The handle number of processor.
2040 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
2041 the requested processor is deposited.
2042 @param[out] HealthData Return processor health data.
2044 @retval EFI_SUCCESS Processor information was returned.
2045 @retval EFI_DEVICE_ERROR The calling processor is an AP.
2046 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
2047 @retval EFI_NOT_FOUND The processor with the handle specified by
2048 ProcessorNumber does not exist in the platform.
2049 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2054 MpInitLibGetProcessorInfo (
2055 IN UINTN ProcessorNumber
,
2056 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
,
2057 OUT EFI_HEALTH_FLAGS
*HealthData OPTIONAL
2060 CPU_MP_DATA
*CpuMpData
;
2062 CPU_INFO_IN_HOB
*CpuInfoInHob
;
2063 UINTN OriginalProcessorNumber
;
2065 CpuMpData
= GetCpuMpData ();
2066 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
2069 // Lower 24 bits contains the actual processor number.
2071 OriginalProcessorNumber
= ProcessorNumber
;
2072 ProcessorNumber
&= BIT24
- 1;
2075 // Check whether caller processor is BSP
2077 MpInitLibWhoAmI (&CallerNumber
);
2078 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2079 return EFI_DEVICE_ERROR
;
2082 if (ProcessorInfoBuffer
== NULL
) {
2083 return EFI_INVALID_PARAMETER
;
2086 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
2087 return EFI_NOT_FOUND
;
2090 ProcessorInfoBuffer
->ProcessorId
= (UINT64
)CpuInfoInHob
[ProcessorNumber
].ApicId
;
2091 ProcessorInfoBuffer
->StatusFlag
= 0;
2092 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
2093 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_AS_BSP_BIT
;
2096 if (CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
) {
2097 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_HEALTH_STATUS_BIT
;
2100 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
2101 ProcessorInfoBuffer
->StatusFlag
&= ~PROCESSOR_ENABLED_BIT
;
2103 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_ENABLED_BIT
;
2107 // Get processor location information
2109 GetProcessorLocationByApicId (
2110 CpuInfoInHob
[ProcessorNumber
].ApicId
,
2111 &ProcessorInfoBuffer
->Location
.Package
,
2112 &ProcessorInfoBuffer
->Location
.Core
,
2113 &ProcessorInfoBuffer
->Location
.Thread
2116 if ((OriginalProcessorNumber
& CPU_V2_EXTENDED_TOPOLOGY
) != 0) {
2117 GetProcessorLocation2ByApicId (
2118 CpuInfoInHob
[ProcessorNumber
].ApicId
,
2119 &ProcessorInfoBuffer
->ExtendedInformation
.Location2
.Package
,
2120 &ProcessorInfoBuffer
->ExtendedInformation
.Location2
.Die
,
2121 &ProcessorInfoBuffer
->ExtendedInformation
.Location2
.Tile
,
2122 &ProcessorInfoBuffer
->ExtendedInformation
.Location2
.Module
,
2123 &ProcessorInfoBuffer
->ExtendedInformation
.Location2
.Core
,
2124 &ProcessorInfoBuffer
->ExtendedInformation
.Location2
.Thread
2128 if (HealthData
!= NULL
) {
2129 HealthData
->Uint32
= CpuInfoInHob
[ProcessorNumber
].Health
;
2136 Worker function to switch the requested AP to be the BSP from that point onward.
2138 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
2139 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
2140 enabled AP. Otherwise, it will be disabled.
2142 @retval EFI_SUCCESS BSP successfully switched.
2143 @retval others Failed to switch BSP.
2148 IN UINTN ProcessorNumber
,
2149 IN BOOLEAN EnableOldBSP
2152 CPU_MP_DATA
*CpuMpData
;
2155 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
2156 BOOLEAN OldInterruptState
;
2157 BOOLEAN OldTimerInterruptState
;
2160 // Save and Disable Local APIC timer interrupt
2162 OldTimerInterruptState
= GetApicTimerInterruptState ();
2163 DisableApicTimerInterrupt ();
2165 // Before send both BSP and AP to a procedure to exchange their roles,
2166 // interrupt must be disabled. This is because during the exchange role
2167 // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
2168 // be corrupted, since interrupt return address will be pushed to stack
2171 OldInterruptState
= SaveAndDisableInterrupts ();
2174 // Mask LINT0 & LINT1 for the old BSP
2176 DisableLvtInterrupts ();
2178 CpuMpData
= GetCpuMpData ();
2181 // Check whether caller processor is BSP
2183 MpInitLibWhoAmI (&CallerNumber
);
2184 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2185 return EFI_DEVICE_ERROR
;
2188 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
2189 return EFI_NOT_FOUND
;
2193 // Check whether specified AP is disabled
2195 State
= GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]);
2196 if (State
== CpuStateDisabled
) {
2197 return EFI_INVALID_PARAMETER
;
2201 // Check whether ProcessorNumber specifies the current BSP
2203 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
2204 return EFI_INVALID_PARAMETER
;
2208 // Check whether specified AP is busy
2210 if (State
== CpuStateBusy
) {
2211 return EFI_NOT_READY
;
2214 CpuMpData
->BSPInfo
.State
= CPU_SWITCH_STATE_IDLE
;
2215 CpuMpData
->APInfo
.State
= CPU_SWITCH_STATE_IDLE
;
2216 CpuMpData
->SwitchBspFlag
= TRUE
;
2217 CpuMpData
->NewBspNumber
= ProcessorNumber
;
2220 // Clear the BSP bit of MSR_IA32_APIC_BASE
2222 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
2223 ApicBaseMsr
.Bits
.BSP
= 0;
2224 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
2227 // Need to wakeUp AP (future BSP).
2229 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, FutureBSPProc
, CpuMpData
, TRUE
);
2231 AsmExchangeRole (&CpuMpData
->BSPInfo
, &CpuMpData
->APInfo
);
2234 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
2236 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
2237 ApicBaseMsr
.Bits
.BSP
= 1;
2238 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
2239 ProgramVirtualWireMode ();
2242 // Wait for old BSP finished AP task
2244 while (GetApState (&CpuMpData
->CpuData
[CallerNumber
]) != CpuStateFinished
) {
2248 CpuMpData
->SwitchBspFlag
= FALSE
;
2250 // Set old BSP enable state
2252 if (!EnableOldBSP
) {
2253 SetApState (&CpuMpData
->CpuData
[CallerNumber
], CpuStateDisabled
);
2255 SetApState (&CpuMpData
->CpuData
[CallerNumber
], CpuStateIdle
);
2259 // Save new BSP number
2261 CpuMpData
->BspNumber
= (UINT32
)ProcessorNumber
;
2264 // Restore interrupt state.
2266 SetInterruptState (OldInterruptState
);
2268 if (OldTimerInterruptState
) {
2269 EnableApicTimerInterrupt ();
2276 Worker function to let the caller enable or disable an AP from this point onward.
2277 This service may only be called from the BSP.
2279 @param[in] ProcessorNumber The handle number of AP.
2280 @param[in] EnableAP Specifies the new state for the processor for
2281 enabled, FALSE for disabled.
2282 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
2283 the new health status of the AP.
2285 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
2286 @retval others Failed to Enable/Disable AP.
2290 EnableDisableApWorker (
2291 IN UINTN ProcessorNumber
,
2292 IN BOOLEAN EnableAP
,
2293 IN UINT32
*HealthFlag OPTIONAL
2296 CPU_MP_DATA
*CpuMpData
;
2299 CpuMpData
= GetCpuMpData ();
2302 // Check whether caller processor is BSP
2304 MpInitLibWhoAmI (&CallerNumber
);
2305 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2306 return EFI_DEVICE_ERROR
;
2309 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
2310 return EFI_INVALID_PARAMETER
;
2313 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
2314 return EFI_NOT_FOUND
;
2318 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateDisabled
);
2320 ResetProcessorToIdleState (ProcessorNumber
);
2323 if (HealthFlag
!= NULL
) {
2324 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
=
2325 (BOOLEAN
)((*HealthFlag
& PROCESSOR_HEALTH_STATUS_BIT
) != 0);
2332 This return the handle number for the calling processor. This service may be
2333 called from the BSP and APs.
2335 @param[out] ProcessorNumber Pointer to the handle number of AP.
2336 The range is from 0 to the total number of
2337 logical processors minus 1. The total number of
2338 logical processors can be retrieved by
2339 MpInitLibGetNumberOfProcessors().
2341 @retval EFI_SUCCESS The current processor handle number was returned
2343 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
2344 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2350 OUT UINTN
*ProcessorNumber
2353 CPU_MP_DATA
*CpuMpData
;
2355 if (ProcessorNumber
== NULL
) {
2356 return EFI_INVALID_PARAMETER
;
2359 CpuMpData
= GetCpuMpData ();
2361 return GetProcessorNumber (CpuMpData
, ProcessorNumber
);
2365 Retrieves the number of logical processor in the platform and the number of
2366 those logical processors that are enabled on this boot. This service may only
2367 be called from the BSP.
2369 @param[out] NumberOfProcessors Pointer to the total number of logical
2370 processors in the system, including the BSP
2372 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
2373 processors that exist in system, including
2376 @retval EFI_SUCCESS The number of logical processors and enabled
2377 logical processors was retrieved.
2378 @retval EFI_DEVICE_ERROR The calling processor is an AP.
2379 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
2381 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2386 MpInitLibGetNumberOfProcessors (
2387 OUT UINTN
*NumberOfProcessors OPTIONAL
,
2388 OUT UINTN
*NumberOfEnabledProcessors OPTIONAL
2391 CPU_MP_DATA
*CpuMpData
;
2393 UINTN ProcessorNumber
;
2394 UINTN EnabledProcessorNumber
;
2397 CpuMpData
= GetCpuMpData ();
2399 if ((NumberOfProcessors
== NULL
) && (NumberOfEnabledProcessors
== NULL
)) {
2400 return EFI_INVALID_PARAMETER
;
2404 // Check whether caller processor is BSP
2406 MpInitLibWhoAmI (&CallerNumber
);
2407 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2408 return EFI_DEVICE_ERROR
;
2411 ProcessorNumber
= CpuMpData
->CpuCount
;
2412 EnabledProcessorNumber
= 0;
2413 for (Index
= 0; Index
< ProcessorNumber
; Index
++) {
2414 if (GetApState (&CpuMpData
->CpuData
[Index
]) != CpuStateDisabled
) {
2415 EnabledProcessorNumber
++;
2419 if (NumberOfProcessors
!= NULL
) {
2420 *NumberOfProcessors
= ProcessorNumber
;
2423 if (NumberOfEnabledProcessors
!= NULL
) {
2424 *NumberOfEnabledProcessors
= EnabledProcessorNumber
;
2431 Worker function to execute a caller provided function on all enabled APs.
2433 @param[in] Procedure A pointer to the function to be run on
2434 enabled APs of the system.
2435 @param[in] SingleThread If TRUE, then all the enabled APs execute
2436 the function specified by Procedure one by
2437 one, in ascending order of processor handle
2438 number. If FALSE, then all the enabled APs
2439 execute the function specified by Procedure
2441 @param[in] ExcludeBsp Whether let BSP also trig this task.
2442 @param[in] WaitEvent The event created by the caller with CreateEvent()
2444 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2445 APs to return from Procedure, either for
2446 blocking or non-blocking mode.
2447 @param[in] ProcedureArgument The parameter passed into Procedure for
2449 @param[out] FailedCpuList If all APs finish successfully, then its
2450 content is set to NULL. If not all APs
2451 finish before timeout expires, then its
2452 content is set to address of the buffer
2453 holding handle numbers of the failed APs.
2455 @retval EFI_SUCCESS In blocking mode, all APs have finished before
2456 the timeout expired.
2457 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2459 @retval others Failed to Startup all APs.
2463 StartupAllCPUsWorker (
2464 IN EFI_AP_PROCEDURE Procedure
,
2465 IN BOOLEAN SingleThread
,
2466 IN BOOLEAN ExcludeBsp
,
2467 IN EFI_EVENT WaitEvent OPTIONAL
,
2468 IN UINTN TimeoutInMicroseconds
,
2469 IN VOID
*ProcedureArgument OPTIONAL
,
2470 OUT UINTN
**FailedCpuList OPTIONAL
2474 CPU_MP_DATA
*CpuMpData
;
2475 UINTN ProcessorCount
;
2476 UINTN ProcessorNumber
;
2478 CPU_AP_DATA
*CpuData
;
2479 BOOLEAN HasEnabledAp
;
2482 CpuMpData
= GetCpuMpData ();
2484 if (FailedCpuList
!= NULL
) {
2485 *FailedCpuList
= NULL
;
2488 if ((CpuMpData
->CpuCount
== 1) && ExcludeBsp
) {
2489 return EFI_NOT_STARTED
;
2492 if (Procedure
== NULL
) {
2493 return EFI_INVALID_PARAMETER
;
2497 // Check whether caller processor is BSP
2499 MpInitLibWhoAmI (&CallerNumber
);
2500 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2501 return EFI_DEVICE_ERROR
;
2507 CheckAndUpdateApsStatus ();
2509 ProcessorCount
= CpuMpData
->CpuCount
;
2510 HasEnabledAp
= FALSE
;
2512 // Check whether all enabled APs are idle.
2513 // If any enabled AP is not idle, return EFI_NOT_READY.
2515 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2516 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2517 if (ProcessorNumber
!= CpuMpData
->BspNumber
) {
2518 ApState
= GetApState (CpuData
);
2519 if (ApState
!= CpuStateDisabled
) {
2520 HasEnabledAp
= TRUE
;
2521 if (ApState
!= CpuStateIdle
) {
2523 // If any enabled APs are busy, return EFI_NOT_READY.
2525 return EFI_NOT_READY
;
2531 if (!HasEnabledAp
&& ExcludeBsp
) {
2533 // If no enabled AP exists and not include Bsp to do the procedure, return EFI_NOT_STARTED.
2535 return EFI_NOT_STARTED
;
2538 CpuMpData
->RunningCount
= 0;
2539 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2540 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2541 CpuData
->Waiting
= FALSE
;
2542 if (ProcessorNumber
!= CpuMpData
->BspNumber
) {
2543 if (CpuData
->State
== CpuStateIdle
) {
2545 // Mark this processor as responsible for current calling.
2547 CpuData
->Waiting
= TRUE
;
2548 CpuMpData
->RunningCount
++;
2553 CpuMpData
->Procedure
= Procedure
;
2554 CpuMpData
->ProcArguments
= ProcedureArgument
;
2555 CpuMpData
->SingleThread
= SingleThread
;
2556 CpuMpData
->FinishedCount
= 0;
2557 CpuMpData
->FailedCpuList
= FailedCpuList
;
2558 CpuMpData
->ExpectedTime
= CalculateTimeout (
2559 TimeoutInMicroseconds
,
2560 &CpuMpData
->CurrentTime
2562 CpuMpData
->TotalTime
= 0;
2563 CpuMpData
->WaitEvent
= WaitEvent
;
2565 if (!SingleThread
) {
2566 WakeUpAP (CpuMpData
, TRUE
, 0, Procedure
, ProcedureArgument
, FALSE
);
2568 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2569 if (ProcessorNumber
== CallerNumber
) {
2573 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
2574 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, Procedure
, ProcedureArgument
, TRUE
);
2584 Procedure (ProcedureArgument
);
2587 Status
= EFI_SUCCESS
;
2588 if (WaitEvent
== NULL
) {
2590 Status
= CheckAllAPs ();
2591 } while (Status
== EFI_NOT_READY
);
2598 Worker function to let the caller get one enabled AP to execute a caller-provided
2601 @param[in] Procedure A pointer to the function to be run on
2602 enabled APs of the system.
2603 @param[in] ProcessorNumber The handle number of the AP.
2604 @param[in] WaitEvent The event created by the caller with CreateEvent()
2606 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2607 APs to return from Procedure, either for
2608 blocking or non-blocking mode.
2609 @param[in] ProcedureArgument The parameter passed into Procedure for
2611 @param[out] Finished If AP returns from Procedure before the
2612 timeout expires, its content is set to TRUE.
2613 Otherwise, the value is set to FALSE.
2615 @retval EFI_SUCCESS In blocking mode, specified AP finished before
2616 the timeout expires.
2617 @retval others Failed to Startup AP.
2621 StartupThisAPWorker (
2622 IN EFI_AP_PROCEDURE Procedure
,
2623 IN UINTN ProcessorNumber
,
2624 IN EFI_EVENT WaitEvent OPTIONAL
,
2625 IN UINTN TimeoutInMicroseconds
,
2626 IN VOID
*ProcedureArgument OPTIONAL
,
2627 OUT BOOLEAN
*Finished OPTIONAL
2631 CPU_MP_DATA
*CpuMpData
;
2632 CPU_AP_DATA
*CpuData
;
2635 CpuMpData
= GetCpuMpData ();
2637 if (Finished
!= NULL
) {
2642 // Check whether caller processor is BSP
2644 MpInitLibWhoAmI (&CallerNumber
);
2645 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2646 return EFI_DEVICE_ERROR
;
2650 // Check whether processor with the handle specified by ProcessorNumber exists
2652 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
2653 return EFI_NOT_FOUND
;
2657 // Check whether specified processor is BSP
2659 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
2660 return EFI_INVALID_PARAMETER
;
2664 // Check parameter Procedure
2666 if (Procedure
== NULL
) {
2667 return EFI_INVALID_PARAMETER
;
2673 CheckAndUpdateApsStatus ();
2676 // Check whether specified AP is disabled
2678 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
2679 return EFI_INVALID_PARAMETER
;
2683 // If WaitEvent is not NULL, execute in non-blocking mode.
2684 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
2685 // CheckAPsStatus() will check completion and timeout periodically.
2687 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2688 CpuData
->WaitEvent
= WaitEvent
;
2689 CpuData
->Finished
= Finished
;
2690 CpuData
->ExpectedTime
= CalculateTimeout (TimeoutInMicroseconds
, &CpuData
->CurrentTime
);
2691 CpuData
->TotalTime
= 0;
2693 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, Procedure
, ProcedureArgument
, TRUE
);
2696 // If WaitEvent is NULL, execute in blocking mode.
2697 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
2699 Status
= EFI_SUCCESS
;
2700 if (WaitEvent
== NULL
) {
2702 Status
= CheckThisAP (ProcessorNumber
);
2703 } while (Status
== EFI_NOT_READY
);
2710 Get pointer to CPU MP Data structure from GUIDed HOB.
2712 @return The pointer to CPU MP Data structure.
2715 GetCpuMpDataFromGuidedHob (
2719 EFI_HOB_GUID_TYPE
*GuidHob
;
2721 CPU_MP_DATA
*CpuMpData
;
2724 GuidHob
= GetFirstGuidHob (&mCpuInitMpLibHobGuid
);
2725 if (GuidHob
!= NULL
) {
2726 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
2727 CpuMpData
= (CPU_MP_DATA
*)(*(UINTN
*)DataInHob
);
2734 This service executes a caller provided function on all enabled CPUs.
2736 @param[in] Procedure A pointer to the function to be run on
2737 enabled APs of the system. See type
2739 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2740 APs to return from Procedure, either for
2741 blocking or non-blocking mode. Zero means
2742 infinity. TimeoutInMicroseconds is ignored
2744 @param[in] ProcedureArgument The parameter passed into Procedure for
2747 @retval EFI_SUCCESS In blocking mode, all CPUs have finished before
2748 the timeout expired.
2749 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2750 to all enabled CPUs.
2751 @retval EFI_DEVICE_ERROR Caller processor is AP.
2752 @retval EFI_NOT_READY Any enabled APs are busy.
2753 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2754 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
2755 all enabled APs have finished.
2756 @retval EFI_INVALID_PARAMETER Procedure is NULL.
2761 MpInitLibStartupAllCPUs (
2762 IN EFI_AP_PROCEDURE Procedure
,
2763 IN UINTN TimeoutInMicroseconds
,
2764 IN VOID
*ProcedureArgument OPTIONAL
2767 return StartupAllCPUsWorker (
2772 TimeoutInMicroseconds
,
2779 The function check if the specified Attr is set.
2781 @param[in] CurrentAttr The current attribute.
2782 @param[in] Attr The attribute to check.
2784 @retval TRUE The specified Attr is set.
2785 @retval FALSE The specified Attr is not set.
2790 AmdMemEncryptionAttrCheck (
2791 IN UINT64 CurrentAttr
,
2792 IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr
2798 // SEV is automatically enabled if SEV-ES or SEV-SNP is active.
2800 return CurrentAttr
>= CCAttrAmdSev
;
2801 case CCAttrAmdSevEs
:
2803 // SEV-ES is automatically enabled if SEV-SNP is active.
2805 return CurrentAttr
>= CCAttrAmdSevEs
;
2806 case CCAttrAmdSevSnp
:
2807 return CurrentAttr
== CCAttrAmdSevSnp
;
2814 Check if the specified confidential computing attribute is active.
2816 @param[in] Attr The attribute to check.
2818 @retval TRUE The specified Attr is active.
2819 @retval FALSE The specified Attr is not active.
2824 ConfidentialComputingGuestHas (
2825 IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr
2831 // Get the current CC attribute.
2833 CurrentAttr
= PcdGet64 (PcdConfidentialComputingGuestAttr
);
2836 // If attr is for the AMD group then call AMD specific checks.
2838 if (((RShiftU64 (CurrentAttr
, 8)) & 0xff) == 1) {
2839 return AmdMemEncryptionAttrCheck (CurrentAttr
, Attr
);
2842 return (CurrentAttr
== Attr
);