2 CPU MP Initialize Library common functions.
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 EFI_GUID mCpuInitMpLibHobGuid
= CPU_INIT_MP_LIB_HOB_GUID
;
20 Get the Application Processors state.
22 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
28 IN CPU_AP_DATA
*CpuData
31 return CpuData
->State
;
35 Set the Application Processors state.
37 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
38 @param[in] State The AP status
42 IN CPU_AP_DATA
*CpuData
,
46 AcquireSpinLock (&CpuData
->ApLock
);
47 CpuData
->State
= State
;
48 ReleaseSpinLock (&CpuData
->ApLock
);
52 Save the volatile registers required to be restored following INIT IPI.
54 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
57 SaveVolatileRegisters (
58 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
61 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
63 VolatileRegisters
->Cr0
= AsmReadCr0 ();
64 VolatileRegisters
->Cr3
= AsmReadCr3 ();
65 VolatileRegisters
->Cr4
= AsmReadCr4 ();
67 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
68 if (VersionInfoEdx
.Bits
.DE
!= 0) {
70 // If processor supports Debugging Extensions feature
71 // by CPUID.[EAX=01H]:EDX.BIT2
73 VolatileRegisters
->Dr0
= AsmReadDr0 ();
74 VolatileRegisters
->Dr1
= AsmReadDr1 ();
75 VolatileRegisters
->Dr2
= AsmReadDr2 ();
76 VolatileRegisters
->Dr3
= AsmReadDr3 ();
77 VolatileRegisters
->Dr6
= AsmReadDr6 ();
78 VolatileRegisters
->Dr7
= AsmReadDr7 ();
83 Restore the volatile registers following INIT IPI.
85 @param[in] VolatileRegisters Pointer to volatile resisters
86 @param[in] IsRestoreDr TRUE: Restore DRx if supported
87 FALSE: Do not restore DRx
90 RestoreVolatileRegisters (
91 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
92 IN BOOLEAN IsRestoreDr
95 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
97 AsmWriteCr0 (VolatileRegisters
->Cr0
);
98 AsmWriteCr3 (VolatileRegisters
->Cr3
);
99 AsmWriteCr4 (VolatileRegisters
->Cr4
);
102 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
103 if (VersionInfoEdx
.Bits
.DE
!= 0) {
105 // If processor supports Debugging Extensions feature
106 // by CPUID.[EAX=01H]:EDX.BIT2
108 AsmWriteDr0 (VolatileRegisters
->Dr0
);
109 AsmWriteDr1 (VolatileRegisters
->Dr1
);
110 AsmWriteDr2 (VolatileRegisters
->Dr2
);
111 AsmWriteDr3 (VolatileRegisters
->Dr3
);
112 AsmWriteDr6 (VolatileRegisters
->Dr6
);
113 AsmWriteDr7 (VolatileRegisters
->Dr7
);
119 Detect whether Mwait-monitor feature is supported.
121 @retval TRUE Mwait-monitor feature is supported.
122 @retval FALSE Mwait-monitor feature is not supported.
129 CPUID_VERSION_INFO_ECX VersionInfoEcx
;
131 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &VersionInfoEcx
.Uint32
, NULL
);
132 return (VersionInfoEcx
.Bits
.MONITOR
== 1) ? TRUE
: FALSE
;
138 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
140 @return The AP loop mode.
144 OUT UINT32
*MonitorFilterSize
148 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx
;
150 ASSERT (MonitorFilterSize
!= NULL
);
152 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
153 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
154 if (ApLoopMode
== ApInMwaitLoop
) {
155 if (!IsMwaitSupport ()) {
157 // If processor does not support MONITOR/MWAIT feature,
158 // force AP in Hlt-loop mode
160 ApLoopMode
= ApInHltLoop
;
164 if (ApLoopMode
!= ApInMwaitLoop
) {
165 *MonitorFilterSize
= sizeof (UINT32
);
168 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
169 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
171 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &MonitorMwaitEbx
.Uint32
, NULL
, NULL
);
172 *MonitorFilterSize
= MonitorMwaitEbx
.Bits
.LargestMonitorLineSize
;
181 @param[in, out] Buffer Pointer to private data buffer.
189 CPU_MP_DATA
*CpuMpData
;
191 CpuMpData
= (CPU_MP_DATA
*) Buffer
;
193 // Sync BSP's MTRR table to AP
195 MtrrSetAllMtrrs (&CpuMpData
->MtrrTable
);
197 // Load microcode on AP
199 MicrocodeDetect (CpuMpData
);
203 Find the current Processor number by APIC ID.
205 @param[in] CpuMpData Pointer to PEI CPU MP Data
206 @param[in] ProcessorNumber Return the pocessor number found
208 @retval EFI_SUCCESS ProcessorNumber is found and returned.
209 @retval EFI_NOT_FOUND ProcessorNumber is not found.
213 IN CPU_MP_DATA
*CpuMpData
,
214 OUT UINTN
*ProcessorNumber
217 UINTN TotalProcessorNumber
;
220 TotalProcessorNumber
= CpuMpData
->CpuCount
;
221 for (Index
= 0; Index
< TotalProcessorNumber
; Index
++) {
222 if (CpuMpData
->CpuData
[Index
].ApicId
== GetApicId ()) {
223 *ProcessorNumber
= Index
;
227 return EFI_NOT_FOUND
;
231 Initialize CPU AP Data when AP is wakeup at the first time.
233 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
234 @param[in] ProcessorNumber The handle number of processor
235 @param[in] BistData Processor BIST data
240 IN OUT CPU_MP_DATA
*CpuMpData
,
241 IN UINTN ProcessorNumber
,
245 CpuMpData
->CpuData
[ProcessorNumber
].Waiting
= FALSE
;
246 CpuMpData
->CpuData
[ProcessorNumber
].Health
= BistData
;
247 CpuMpData
->CpuData
[ProcessorNumber
].CpuHealthy
= (BistData
== 0) ? TRUE
: FALSE
;
248 CpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetApicId ();
249 CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
250 if (CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
>= 0xFF) {
252 // Set x2APIC mode if there are any logical processor reporting
253 // an Initial APIC ID of 255 or greater.
255 AcquireSpinLock(&CpuMpData
->MpLock
);
256 CpuMpData
->X2ApicEnable
= TRUE
;
257 ReleaseSpinLock(&CpuMpData
->MpLock
);
260 InitializeSpinLock(&CpuMpData
->CpuData
[ProcessorNumber
].ApLock
);
261 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateIdle
);
265 This function will be called from AP reset code if BSP uses WakeUpAP.
267 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
268 @param[in] NumApsExecuting Number of current executing AP
273 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
274 IN UINTN NumApsExecuting
277 CPU_MP_DATA
*CpuMpData
;
278 UINTN ProcessorNumber
;
279 EFI_AP_PROCEDURE Procedure
;
282 volatile UINT32
*ApStartupSignalBuffer
;
285 // AP finished assembly code and begin to execute C code
287 CpuMpData
= ExchangeInfo
->CpuMpData
;
289 ProgramVirtualWireMode ();
292 if (CpuMpData
->InitFlag
== ApInitConfig
) {
296 InterlockedIncrement ((UINT32
*) &CpuMpData
->CpuCount
);
297 ProcessorNumber
= NumApsExecuting
;
299 // This is first time AP wakeup, get BIST information from AP stack
301 BistData
= *(UINT32
*) (CpuMpData
->Buffer
+ ProcessorNumber
* CpuMpData
->CpuApStackSize
- sizeof (UINTN
));
303 // Do some AP initialize sync
305 ApInitializeSync (CpuMpData
);
307 // Sync BSP's Control registers to APs
309 RestoreVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
310 InitializeApData (CpuMpData
, ProcessorNumber
, BistData
);
311 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
314 // Execute AP function if AP is ready
316 GetProcessorNumber (CpuMpData
, &ProcessorNumber
);
318 // Clear AP start-up signal when AP waken up
320 ApStartupSignalBuffer
= CpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
321 InterlockedCompareExchange32 (
322 (UINT32
*) ApStartupSignalBuffer
,
326 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
328 // Restore AP's volatile registers saved
330 RestoreVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
333 if (GetApState (&CpuMpData
->CpuData
[ProcessorNumber
]) == CpuStateReady
) {
334 Procedure
= (EFI_AP_PROCEDURE
)CpuMpData
->CpuData
[ProcessorNumber
].ApFunction
;
335 Parameter
= (VOID
*) CpuMpData
->CpuData
[ProcessorNumber
].ApFunctionArgument
;
336 if (Procedure
!= NULL
) {
337 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateBusy
);
339 // Invoke AP function here
341 Procedure (Parameter
);
343 // Re-get the CPU APICID and Initial APICID
345 CpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetApicId ();
346 CpuMpData
->CpuData
[ProcessorNumber
].InitialApicId
= GetInitialApicId ();
348 SetApState (&CpuMpData
->CpuData
[ProcessorNumber
], CpuStateFinished
);
353 // AP finished executing C code
355 InterlockedIncrement ((UINT32
*) &CpuMpData
->FinishedCount
);
358 // Place AP is specified loop mode
360 if (CpuMpData
->ApLoopMode
== ApInHltLoop
) {
362 // Save AP volatile registers
364 SaveVolatileRegisters (&CpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
366 // Place AP in HLT-loop
369 DisableInterrupts ();
375 DisableInterrupts ();
376 if (CpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
378 // Place AP in MWAIT-loop
380 AsmMonitor ((UINTN
) ApStartupSignalBuffer
, 0, 0);
381 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
383 // Check AP start-up signal again.
384 // If AP start-up signal is not set, place AP into
385 // the specified C-state
387 AsmMwait (CpuMpData
->ApTargetCState
<< 4, 0);
389 } else if (CpuMpData
->ApLoopMode
== ApInRunLoop
) {
391 // Place AP in Run-loop
399 // If AP start-up signal is written, AP is waken up
400 // otherwise place AP in loop again
402 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
410 MP Initialize Library initialization.
412 This service will allocate AP reset vector and wakeup all APs to do APs
415 This service must be invoked before all other MP Initialize Library
418 @retval EFI_SUCCESS MP initialization succeeds.
419 @retval Others MP initialization fails.
424 MpInitLibInitialize (
428 UINT32 MaxLogicalProcessorNumber
;
430 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
432 UINT32 MonitorFilterSize
;
435 CPU_MP_DATA
*CpuMpData
;
437 UINT8
*MonitorBuffer
;
439 UINTN ApResetVectorSize
;
440 UINTN BackupBufferAddr
;
441 MaxLogicalProcessorNumber
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
443 AsmGetAddressMap (&AddressMap
);
444 ApResetVectorSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
445 ApStackSize
= PcdGet32(PcdCpuApStackSize
);
446 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
448 BufferSize
= ApStackSize
* MaxLogicalProcessorNumber
;
449 BufferSize
+= MonitorFilterSize
* MaxLogicalProcessorNumber
;
450 BufferSize
+= sizeof (CPU_MP_DATA
);
451 BufferSize
+= ApResetVectorSize
;
452 BufferSize
+= (sizeof (CPU_AP_DATA
) + sizeof (CPU_INFO_IN_HOB
))* MaxLogicalProcessorNumber
;
453 MpBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (BufferSize
));
454 ASSERT (MpBuffer
!= NULL
);
455 ZeroMem (MpBuffer
, BufferSize
);
456 Buffer
= (UINTN
) MpBuffer
;
458 MonitorBuffer
= (UINT8
*) (Buffer
+ ApStackSize
* MaxLogicalProcessorNumber
);
459 BackupBufferAddr
= (UINTN
) MonitorBuffer
+ MonitorFilterSize
* MaxLogicalProcessorNumber
;
460 CpuMpData
= (CPU_MP_DATA
*) (BackupBufferAddr
+ ApResetVectorSize
);
461 CpuMpData
->Buffer
= Buffer
;
462 CpuMpData
->CpuApStackSize
= ApStackSize
;
463 CpuMpData
->BackupBuffer
= BackupBufferAddr
;
464 CpuMpData
->BackupBufferSize
= ApResetVectorSize
;
465 CpuMpData
->EndOfPeiFlag
= FALSE
;
466 CpuMpData
->WakeupBuffer
= (UINTN
) -1;
467 CpuMpData
->CpuCount
= 1;
468 CpuMpData
->BspNumber
= 0;
469 CpuMpData
->WaitEvent
= NULL
;
470 CpuMpData
->CpuData
= (CPU_AP_DATA
*) (CpuMpData
+ 1);
471 CpuMpData
->CpuInfoInHob
= (UINT64
) (UINTN
) (CpuMpData
->CpuData
+ MaxLogicalProcessorNumber
);
472 InitializeSpinLock(&CpuMpData
->MpLock
);
474 // Save BSP's Control registers to APs
476 SaveVolatileRegisters (&CpuMpData
->CpuData
[0].VolatileRegisters
);
478 // Set BSP basic information
480 InitializeApData (CpuMpData
, 0, 0);
482 // Save assembly code information
484 CopyMem (&CpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
486 // Finally set AP loop mode
488 CpuMpData
->ApLoopMode
= ApLoopMode
;
489 DEBUG ((DEBUG_INFO
, "AP Loop Mode is %d\n", CpuMpData
->ApLoopMode
));
491 // Set up APs wakeup signal buffer
493 for (Index
= 0; Index
< MaxLogicalProcessorNumber
; Index
++) {
494 CpuMpData
->CpuData
[Index
].StartupApSignal
=
495 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
498 // Load Microcode on BSP
500 MicrocodeDetect (CpuMpData
);
502 // Store BSP's MTRR setting
504 MtrrGetAllMtrrs (&CpuMpData
->MtrrTable
);
508 // Initialize global data for MP support
510 InitMpGlobalData (CpuMpData
);
516 Gets detailed MP-related information on the requested processor at the
517 instant this call is made. This service may only be called from the BSP.
519 @param[in] ProcessorNumber The handle number of processor.
520 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
521 the requested processor is deposited.
522 @param[out] HealthData Return processor health data.
524 @retval EFI_SUCCESS Processor information was returned.
525 @retval EFI_DEVICE_ERROR The calling processor is an AP.
526 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
527 @retval EFI_NOT_FOUND The processor with the handle specified by
528 ProcessorNumber does not exist in the platform.
529 @retval EFI_NOT_READY MP Initialize Library is not initialized.
534 MpInitLibGetProcessorInfo (
535 IN UINTN ProcessorNumber
,
536 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
,
537 OUT EFI_HEALTH_FLAGS
*HealthData OPTIONAL
540 return EFI_UNSUPPORTED
;
543 This return the handle number for the calling processor. This service may be
544 called from the BSP and APs.
546 @param[out] ProcessorNumber Pointer to the handle number of AP.
547 The range is from 0 to the total number of
548 logical processors minus 1. The total number of
549 logical processors can be retrieved by
550 MpInitLibGetNumberOfProcessors().
552 @retval EFI_SUCCESS The current processor handle number was returned
554 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
555 @retval EFI_NOT_READY MP Initialize Library is not initialized.
561 OUT UINTN
*ProcessorNumber
564 return EFI_UNSUPPORTED
;
567 Retrieves the number of logical processor in the platform and the number of
568 those logical processors that are enabled on this boot. This service may only
569 be called from the BSP.
571 @param[out] NumberOfProcessors Pointer to the total number of logical
572 processors in the system, including the BSP
574 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
575 processors that exist in system, including
578 @retval EFI_SUCCESS The number of logical processors and enabled
579 logical processors was retrieved.
580 @retval EFI_DEVICE_ERROR The calling processor is an AP.
581 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
583 @retval EFI_NOT_READY MP Initialize Library is not initialized.
588 MpInitLibGetNumberOfProcessors (
589 OUT UINTN
*NumberOfProcessors
, OPTIONAL
590 OUT UINTN
*NumberOfEnabledProcessors OPTIONAL
593 return EFI_UNSUPPORTED
;
596 Get pointer to CPU MP Data structure from GUIDed HOB.
598 @return The pointer to CPU MP Data structure.
601 GetCpuMpDataFromGuidedHob (
605 EFI_HOB_GUID_TYPE
*GuidHob
;
607 CPU_MP_DATA
*CpuMpData
;
610 GuidHob
= GetFirstGuidHob (&mCpuInitMpLibHobGuid
);
611 if (GuidHob
!= NULL
) {
612 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
613 CpuMpData
= (CPU_MP_DATA
*) (*(UINTN
*) DataInHob
);