2 CPU MP Initialize Library common functions.
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 EFI_GUID mCpuInitMpLibHobGuid
= CPU_INIT_MP_LIB_HOB_GUID
;
20 The function will check if BSP Execute Disable is enabled.
22 DxeIpl may have enabled Execute Disable for BSP, APs need to
23 get the status and sync up the settings.
24 If BSP's CR0.Paging is not set, BSP execute Disble feature is
27 @retval TRUE BSP Execute Disable is enabled.
28 @retval FALSE BSP Execute Disable is not enabled.
31 IsBspExecuteDisableEnabled (
36 CPUID_EXTENDED_CPU_SIG_EDX Edx
;
37 MSR_IA32_EFER_REGISTER EferMsr
;
42 Cr0
.UintN
= AsmReadCr0 ();
43 if (Cr0
.Bits
.PG
!= 0) {
45 // If CR0 Paging bit is set
47 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &Eax
, NULL
, NULL
, NULL
);
48 if (Eax
>= CPUID_EXTENDED_CPU_SIG
) {
49 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &Edx
.Uint32
);
52 // Bit 20: Execute Disable Bit available.
54 if (Edx
.Bits
.NX
!= 0) {
55 EferMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_EFER
);
58 // Bit 11: Execute Disable Bit enable.
60 if (EferMsr
.Bits
.NXE
!= 0) {
71 Worker function for SwitchBSP().
73 Worker function for SwitchBSP(), assigned to the AP which is intended
76 @param[in] Buffer Pointer to CPU MP Data
84 CPU_MP_DATA
*DataInHob
;
86 DataInHob
= (CPU_MP_DATA
*) Buffer
;
87 AsmExchangeRole (&DataInHob
->APInfo
, &DataInHob
->BSPInfo
);
91 Get the Application Processors state.
93 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
99 IN CPU_AP_DATA
*CpuData
102 return CpuData
->State
;
106 Set the Application Processors state.
108 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
109 @param[in] State The AP status
113 IN CPU_AP_DATA
*CpuData
,
117 AcquireSpinLock (&CpuData
->ApLock
);
118 CpuData
->State
= State
;
119 ReleaseSpinLock (&CpuData
->ApLock
);
123 Save BSP's local APIC timer setting.
125 @param[in] CpuMpData Pointer to CPU MP Data
128 SaveLocalApicTimerSetting (
129 IN CPU_MP_DATA
*CpuMpData
133 // Record the current local APIC timer setting of BSP
136 &CpuMpData
->DivideValue
,
137 &CpuMpData
->PeriodicMode
,
140 CpuMpData
->CurrentTimerCount
= GetApicTimerCurrentCount ();
141 CpuMpData
->TimerInterruptState
= GetApicTimerInterruptState ();
145 Sync local APIC timer setting from BSP to AP.
147 @param[in] CpuMpData Pointer to CPU MP Data
150 SyncLocalApicTimerSetting (
151 IN CPU_MP_DATA
*CpuMpData
155 // Sync local APIC timer setting from BSP to AP
157 InitializeApicTimer (
158 CpuMpData
->DivideValue
,
159 CpuMpData
->CurrentTimerCount
,
160 CpuMpData
->PeriodicMode
,
164 // Disable AP's local APIC timer interrupt
166 DisableApicTimerInterrupt ();
170 Save the volatile registers required to be restored following INIT IPI.
172 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
175 SaveVolatileRegisters (
176 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
179 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
181 VolatileRegisters
->Cr0
= AsmReadCr0 ();
182 VolatileRegisters
->Cr3
= AsmReadCr3 ();
183 VolatileRegisters
->Cr4
= AsmReadCr4 ();
185 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
186 if (VersionInfoEdx
.Bits
.DE
!= 0) {
188 // If processor supports Debugging Extensions feature
189 // by CPUID.[EAX=01H]:EDX.BIT2
191 VolatileRegisters
->Dr0
= AsmReadDr0 ();
192 VolatileRegisters
->Dr1
= AsmReadDr1 ();
193 VolatileRegisters
->Dr2
= AsmReadDr2 ();
194 VolatileRegisters
->Dr3
= AsmReadDr3 ();
195 VolatileRegisters
->Dr6
= AsmReadDr6 ();
196 VolatileRegisters
->Dr7
= AsmReadDr7 ();
199 AsmReadGdtr (&VolatileRegisters
->Gdtr
);
200 AsmReadIdtr (&VolatileRegisters
->Idtr
);
201 VolatileRegisters
->Tr
= AsmReadTr ();
205 Restore the volatile registers following INIT IPI.
207 @param[in] VolatileRegisters Pointer to volatile resisters
208 @param[in] IsRestoreDr TRUE: Restore DRx if supported
209 FALSE: Do not restore DRx
212 RestoreVolatileRegisters (
213 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
214 IN BOOLEAN IsRestoreDr
217 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
218 IA32_TSS_DESCRIPTOR
*Tss
;
220 AsmWriteCr0 (VolatileRegisters
->Cr0
);
221 AsmWriteCr3 (VolatileRegisters
->Cr3
);
222 AsmWriteCr4 (VolatileRegisters
->Cr4
);
225 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
226 if (VersionInfoEdx
.Bits
.DE
!= 0) {
228 // If processor supports Debugging Extensions feature
229 // by CPUID.[EAX=01H]:EDX.BIT2
231 AsmWriteDr0 (VolatileRegisters
->Dr0
);
232 AsmWriteDr1 (VolatileRegisters
->Dr1
);
233 AsmWriteDr2 (VolatileRegisters
->Dr2
);
234 AsmWriteDr3 (VolatileRegisters
->Dr3
);
235 AsmWriteDr6 (VolatileRegisters
->Dr6
);
236 AsmWriteDr7 (VolatileRegisters
->Dr7
);
240 AsmWriteGdtr (&VolatileRegisters
->Gdtr
);
241 AsmWriteIdtr (&VolatileRegisters
->Idtr
);
242 if (VolatileRegisters
->Tr
!= 0 &&
243 VolatileRegisters
->Tr
< VolatileRegisters
->Gdtr
.Limit
) {
244 Tss
= (IA32_TSS_DESCRIPTOR
*)(VolatileRegisters
->Gdtr
.Base
+
245 VolatileRegisters
->Tr
);
246 if (Tss
->Bits
.P
== 1) {
247 Tss
->Bits
.Type
&= 0xD; // 1101 - Clear busy bit just in case
248 AsmWriteTr (VolatileRegisters
->Tr
);
254 Detect whether Mwait-monitor feature is supported.
256 @retval TRUE Mwait-monitor feature is supported.
257 @retval FALSE Mwait-monitor feature is not supported.
264 CPUID_VERSION_INFO_ECX VersionInfoEcx
;
266 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &VersionInfoEcx
.Uint32
, NULL
);
267 return (VersionInfoEcx
.Bits
.MONITOR
== 1) ? TRUE
: FALSE
;
273 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
275 @return The AP loop mode.
279 OUT UINT32
*MonitorFilterSize
283 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx
;
285 ASSERT (MonitorFilterSize
!= NULL
);
287 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
288 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
289 if (ApLoopMode
== ApInMwaitLoop
) {
290 if (!IsMwaitSupport ()) {
292 // If processor does not support MONITOR/MWAIT feature,
293 // force AP in Hlt-loop mode
295 ApLoopMode
= ApInHltLoop
;
299 if (ApLoopMode
!= ApInMwaitLoop
) {
300 *MonitorFilterSize
= sizeof (UINT32
);
303 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
304 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
306 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &MonitorMwaitEbx
.Uint32
, NULL
, NULL
);
307 *MonitorFilterSize
= MonitorMwaitEbx
.Bits
.LargestMonitorLineSize
;
314 Sort the APIC ID of all processors.
316 This function sorts the APIC ID of all processors so that processor number is
317 assigned in the ascending order of APIC ID which eases MP debugging.
319 @param[in] CpuMpData Pointer to PEI CPU MP Data
323 IN CPU_MP_DATA
*CpuMpData
330 CPU_INFO_IN_HOB CpuInfo
;
332 CPU_INFO_IN_HOB
*CpuInfoInHob
;
333 volatile UINT32
*StartupApSignal
;
335 ApCount
= CpuMpData
->CpuCount
- 1;
336 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
338 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
341 // Sort key is the hardware default APIC ID
343 ApicId
= CpuInfoInHob
[Index1
].ApicId
;
344 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
345 if (ApicId
> CpuInfoInHob
[Index2
].ApicId
) {
347 ApicId
= CpuInfoInHob
[Index2
].ApicId
;
350 if (Index3
!= Index1
) {
351 CopyMem (&CpuInfo
, &CpuInfoInHob
[Index3
], sizeof (CPU_INFO_IN_HOB
));
353 &CpuInfoInHob
[Index3
],
354 &CpuInfoInHob
[Index1
],
355 sizeof (CPU_INFO_IN_HOB
)
357 CopyMem (&CpuInfoInHob
[Index1
], &CpuInfo
, sizeof (CPU_INFO_IN_HOB
));
360 // Also exchange the StartupApSignal.
362 StartupApSignal
= CpuMpData
->CpuData
[Index3
].StartupApSignal
;
363 CpuMpData
->CpuData
[Index3
].StartupApSignal
=
364 CpuMpData
->CpuData
[Index1
].StartupApSignal
;
365 CpuMpData
->CpuData
[Index1
].StartupApSignal
= StartupApSignal
;
370 // Get the processor number for the BSP
372 ApicId
= GetInitialApicId ();
373 for (Index1
= 0; Index1
< CpuMpData
->CpuCount
; Index1
++) {
374 if (CpuInfoInHob
[Index1
].ApicId
== ApicId
) {
375 CpuMpData
->BspNumber
= (UINT32
) Index1
;
383 Enable x2APIC mode on APs.
385 @param[in, out] Buffer Pointer to private data buffer.
393 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
399 @param[in, out] Buffer Pointer to private data buffer.
407 CPU_MP_DATA
*CpuMpData
;
409 CpuMpData
= (CPU_MP_DATA
*) Buffer
;
411 // Load microcode on AP
413 MicrocodeDetect (CpuMpData
);
415 // Sync BSP's MTRR table to AP
417 MtrrSetAllMtrrs (&CpuMpData
->MtrrTable
);
421 Find the current Processor number by APIC ID.
423 @param[in] CpuMpData Pointer to PEI CPU MP Data
424 @param[out] ProcessorNumber Return the pocessor number found
426 @retval EFI_SUCCESS ProcessorNumber is found and returned.
427 @retval EFI_NOT_FOUND ProcessorNumber is not found.
431 IN CPU_MP_DATA
*CpuMpData
,
432 OUT UINTN
*ProcessorNumber
435 UINTN TotalProcessorNumber
;
437 CPU_INFO_IN_HOB
*CpuInfoInHob
;
439 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
441 TotalProcessorNumber
= CpuMpData
->CpuCount
;
442 for (Index
= 0; Index
< TotalProcessorNumber
; Index
++) {
443 if (CpuInfoInHob
[Index
].ApicId
== GetApicId ()) {
444 *ProcessorNumber
= Index
;
448 return EFI_NOT_FOUND
;
452 This function will get CPU count in the system.
454 @param[in] CpuMpData Pointer to PEI CPU MP Data
456 @return CPU count detected
459 CollectProcessorCount (
460 IN CPU_MP_DATA
*CpuMpData
466 // Send 1st broadcast IPI to APs to wakeup APs
468 CpuMpData
->InitFlag
= ApInitConfig
;
469 CpuMpData
->X2ApicEnable
= FALSE
;
470 WakeUpAP (CpuMpData
, TRUE
, 0, NULL
, NULL
);
471 CpuMpData
->InitFlag
= ApInitDone
;
472 ASSERT (CpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
474 // Wait for all APs finished the initialization
476 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
480 if (CpuMpData
->CpuCount
> 255) {
482 // If there are more than 255 processor found, force to enable X2APIC
484 CpuMpData
->X2ApicEnable
= TRUE
;
486 if (CpuMpData
->X2ApicEnable
) {
487 DEBUG ((DEBUG_INFO
, "Force x2APIC mode!\n"));
489 // Wakeup all APs to enable x2APIC mode
491 WakeUpAP (CpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
);
493 // Wait for all known APs finished
495 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
499 // Enable x2APIC on BSP
501 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
503 // Set BSP/Aps state to IDLE
505 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
506 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
509 DEBUG ((DEBUG_INFO
, "APIC MODE is %d\n", GetApicMode ()));
511 // Sort BSP/Aps by CPU APIC ID in ascending order
513 SortApicId (CpuMpData
);
515 DEBUG ((DEBUG_INFO
, "MpInitLib: Find %d processors in system.\n", CpuMpData
->CpuCount
));
517 return CpuMpData
->CpuCount
;
521 Initialize CPU AP Data when AP is wakeup at the first time.
523 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
524 @param[in] ProcessorNumber The handle number of processor
525 @param[in] BistData Processor BIST data
526 @param[in] ApTopOfStack Top of AP stack
531 IN OUT CPU_MP_DATA
*CpuMpData
,
532 IN UINTN ProcessorNumber
,
534 IN UINT64 ApTopOfStack
537 CPU_INFO_IN_HOB
*CpuInfoInHob
;
539 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
540 CpuInfoInHob
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
541 CpuInfoInHob
[ProcessorNumber
].ApicId
= GetApicId ();
542 CpuInfoInHob
[ProcessorNumber
].Health
= BistData
;
543 CpuInfoInHob
[ProcessorNumber
].ApTopOfStack
= ApTopOfStack
;
545 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
546 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
= (BistData
== 0) ? TRUE
: FALSE
;
547 if (CpuInfoInHob
[ProcessorNumber
].InitialApicId
>= 0xFF) {
549 // Set x2APIC mode if there are any logical processor reporting
550 // an Initial APIC ID of 255 or greater.
552 AcquireSpinLock(&CpuMpData
->MpLock
);
553 CpuMpData
->X2ApicEnable
= TRUE
;
554 ReleaseSpinLock(&CpuMpData
->MpLock
);
557 InitializeSpinLock(&CpuMpData
->CpuData
[ProcessorNumber
].ApLock
);
558 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
562 This function will be called from AP reset code if BSP uses WakeUpAP.
564 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
565 @param[in] ApIndex Number of current executing AP
570 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
574 CPU_MP_DATA
*CpuMpData
;
575 UINTN ProcessorNumber
;
576 EFI_AP_PROCEDURE Procedure
;
579 volatile UINT32
*ApStartupSignalBuffer
;
580 CPU_INFO_IN_HOB
*CpuInfoInHob
;
582 UINTN CurrentApicMode
;
585 // AP finished assembly code and begin to execute C code
587 CpuMpData
= ExchangeInfo
->CpuMpData
;
590 // AP's local APIC settings will be lost after received INIT IPI
591 // We need to re-initialize them at here
593 ProgramVirtualWireMode ();
595 // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.
597 DisableLvtInterrupts ();
598 SyncLocalApicTimerSetting (CpuMpData
);
600 CurrentApicMode
= GetApicMode ();
602 if (CpuMpData
->InitFlag
== ApInitConfig
) {
606 InterlockedIncrement ((UINT32
*) &CpuMpData
->CpuCount
);
607 ProcessorNumber
= ApIndex
;
609 // This is first time AP wakeup, get BIST information from AP stack
611 ApTopOfStack
= CpuMpData
->Buffer
+ (ProcessorNumber
+ 1) * CpuMpData
->CpuApStackSize
;
612 BistData
= *(UINT32
*) ((UINTN
) ApTopOfStack
- sizeof (UINTN
));
614 // Do some AP initialize sync
616 ApInitializeSync (CpuMpData
);
618 // Sync BSP's Control registers to APs
620 RestoreVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
621 InitializeApData (CpuMpData
, ProcessorNumber
, BistData
, ApTopOfStack
);
622 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
625 // Execute AP function if AP is ready
627 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
629 // Clear AP start-up signal when AP waken up
631 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
632 InterlockedCompareExchange32 (
633 (UINT32
*) ApStartupSignalBuffer
,
637 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
639 // Restore AP's volatile registers saved
641 RestoreVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
644 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateReady
) {
645 Procedure
= (EFI_AP_PROCEDURE
)CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
;
646 Parameter
= (VOID
*) CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
;
647 if (Procedure
!= NULL
) {
648 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateBusy
);
650 // Enable source debugging on AP function
654 // Invoke AP function here
656 Procedure (Parameter
);
657 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
658 if (CpuMpData
->SwitchBspFlag
) {
660 // Re-get the processor number due to BSP/AP maybe exchange in AP function
662 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
663 CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
= 0;
664 CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
= 0;
665 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
666 CpuInfoInHob
[ProcessorNumber
].ApTopOfStack
= CpuInfoInHob
[CpuMpData
->NewBspNumber
].ApTopOfStack
;
668 if (CpuInfoInHob
[ProcessorNumber
].ApicId
!= GetApicId () ||
669 CpuInfoInHob
[ProcessorNumber
].InitialApicId
!= GetInitialApicId ()) {
670 if (CurrentApicMode
!= GetApicMode ()) {
672 // If APIC mode change happened during AP function execution,
673 // we do not support APIC ID value changed.
679 // Re-get the CPU APICID and Initial APICID if they are changed
681 CpuInfoInHob
[ProcessorNumber
].ApicId
= GetApicId ();
682 CpuInfoInHob
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
687 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateFinished
);
692 // AP finished executing C code
694 InterlockedIncrement ((UINT32
*) &CpuMpData
->FinishedCount
);
695 InterlockedDecrement ((UINT32
*) &CpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
);
698 // Place AP is specified loop mode
700 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
702 // Save AP volatile registers
704 SaveVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
706 // Place AP in HLT-loop
709 DisableInterrupts ();
715 DisableInterrupts ();
716 if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
718 // Place AP in MWAIT-loop
720 AsmMonitor ((UINTN
) ApStartupSignalBuffer
, 0, 0);
721 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
723 // Check AP start-up signal again.
724 // If AP start-up signal is not set, place AP into
725 // the specified C-state
727 AsmMwait (CpuMpData
->ApTargetCState
<< 4, 0);
729 } else if (CpuMpData
->ApLoopMode
== ApInRunLoop
) {
731 // Place AP in Run-loop
739 // If AP start-up signal is written, AP is waken up
740 // otherwise place AP in loop again
742 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
750 Wait for AP wakeup and write AP start-up signal till AP is waken up.
752 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
756 IN
volatile UINT32
*ApStartupSignalBuffer
760 // If AP is waken up, StartupApSignal should be cleared.
761 // Otherwise, write StartupApSignal again till AP waken up.
763 while (InterlockedCompareExchange32 (
764 (UINT32
*) ApStartupSignalBuffer
,
773 This function will fill the exchange info structure.
775 @param[in] CpuMpData Pointer to CPU MP Data
779 FillExchangeInfoData (
780 IN CPU_MP_DATA
*CpuMpData
783 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
785 IA32_SEGMENT_DESCRIPTOR
*Selector
;
787 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
788 ExchangeInfo
->Lock
= 0;
789 ExchangeInfo
->StackStart
= CpuMpData
->Buffer
;
790 ExchangeInfo
->StackSize
= CpuMpData
->CpuApStackSize
;
791 ExchangeInfo
->BufferStart
= CpuMpData
->WakeupBuffer
;
792 ExchangeInfo
->ModeOffset
= CpuMpData
->AddressMap
.ModeEntryOffset
;
794 ExchangeInfo
->CodeSegment
= AsmReadCs ();
795 ExchangeInfo
->DataSegment
= AsmReadDs ();
797 ExchangeInfo
->Cr3
= AsmReadCr3 ();
799 ExchangeInfo
->CFunction
= (UINTN
) ApWakeupFunction
;
800 ExchangeInfo
->ApIndex
= 0;
801 ExchangeInfo
->NumApsExecuting
= 0;
802 ExchangeInfo
->InitFlag
= (UINTN
) CpuMpData
->InitFlag
;
803 ExchangeInfo
->CpuInfo
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
804 ExchangeInfo
->CpuMpData
= CpuMpData
;
806 ExchangeInfo
->EnableExecuteDisable
= IsBspExecuteDisableEnabled ();
808 ExchangeInfo
->InitializeFloatingPointUnitsAddress
= (UINTN
)InitializeFloatingPointUnits
;
811 // Get the BSP's data of GDT and IDT
813 AsmReadGdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->GdtrProfile
);
814 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
817 // Find a 32-bit code segment
819 Selector
= (IA32_SEGMENT_DESCRIPTOR
*)ExchangeInfo
->GdtrProfile
.Base
;
820 Size
= ExchangeInfo
->GdtrProfile
.Limit
+ 1;
822 if (Selector
->Bits
.L
== 0 && Selector
->Bits
.Type
>= 8) {
823 ExchangeInfo
->ModeTransitionSegment
=
824 (UINT16
)((UINTN
)Selector
- ExchangeInfo
->GdtrProfile
.Base
);
828 Size
-= sizeof (IA32_SEGMENT_DESCRIPTOR
);
832 // Copy all 32-bit code and 64-bit code into memory with type of
833 // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
835 if (CpuMpData
->WakeupBufferHigh
!= 0) {
836 Size
= CpuMpData
->AddressMap
.RendezvousFunnelSize
-
837 CpuMpData
->AddressMap
.ModeTransitionOffset
;
839 (VOID
*)CpuMpData
->WakeupBufferHigh
,
840 CpuMpData
->AddressMap
.RendezvousFunnelAddress
+
841 CpuMpData
->AddressMap
.ModeTransitionOffset
,
845 ExchangeInfo
->ModeTransitionMemory
= (UINT32
)CpuMpData
->WakeupBufferHigh
;
847 ExchangeInfo
->ModeTransitionMemory
= (UINT32
)
848 (ExchangeInfo
->BufferStart
+ CpuMpData
->AddressMap
.ModeTransitionOffset
);
851 ExchangeInfo
->ModeHighMemory
= ExchangeInfo
->ModeTransitionMemory
+
852 (UINT32
)ExchangeInfo
->ModeOffset
-
853 (UINT32
)CpuMpData
->AddressMap
.ModeTransitionOffset
;
854 ExchangeInfo
->ModeHighSegment
= (UINT16
)ExchangeInfo
->CodeSegment
;
858 Helper function that waits until the finished AP count reaches the specified
859 limit, or the specified timeout elapses (whichever comes first).
861 @param[in] CpuMpData Pointer to CPU MP Data.
862 @param[in] FinishedApLimit The number of finished APs to wait for.
863 @param[in] TimeLimit The number of microseconds to wait for.
866 TimedWaitForApFinish (
867 IN CPU_MP_DATA
*CpuMpData
,
868 IN UINT32 FinishedApLimit
,
873 Get available system memory below 1MB by specified size.
875 @param[in] CpuMpData The pointer to CPU MP Data structure.
878 BackupAndPrepareWakeupBuffer(
879 IN CPU_MP_DATA
*CpuMpData
883 (VOID
*) CpuMpData
->BackupBuffer
,
884 (VOID
*) CpuMpData
->WakeupBuffer
,
885 CpuMpData
->BackupBufferSize
888 (VOID
*) CpuMpData
->WakeupBuffer
,
889 (VOID
*) CpuMpData
->AddressMap
.RendezvousFunnelAddress
,
890 CpuMpData
->AddressMap
.RendezvousFunnelSize
895 Restore wakeup buffer data.
897 @param[in] CpuMpData The pointer to CPU MP Data structure.
901 IN CPU_MP_DATA
*CpuMpData
905 (VOID
*) CpuMpData
->WakeupBuffer
,
906 (VOID
*) CpuMpData
->BackupBuffer
,
907 CpuMpData
->BackupBufferSize
912 Allocate reset vector buffer.
914 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
917 AllocateResetVector (
918 IN OUT CPU_MP_DATA
*CpuMpData
921 UINTN ApResetVectorSize
;
923 if (CpuMpData
->WakeupBuffer
== (UINTN
) -1) {
924 ApResetVectorSize
= CpuMpData
->AddressMap
.RendezvousFunnelSize
+
925 sizeof (MP_CPU_EXCHANGE_INFO
);
927 CpuMpData
->WakeupBuffer
= GetWakeupBuffer (ApResetVectorSize
);
928 CpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
)
929 (CpuMpData
->WakeupBuffer
+ CpuMpData
->AddressMap
.RendezvousFunnelSize
);
930 CpuMpData
->WakeupBufferHigh
= GetModeTransitionBuffer (
931 CpuMpData
->AddressMap
.RendezvousFunnelSize
-
932 CpuMpData
->AddressMap
.ModeTransitionOffset
935 BackupAndPrepareWakeupBuffer (CpuMpData
);
939 Free AP reset vector buffer.
941 @param[in] CpuMpData The pointer to CPU MP Data structure.
945 IN CPU_MP_DATA
*CpuMpData
948 RestoreWakeupBuffer (CpuMpData
);
952 This function will be called by BSP to wakeup AP.
954 @param[in] CpuMpData Pointer to CPU MP Data
955 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
956 FALSE: Send IPI to AP by ApicId
957 @param[in] ProcessorNumber The handle number of specified processor
958 @param[in] Procedure The function to be invoked by AP
959 @param[in] ProcedureArgument The argument to be passed into AP function
963 IN CPU_MP_DATA
*CpuMpData
,
964 IN BOOLEAN Broadcast
,
965 IN UINTN ProcessorNumber
,
966 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
967 IN VOID
*ProcedureArgument OPTIONAL
970 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
972 CPU_AP_DATA
*CpuData
;
973 BOOLEAN ResetVectorRequired
;
974 CPU_INFO_IN_HOB
*CpuInfoInHob
;
976 CpuMpData
->FinishedCount
= 0;
977 ResetVectorRequired
= FALSE
;
979 if (CpuMpData
->ApLoopMode
== ApInHltLoop
||
980 CpuMpData
->InitFlag
!= ApInitDone
) {
981 ResetVectorRequired
= TRUE
;
982 AllocateResetVector (CpuMpData
);
983 FillExchangeInfoData (CpuMpData
);
984 SaveLocalApicTimerSetting (CpuMpData
);
985 } else if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
987 // Get AP target C-state each time when waking up AP,
988 // for it maybe updated by platform again
990 CpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
993 ExchangeInfo
= CpuMpData
->MpCpuExchangeInfo
;
996 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
997 if (Index
!= CpuMpData
->BspNumber
) {
998 CpuData
= &CpuMpData
->CpuData
[Index
];
999 CpuData
->ApFunction
= (UINTN
) Procedure
;
1000 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
1001 SetApState (CpuData
, CpuStateReady
);
1002 if (CpuMpData
->InitFlag
!= ApInitConfig
) {
1003 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
1007 if (ResetVectorRequired
) {
1011 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
1013 if (CpuMpData
->InitFlag
== ApInitConfig
) {
1015 // Here support two methods to collect AP count through adjust
1016 // PcdCpuApInitTimeOutInMicroSeconds values.
1018 // one way is set a value to just let the first AP to start the
1019 // initialization, then through the later while loop to wait all Aps
1020 // finsh the initialization.
1021 // The other way is set a value to let all APs finished the initialzation.
1022 // In this case, the later while loop is useless.
1024 TimedWaitForApFinish (
1026 PcdGet32 (PcdCpuMaxLogicalProcessorNumber
) - 1,
1027 PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
)
1030 while (CpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
!= 0) {
1035 // Wait all APs waken up if this is not the 1st broadcast of SIPI
1037 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1038 CpuData
= &CpuMpData
->CpuData
[Index
];
1039 if (Index
!= CpuMpData
->BspNumber
) {
1040 WaitApWakeup (CpuData
->StartupApSignal
);
1045 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1046 CpuData
->ApFunction
= (UINTN
) Procedure
;
1047 CpuData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
1048 SetApState (CpuData
, CpuStateReady
);
1050 // Wakeup specified AP
1052 ASSERT (CpuMpData
->InitFlag
!= ApInitConfig
);
1053 *(UINT32
*) CpuData
->StartupApSignal
= WAKEUP_AP_SIGNAL
;
1054 if (ResetVectorRequired
) {
1055 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
1057 CpuInfoInHob
[ProcessorNumber
].ApicId
,
1058 (UINT32
) ExchangeInfo
->BufferStart
1062 // Wait specified AP waken up
1064 WaitApWakeup (CpuData
->StartupApSignal
);
1067 if (ResetVectorRequired
) {
1068 FreeResetVector (CpuMpData
);
1073 Calculate timeout value and return the current performance counter value.
1075 Calculate the number of performance counter ticks required for a timeout.
1076 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1079 @param[in] TimeoutInMicroseconds Timeout value in microseconds.
1080 @param[out] CurrentTime Returns the current value of the performance counter.
1082 @return Expected time stamp counter for timeout.
1083 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1089 IN UINTN TimeoutInMicroseconds
,
1090 OUT UINT64
*CurrentTime
1093 UINT64 TimeoutInSeconds
;
1094 UINT64 TimestampCounterFreq
;
1097 // Read the current value of the performance counter
1099 *CurrentTime
= GetPerformanceCounter ();
1102 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1105 if (TimeoutInMicroseconds
== 0) {
1110 // GetPerformanceCounterProperties () returns the timestamp counter's frequency
1113 TimestampCounterFreq
= GetPerformanceCounterProperties (NULL
, NULL
);
1116 // Check the potential overflow before calculate the number of ticks for the timeout value.
1118 if (DivU64x64Remainder (MAX_UINT64
, TimeoutInMicroseconds
, NULL
) < TimestampCounterFreq
) {
1120 // Convert microseconds into seconds if direct multiplication overflows
1122 TimeoutInSeconds
= DivU64x32 (TimeoutInMicroseconds
, 1000000);
1124 // Assertion if the final tick count exceeds MAX_UINT64
1126 ASSERT (DivU64x64Remainder (MAX_UINT64
, TimeoutInSeconds
, NULL
) >= TimestampCounterFreq
);
1127 return MultU64x64 (TimestampCounterFreq
, TimeoutInSeconds
);
1130 // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
1131 // it by 1,000,000, to get the number of ticks for the timeout value.
1135 TimestampCounterFreq
,
1136 TimeoutInMicroseconds
1144 Checks whether timeout expires.
1146 Check whether the number of elapsed performance counter ticks required for
1147 a timeout condition has been reached.
1148 If Timeout is zero, which means infinity, return value is always FALSE.
1150 @param[in, out] PreviousTime On input, the value of the performance counter
1151 when it was last read.
1152 On output, the current value of the performance
1154 @param[in] TotalTime The total amount of elapsed time in performance
1156 @param[in] Timeout The number of performance counter ticks required
1157 to reach a timeout condition.
1159 @retval TRUE A timeout condition has been reached.
1160 @retval FALSE A timeout condition has not been reached.
1165 IN OUT UINT64
*PreviousTime
,
1166 IN UINT64
*TotalTime
,
1179 GetPerformanceCounterProperties (&Start
, &End
);
1180 Cycle
= End
- Start
;
1185 CurrentTime
= GetPerformanceCounter();
1186 Delta
= (INT64
) (CurrentTime
- *PreviousTime
);
1193 *TotalTime
+= Delta
;
1194 *PreviousTime
= CurrentTime
;
1195 if (*TotalTime
> Timeout
) {
1202 Helper function that waits until the finished AP count reaches the specified
1203 limit, or the specified timeout elapses (whichever comes first).
1205 @param[in] CpuMpData Pointer to CPU MP Data.
1206 @param[in] FinishedApLimit The number of finished APs to wait for.
1207 @param[in] TimeLimit The number of microseconds to wait for.
1210 TimedWaitForApFinish (
1211 IN CPU_MP_DATA
*CpuMpData
,
1212 IN UINT32 FinishedApLimit
,
1217 // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
1218 // "infinity", so check for (TimeLimit == 0) explicitly.
1220 if (TimeLimit
== 0) {
1224 CpuMpData
->TotalTime
= 0;
1225 CpuMpData
->ExpectedTime
= CalculateTimeout (
1227 &CpuMpData
->CurrentTime
1229 while (CpuMpData
->FinishedCount
< FinishedApLimit
&&
1231 &CpuMpData
->CurrentTime
,
1232 &CpuMpData
->TotalTime
,
1233 CpuMpData
->ExpectedTime
1238 if (CpuMpData
->FinishedCount
>= FinishedApLimit
) {
1241 "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
1244 DivU64x64Remainder (
1245 MultU64x32 (CpuMpData
->TotalTime
, 1000000),
1246 GetPerformanceCounterProperties (NULL
, NULL
),
1254 Reset an AP to Idle state.
1256 Any task being executed by the AP will be aborted and the AP
1257 will be waiting for a new task in Wait-For-SIPI state.
1259 @param[in] ProcessorNumber The handle number of processor.
1262 ResetProcessorToIdleState (
1263 IN UINTN ProcessorNumber
1266 CPU_MP_DATA
*CpuMpData
;
1268 CpuMpData
= GetCpuMpData ();
1270 CpuMpData
->InitFlag
= ApInitReconfig
;
1271 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, NULL
, NULL
);
1272 while (CpuMpData
->FinishedCount
< 1) {
1275 CpuMpData
->InitFlag
= ApInitDone
;
1277 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
1281 Searches for the next waiting AP.
1283 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
1285 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
1287 @retval EFI_SUCCESS The next waiting AP has been found.
1288 @retval EFI_NOT_FOUND No waiting AP exists.
1292 GetNextWaitingProcessorNumber (
1293 OUT UINTN
*NextProcessorNumber
1296 UINTN ProcessorNumber
;
1297 CPU_MP_DATA
*CpuMpData
;
1299 CpuMpData
= GetCpuMpData ();
1301 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1302 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1303 *NextProcessorNumber
= ProcessorNumber
;
1308 return EFI_NOT_FOUND
;
1311 /** Checks status of specified AP.
1313 This function checks whether the specified AP has finished the task assigned
1314 by StartupThisAP(), and whether timeout expires.
1316 @param[in] ProcessorNumber The handle number of processor.
1318 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
1319 @retval EFI_TIMEOUT The timeout expires.
1320 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
1324 IN UINTN ProcessorNumber
1327 CPU_MP_DATA
*CpuMpData
;
1328 CPU_AP_DATA
*CpuData
;
1330 CpuMpData
= GetCpuMpData ();
1331 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1334 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
1335 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1336 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
1339 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
1341 if (GetApState(CpuData
) == CpuStateFinished
) {
1342 if (CpuData
->Finished
!= NULL
) {
1343 *(CpuData
->Finished
) = TRUE
;
1345 SetApState (CpuData
, CpuStateIdle
);
1349 // If timeout expires for StartupThisAP(), report timeout.
1351 if (CheckTimeout (&CpuData
->CurrentTime
, &CpuData
->TotalTime
, CpuData
->ExpectedTime
)) {
1352 if (CpuData
->Finished
!= NULL
) {
1353 *(CpuData
->Finished
) = FALSE
;
1356 // Reset failed AP to idle state
1358 ResetProcessorToIdleState (ProcessorNumber
);
1363 return EFI_NOT_READY
;
1367 Checks status of all APs.
1369 This function checks whether all APs have finished task assigned by StartupAllAPs(),
1370 and whether timeout expires.
1372 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
1373 @retval EFI_TIMEOUT The timeout expires.
1374 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
1381 UINTN ProcessorNumber
;
1382 UINTN NextProcessorNumber
;
1385 CPU_MP_DATA
*CpuMpData
;
1386 CPU_AP_DATA
*CpuData
;
1388 CpuMpData
= GetCpuMpData ();
1390 NextProcessorNumber
= 0;
1393 // Go through all APs that are responsible for the StartupAllAPs().
1395 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1396 if (!CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1400 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
1402 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
1403 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1404 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
1406 if (GetApState(CpuData
) == CpuStateFinished
) {
1407 CpuMpData
->RunningCount
++;
1408 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
1409 SetApState(CpuData
, CpuStateIdle
);
1412 // If in Single Thread mode, then search for the next waiting AP for execution.
1414 if (CpuMpData
->SingleThread
) {
1415 Status
= GetNextWaitingProcessorNumber (&NextProcessorNumber
);
1417 if (!EFI_ERROR (Status
)) {
1421 (UINT32
) NextProcessorNumber
,
1422 CpuMpData
->Procedure
,
1423 CpuMpData
->ProcArguments
1431 // If all APs finish, return EFI_SUCCESS.
1433 if (CpuMpData
->RunningCount
== CpuMpData
->StartCount
) {
1438 // If timeout expires, report timeout.
1441 &CpuMpData
->CurrentTime
,
1442 &CpuMpData
->TotalTime
,
1443 CpuMpData
->ExpectedTime
)
1446 // If FailedCpuList is not NULL, record all failed APs in it.
1448 if (CpuMpData
->FailedCpuList
!= NULL
) {
1449 *CpuMpData
->FailedCpuList
=
1450 AllocatePool ((CpuMpData
->StartCount
- CpuMpData
->FinishedCount
+ 1) * sizeof (UINTN
));
1451 ASSERT (*CpuMpData
->FailedCpuList
!= NULL
);
1455 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
1457 // Check whether this processor is responsible for StartupAllAPs().
1459 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
1461 // Reset failed APs to idle state
1463 ResetProcessorToIdleState (ProcessorNumber
);
1464 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
1465 if (CpuMpData
->FailedCpuList
!= NULL
) {
1466 (*CpuMpData
->FailedCpuList
)[ListIndex
++] = ProcessorNumber
;
1470 if (CpuMpData
->FailedCpuList
!= NULL
) {
1471 (*CpuMpData
->FailedCpuList
)[ListIndex
] = END_OF_CPU_LIST
;
1475 return EFI_NOT_READY
;
1479 MP Initialize Library initialization.
1481 This service will allocate AP reset vector and wakeup all APs to do APs
1484 This service must be invoked before all other MP Initialize Library
1485 service are invoked.
1487 @retval EFI_SUCCESS MP initialization succeeds.
1488 @retval Others MP initialization fails.
1493 MpInitLibInitialize (
1497 CPU_MP_DATA
*OldCpuMpData
;
1498 CPU_INFO_IN_HOB
*CpuInfoInHob
;
1499 UINT32 MaxLogicalProcessorNumber
;
1501 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
1503 UINT32 MonitorFilterSize
;
1506 CPU_MP_DATA
*CpuMpData
;
1508 UINT8
*MonitorBuffer
;
1510 UINTN ApResetVectorSize
;
1511 UINTN BackupBufferAddr
;
1513 OldCpuMpData
= GetCpuMpDataFromGuidedHob ();
1514 if (OldCpuMpData
== NULL
) {
1515 MaxLogicalProcessorNumber
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
1517 MaxLogicalProcessorNumber
= OldCpuMpData
->CpuCount
;
1519 ASSERT (MaxLogicalProcessorNumber
!= 0);
1521 AsmGetAddressMap (&AddressMap
);
1522 ApResetVectorSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
1523 ApStackSize
= PcdGet32(PcdCpuApStackSize
);
1524 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
1526 BufferSize
= ApStackSize
* MaxLogicalProcessorNumber
;
1527 BufferSize
+= MonitorFilterSize
* MaxLogicalProcessorNumber
;
1528 BufferSize
+= sizeof (CPU_MP_DATA
);
1529 BufferSize
+= ApResetVectorSize
;
1530 BufferSize
+= (sizeof (CPU_AP_DATA
) + sizeof (CPU_INFO_IN_HOB
))* MaxLogicalProcessorNumber
;
1531 MpBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (BufferSize
));
1532 ASSERT (MpBuffer
!= NULL
);
1533 ZeroMem (MpBuffer
, BufferSize
);
1534 Buffer
= (UINTN
) MpBuffer
;
1536 MonitorBuffer
= (UINT8
*) (Buffer
+ ApStackSize
* MaxLogicalProcessorNumber
);
1537 BackupBufferAddr
= (UINTN
) MonitorBuffer
+ MonitorFilterSize
* MaxLogicalProcessorNumber
;
1538 CpuMpData
= (CPU_MP_DATA
*) (BackupBufferAddr
+ ApResetVectorSize
);
1539 CpuMpData
->Buffer
= Buffer
;
1540 CpuMpData
->CpuApStackSize
= ApStackSize
;
1541 CpuMpData
->BackupBuffer
= BackupBufferAddr
;
1542 CpuMpData
->BackupBufferSize
= ApResetVectorSize
;
1543 CpuMpData
->WakeupBuffer
= (UINTN
) -1;
1544 CpuMpData
->CpuCount
= 1;
1545 CpuMpData
->BspNumber
= 0;
1546 CpuMpData
->WaitEvent
= NULL
;
1547 CpuMpData
->SwitchBspFlag
= FALSE
;
1548 CpuMpData
->CpuData
= (CPU_AP_DATA
*) (CpuMpData
+ 1);
1549 CpuMpData
->CpuInfoInHob
= (UINT64
) (UINTN
) (CpuMpData
->CpuData
+ MaxLogicalProcessorNumber
);
1550 CpuMpData
->MicrocodePatchAddress
= PcdGet64 (PcdCpuMicrocodePatchAddress
);
1551 CpuMpData
->MicrocodePatchRegionSize
= PcdGet64 (PcdCpuMicrocodePatchRegionSize
);
1552 InitializeSpinLock(&CpuMpData
->MpLock
);
1554 // Save BSP's Control registers to APs
1556 SaveVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
);
1558 // Set BSP basic information
1560 InitializeApData (CpuMpData
, 0, 0, CpuMpData
->Buffer
+ ApStackSize
);
1562 // Save assembly code information
1564 CopyMem (&CpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
1566 // Finally set AP loop mode
1568 CpuMpData
->ApLoopMode
= ApLoopMode
;
1569 DEBUG ((DEBUG_INFO
, "AP Loop Mode is %d\n", CpuMpData
->ApLoopMode
));
1571 // Set up APs wakeup signal buffer
1573 for (Index
= 0; Index
< MaxLogicalProcessorNumber
; Index
++) {
1574 CpuMpData
->CpuData
[Index
].StartupApSignal
=
1575 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
1578 // Load Microcode on BSP
1580 MicrocodeDetect (CpuMpData
);
1582 // Store BSP's MTRR setting
1584 MtrrGetAllMtrrs (&CpuMpData
->MtrrTable
);
1586 // Enable the local APIC for Virtual Wire Mode.
1588 ProgramVirtualWireMode ();
1590 if (OldCpuMpData
== NULL
) {
1591 if (MaxLogicalProcessorNumber
> 1) {
1593 // Wakeup all APs and calculate the processor count in system
1595 CollectProcessorCount (CpuMpData
);
1599 // APs have been wakeup before, just get the CPU Information
1602 CpuMpData
->CpuCount
= OldCpuMpData
->CpuCount
;
1603 CpuMpData
->BspNumber
= OldCpuMpData
->BspNumber
;
1604 CpuMpData
->InitFlag
= ApInitReconfig
;
1605 CpuMpData
->CpuInfoInHob
= OldCpuMpData
->CpuInfoInHob
;
1606 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
1607 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1608 InitializeSpinLock(&CpuMpData
->CpuData
[Index
].ApLock
);
1609 if (CpuInfoInHob
[Index
].InitialApicId
>= 255 || Index
> 254) {
1610 CpuMpData
->X2ApicEnable
= TRUE
;
1612 CpuMpData
->CpuData
[Index
].CpuHealthy
= (CpuInfoInHob
[Index
].Health
== 0)? TRUE
:FALSE
;
1613 CpuMpData
->CpuData
[Index
].ApFunction
= 0;
1615 &CpuMpData
->CpuData
[Index
].VolatileRegisters
,
1616 &CpuMpData
->CpuData
[0].VolatileRegisters
,
1617 sizeof (CPU_VOLATILE_REGISTERS
)
1620 if (MaxLogicalProcessorNumber
> 1) {
1622 // Wakeup APs to do some AP initialize sync
1624 WakeUpAP (CpuMpData
, TRUE
, 0, ApInitializeSync
, CpuMpData
);
1626 // Wait for all APs finished initialization
1628 while (CpuMpData
->FinishedCount
< (CpuMpData
->CpuCount
- 1)) {
1631 CpuMpData
->InitFlag
= ApInitDone
;
1632 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
1633 SetApState (&CpuMpData
->CpuData
[Index
], CpuStateIdle
);
1639 // Initialize global data for MP support
1641 InitMpGlobalData (CpuMpData
);
1647 Gets detailed MP-related information on the requested processor at the
1648 instant this call is made. This service may only be called from the BSP.
1650 @param[in] ProcessorNumber The handle number of processor.
1651 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
1652 the requested processor is deposited.
1653 @param[out] HealthData Return processor health data.
1655 @retval EFI_SUCCESS Processor information was returned.
1656 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1657 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
1658 @retval EFI_NOT_FOUND The processor with the handle specified by
1659 ProcessorNumber does not exist in the platform.
1660 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1665 MpInitLibGetProcessorInfo (
1666 IN UINTN ProcessorNumber
,
1667 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
,
1668 OUT EFI_HEALTH_FLAGS
*HealthData OPTIONAL
1671 CPU_MP_DATA
*CpuMpData
;
1673 CPU_INFO_IN_HOB
*CpuInfoInHob
;
1675 CpuMpData
= GetCpuMpData ();
1676 CpuInfoInHob
= (CPU_INFO_IN_HOB
*) (UINTN
) CpuMpData
->CpuInfoInHob
;
1679 // Check whether caller processor is BSP
1681 MpInitLibWhoAmI (&CallerNumber
);
1682 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1683 return EFI_DEVICE_ERROR
;
1686 if (ProcessorInfoBuffer
== NULL
) {
1687 return EFI_INVALID_PARAMETER
;
1690 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1691 return EFI_NOT_FOUND
;
1694 ProcessorInfoBuffer
->ProcessorId
= (UINT64
) CpuInfoInHob
[ProcessorNumber
].ApicId
;
1695 ProcessorInfoBuffer
->StatusFlag
= 0;
1696 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1697 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_AS_BSP_BIT
;
1699 if (CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
) {
1700 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_HEALTH_STATUS_BIT
;
1702 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
1703 ProcessorInfoBuffer
->StatusFlag
&= ~PROCESSOR_ENABLED_BIT
;
1705 ProcessorInfoBuffer
->StatusFlag
|= PROCESSOR_ENABLED_BIT
;
1709 // Get processor location information
1711 GetProcessorLocationByApicId (
1712 CpuInfoInHob
[ProcessorNumber
].ApicId
,
1713 &ProcessorInfoBuffer
->Location
.Package
,
1714 &ProcessorInfoBuffer
->Location
.Core
,
1715 &ProcessorInfoBuffer
->Location
.Thread
1718 if (HealthData
!= NULL
) {
1719 HealthData
->Uint32
= CpuInfoInHob
[ProcessorNumber
].Health
;
1726 Worker function to switch the requested AP to be the BSP from that point onward.
1728 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
1729 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
1730 enabled AP. Otherwise, it will be disabled.
1732 @retval EFI_SUCCESS BSP successfully switched.
1733 @retval others Failed to switch BSP.
1738 IN UINTN ProcessorNumber
,
1739 IN BOOLEAN EnableOldBSP
1742 CPU_MP_DATA
*CpuMpData
;
1745 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
1746 BOOLEAN OldInterruptState
;
1747 BOOLEAN OldTimerInterruptState
;
1750 // Save and Disable Local APIC timer interrupt
1752 OldTimerInterruptState
= GetApicTimerInterruptState ();
1753 DisableApicTimerInterrupt ();
1755 // Before send both BSP and AP to a procedure to exchange their roles,
1756 // interrupt must be disabled. This is because during the exchange role
1757 // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
1758 // be corrupted, since interrupt return address will be pushed to stack
1761 OldInterruptState
= SaveAndDisableInterrupts ();
1764 // Mask LINT0 & LINT1 for the old BSP
1766 DisableLvtInterrupts ();
1768 CpuMpData
= GetCpuMpData ();
1771 // Check whether caller processor is BSP
1773 MpInitLibWhoAmI (&CallerNumber
);
1774 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1775 return EFI_DEVICE_ERROR
;
1778 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1779 return EFI_NOT_FOUND
;
1783 // Check whether specified AP is disabled
1785 State
= GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]);
1786 if (State
== CpuStateDisabled
) {
1787 return EFI_INVALID_PARAMETER
;
1791 // Check whether ProcessorNumber specifies the current BSP
1793 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1794 return EFI_INVALID_PARAMETER
;
1798 // Check whether specified AP is busy
1800 if (State
== CpuStateBusy
) {
1801 return EFI_NOT_READY
;
1804 CpuMpData
->BSPInfo
.State
= CPU_SWITCH_STATE_IDLE
;
1805 CpuMpData
->APInfo
.State
= CPU_SWITCH_STATE_IDLE
;
1806 CpuMpData
->SwitchBspFlag
= TRUE
;
1807 CpuMpData
->NewBspNumber
= ProcessorNumber
;
1810 // Clear the BSP bit of MSR_IA32_APIC_BASE
1812 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
1813 ApicBaseMsr
.Bits
.BSP
= 0;
1814 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
1817 // Need to wakeUp AP (future BSP).
1819 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, FutureBSPProc
, CpuMpData
);
1821 AsmExchangeRole (&CpuMpData
->BSPInfo
, &CpuMpData
->APInfo
);
1824 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
1826 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
1827 ApicBaseMsr
.Bits
.BSP
= 1;
1828 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
1829 ProgramVirtualWireMode ();
1832 // Wait for old BSP finished AP task
1834 while (GetApState (&CpuMpData
->CpuData
[CallerNumber
]) != CpuStateFinished
) {
1838 CpuMpData
->SwitchBspFlag
= FALSE
;
1840 // Set old BSP enable state
1842 if (!EnableOldBSP
) {
1843 SetApState (&CpuMpData
->CpuData
[CallerNumber
], CpuStateDisabled
);
1845 SetApState (&CpuMpData
->CpuData
[CallerNumber
], CpuStateIdle
);
1848 // Save new BSP number
1850 CpuMpData
->BspNumber
= (UINT32
) ProcessorNumber
;
1853 // Restore interrupt state.
1855 SetInterruptState (OldInterruptState
);
1857 if (OldTimerInterruptState
) {
1858 EnableApicTimerInterrupt ();
1865 Worker function to let the caller enable or disable an AP from this point onward.
1866 This service may only be called from the BSP.
1868 @param[in] ProcessorNumber The handle number of AP.
1869 @param[in] EnableAP Specifies the new state for the processor for
1870 enabled, FALSE for disabled.
1871 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
1872 the new health status of the AP.
1874 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
1875 @retval others Failed to Enable/Disable AP.
1879 EnableDisableApWorker (
1880 IN UINTN ProcessorNumber
,
1881 IN BOOLEAN EnableAP
,
1882 IN UINT32
*HealthFlag OPTIONAL
1885 CPU_MP_DATA
*CpuMpData
;
1888 CpuMpData
= GetCpuMpData ();
1891 // Check whether caller processor is BSP
1893 MpInitLibWhoAmI (&CallerNumber
);
1894 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1895 return EFI_DEVICE_ERROR
;
1898 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
1899 return EFI_INVALID_PARAMETER
;
1902 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
1903 return EFI_NOT_FOUND
;
1907 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateDisabled
);
1909 ResetProcessorToIdleState (ProcessorNumber
);
1912 if (HealthFlag
!= NULL
) {
1913 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
=
1914 (BOOLEAN
) ((*HealthFlag
& PROCESSOR_HEALTH_STATUS_BIT
) != 0);
1921 This return the handle number for the calling processor. This service may be
1922 called from the BSP and APs.
1924 @param[out] ProcessorNumber Pointer to the handle number of AP.
1925 The range is from 0 to the total number of
1926 logical processors minus 1. The total number of
1927 logical processors can be retrieved by
1928 MpInitLibGetNumberOfProcessors().
1930 @retval EFI_SUCCESS The current processor handle number was returned
1932 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1933 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1939 OUT UINTN
*ProcessorNumber
1942 CPU_MP_DATA
*CpuMpData
;
1944 if (ProcessorNumber
== NULL
) {
1945 return EFI_INVALID_PARAMETER
;
1948 CpuMpData
= GetCpuMpData ();
1950 return GetProcessorNumber (CpuMpData
, ProcessorNumber
);
1954 Retrieves the number of logical processor in the platform and the number of
1955 those logical processors that are enabled on this boot. This service may only
1956 be called from the BSP.
1958 @param[out] NumberOfProcessors Pointer to the total number of logical
1959 processors in the system, including the BSP
1961 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
1962 processors that exist in system, including
1965 @retval EFI_SUCCESS The number of logical processors and enabled
1966 logical processors was retrieved.
1967 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1968 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
1970 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1975 MpInitLibGetNumberOfProcessors (
1976 OUT UINTN
*NumberOfProcessors
, OPTIONAL
1977 OUT UINTN
*NumberOfEnabledProcessors OPTIONAL
1980 CPU_MP_DATA
*CpuMpData
;
1982 UINTN ProcessorNumber
;
1983 UINTN EnabledProcessorNumber
;
1986 CpuMpData
= GetCpuMpData ();
1988 if ((NumberOfProcessors
== NULL
) && (NumberOfEnabledProcessors
== NULL
)) {
1989 return EFI_INVALID_PARAMETER
;
1993 // Check whether caller processor is BSP
1995 MpInitLibWhoAmI (&CallerNumber
);
1996 if (CallerNumber
!= CpuMpData
->BspNumber
) {
1997 return EFI_DEVICE_ERROR
;
2000 ProcessorNumber
= CpuMpData
->CpuCount
;
2001 EnabledProcessorNumber
= 0;
2002 for (Index
= 0; Index
< ProcessorNumber
; Index
++) {
2003 if (GetApState (&CpuMpData
->CpuData
[Index
]) != CpuStateDisabled
) {
2004 EnabledProcessorNumber
++;
2008 if (NumberOfProcessors
!= NULL
) {
2009 *NumberOfProcessors
= ProcessorNumber
;
2011 if (NumberOfEnabledProcessors
!= NULL
) {
2012 *NumberOfEnabledProcessors
= EnabledProcessorNumber
;
2020 Worker function to execute a caller provided function on all enabled APs.
2022 @param[in] Procedure A pointer to the function to be run on
2023 enabled APs of the system.
2024 @param[in] SingleThread If TRUE, then all the enabled APs execute
2025 the function specified by Procedure one by
2026 one, in ascending order of processor handle
2027 number. If FALSE, then all the enabled APs
2028 execute the function specified by Procedure
2030 @param[in] WaitEvent The event created by the caller with CreateEvent()
2032 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2033 APs to return from Procedure, either for
2034 blocking or non-blocking mode.
2035 @param[in] ProcedureArgument The parameter passed into Procedure for
2037 @param[out] FailedCpuList If all APs finish successfully, then its
2038 content is set to NULL. If not all APs
2039 finish before timeout expires, then its
2040 content is set to address of the buffer
2041 holding handle numbers of the failed APs.
2043 @retval EFI_SUCCESS In blocking mode, all APs have finished before
2044 the timeout expired.
2045 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2047 @retval others Failed to Startup all APs.
2051 StartupAllAPsWorker (
2052 IN EFI_AP_PROCEDURE Procedure
,
2053 IN BOOLEAN SingleThread
,
2054 IN EFI_EVENT WaitEvent OPTIONAL
,
2055 IN UINTN TimeoutInMicroseconds
,
2056 IN VOID
*ProcedureArgument OPTIONAL
,
2057 OUT UINTN
**FailedCpuList OPTIONAL
2061 CPU_MP_DATA
*CpuMpData
;
2062 UINTN ProcessorCount
;
2063 UINTN ProcessorNumber
;
2065 CPU_AP_DATA
*CpuData
;
2066 BOOLEAN HasEnabledAp
;
2069 CpuMpData
= GetCpuMpData ();
2071 if (FailedCpuList
!= NULL
) {
2072 *FailedCpuList
= NULL
;
2075 if (CpuMpData
->CpuCount
== 1) {
2076 return EFI_NOT_STARTED
;
2079 if (Procedure
== NULL
) {
2080 return EFI_INVALID_PARAMETER
;
2084 // Check whether caller processor is BSP
2086 MpInitLibWhoAmI (&CallerNumber
);
2087 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2088 return EFI_DEVICE_ERROR
;
2094 CheckAndUpdateApsStatus ();
2096 ProcessorCount
= CpuMpData
->CpuCount
;
2097 HasEnabledAp
= FALSE
;
2099 // Check whether all enabled APs are idle.
2100 // If any enabled AP is not idle, return EFI_NOT_READY.
2102 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2103 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2104 if (ProcessorNumber
!= CpuMpData
->BspNumber
) {
2105 ApState
= GetApState (CpuData
);
2106 if (ApState
!= CpuStateDisabled
) {
2107 HasEnabledAp
= TRUE
;
2108 if (ApState
!= CpuStateIdle
) {
2110 // If any enabled APs are busy, return EFI_NOT_READY.
2112 return EFI_NOT_READY
;
2118 if (!HasEnabledAp
) {
2120 // If no enabled AP exists, return EFI_NOT_STARTED.
2122 return EFI_NOT_STARTED
;
2125 CpuMpData
->StartCount
= 0;
2126 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2127 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2128 CpuData
->Waiting
= FALSE
;
2129 if (ProcessorNumber
!= CpuMpData
->BspNumber
) {
2130 if (CpuData
->State
== CpuStateIdle
) {
2132 // Mark this processor as responsible for current calling.
2134 CpuData
->Waiting
= TRUE
;
2135 CpuMpData
->StartCount
++;
2140 CpuMpData
->Procedure
= Procedure
;
2141 CpuMpData
->ProcArguments
= ProcedureArgument
;
2142 CpuMpData
->SingleThread
= SingleThread
;
2143 CpuMpData
->FinishedCount
= 0;
2144 CpuMpData
->RunningCount
= 0;
2145 CpuMpData
->FailedCpuList
= FailedCpuList
;
2146 CpuMpData
->ExpectedTime
= CalculateTimeout (
2147 TimeoutInMicroseconds
,
2148 &CpuMpData
->CurrentTime
2150 CpuMpData
->TotalTime
= 0;
2151 CpuMpData
->WaitEvent
= WaitEvent
;
2153 if (!SingleThread
) {
2154 WakeUpAP (CpuMpData
, TRUE
, 0, Procedure
, ProcedureArgument
);
2156 for (ProcessorNumber
= 0; ProcessorNumber
< ProcessorCount
; ProcessorNumber
++) {
2157 if (ProcessorNumber
== CallerNumber
) {
2160 if (CpuMpData
->CpuData
[ProcessorNumber
].Waiting
) {
2161 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, Procedure
, ProcedureArgument
);
2167 Status
= EFI_SUCCESS
;
2168 if (WaitEvent
== NULL
) {
2170 Status
= CheckAllAPs ();
2171 } while (Status
== EFI_NOT_READY
);
2178 Worker function to let the caller get one enabled AP to execute a caller-provided
2181 @param[in] Procedure A pointer to the function to be run on
2182 enabled APs of the system.
2183 @param[in] ProcessorNumber The handle number of the AP.
2184 @param[in] WaitEvent The event created by the caller with CreateEvent()
2186 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2187 APs to return from Procedure, either for
2188 blocking or non-blocking mode.
2189 @param[in] ProcedureArgument The parameter passed into Procedure for
2191 @param[out] Finished If AP returns from Procedure before the
2192 timeout expires, its content is set to TRUE.
2193 Otherwise, the value is set to FALSE.
2195 @retval EFI_SUCCESS In blocking mode, specified AP finished before
2196 the timeout expires.
2197 @retval others Failed to Startup AP.
2201 StartupThisAPWorker (
2202 IN EFI_AP_PROCEDURE Procedure
,
2203 IN UINTN ProcessorNumber
,
2204 IN EFI_EVENT WaitEvent OPTIONAL
,
2205 IN UINTN TimeoutInMicroseconds
,
2206 IN VOID
*ProcedureArgument OPTIONAL
,
2207 OUT BOOLEAN
*Finished OPTIONAL
2211 CPU_MP_DATA
*CpuMpData
;
2212 CPU_AP_DATA
*CpuData
;
2215 CpuMpData
= GetCpuMpData ();
2217 if (Finished
!= NULL
) {
2222 // Check whether caller processor is BSP
2224 MpInitLibWhoAmI (&CallerNumber
);
2225 if (CallerNumber
!= CpuMpData
->BspNumber
) {
2226 return EFI_DEVICE_ERROR
;
2230 // Check whether processor with the handle specified by ProcessorNumber exists
2232 if (ProcessorNumber
>= CpuMpData
->CpuCount
) {
2233 return EFI_NOT_FOUND
;
2237 // Check whether specified processor is BSP
2239 if (ProcessorNumber
== CpuMpData
->BspNumber
) {
2240 return EFI_INVALID_PARAMETER
;
2244 // Check parameter Procedure
2246 if (Procedure
== NULL
) {
2247 return EFI_INVALID_PARAMETER
;
2253 CheckAndUpdateApsStatus ();
2256 // Check whether specified AP is disabled
2258 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateDisabled
) {
2259 return EFI_INVALID_PARAMETER
;
2263 // If WaitEvent is not NULL, execute in non-blocking mode.
2264 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
2265 // CheckAPsStatus() will check completion and timeout periodically.
2267 CpuData
= &CpuMpData
->CpuData
[ProcessorNumber
];
2268 CpuData
->WaitEvent
= WaitEvent
;
2269 CpuData
->Finished
= Finished
;
2270 CpuData
->ExpectedTime
= CalculateTimeout (TimeoutInMicroseconds
, &CpuData
->CurrentTime
);
2271 CpuData
->TotalTime
= 0;
2273 WakeUpAP (CpuMpData
, FALSE
, ProcessorNumber
, Procedure
, ProcedureArgument
);
2276 // If WaitEvent is NULL, execute in blocking mode.
2277 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
2279 Status
= EFI_SUCCESS
;
2280 if (WaitEvent
== NULL
) {
2282 Status
= CheckThisAP (ProcessorNumber
);
2283 } while (Status
== EFI_NOT_READY
);
2290 Get pointer to CPU MP Data structure from GUIDed HOB.
2292 @return The pointer to CPU MP Data structure.
2295 GetCpuMpDataFromGuidedHob (
2299 EFI_HOB_GUID_TYPE
*GuidHob
;
2301 CPU_MP_DATA
*CpuMpData
;
2304 GuidHob
= GetFirstGuidHob (&mCpuInitMpLibHobGuid
);
2305 if (GuidHob
!= NULL
) {
2306 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
2307 CpuMpData
= (CPU_MP_DATA
*) (*(UINTN
*) DataInHob
);