2 MP initialize support functions for DXE phase.
4 Copyright (c) 2016 - 2020, 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/VmgExitLib.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;
33 Enable Debug Agent to support source debugging on AP function.
42 // Initialize Debug Agent to support source level debug in DXE phase
44 InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP
, NULL
, NULL
);
48 Get the pointer to CPU MP Data structure.
50 @return The pointer to CPU MP Data structure.
57 ASSERT (mCpuMpData
!= NULL
);
62 Save the pointer to CPU MP Data structure.
64 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
68 IN CPU_MP_DATA
*CpuMpData
71 mCpuMpData
= CpuMpData
;
75 Get available system memory below 0x88000 by specified size.
77 @param[in] WakeupBufferSize Wakeup buffer size required
79 @retval other Return wakeup buffer address below 1MB.
80 @retval -1 Cannot find free memory below 1MB.
84 IN UINTN WakeupBufferSize
88 EFI_PHYSICAL_ADDRESS StartAddress
;
89 EFI_MEMORY_TYPE MemoryType
;
91 if (PcdGetBool (PcdSevEsIsEnabled
)) {
92 MemoryType
= EfiReservedMemoryType
;
94 MemoryType
= EfiBootServicesData
;
98 // Try to allocate buffer below 1M for waking vector.
99 // LegacyBios driver only reports warning when page allocation in range
100 // [0x60000, 0x88000) fails.
101 // This library is consumed by CpuDxe driver to produce CPU Arch protocol.
102 // LagacyBios driver depends on CPU Arch protocol which guarantees below
103 // allocation runs earlier than LegacyBios driver.
105 StartAddress
= 0x88000;
106 Status
= gBS
->AllocatePages (
109 EFI_SIZE_TO_PAGES (WakeupBufferSize
),
112 ASSERT_EFI_ERROR (Status
);
113 if (EFI_ERROR (Status
)) {
114 StartAddress
= (EFI_PHYSICAL_ADDRESS
) -1;
117 DEBUG ((DEBUG_INFO
, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
118 (UINTN
) StartAddress
, WakeupBufferSize
));
120 return (UINTN
) StartAddress
;
124 Get available EfiBootServicesCode memory below 4GB by specified size.
126 This buffer is required to safely transfer AP from real address mode to
127 protected mode or long mode, due to the fact that the buffer returned by
128 GetWakeupBuffer() may be marked as non-executable.
130 @param[in] BufferSize Wakeup transition buffer size.
132 @retval other Return wakeup transition buffer address below 4GB.
133 @retval 0 Cannot find free memory below 4GB.
136 GetModeTransitionBuffer (
141 EFI_PHYSICAL_ADDRESS StartAddress
;
143 StartAddress
= BASE_4GB
- 1;
144 Status
= gBS
->AllocatePages (
147 EFI_SIZE_TO_PAGES (BufferSize
),
150 if (EFI_ERROR (Status
)) {
154 return (UINTN
)StartAddress
;
158 Return the address of the SEV-ES AP jump table.
160 This buffer is required in order for an SEV-ES guest to transition from
163 @return Return SEV-ES AP jump table buffer
171 EFI_PHYSICAL_ADDRESS StartAddress
;
172 MSR_SEV_ES_GHCB_REGISTER Msr
;
174 BOOLEAN InterruptState
;
177 // Allocate 1 page for AP jump table page
179 StartAddress
= BASE_4GB
- 1;
180 Status
= gBS
->AllocatePages (
182 EfiReservedMemoryType
,
186 ASSERT_EFI_ERROR (Status
);
188 DEBUG ((DEBUG_INFO
, "Dxe: SevEsAPMemory = %lx\n", (UINTN
) StartAddress
));
191 // Save the SevEsAPMemory as the AP jump table.
193 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
196 VmgInit (Ghcb
, &InterruptState
);
197 VmgExit (Ghcb
, SVM_EXIT_AP_JUMP_TABLE
, 0, (UINT64
) (UINTN
) StartAddress
);
198 VmgDone (Ghcb
, InterruptState
);
200 return (UINTN
) StartAddress
;
204 Checks APs status and updates APs status if needed.
208 CheckAndUpdateApsStatus (
212 UINTN ProcessorNumber
;
214 CPU_MP_DATA
*CpuMpData
;
216 CpuMpData
= GetCpuMpData ();
219 // First, check whether pending StartupAllAPs() exists.
221 if (CpuMpData
->WaitEvent
!= NULL
) {
223 Status
= CheckAllAPs ();
225 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
227 if (Status
!= EFI_NOT_READY
) {
228 Status
= gBS
->SignalEvent (CpuMpData
->WaitEvent
);
229 CpuMpData
->WaitEvent
= NULL
;
234 // Second, check whether pending StartupThisAPs() callings exist.
236 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
238 if (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
== NULL
) {
242 Status
= CheckThisAP (ProcessorNumber
);
244 if (Status
!= EFI_NOT_READY
) {
245 gBS
->SignalEvent (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
);
246 CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
= NULL
;
252 Checks APs' status periodically.
254 This function is triggered by timer periodically to check the
255 state of APs for StartupAllAPs() and StartupThisAP() executed
256 in non-blocking mode.
258 @param[in] Event Event triggered.
259 @param[in] Context Parameter passed with the event.
270 // If CheckApsStatus() is not stopped, otherwise return immediately.
272 if (!mStopCheckAllApsStatus
) {
273 CheckAndUpdateApsStatus ();
278 Get Protected mode code segment with 16-bit default addressing
279 from current GDT table.
281 @return Protected mode 16-bit code segment value.
284 GetProtectedMode16CS (
288 IA32_DESCRIPTOR GdtrDesc
;
289 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
294 AsmReadGdtr (&GdtrDesc
);
295 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
296 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
297 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
298 if (GdtEntry
->Bits
.L
== 0) {
299 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.DB
== 0) {
305 ASSERT (Index
!= GdtEntryCount
);
310 Get Protected mode code segment from current GDT table.
312 @return Protected mode code segment value.
319 IA32_DESCRIPTOR GdtrDesc
;
320 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
324 AsmReadGdtr (&GdtrDesc
);
325 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
326 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
327 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
328 if (GdtEntry
->Bits
.L
== 0) {
329 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.DB
== 1) {
335 ASSERT (Index
!= GdtEntryCount
);
342 @param[in, out] Buffer Pointer to private data buffer.
350 CPU_MP_DATA
*CpuMpData
;
351 BOOLEAN MwaitSupport
;
352 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc
;
353 UINTN ProcessorNumber
;
356 MpInitLibWhoAmI (&ProcessorNumber
);
357 CpuMpData
= GetCpuMpData ();
358 MwaitSupport
= IsMwaitSupport ();
359 if (CpuMpData
->SevEsIsEnabled
) {
360 StackStart
= CpuMpData
->SevEsAPResetStackStart
;
362 StackStart
= mReservedTopOfApStack
;
364 AsmRelocateApLoopFunc
= (ASM_RELOCATE_AP_LOOP
) (UINTN
) mReservedApLoopFunc
;
365 AsmRelocateApLoopFunc (
367 CpuMpData
->ApTargetCState
,
368 CpuMpData
->PmCodeSegment
,
369 StackStart
- ProcessorNumber
* AP_SAFE_STACK_SIZE
,
370 (UINTN
) &mNumberToFinish
,
371 CpuMpData
->Pm16CodeSegment
,
372 CpuMpData
->SevEsAPBuffer
,
373 CpuMpData
->WakeupBuffer
376 // It should never reach here
382 Callback function for ExitBootServices.
384 @param[in] Event Event whose notification function is being invoked.
385 @param[in] Context The pointer to the notification function's context,
386 which is implementation-dependent.
391 MpInitChangeApLoopCallback (
396 CPU_MP_DATA
*CpuMpData
;
398 CpuMpData
= GetCpuMpData ();
399 CpuMpData
->PmCodeSegment
= GetProtectedModeCS ();
400 CpuMpData
->Pm16CodeSegment
= GetProtectedMode16CS ();
401 CpuMpData
->ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
402 mNumberToFinish
= CpuMpData
->CpuCount
- 1;
403 WakeUpAP (CpuMpData
, TRUE
, 0, RelocateApLoop
, NULL
, TRUE
);
404 while (mNumberToFinish
> 0) {
408 if (CpuMpData
->SevEsIsEnabled
&& (CpuMpData
->WakeupBuffer
!= (UINTN
) -1)) {
410 // There are APs present. Re-use reserved memory area below 1MB from
411 // WakeupBuffer as the area to be used for transitioning to 16-bit mode
412 // in support of booting of the AP by an OS.
415 (VOID
*) CpuMpData
->WakeupBuffer
,
416 (VOID
*) (CpuMpData
->AddressMap
.RendezvousFunnelAddress
+
417 CpuMpData
->AddressMap
.SwitchToRealPM16ModeOffset
),
418 CpuMpData
->AddressMap
.SwitchToRealPM16ModeSize
422 DEBUG ((DEBUG_INFO
, "%a() done!\n", __FUNCTION__
));
426 Initialize global data for MP support.
428 @param[in] CpuMpData The pointer to CPU MP Data structure.
432 IN CPU_MP_DATA
*CpuMpData
436 EFI_PHYSICAL_ADDRESS Address
;
437 UINTN ApSafeBufferSize
;
439 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc
;
441 CPU_INFO_IN_HOB
*CpuInfoInHob
;
443 SaveCpuMpData (CpuMpData
);
445 if (CpuMpData
->CpuCount
== 1) {
447 // If only BSP exists, return
452 if (PcdGetBool (PcdCpuStackGuard
)) {
454 // One extra page at the bottom of the stack is needed for Guard page.
456 if (CpuMpData
->CpuApStackSize
<= EFI_PAGE_SIZE
) {
457 DEBUG ((DEBUG_ERROR
, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
462 // DXE will reuse stack allocated for APs at PEI phase if it's available.
463 // Let's check it here.
465 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of
466 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be
469 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
470 for (Index
= 0; Index
< CpuMpData
->CpuCount
; ++Index
) {
471 if (CpuInfoInHob
!= NULL
&& CpuInfoInHob
[Index
].ApTopOfStack
!= 0) {
472 StackBase
= (UINTN
)CpuInfoInHob
[Index
].ApTopOfStack
- CpuMpData
->CpuApStackSize
;
474 StackBase
= CpuMpData
->Buffer
+ Index
* CpuMpData
->CpuApStackSize
;
477 Status
= gDS
->GetMemorySpaceDescriptor (StackBase
, &MemDesc
);
478 ASSERT_EFI_ERROR (Status
);
480 Status
= gDS
->SetMemorySpaceAttributes (
482 EFI_PAGES_TO_SIZE (1),
483 MemDesc
.Attributes
| EFI_MEMORY_RP
485 ASSERT_EFI_ERROR (Status
);
487 DEBUG ((DEBUG_INFO
, "Stack Guard set at %lx [cpu%lu]!\n",
488 (UINT64
)StackBase
, (UINT64
)Index
));
493 // Avoid APs access invalid buffer data which allocated by BootServices,
494 // so we will allocate reserved data for AP loop code. We also need to
495 // allocate this buffer below 4GB due to APs may be transferred to 32bit
496 // protected mode on long mode DXE.
497 // Allocating it in advance since memory services are not available in
498 // Exit Boot Services callback function.
500 ApSafeBufferSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (
501 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
503 Address
= BASE_4GB
- 1;
504 Status
= gBS
->AllocatePages (
506 EfiReservedMemoryType
,
507 EFI_SIZE_TO_PAGES (ApSafeBufferSize
),
510 ASSERT_EFI_ERROR (Status
);
512 mReservedApLoopFunc
= (VOID
*) (UINTN
) Address
;
513 ASSERT (mReservedApLoopFunc
!= NULL
);
516 // Make sure that the buffer memory is executable if NX protection is enabled
517 // for EfiReservedMemoryType.
519 // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD
522 Status
= gDS
->GetMemorySpaceDescriptor (Address
, &MemDesc
);
523 if (!EFI_ERROR (Status
)) {
524 gDS
->SetMemorySpaceAttributes (
527 MemDesc
.Attributes
& (~EFI_MEMORY_XP
)
531 ApSafeBufferSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (
532 CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
534 Address
= BASE_4GB
- 1;
535 Status
= gBS
->AllocatePages (
537 EfiReservedMemoryType
,
538 EFI_SIZE_TO_PAGES (ApSafeBufferSize
),
541 ASSERT_EFI_ERROR (Status
);
543 mReservedTopOfApStack
= (UINTN
) Address
+ ApSafeBufferSize
;
544 ASSERT ((mReservedTopOfApStack
& (UINTN
)(CPU_STACK_ALIGNMENT
- 1)) == 0);
547 CpuMpData
->AddressMap
.RelocateApLoopFuncAddress
,
548 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
551 Status
= gBS
->CreateEvent (
552 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
558 ASSERT_EFI_ERROR (Status
);
561 // Set timer to check all APs status.
563 Status
= gBS
->SetTimer (
566 EFI_TIMER_PERIOD_MICROSECONDS (
567 PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds
)
570 ASSERT_EFI_ERROR (Status
);
572 Status
= gBS
->CreateEvent (
573 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
575 MpInitChangeApLoopCallback
,
577 &mMpInitExitBootServicesEvent
579 ASSERT_EFI_ERROR (Status
);
581 Status
= gBS
->CreateEventEx (
584 MpInitChangeApLoopCallback
,
586 &gEfiEventLegacyBootGuid
,
589 ASSERT_EFI_ERROR (Status
);
593 This service executes a caller provided function on all enabled APs.
595 @param[in] Procedure A pointer to the function to be run on
596 enabled APs of the system. See type
598 @param[in] SingleThread If TRUE, then all the enabled APs execute
599 the function specified by Procedure one by
600 one, in ascending order of processor handle
601 number. If FALSE, then all the enabled APs
602 execute the function specified by Procedure
604 @param[in] WaitEvent The event created by the caller with CreateEvent()
605 service. If it is NULL, then execute in
606 blocking mode. BSP waits until all APs finish
607 or TimeoutInMicroSeconds expires. If it's
608 not NULL, then execute in non-blocking mode.
609 BSP requests the function specified by
610 Procedure to be started on all the enabled
611 APs, and go on executing immediately. If
612 all return from Procedure, or TimeoutInMicroSeconds
613 expires, this event is signaled. The BSP
614 can use the CheckEvent() or WaitForEvent()
615 services to check the state of event. Type
616 EFI_EVENT is defined in CreateEvent() in
617 the Unified Extensible Firmware Interface
619 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
620 APs to return from Procedure, either for
621 blocking or non-blocking mode. Zero means
622 infinity. If the timeout expires before
623 all APs return from Procedure, then Procedure
624 on the failed APs is terminated. All enabled
625 APs are available for next function assigned
626 by MpInitLibStartupAllAPs() or
627 MPInitLibStartupThisAP().
628 If the timeout expires in blocking mode,
629 BSP returns EFI_TIMEOUT. If the timeout
630 expires in non-blocking mode, WaitEvent
631 is signaled with SignalEvent().
632 @param[in] ProcedureArgument The parameter passed into Procedure for
634 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
635 if all APs finish successfully, then its
636 content is set to NULL. If not all APs
637 finish before timeout expires, then its
638 content is set to address of the buffer
639 holding handle numbers of the failed APs.
640 The buffer is allocated by MP Initialization
641 library, and it's the caller's responsibility to
642 free the buffer with FreePool() service.
643 In blocking mode, it is ready for consumption
644 when the call returns. In non-blocking mode,
645 it is ready when WaitEvent is signaled. The
646 list of failed CPU is terminated by
649 @retval EFI_SUCCESS In blocking mode, all APs have finished before
651 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
653 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
654 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
656 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
658 @retval EFI_DEVICE_ERROR Caller processor is AP.
659 @retval EFI_NOT_STARTED No enabled APs exist in the system.
660 @retval EFI_NOT_READY Any enabled APs are busy.
661 @retval EFI_NOT_READY MP Initialize Library is not initialized.
662 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
663 all enabled APs have finished.
664 @retval EFI_INVALID_PARAMETER Procedure is NULL.
669 MpInitLibStartupAllAPs (
670 IN EFI_AP_PROCEDURE Procedure
,
671 IN BOOLEAN SingleThread
,
672 IN EFI_EVENT WaitEvent OPTIONAL
,
673 IN UINTN TimeoutInMicroseconds
,
674 IN VOID
*ProcedureArgument OPTIONAL
,
675 OUT UINTN
**FailedCpuList OPTIONAL
681 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
683 mStopCheckAllApsStatus
= TRUE
;
685 Status
= StartupAllCPUsWorker (
690 TimeoutInMicroseconds
,
696 // Start checkAllApsStatus
698 mStopCheckAllApsStatus
= FALSE
;
704 This service lets the caller get one enabled AP to execute a caller-provided
707 @param[in] Procedure A pointer to the function to be run on the
708 designated AP of the system. See type
710 @param[in] ProcessorNumber The handle number of the AP. The range is
711 from 0 to the total number of logical
712 processors minus 1. The total number of
713 logical processors can be retrieved by
714 MpInitLibGetNumberOfProcessors().
715 @param[in] WaitEvent The event created by the caller with CreateEvent()
716 service. If it is NULL, then execute in
717 blocking mode. BSP waits until this AP finish
718 or TimeoutInMicroSeconds expires. If it's
719 not NULL, then execute in non-blocking mode.
720 BSP requests the function specified by
721 Procedure to be started on this AP,
722 and go on executing immediately. If this AP
723 return from Procedure or TimeoutInMicroSeconds
724 expires, this event is signaled. The BSP
725 can use the CheckEvent() or WaitForEvent()
726 services to check the state of event. Type
727 EFI_EVENT is defined in CreateEvent() in
728 the Unified Extensible Firmware Interface
730 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
731 this AP to finish this Procedure, either for
732 blocking or non-blocking mode. Zero means
733 infinity. If the timeout expires before
734 this AP returns from Procedure, then Procedure
735 on the AP is terminated. The
736 AP is available for next function assigned
737 by MpInitLibStartupAllAPs() or
738 MpInitLibStartupThisAP().
739 If the timeout expires in blocking mode,
740 BSP returns EFI_TIMEOUT. If the timeout
741 expires in non-blocking mode, WaitEvent
742 is signaled with SignalEvent().
743 @param[in] ProcedureArgument The parameter passed into Procedure on the
745 @param[out] Finished If NULL, this parameter is ignored. In
746 blocking mode, this parameter is ignored.
747 In non-blocking mode, if AP returns from
748 Procedure before the timeout expires, its
749 content is set to TRUE. Otherwise, the
750 value is set to FALSE. The caller can
751 determine if the AP returned from Procedure
752 by evaluating this value.
754 @retval EFI_SUCCESS In blocking mode, specified AP finished before
756 @retval EFI_SUCCESS In non-blocking mode, the function has been
757 dispatched to specified AP.
758 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
759 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
761 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
763 @retval EFI_DEVICE_ERROR The calling processor is an AP.
764 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
765 the specified AP has finished.
766 @retval EFI_NOT_READY The specified AP is busy.
767 @retval EFI_NOT_READY MP Initialize Library is not initialized.
768 @retval EFI_NOT_FOUND The processor with the handle specified by
769 ProcessorNumber does not exist.
770 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
771 @retval EFI_INVALID_PARAMETER Procedure is NULL.
776 MpInitLibStartupThisAP (
777 IN EFI_AP_PROCEDURE Procedure
,
778 IN UINTN ProcessorNumber
,
779 IN EFI_EVENT WaitEvent OPTIONAL
,
780 IN UINTN TimeoutInMicroseconds
,
781 IN VOID
*ProcedureArgument OPTIONAL
,
782 OUT BOOLEAN
*Finished OPTIONAL
788 // temporarily stop checkAllApsStatus for avoid resource dead-lock.
790 mStopCheckAllApsStatus
= TRUE
;
792 Status
= StartupThisAPWorker (
796 TimeoutInMicroseconds
,
801 mStopCheckAllApsStatus
= FALSE
;
807 This service switches the requested AP to be the BSP from that point onward.
808 This service changes the BSP for all purposes. This call can only be performed
811 @param[in] ProcessorNumber The handle number of AP that is to become the new
812 BSP. The range is from 0 to the total number of
813 logical processors minus 1. The total number of
814 logical processors can be retrieved by
815 MpInitLibGetNumberOfProcessors().
816 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
817 enabled AP. Otherwise, it will be disabled.
819 @retval EFI_SUCCESS BSP successfully switched.
820 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
821 this service returning.
822 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
823 @retval EFI_DEVICE_ERROR The calling processor is an AP.
824 @retval EFI_NOT_FOUND The processor with the handle specified by
825 ProcessorNumber does not exist.
826 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
828 @retval EFI_NOT_READY The specified AP is busy.
829 @retval EFI_NOT_READY MP Initialize Library is not initialized.
835 IN UINTN ProcessorNumber
,
836 IN BOOLEAN EnableOldBSP
840 EFI_TIMER_ARCH_PROTOCOL
*Timer
;
845 // Locate Timer Arch Protocol
847 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**) &Timer
);
848 if (EFI_ERROR (Status
)) {
854 // Save current rate of DXE Timer
856 Timer
->GetTimerPeriod (Timer
, &TimerPeriod
);
858 // Disable DXE Timer and drain pending interrupts
860 Timer
->SetTimerPeriod (Timer
, 0);
863 Status
= SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
867 // Enable and restore rate of DXE Timer
869 Timer
->SetTimerPeriod (Timer
, TimerPeriod
);
876 This service lets the caller enable or disable an AP from this point onward.
877 This service may only be called from the BSP.
879 @param[in] ProcessorNumber The handle number of AP.
880 The range is from 0 to the total number of
881 logical processors minus 1. The total number of
882 logical processors can be retrieved by
883 MpInitLibGetNumberOfProcessors().
884 @param[in] EnableAP Specifies the new state for the processor for
885 enabled, FALSE for disabled.
886 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
887 the new health status of the AP. This flag
888 corresponds to StatusFlag defined in
889 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
890 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
891 bits are ignored. If it is NULL, this parameter
894 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
895 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
896 prior to this service returning.
897 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
898 @retval EFI_DEVICE_ERROR The calling processor is an AP.
899 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
901 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
902 @retval EFI_NOT_READY MP Initialize Library is not initialized.
907 MpInitLibEnableDisableAP (
908 IN UINTN ProcessorNumber
,
910 IN UINT32
*HealthFlag OPTIONAL
914 BOOLEAN TempStopCheckState
;
916 TempStopCheckState
= FALSE
;
918 // temporarily stop checkAllAPsStatus for initialize parameters.
920 if (!mStopCheckAllApsStatus
) {
921 mStopCheckAllApsStatus
= TRUE
;
922 TempStopCheckState
= TRUE
;
925 Status
= EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
927 if (TempStopCheckState
) {
928 mStopCheckAllApsStatus
= FALSE
;
935 This funtion will try to invoke platform specific microcode shadow logic to
936 relocate microcode update patches into memory.
938 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
940 @retval EFI_SUCCESS Shadow microcode success.
941 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
942 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
946 PlatformShadowMicrocode (
947 IN OUT CPU_MP_DATA
*CpuMpData
951 // There is no DXE version of platform shadow microcode protocol so far.
952 // A platform which only uses DxeMpInitLib instance could only supports
953 // the PCD based microcode shadowing.
955 return EFI_UNSUPPORTED
;