2 MP initialize support functions for DXE phase.
4 Copyright (c) 2016 - 2023, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Library/UefiLib.h>
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Library/DebugAgentLib.h>
14 #include <Library/DxeServicesTableLib.h>
15 #include <Library/CcExitLib.h>
16 #include <Register/Amd/Fam17Msr.h>
17 #include <Register/Amd/Ghcb.h>
19 #include <Protocol/Timer.h>
21 #define AP_SAFE_STACK_SIZE 128
23 CPU_MP_DATA
*mCpuMpData
= NULL
;
24 EFI_EVENT mCheckAllApsEvent
= NULL
;
25 EFI_EVENT mMpInitExitBootServicesEvent
= NULL
;
26 EFI_EVENT mLegacyBootEvent
= NULL
;
27 volatile BOOLEAN mStopCheckAllApsStatus
= TRUE
;
28 RELOCATE_AP_LOOP_ENTRY mReservedApLoop
;
29 UINTN mReservedTopOfApStack
;
30 volatile UINT32 mNumberToFinish
= 0;
34 // Begin wakeup buffer allocation below 0x88000
36 STATIC EFI_PHYSICAL_ADDRESS mSevEsDxeWakeupBuffer
= 0x88000;
39 Enable Debug Agent to support source debugging on AP function.
48 // Initialize Debug Agent to support source level debug in DXE phase
50 InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP
, NULL
, NULL
);
54 Get the pointer to CPU MP Data structure.
56 @return The pointer to CPU MP Data structure.
63 ASSERT (mCpuMpData
!= NULL
);
68 Save the pointer to CPU MP Data structure.
70 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
74 IN CPU_MP_DATA
*CpuMpData
77 mCpuMpData
= CpuMpData
;
81 Get available system memory below 0x88000 by specified size.
83 @param[in] WakeupBufferSize Wakeup buffer size required
85 @retval other Return wakeup buffer address below 1MB.
86 @retval -1 Cannot find free memory below 1MB.
90 IN UINTN WakeupBufferSize
94 EFI_PHYSICAL_ADDRESS StartAddress
;
95 EFI_MEMORY_TYPE MemoryType
;
97 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
) &&
98 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp
))
101 // An SEV-ES-only guest requires the memory to be reserved. SEV-SNP, which
102 // is also considered SEV-ES, uses a different AP startup method, though,
103 // which does not have the same requirement.
105 MemoryType
= EfiReservedMemoryType
;
107 MemoryType
= EfiBootServicesData
;
111 // Try to allocate buffer below 1M for waking vector.
112 // LegacyBios driver only reports warning when page allocation in range
113 // [0x60000, 0x88000) fails.
114 // This library is consumed by CpuDxe driver to produce CPU Arch protocol.
115 // LagacyBios driver depends on CPU Arch protocol which guarantees below
116 // allocation runs earlier than LegacyBios driver.
118 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
)) {
120 // SEV-ES Wakeup buffer should be under 0x88000 and under any previous one
122 StartAddress
= mSevEsDxeWakeupBuffer
;
124 StartAddress
= 0x88000;
127 Status
= gBS
->AllocatePages (
130 EFI_SIZE_TO_PAGES (WakeupBufferSize
),
133 ASSERT_EFI_ERROR (Status
);
134 if (EFI_ERROR (Status
)) {
135 StartAddress
= (EFI_PHYSICAL_ADDRESS
)-1;
136 } else if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
)) {
138 // Next SEV-ES wakeup buffer allocation must be below this allocation
140 mSevEsDxeWakeupBuffer
= StartAddress
;
145 "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
150 return (UINTN
)StartAddress
;
154 Get available EfiBootServicesCode memory below 4GB by specified size.
156 This buffer is required to safely transfer AP from real address mode to
157 protected mode or long mode, due to the fact that the buffer returned by
158 GetWakeupBuffer() may be marked as non-executable.
160 @param[in] BufferSize Wakeup transition buffer size.
162 @retval other Return wakeup transition buffer address below 4GB.
163 @retval 0 Cannot find free memory below 4GB.
171 EFI_PHYSICAL_ADDRESS StartAddress
;
173 StartAddress
= BASE_4GB
- 1;
174 Status
= gBS
->AllocatePages (
177 EFI_SIZE_TO_PAGES (BufferSize
),
180 if (EFI_ERROR (Status
)) {
184 return (UINTN
)StartAddress
;
188 Return the address of the SEV-ES AP jump table.
190 This buffer is required in order for an SEV-ES guest to transition from
193 @return Return SEV-ES AP jump table buffer
201 EFI_PHYSICAL_ADDRESS StartAddress
;
202 MSR_SEV_ES_GHCB_REGISTER Msr
;
204 BOOLEAN InterruptState
;
207 // Allocate 1 page for AP jump table page
209 StartAddress
= BASE_4GB
- 1;
210 Status
= gBS
->AllocatePages (
212 EfiReservedMemoryType
,
216 ASSERT_EFI_ERROR (Status
);
218 DEBUG ((DEBUG_INFO
, "Dxe: SevEsAPMemory = %lx\n", (UINTN
)StartAddress
));
221 // Save the SevEsAPMemory as the AP jump table.
223 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
226 CcExitVmgInit (Ghcb
, &InterruptState
);
227 CcExitVmgExit (Ghcb
, SVM_EXIT_AP_JUMP_TABLE
, 0, (UINT64
)(UINTN
)StartAddress
);
228 CcExitVmgDone (Ghcb
, InterruptState
);
230 return (UINTN
)StartAddress
;
234 Checks APs status and updates APs status if needed.
238 CheckAndUpdateApsStatus (
242 UINTN ProcessorNumber
;
244 CPU_MP_DATA
*CpuMpData
;
246 CpuMpData
= GetCpuMpData ();
249 // First, check whether pending StartupAllAPs() exists.
251 if (CpuMpData
->WaitEvent
!= NULL
) {
252 Status
= CheckAllAPs ();
254 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
256 if (Status
!= EFI_NOT_READY
) {
257 Status
= gBS
->SignalEvent (CpuMpData
->WaitEvent
);
258 CpuMpData
->WaitEvent
= NULL
;
263 // Second, check whether pending StartupThisAPs() callings exist.
265 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
266 if (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
== NULL
) {
270 Status
= CheckThisAP (ProcessorNumber
);
272 if (Status
!= EFI_NOT_READY
) {
273 gBS
->SignalEvent (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
);
274 CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
= NULL
;
280 Checks APs' status periodically.
282 This function is triggered by timer periodically to check the
283 state of APs for StartupAllAPs() and StartupThisAP() executed
284 in non-blocking mode.
286 @param[in] Event Event triggered.
287 @param[in] Context Parameter passed with the event.
298 // If CheckApsStatus() is not stopped, otherwise return immediately.
300 if (!mStopCheckAllApsStatus
) {
301 CheckAndUpdateApsStatus ();
306 Get Protected mode code segment with 16-bit default addressing
307 from current GDT table.
309 @return Protected mode 16-bit code segment value.
312 GetProtectedMode16CS (
316 IA32_DESCRIPTOR GdtrDesc
;
317 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
322 AsmReadGdtr (&GdtrDesc
);
323 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
324 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*)GdtrDesc
.Base
;
325 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
326 if (GdtEntry
->Bits
.L
== 0) {
327 if ((GdtEntry
->Bits
.Type
> 8) && (GdtEntry
->Bits
.DB
== 0)) {
335 ASSERT (Index
!= GdtEntryCount
);
340 Get Protected mode code segment from current GDT table.
342 @return Protected mode code segment value.
349 IA32_DESCRIPTOR GdtrDesc
;
350 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
354 AsmReadGdtr (&GdtrDesc
);
355 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
356 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*)GdtrDesc
.Base
;
357 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
358 if (GdtEntry
->Bits
.L
== 0) {
359 if ((GdtEntry
->Bits
.Type
> 8) && (GdtEntry
->Bits
.DB
== 1)) {
367 ASSERT (Index
!= GdtEntryCount
);
374 @param[in, out] Buffer Pointer to private data buffer.
382 CPU_MP_DATA
*CpuMpData
;
383 BOOLEAN MwaitSupport
;
384 UINTN ProcessorNumber
;
387 MpInitLibWhoAmI (&ProcessorNumber
);
388 CpuMpData
= GetCpuMpData ();
389 MwaitSupport
= IsMwaitSupport ();
390 if (CpuMpData
->UseSevEsAPMethod
) {
392 // 64-bit AMD processors with SEV-ES
394 StackStart
= CpuMpData
->SevEsAPResetStackStart
;
395 mReservedApLoop
.AmdSevEntry (
397 CpuMpData
->ApTargetCState
,
398 CpuMpData
->PmCodeSegment
,
399 StackStart
- ProcessorNumber
* AP_SAFE_STACK_SIZE
,
400 (UINTN
)&mNumberToFinish
,
401 CpuMpData
->Pm16CodeSegment
,
402 CpuMpData
->SevEsAPBuffer
,
403 CpuMpData
->WakeupBuffer
407 // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or 64-bit AMD processors without SEV-ES
409 StackStart
= mReservedTopOfApStack
;
410 mReservedApLoop
.GenericEntry (
412 CpuMpData
->ApTargetCState
,
413 StackStart
- ProcessorNumber
* AP_SAFE_STACK_SIZE
,
414 (UINTN
)&mNumberToFinish
,
420 // It should never reach here
426 Callback function for ExitBootServices.
428 @param[in] Event Event whose notification function is being invoked.
429 @param[in] Context The pointer to the notification function's context,
430 which is implementation-dependent.
435 MpInitChangeApLoopCallback (
440 CPU_MP_DATA
*CpuMpData
;
442 CpuMpData
= GetCpuMpData ();
443 CpuMpData
->PmCodeSegment
= GetProtectedModeCS ();
444 CpuMpData
->Pm16CodeSegment
= GetProtectedMode16CS ();
445 CpuMpData
->ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
446 mNumberToFinish
= CpuMpData
->CpuCount
- 1;
447 WakeUpAP (CpuMpData
, TRUE
, 0, RelocateApLoop
, NULL
, TRUE
);
448 while (mNumberToFinish
> 0) {
452 if (CpuMpData
->UseSevEsAPMethod
&& (CpuMpData
->WakeupBuffer
!= (UINTN
)-1)) {
454 // There are APs present. Re-use reserved memory area below 1MB from
455 // WakeupBuffer as the area to be used for transitioning to 16-bit mode
456 // in support of booting of the AP by an OS.
459 (VOID
*)CpuMpData
->WakeupBuffer
,
460 (VOID
*)(CpuMpData
->AddressMap
.RendezvousFunnelAddress
+
461 CpuMpData
->AddressMap
.SwitchToRealPM16ModeOffset
),
462 CpuMpData
->AddressMap
.SwitchToRealPM16ModeSize
466 DEBUG ((DEBUG_INFO
, "%a() done!\n", __FUNCTION__
));
470 Initialize global data for MP support.
472 @param[in] CpuMpData The pointer to CPU MP Data structure.
476 IN CPU_MP_DATA
*CpuMpData
480 EFI_PHYSICAL_ADDRESS Address
;
482 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc
;
484 CPU_INFO_IN_HOB
*CpuInfoInHob
;
485 MP_ASSEMBLY_ADDRESS_MAP
*AddressMap
;
487 UINTN ApLoopFuncSize
;
491 SaveCpuMpData (CpuMpData
);
493 if (CpuMpData
->CpuCount
== 1) {
495 // If only BSP exists, return
500 if (PcdGetBool (PcdCpuStackGuard
)) {
502 // One extra page at the bottom of the stack is needed for Guard page.
504 if (CpuMpData
->CpuApStackSize
<= EFI_PAGE_SIZE
) {
505 DEBUG ((DEBUG_ERROR
, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
510 // DXE will reuse stack allocated for APs at PEI phase if it's available.
511 // Let's check it here.
513 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of
514 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be
517 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
518 for (Index
= 0; Index
< CpuMpData
->CpuCount
; ++Index
) {
519 if ((CpuInfoInHob
!= NULL
) && (CpuInfoInHob
[Index
].ApTopOfStack
!= 0)) {
520 StackBase
= (UINTN
)CpuInfoInHob
[Index
].ApTopOfStack
- CpuMpData
->CpuApStackSize
;
522 StackBase
= CpuMpData
->Buffer
+ Index
* CpuMpData
->CpuApStackSize
;
525 Status
= gDS
->GetMemorySpaceDescriptor (StackBase
, &MemDesc
);
526 ASSERT_EFI_ERROR (Status
);
528 Status
= gDS
->SetMemorySpaceAttributes (
530 EFI_PAGES_TO_SIZE (1),
531 MemDesc
.Attributes
| EFI_MEMORY_RP
533 ASSERT_EFI_ERROR (Status
);
537 "Stack Guard set at %lx [cpu%lu]!\n",
544 AddressMap
= &CpuMpData
->AddressMap
;
545 if (CpuMpData
->UseSevEsAPMethod
) {
547 // 64-bit AMD processors with SEV-ES
549 Address
= BASE_4GB
- 1;
550 ApLoopFunc
= AddressMap
->RelocateApLoopFuncAddressAmdSev
;
551 ApLoopFuncSize
= AddressMap
->RelocateApLoopFuncSizeAmdSev
;
554 // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or 64-bit AMD processors without SEV-ES
556 Address
= MAX_ADDRESS
;
557 ApLoopFunc
= AddressMap
->RelocateApLoopFuncAddressGeneric
;
558 ApLoopFuncSize
= AddressMap
->RelocateApLoopFuncSizeGeneric
;
562 // Avoid APs access invalid buffer data which allocated by BootServices,
563 // so we will allocate reserved data for AP loop code. We also need to
564 // allocate this buffer below 4GB due to APs may be transferred to 32bit
565 // protected mode on long mode DXE.
566 // Allocating it in advance since memory services are not available in
567 // Exit Boot Services callback function.
569 // +------------+ (TopOfApStack)
571 // +------------+ (stack base, 4k aligned)
575 // +------------+ ((low address, 4k-aligned)
578 StackPages
= EFI_SIZE_TO_PAGES (CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
);
579 FuncPages
= EFI_SIZE_TO_PAGES (ApLoopFuncSize
);
581 Status
= gBS
->AllocatePages (
583 EfiReservedMemoryType
,
584 StackPages
+ FuncPages
,
587 ASSERT_EFI_ERROR (Status
);
590 // Make sure that the buffer memory is executable if NX protection is enabled
591 // for EfiReservedMemoryType.
593 // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD
596 Status
= gDS
->GetMemorySpaceDescriptor (Address
, &MemDesc
);
597 if (!EFI_ERROR (Status
)) {
598 gDS
->SetMemorySpaceAttributes (
600 EFI_PAGES_TO_SIZE (FuncPages
),
601 MemDesc
.Attributes
& (~EFI_MEMORY_XP
)
605 mReservedTopOfApStack
= (UINTN
)Address
+ EFI_PAGES_TO_SIZE (StackPages
+FuncPages
);
606 ASSERT ((mReservedTopOfApStack
& (UINTN
)(CPU_STACK_ALIGNMENT
- 1)) == 0);
607 mReservedApLoop
.Data
= (VOID
*)(UINTN
)Address
;
608 ASSERT (mReservedApLoop
.Data
!= NULL
);
609 CopyMem (mReservedApLoop
.Data
, ApLoopFunc
, ApLoopFuncSize
);
610 if (!CpuMpData
->UseSevEsAPMethod
) {
612 // processors without SEV-ES
614 mApPageTable
= CreatePageTable (
616 EFI_PAGES_TO_SIZE (StackPages
+FuncPages
)
620 Status
= gBS
->CreateEvent (
621 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
627 ASSERT_EFI_ERROR (Status
);
630 // Set timer to check all APs status.
632 Status
= gBS
->SetTimer (
635 EFI_TIMER_PERIOD_MICROSECONDS (
636 PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds
)
639 ASSERT_EFI_ERROR (Status
);
641 Status
= gBS
->CreateEvent (
642 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
644 MpInitChangeApLoopCallback
,
646 &mMpInitExitBootServicesEvent
648 ASSERT_EFI_ERROR (Status
);
650 Status
= gBS
->CreateEventEx (
653 MpInitChangeApLoopCallback
,
655 &gEfiEventLegacyBootGuid
,
658 ASSERT_EFI_ERROR (Status
);
662 This service executes a caller provided function on all enabled APs.
664 @param[in] Procedure A pointer to the function to be run on
665 enabled APs of the system. See type
667 @param[in] SingleThread If TRUE, then all the enabled APs execute
668 the function specified by Procedure one by
669 one, in ascending order of processor handle
670 number. If FALSE, then all the enabled APs
671 execute the function specified by Procedure
673 @param[in] WaitEvent The event created by the caller with CreateEvent()
674 service. If it is NULL, then execute in
675 blocking mode. BSP waits until all APs finish
676 or TimeoutInMicroSeconds expires. If it's
677 not NULL, then execute in non-blocking mode.
678 BSP requests the function specified by
679 Procedure to be started on all the enabled
680 APs, and go on executing immediately. If
681 all return from Procedure, or TimeoutInMicroSeconds
682 expires, this event is signaled. The BSP
683 can use the CheckEvent() or WaitForEvent()
684 services to check the state of event. Type
685 EFI_EVENT is defined in CreateEvent() in
686 the Unified Extensible Firmware Interface
688 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
689 APs to return from Procedure, either for
690 blocking or non-blocking mode. Zero means
691 infinity. If the timeout expires before
692 all APs return from Procedure, then Procedure
693 on the failed APs is terminated. All enabled
694 APs are available for next function assigned
695 by MpInitLibStartupAllAPs() or
696 MPInitLibStartupThisAP().
697 If the timeout expires in blocking mode,
698 BSP returns EFI_TIMEOUT. If the timeout
699 expires in non-blocking mode, WaitEvent
700 is signaled with SignalEvent().
701 @param[in] ProcedureArgument The parameter passed into Procedure for
703 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
704 if all APs finish successfully, then its
705 content is set to NULL. If not all APs
706 finish before timeout expires, then its
707 content is set to address of the buffer
708 holding handle numbers of the failed APs.
709 The buffer is allocated by MP Initialization
710 library, and it's the caller's responsibility to
711 free the buffer with FreePool() service.
712 In blocking mode, it is ready for consumption
713 when the call returns. In non-blocking mode,
714 it is ready when WaitEvent is signaled. The
715 list of failed CPU is terminated by
718 @retval EFI_SUCCESS In blocking mode, all APs have finished before
720 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
722 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
723 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
725 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
727 @retval EFI_DEVICE_ERROR Caller processor is AP.
728 @retval EFI_NOT_STARTED No enabled APs exist in the system.
729 @retval EFI_NOT_READY Any enabled APs are busy.
730 @retval EFI_NOT_READY MP Initialize Library is not initialized.
731 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
732 all enabled APs have finished.
733 @retval EFI_INVALID_PARAMETER Procedure is NULL.
738 MpInitLibStartupAllAPs (
739 IN EFI_AP_PROCEDURE Procedure
,
740 IN BOOLEAN SingleThread
,
741 IN EFI_EVENT WaitEvent OPTIONAL
,
742 IN UINTN TimeoutInMicroseconds
,
743 IN VOID
*ProcedureArgument OPTIONAL
,
744 OUT UINTN
**FailedCpuList OPTIONAL
750 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
752 mStopCheckAllApsStatus
= TRUE
;
754 Status
= StartupAllCPUsWorker (
759 TimeoutInMicroseconds
,
765 // Start checkAllApsStatus
767 mStopCheckAllApsStatus
= FALSE
;
773 This service lets the caller get one enabled AP to execute a caller-provided
776 @param[in] Procedure A pointer to the function to be run on the
777 designated AP of the system. See type
779 @param[in] ProcessorNumber The handle number of the AP. The range is
780 from 0 to the total number of logical
781 processors minus 1. The total number of
782 logical processors can be retrieved by
783 MpInitLibGetNumberOfProcessors().
784 @param[in] WaitEvent The event created by the caller with CreateEvent()
785 service. If it is NULL, then execute in
786 blocking mode. BSP waits until this AP finish
787 or TimeoutInMicroSeconds expires. If it's
788 not NULL, then execute in non-blocking mode.
789 BSP requests the function specified by
790 Procedure to be started on this AP,
791 and go on executing immediately. If this AP
792 return from Procedure or TimeoutInMicroSeconds
793 expires, this event is signaled. The BSP
794 can use the CheckEvent() or WaitForEvent()
795 services to check the state of event. Type
796 EFI_EVENT is defined in CreateEvent() in
797 the Unified Extensible Firmware Interface
799 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
800 this AP to finish this Procedure, either for
801 blocking or non-blocking mode. Zero means
802 infinity. If the timeout expires before
803 this AP returns from Procedure, then Procedure
804 on the AP is terminated. The
805 AP is available for next function assigned
806 by MpInitLibStartupAllAPs() or
807 MpInitLibStartupThisAP().
808 If the timeout expires in blocking mode,
809 BSP returns EFI_TIMEOUT. If the timeout
810 expires in non-blocking mode, WaitEvent
811 is signaled with SignalEvent().
812 @param[in] ProcedureArgument The parameter passed into Procedure on the
814 @param[out] Finished If NULL, this parameter is ignored. In
815 blocking mode, this parameter is ignored.
816 In non-blocking mode, if AP returns from
817 Procedure before the timeout expires, its
818 content is set to TRUE. Otherwise, the
819 value is set to FALSE. The caller can
820 determine if the AP returned from Procedure
821 by evaluating this value.
823 @retval EFI_SUCCESS In blocking mode, specified AP finished before
825 @retval EFI_SUCCESS In non-blocking mode, the function has been
826 dispatched to specified AP.
827 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
828 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
830 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
832 @retval EFI_DEVICE_ERROR The calling processor is an AP.
833 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
834 the specified AP has finished.
835 @retval EFI_NOT_READY The specified AP is busy.
836 @retval EFI_NOT_READY MP Initialize Library is not initialized.
837 @retval EFI_NOT_FOUND The processor with the handle specified by
838 ProcessorNumber does not exist.
839 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
840 @retval EFI_INVALID_PARAMETER Procedure is NULL.
845 MpInitLibStartupThisAP (
846 IN EFI_AP_PROCEDURE Procedure
,
847 IN UINTN ProcessorNumber
,
848 IN EFI_EVENT WaitEvent OPTIONAL
,
849 IN UINTN TimeoutInMicroseconds
,
850 IN VOID
*ProcedureArgument OPTIONAL
,
851 OUT BOOLEAN
*Finished OPTIONAL
857 // temporarily stop checkAllApsStatus for avoid resource dead-lock.
859 mStopCheckAllApsStatus
= TRUE
;
861 Status
= StartupThisAPWorker (
865 TimeoutInMicroseconds
,
870 mStopCheckAllApsStatus
= FALSE
;
876 This service switches the requested AP to be the BSP from that point onward.
877 This service changes the BSP for all purposes. This call can only be performed
880 @param[in] ProcessorNumber The handle number of AP that is to become the new
881 BSP. The range is from 0 to the total number of
882 logical processors minus 1. The total number of
883 logical processors can be retrieved by
884 MpInitLibGetNumberOfProcessors().
885 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
886 enabled AP. Otherwise, it will be disabled.
888 @retval EFI_SUCCESS BSP successfully switched.
889 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
890 this service returning.
891 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
892 @retval EFI_DEVICE_ERROR The calling processor is an AP.
893 @retval EFI_NOT_FOUND The processor with the handle specified by
894 ProcessorNumber does not exist.
895 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
897 @retval EFI_NOT_READY The specified AP is busy.
898 @retval EFI_NOT_READY MP Initialize Library is not initialized.
904 IN UINTN ProcessorNumber
,
905 IN BOOLEAN EnableOldBSP
909 EFI_TIMER_ARCH_PROTOCOL
*Timer
;
914 // Locate Timer Arch Protocol
916 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**)&Timer
);
917 if (EFI_ERROR (Status
)) {
923 // Save current rate of DXE Timer
925 Timer
->GetTimerPeriod (Timer
, &TimerPeriod
);
927 // Disable DXE Timer and drain pending interrupts
929 Timer
->SetTimerPeriod (Timer
, 0);
932 Status
= SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
936 // Enable and restore rate of DXE Timer
938 Timer
->SetTimerPeriod (Timer
, TimerPeriod
);
945 This service lets the caller enable or disable an AP from this point onward.
946 This service may only be called from the BSP.
948 @param[in] ProcessorNumber The handle number of AP.
949 The range is from 0 to the total number of
950 logical processors minus 1. The total number of
951 logical processors can be retrieved by
952 MpInitLibGetNumberOfProcessors().
953 @param[in] EnableAP Specifies the new state for the processor for
954 enabled, FALSE for disabled.
955 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
956 the new health status of the AP. This flag
957 corresponds to StatusFlag defined in
958 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
959 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
960 bits are ignored. If it is NULL, this parameter
963 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
964 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
965 prior to this service returning.
966 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
967 @retval EFI_DEVICE_ERROR The calling processor is an AP.
968 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
970 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
971 @retval EFI_NOT_READY MP Initialize Library is not initialized.
976 MpInitLibEnableDisableAP (
977 IN UINTN ProcessorNumber
,
979 IN UINT32
*HealthFlag OPTIONAL
983 BOOLEAN TempStopCheckState
;
985 TempStopCheckState
= FALSE
;
987 // temporarily stop checkAllAPsStatus for initialize parameters.
989 if (!mStopCheckAllApsStatus
) {
990 mStopCheckAllApsStatus
= TRUE
;
991 TempStopCheckState
= TRUE
;
994 Status
= EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
996 if (TempStopCheckState
) {
997 mStopCheckAllApsStatus
= FALSE
;
1004 This funtion will try to invoke platform specific microcode shadow logic to
1005 relocate microcode update patches into memory.
1007 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
1009 @retval EFI_SUCCESS Shadow microcode success.
1010 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
1011 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
1015 PlatformShadowMicrocode (
1016 IN OUT CPU_MP_DATA
*CpuMpData
1020 // There is no DXE version of platform shadow microcode protocol so far.
1021 // A platform which only uses DxeMpInitLib instance could only supports
1022 // the PCD based microcode shadowing.
1024 return EFI_UNSUPPORTED
;