2 MP initialize support functions for DXE phase.
4 Copyright (c) 2016 - 2022, 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 VOID
*mReservedApLoopFunc
= NULL
;
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 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc
;
385 ASM_RELOCATE_AP_LOOP_AMD AsmRelocateApLoopFuncAmd
;
386 UINTN ProcessorNumber
;
389 MpInitLibWhoAmI (&ProcessorNumber
);
390 CpuMpData
= GetCpuMpData ();
391 MwaitSupport
= IsMwaitSupport ();
392 if (StandardSignatureIsAuthenticAMD ()) {
393 StackStart
= CpuMpData
->UseSevEsAPMethod
? CpuMpData
->SevEsAPResetStackStart
: mReservedTopOfApStack
;
394 AsmRelocateApLoopFuncAmd
= (ASM_RELOCATE_AP_LOOP_AMD
)(UINTN
)mReservedApLoopFunc
;
395 AsmRelocateApLoopFuncAmd (
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
406 StackStart
= mReservedTopOfApStack
;
407 AsmRelocateApLoopFunc
= (ASM_RELOCATE_AP_LOOP
)(UINTN
)mReservedApLoopFunc
;
408 AsmRelocateApLoopFunc (
410 CpuMpData
->ApTargetCState
,
411 StackStart
- ProcessorNumber
* AP_SAFE_STACK_SIZE
,
412 (UINTN
)&mNumberToFinish
,
418 // It should never reach here
424 Callback function for ExitBootServices.
426 @param[in] Event Event whose notification function is being invoked.
427 @param[in] Context The pointer to the notification function's context,
428 which is implementation-dependent.
433 MpInitChangeApLoopCallback (
438 CPU_MP_DATA
*CpuMpData
;
440 CpuMpData
= GetCpuMpData ();
441 CpuMpData
->PmCodeSegment
= GetProtectedModeCS ();
442 CpuMpData
->Pm16CodeSegment
= GetProtectedMode16CS ();
443 CpuMpData
->ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
444 mNumberToFinish
= CpuMpData
->CpuCount
- 1;
445 WakeUpAP (CpuMpData
, TRUE
, 0, RelocateApLoop
, NULL
, TRUE
);
446 while (mNumberToFinish
> 0) {
450 if (CpuMpData
->UseSevEsAPMethod
&& (CpuMpData
->WakeupBuffer
!= (UINTN
)-1)) {
452 // There are APs present. Re-use reserved memory area below 1MB from
453 // WakeupBuffer as the area to be used for transitioning to 16-bit mode
454 // in support of booting of the AP by an OS.
457 (VOID
*)CpuMpData
->WakeupBuffer
,
458 (VOID
*)(CpuMpData
->AddressMap
.RendezvousFunnelAddress
+
459 CpuMpData
->AddressMap
.SwitchToRealPM16ModeOffset
),
460 CpuMpData
->AddressMap
.SwitchToRealPM16ModeSize
464 DEBUG ((DEBUG_INFO
, "%a() done!\n", __FUNCTION__
));
468 Initialize global data for MP support.
470 @param[in] CpuMpData The pointer to CPU MP Data structure.
474 IN CPU_MP_DATA
*CpuMpData
478 UINTN ApSafeBufferSize
;
480 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc
;
482 CPU_INFO_IN_HOB
*CpuInfoInHob
;
484 SaveCpuMpData (CpuMpData
);
486 if (CpuMpData
->CpuCount
== 1) {
488 // If only BSP exists, return
493 if (PcdGetBool (PcdCpuStackGuard
)) {
495 // One extra page at the bottom of the stack is needed for Guard page.
497 if (CpuMpData
->CpuApStackSize
<= EFI_PAGE_SIZE
) {
498 DEBUG ((DEBUG_ERROR
, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
503 // DXE will reuse stack allocated for APs at PEI phase if it's available.
504 // Let's check it here.
506 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of
507 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be
510 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
511 for (Index
= 0; Index
< CpuMpData
->CpuCount
; ++Index
) {
512 if ((CpuInfoInHob
!= NULL
) && (CpuInfoInHob
[Index
].ApTopOfStack
!= 0)) {
513 StackBase
= (UINTN
)CpuInfoInHob
[Index
].ApTopOfStack
- CpuMpData
->CpuApStackSize
;
515 StackBase
= CpuMpData
->Buffer
+ Index
* CpuMpData
->CpuApStackSize
;
518 Status
= gDS
->GetMemorySpaceDescriptor (StackBase
, &MemDesc
);
519 ASSERT_EFI_ERROR (Status
);
521 Status
= gDS
->SetMemorySpaceAttributes (
523 EFI_PAGES_TO_SIZE (1),
524 MemDesc
.Attributes
| EFI_MEMORY_RP
526 ASSERT_EFI_ERROR (Status
);
530 "Stack Guard set at %lx [cpu%lu]!\n",
538 // Avoid APs access invalid buffer data which allocated by BootServices,
539 // so we will allocate reserved data for AP loop code. We also need to
540 // allocate this buffer below 4GB due to APs may be transferred to 32bit
541 // protected mode on long mode DXE.
542 // Allocating it in advance since memory services are not available in
543 // Exit Boot Services callback function.
549 // +------------+ (low address)
551 ApSafeBufferSize
= EFI_PAGES_TO_SIZE (
553 CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
554 + CpuMpData
->AddressMap
.RelocateApLoopFuncSize
558 mReservedTopOfApStack
= (UINTN
)AllocateReservedPages (EFI_SIZE_TO_PAGES (ApSafeBufferSize
));
559 ASSERT (mReservedTopOfApStack
!= 0);
560 ASSERT ((mReservedTopOfApStack
& (UINTN
)(CPU_STACK_ALIGNMENT
- 1)) == 0);
561 ASSERT ((AP_SAFE_STACK_SIZE
& (CPU_STACK_ALIGNMENT
- 1)) == 0);
563 mReservedApLoopFunc
= (VOID
*)(mReservedTopOfApStack
+ CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
);
564 if (StandardSignatureIsAuthenticAMD ()) {
567 CpuMpData
->AddressMap
.RelocateApLoopFuncAddressAmd
,
568 CpuMpData
->AddressMap
.RelocateApLoopFuncSizeAmd
573 CpuMpData
->AddressMap
.RelocateApLoopFuncAddress
,
574 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
577 mApPageTable
= CreatePageTable (
578 mReservedTopOfApStack
,
583 mReservedTopOfApStack
+= CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
;
585 Status
= gBS
->CreateEvent (
586 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
592 ASSERT_EFI_ERROR (Status
);
595 // Set timer to check all APs status.
597 Status
= gBS
->SetTimer (
600 EFI_TIMER_PERIOD_MICROSECONDS (
601 PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds
)
604 ASSERT_EFI_ERROR (Status
);
606 Status
= gBS
->CreateEvent (
607 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
609 MpInitChangeApLoopCallback
,
611 &mMpInitExitBootServicesEvent
613 ASSERT_EFI_ERROR (Status
);
615 Status
= gBS
->CreateEventEx (
618 MpInitChangeApLoopCallback
,
620 &gEfiEventLegacyBootGuid
,
623 ASSERT_EFI_ERROR (Status
);
627 This service executes a caller provided function on all enabled APs.
629 @param[in] Procedure A pointer to the function to be run on
630 enabled APs of the system. See type
632 @param[in] SingleThread If TRUE, then all the enabled APs execute
633 the function specified by Procedure one by
634 one, in ascending order of processor handle
635 number. If FALSE, then all the enabled APs
636 execute the function specified by Procedure
638 @param[in] WaitEvent The event created by the caller with CreateEvent()
639 service. If it is NULL, then execute in
640 blocking mode. BSP waits until all APs finish
641 or TimeoutInMicroSeconds expires. If it's
642 not NULL, then execute in non-blocking mode.
643 BSP requests the function specified by
644 Procedure to be started on all the enabled
645 APs, and go on executing immediately. If
646 all return from Procedure, or TimeoutInMicroSeconds
647 expires, this event is signaled. The BSP
648 can use the CheckEvent() or WaitForEvent()
649 services to check the state of event. Type
650 EFI_EVENT is defined in CreateEvent() in
651 the Unified Extensible Firmware Interface
653 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
654 APs to return from Procedure, either for
655 blocking or non-blocking mode. Zero means
656 infinity. If the timeout expires before
657 all APs return from Procedure, then Procedure
658 on the failed APs is terminated. All enabled
659 APs are available for next function assigned
660 by MpInitLibStartupAllAPs() or
661 MPInitLibStartupThisAP().
662 If the timeout expires in blocking mode,
663 BSP returns EFI_TIMEOUT. If the timeout
664 expires in non-blocking mode, WaitEvent
665 is signaled with SignalEvent().
666 @param[in] ProcedureArgument The parameter passed into Procedure for
668 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
669 if all APs finish successfully, then its
670 content is set to NULL. If not all APs
671 finish before timeout expires, then its
672 content is set to address of the buffer
673 holding handle numbers of the failed APs.
674 The buffer is allocated by MP Initialization
675 library, and it's the caller's responsibility to
676 free the buffer with FreePool() service.
677 In blocking mode, it is ready for consumption
678 when the call returns. In non-blocking mode,
679 it is ready when WaitEvent is signaled. The
680 list of failed CPU is terminated by
683 @retval EFI_SUCCESS In blocking mode, all APs have finished before
685 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
687 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
688 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
690 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
692 @retval EFI_DEVICE_ERROR Caller processor is AP.
693 @retval EFI_NOT_STARTED No enabled APs exist in the system.
694 @retval EFI_NOT_READY Any enabled APs are busy.
695 @retval EFI_NOT_READY MP Initialize Library is not initialized.
696 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
697 all enabled APs have finished.
698 @retval EFI_INVALID_PARAMETER Procedure is NULL.
703 MpInitLibStartupAllAPs (
704 IN EFI_AP_PROCEDURE Procedure
,
705 IN BOOLEAN SingleThread
,
706 IN EFI_EVENT WaitEvent OPTIONAL
,
707 IN UINTN TimeoutInMicroseconds
,
708 IN VOID
*ProcedureArgument OPTIONAL
,
709 OUT UINTN
**FailedCpuList OPTIONAL
715 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
717 mStopCheckAllApsStatus
= TRUE
;
719 Status
= StartupAllCPUsWorker (
724 TimeoutInMicroseconds
,
730 // Start checkAllApsStatus
732 mStopCheckAllApsStatus
= FALSE
;
738 This service lets the caller get one enabled AP to execute a caller-provided
741 @param[in] Procedure A pointer to the function to be run on the
742 designated AP of the system. See type
744 @param[in] ProcessorNumber The handle number of the AP. The range is
745 from 0 to the total number of logical
746 processors minus 1. The total number of
747 logical processors can be retrieved by
748 MpInitLibGetNumberOfProcessors().
749 @param[in] WaitEvent The event created by the caller with CreateEvent()
750 service. If it is NULL, then execute in
751 blocking mode. BSP waits until this AP finish
752 or TimeoutInMicroSeconds expires. If it's
753 not NULL, then execute in non-blocking mode.
754 BSP requests the function specified by
755 Procedure to be started on this AP,
756 and go on executing immediately. If this AP
757 return from Procedure or TimeoutInMicroSeconds
758 expires, this event is signaled. The BSP
759 can use the CheckEvent() or WaitForEvent()
760 services to check the state of event. Type
761 EFI_EVENT is defined in CreateEvent() in
762 the Unified Extensible Firmware Interface
764 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
765 this AP to finish this Procedure, either for
766 blocking or non-blocking mode. Zero means
767 infinity. If the timeout expires before
768 this AP returns from Procedure, then Procedure
769 on the AP is terminated. The
770 AP is available for next function assigned
771 by MpInitLibStartupAllAPs() or
772 MpInitLibStartupThisAP().
773 If the timeout expires in blocking mode,
774 BSP returns EFI_TIMEOUT. If the timeout
775 expires in non-blocking mode, WaitEvent
776 is signaled with SignalEvent().
777 @param[in] ProcedureArgument The parameter passed into Procedure on the
779 @param[out] Finished If NULL, this parameter is ignored. In
780 blocking mode, this parameter is ignored.
781 In non-blocking mode, if AP returns from
782 Procedure before the timeout expires, its
783 content is set to TRUE. Otherwise, the
784 value is set to FALSE. The caller can
785 determine if the AP returned from Procedure
786 by evaluating this value.
788 @retval EFI_SUCCESS In blocking mode, specified AP finished before
790 @retval EFI_SUCCESS In non-blocking mode, the function has been
791 dispatched to specified AP.
792 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
793 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
795 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
797 @retval EFI_DEVICE_ERROR The calling processor is an AP.
798 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
799 the specified AP has finished.
800 @retval EFI_NOT_READY The specified AP is busy.
801 @retval EFI_NOT_READY MP Initialize Library is not initialized.
802 @retval EFI_NOT_FOUND The processor with the handle specified by
803 ProcessorNumber does not exist.
804 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
805 @retval EFI_INVALID_PARAMETER Procedure is NULL.
810 MpInitLibStartupThisAP (
811 IN EFI_AP_PROCEDURE Procedure
,
812 IN UINTN ProcessorNumber
,
813 IN EFI_EVENT WaitEvent OPTIONAL
,
814 IN UINTN TimeoutInMicroseconds
,
815 IN VOID
*ProcedureArgument OPTIONAL
,
816 OUT BOOLEAN
*Finished OPTIONAL
822 // temporarily stop checkAllApsStatus for avoid resource dead-lock.
824 mStopCheckAllApsStatus
= TRUE
;
826 Status
= StartupThisAPWorker (
830 TimeoutInMicroseconds
,
835 mStopCheckAllApsStatus
= FALSE
;
841 This service switches the requested AP to be the BSP from that point onward.
842 This service changes the BSP for all purposes. This call can only be performed
845 @param[in] ProcessorNumber The handle number of AP that is to become the new
846 BSP. The range is from 0 to the total number of
847 logical processors minus 1. The total number of
848 logical processors can be retrieved by
849 MpInitLibGetNumberOfProcessors().
850 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
851 enabled AP. Otherwise, it will be disabled.
853 @retval EFI_SUCCESS BSP successfully switched.
854 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
855 this service returning.
856 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
857 @retval EFI_DEVICE_ERROR The calling processor is an AP.
858 @retval EFI_NOT_FOUND The processor with the handle specified by
859 ProcessorNumber does not exist.
860 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
862 @retval EFI_NOT_READY The specified AP is busy.
863 @retval EFI_NOT_READY MP Initialize Library is not initialized.
869 IN UINTN ProcessorNumber
,
870 IN BOOLEAN EnableOldBSP
874 EFI_TIMER_ARCH_PROTOCOL
*Timer
;
879 // Locate Timer Arch Protocol
881 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**)&Timer
);
882 if (EFI_ERROR (Status
)) {
888 // Save current rate of DXE Timer
890 Timer
->GetTimerPeriod (Timer
, &TimerPeriod
);
892 // Disable DXE Timer and drain pending interrupts
894 Timer
->SetTimerPeriod (Timer
, 0);
897 Status
= SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
901 // Enable and restore rate of DXE Timer
903 Timer
->SetTimerPeriod (Timer
, TimerPeriod
);
910 This service lets the caller enable or disable an AP from this point onward.
911 This service may only be called from the BSP.
913 @param[in] ProcessorNumber The handle number of AP.
914 The range is from 0 to the total number of
915 logical processors minus 1. The total number of
916 logical processors can be retrieved by
917 MpInitLibGetNumberOfProcessors().
918 @param[in] EnableAP Specifies the new state for the processor for
919 enabled, FALSE for disabled.
920 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
921 the new health status of the AP. This flag
922 corresponds to StatusFlag defined in
923 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
924 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
925 bits are ignored. If it is NULL, this parameter
928 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
929 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
930 prior to this service returning.
931 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
932 @retval EFI_DEVICE_ERROR The calling processor is an AP.
933 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
935 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
936 @retval EFI_NOT_READY MP Initialize Library is not initialized.
941 MpInitLibEnableDisableAP (
942 IN UINTN ProcessorNumber
,
944 IN UINT32
*HealthFlag OPTIONAL
948 BOOLEAN TempStopCheckState
;
950 TempStopCheckState
= FALSE
;
952 // temporarily stop checkAllAPsStatus for initialize parameters.
954 if (!mStopCheckAllApsStatus
) {
955 mStopCheckAllApsStatus
= TRUE
;
956 TempStopCheckState
= TRUE
;
959 Status
= EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
961 if (TempStopCheckState
) {
962 mStopCheckAllApsStatus
= FALSE
;
969 This funtion will try to invoke platform specific microcode shadow logic to
970 relocate microcode update patches into memory.
972 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
974 @retval EFI_SUCCESS Shadow microcode success.
975 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
976 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
980 PlatformShadowMicrocode (
981 IN OUT CPU_MP_DATA
*CpuMpData
985 // There is no DXE version of platform shadow microcode protocol so far.
986 // A platform which only uses DxeMpInitLib instance could only supports
987 // the PCD based microcode shadowing.
989 return EFI_UNSUPPORTED
;