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
;
176 // Allocate 1 page for AP jump table page
178 StartAddress
= BASE_4GB
- 1;
179 Status
= gBS
->AllocatePages (
181 EfiReservedMemoryType
,
185 ASSERT_EFI_ERROR (Status
);
187 DEBUG ((DEBUG_INFO
, "Dxe: SevEsAPMemory = %lx\n", (UINTN
) StartAddress
));
190 // Save the SevEsAPMemory as the AP jump table.
192 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
196 VmgExit (Ghcb
, SVM_EXIT_AP_JUMP_TABLE
, 0, (UINT64
) (UINTN
) StartAddress
);
199 return (UINTN
) StartAddress
;
203 Checks APs status and updates APs status if needed.
207 CheckAndUpdateApsStatus (
211 UINTN ProcessorNumber
;
213 CPU_MP_DATA
*CpuMpData
;
215 CpuMpData
= GetCpuMpData ();
218 // First, check whether pending StartupAllAPs() exists.
220 if (CpuMpData
->WaitEvent
!= NULL
) {
222 Status
= CheckAllAPs ();
224 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
226 if (Status
!= EFI_NOT_READY
) {
227 Status
= gBS
->SignalEvent (CpuMpData
->WaitEvent
);
228 CpuMpData
->WaitEvent
= NULL
;
233 // Second, check whether pending StartupThisAPs() callings exist.
235 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
237 if (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
== NULL
) {
241 Status
= CheckThisAP (ProcessorNumber
);
243 if (Status
!= EFI_NOT_READY
) {
244 gBS
->SignalEvent (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
);
245 CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
= NULL
;
251 Checks APs' status periodically.
253 This function is triggered by timer periodically to check the
254 state of APs for StartupAllAPs() and StartupThisAP() executed
255 in non-blocking mode.
257 @param[in] Event Event triggered.
258 @param[in] Context Parameter passed with the event.
269 // If CheckApsStatus() is not stopped, otherwise return immediately.
271 if (!mStopCheckAllApsStatus
) {
272 CheckAndUpdateApsStatus ();
277 Get Protected mode code segment with 16-bit default addressing
278 from current GDT table.
280 @return Protected mode 16-bit code segment value.
283 GetProtectedMode16CS (
287 IA32_DESCRIPTOR GdtrDesc
;
288 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
293 AsmReadGdtr (&GdtrDesc
);
294 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
295 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
296 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
297 if (GdtEntry
->Bits
.L
== 0) {
298 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.DB
== 0) {
304 ASSERT (Index
!= GdtEntryCount
);
309 Get Protected mode code segment from current GDT table.
311 @return Protected mode code segment value.
318 IA32_DESCRIPTOR GdtrDesc
;
319 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
323 AsmReadGdtr (&GdtrDesc
);
324 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
325 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
326 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
327 if (GdtEntry
->Bits
.L
== 0) {
328 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.DB
== 1) {
334 ASSERT (Index
!= GdtEntryCount
);
341 @param[in, out] Buffer Pointer to private data buffer.
349 CPU_MP_DATA
*CpuMpData
;
350 BOOLEAN MwaitSupport
;
351 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc
;
352 UINTN ProcessorNumber
;
355 MpInitLibWhoAmI (&ProcessorNumber
);
356 CpuMpData
= GetCpuMpData ();
357 MwaitSupport
= IsMwaitSupport ();
358 if (CpuMpData
->SevEsIsEnabled
) {
359 StackStart
= CpuMpData
->SevEsAPResetStackStart
;
361 StackStart
= mReservedTopOfApStack
;
363 AsmRelocateApLoopFunc
= (ASM_RELOCATE_AP_LOOP
) (UINTN
) mReservedApLoopFunc
;
364 AsmRelocateApLoopFunc (
366 CpuMpData
->ApTargetCState
,
367 CpuMpData
->PmCodeSegment
,
368 StackStart
- ProcessorNumber
* AP_SAFE_STACK_SIZE
,
369 (UINTN
) &mNumberToFinish
,
370 CpuMpData
->Pm16CodeSegment
,
371 CpuMpData
->SevEsAPBuffer
,
372 CpuMpData
->WakeupBuffer
375 // It should never reach here
381 Callback function for ExitBootServices.
383 @param[in] Event Event whose notification function is being invoked.
384 @param[in] Context The pointer to the notification function's context,
385 which is implementation-dependent.
390 MpInitChangeApLoopCallback (
395 CPU_MP_DATA
*CpuMpData
;
397 CpuMpData
= GetCpuMpData ();
398 CpuMpData
->PmCodeSegment
= GetProtectedModeCS ();
399 CpuMpData
->Pm16CodeSegment
= GetProtectedMode16CS ();
400 CpuMpData
->ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
401 mNumberToFinish
= CpuMpData
->CpuCount
- 1;
402 WakeUpAP (CpuMpData
, TRUE
, 0, RelocateApLoop
, NULL
, TRUE
);
403 while (mNumberToFinish
> 0) {
407 if (CpuMpData
->SevEsIsEnabled
&& (CpuMpData
->WakeupBuffer
!= (UINTN
) -1)) {
409 // There are APs present. Re-use reserved memory area below 1MB from
410 // WakeupBuffer as the area to be used for transitioning to 16-bit mode
411 // in support of booting of the AP by an OS.
414 (VOID
*) CpuMpData
->WakeupBuffer
,
415 (VOID
*) (CpuMpData
->AddressMap
.RendezvousFunnelAddress
+
416 CpuMpData
->AddressMap
.SwitchToRealPM16ModeOffset
),
417 CpuMpData
->AddressMap
.SwitchToRealPM16ModeSize
421 DEBUG ((DEBUG_INFO
, "%a() done!\n", __FUNCTION__
));
425 Initialize global data for MP support.
427 @param[in] CpuMpData The pointer to CPU MP Data structure.
431 IN CPU_MP_DATA
*CpuMpData
435 EFI_PHYSICAL_ADDRESS Address
;
436 UINTN ApSafeBufferSize
;
438 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc
;
440 CPU_INFO_IN_HOB
*CpuInfoInHob
;
442 SaveCpuMpData (CpuMpData
);
444 if (CpuMpData
->CpuCount
== 1) {
446 // If only BSP exists, return
451 if (PcdGetBool (PcdCpuStackGuard
)) {
453 // One extra page at the bottom of the stack is needed for Guard page.
455 if (CpuMpData
->CpuApStackSize
<= EFI_PAGE_SIZE
) {
456 DEBUG ((DEBUG_ERROR
, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
461 // DXE will reuse stack allocated for APs at PEI phase if it's available.
462 // Let's check it here.
464 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of
465 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be
468 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
469 for (Index
= 0; Index
< CpuMpData
->CpuCount
; ++Index
) {
470 if (CpuInfoInHob
!= NULL
&& CpuInfoInHob
[Index
].ApTopOfStack
!= 0) {
471 StackBase
= (UINTN
)CpuInfoInHob
[Index
].ApTopOfStack
- CpuMpData
->CpuApStackSize
;
473 StackBase
= CpuMpData
->Buffer
+ Index
* CpuMpData
->CpuApStackSize
;
476 Status
= gDS
->GetMemorySpaceDescriptor (StackBase
, &MemDesc
);
477 ASSERT_EFI_ERROR (Status
);
479 Status
= gDS
->SetMemorySpaceAttributes (
481 EFI_PAGES_TO_SIZE (1),
482 MemDesc
.Attributes
| EFI_MEMORY_RP
484 ASSERT_EFI_ERROR (Status
);
486 DEBUG ((DEBUG_INFO
, "Stack Guard set at %lx [cpu%lu]!\n",
487 (UINT64
)StackBase
, (UINT64
)Index
));
492 // Avoid APs access invalid buffer data which allocated by BootServices,
493 // so we will allocate reserved data for AP loop code. We also need to
494 // allocate this buffer below 4GB due to APs may be transferred to 32bit
495 // protected mode on long mode DXE.
496 // Allocating it in advance since memory services are not available in
497 // Exit Boot Services callback function.
499 ApSafeBufferSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (
500 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
502 Address
= BASE_4GB
- 1;
503 Status
= gBS
->AllocatePages (
505 EfiReservedMemoryType
,
506 EFI_SIZE_TO_PAGES (ApSafeBufferSize
),
509 ASSERT_EFI_ERROR (Status
);
511 mReservedApLoopFunc
= (VOID
*) (UINTN
) Address
;
512 ASSERT (mReservedApLoopFunc
!= NULL
);
515 // Make sure that the buffer memory is executable if NX protection is enabled
516 // for EfiReservedMemoryType.
518 // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD
521 Status
= gDS
->GetMemorySpaceDescriptor (Address
, &MemDesc
);
522 if (!EFI_ERROR (Status
)) {
523 gDS
->SetMemorySpaceAttributes (
526 MemDesc
.Attributes
& (~EFI_MEMORY_XP
)
530 ApSafeBufferSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (
531 CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
533 Address
= BASE_4GB
- 1;
534 Status
= gBS
->AllocatePages (
536 EfiReservedMemoryType
,
537 EFI_SIZE_TO_PAGES (ApSafeBufferSize
),
540 ASSERT_EFI_ERROR (Status
);
542 mReservedTopOfApStack
= (UINTN
) Address
+ ApSafeBufferSize
;
543 ASSERT ((mReservedTopOfApStack
& (UINTN
)(CPU_STACK_ALIGNMENT
- 1)) == 0);
546 CpuMpData
->AddressMap
.RelocateApLoopFuncAddress
,
547 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
550 Status
= gBS
->CreateEvent (
551 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
557 ASSERT_EFI_ERROR (Status
);
560 // Set timer to check all APs status.
562 Status
= gBS
->SetTimer (
565 EFI_TIMER_PERIOD_MICROSECONDS (
566 PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds
)
569 ASSERT_EFI_ERROR (Status
);
571 Status
= gBS
->CreateEvent (
572 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
574 MpInitChangeApLoopCallback
,
576 &mMpInitExitBootServicesEvent
578 ASSERT_EFI_ERROR (Status
);
580 Status
= gBS
->CreateEventEx (
583 MpInitChangeApLoopCallback
,
585 &gEfiEventLegacyBootGuid
,
588 ASSERT_EFI_ERROR (Status
);
592 This service executes a caller provided function on all enabled APs.
594 @param[in] Procedure A pointer to the function to be run on
595 enabled APs of the system. See type
597 @param[in] SingleThread If TRUE, then all the enabled APs execute
598 the function specified by Procedure one by
599 one, in ascending order of processor handle
600 number. If FALSE, then all the enabled APs
601 execute the function specified by Procedure
603 @param[in] WaitEvent The event created by the caller with CreateEvent()
604 service. If it is NULL, then execute in
605 blocking mode. BSP waits until all APs finish
606 or TimeoutInMicroSeconds expires. If it's
607 not NULL, then execute in non-blocking mode.
608 BSP requests the function specified by
609 Procedure to be started on all the enabled
610 APs, and go on executing immediately. If
611 all return from Procedure, or TimeoutInMicroSeconds
612 expires, this event is signaled. The BSP
613 can use the CheckEvent() or WaitForEvent()
614 services to check the state of event. Type
615 EFI_EVENT is defined in CreateEvent() in
616 the Unified Extensible Firmware Interface
618 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
619 APs to return from Procedure, either for
620 blocking or non-blocking mode. Zero means
621 infinity. If the timeout expires before
622 all APs return from Procedure, then Procedure
623 on the failed APs is terminated. All enabled
624 APs are available for next function assigned
625 by MpInitLibStartupAllAPs() or
626 MPInitLibStartupThisAP().
627 If the timeout expires in blocking mode,
628 BSP returns EFI_TIMEOUT. If the timeout
629 expires in non-blocking mode, WaitEvent
630 is signaled with SignalEvent().
631 @param[in] ProcedureArgument The parameter passed into Procedure for
633 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
634 if all APs finish successfully, then its
635 content is set to NULL. If not all APs
636 finish before timeout expires, then its
637 content is set to address of the buffer
638 holding handle numbers of the failed APs.
639 The buffer is allocated by MP Initialization
640 library, and it's the caller's responsibility to
641 free the buffer with FreePool() service.
642 In blocking mode, it is ready for consumption
643 when the call returns. In non-blocking mode,
644 it is ready when WaitEvent is signaled. The
645 list of failed CPU is terminated by
648 @retval EFI_SUCCESS In blocking mode, all APs have finished before
650 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
652 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
653 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
655 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
657 @retval EFI_DEVICE_ERROR Caller processor is AP.
658 @retval EFI_NOT_STARTED No enabled APs exist in the system.
659 @retval EFI_NOT_READY Any enabled APs are busy.
660 @retval EFI_NOT_READY MP Initialize Library is not initialized.
661 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
662 all enabled APs have finished.
663 @retval EFI_INVALID_PARAMETER Procedure is NULL.
668 MpInitLibStartupAllAPs (
669 IN EFI_AP_PROCEDURE Procedure
,
670 IN BOOLEAN SingleThread
,
671 IN EFI_EVENT WaitEvent OPTIONAL
,
672 IN UINTN TimeoutInMicroseconds
,
673 IN VOID
*ProcedureArgument OPTIONAL
,
674 OUT UINTN
**FailedCpuList OPTIONAL
680 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
682 mStopCheckAllApsStatus
= TRUE
;
684 Status
= StartupAllCPUsWorker (
689 TimeoutInMicroseconds
,
695 // Start checkAllApsStatus
697 mStopCheckAllApsStatus
= FALSE
;
703 This service lets the caller get one enabled AP to execute a caller-provided
706 @param[in] Procedure A pointer to the function to be run on the
707 designated AP of the system. See type
709 @param[in] ProcessorNumber The handle number of the AP. The range is
710 from 0 to the total number of logical
711 processors minus 1. The total number of
712 logical processors can be retrieved by
713 MpInitLibGetNumberOfProcessors().
714 @param[in] WaitEvent The event created by the caller with CreateEvent()
715 service. If it is NULL, then execute in
716 blocking mode. BSP waits until this AP finish
717 or TimeoutInMicroSeconds expires. If it's
718 not NULL, then execute in non-blocking mode.
719 BSP requests the function specified by
720 Procedure to be started on this AP,
721 and go on executing immediately. If this AP
722 return from Procedure or TimeoutInMicroSeconds
723 expires, this event is signaled. The BSP
724 can use the CheckEvent() or WaitForEvent()
725 services to check the state of event. Type
726 EFI_EVENT is defined in CreateEvent() in
727 the Unified Extensible Firmware Interface
729 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
730 this AP to finish this Procedure, either for
731 blocking or non-blocking mode. Zero means
732 infinity. If the timeout expires before
733 this AP returns from Procedure, then Procedure
734 on the AP is terminated. The
735 AP is available for next function assigned
736 by MpInitLibStartupAllAPs() or
737 MpInitLibStartupThisAP().
738 If the timeout expires in blocking mode,
739 BSP returns EFI_TIMEOUT. If the timeout
740 expires in non-blocking mode, WaitEvent
741 is signaled with SignalEvent().
742 @param[in] ProcedureArgument The parameter passed into Procedure on the
744 @param[out] Finished If NULL, this parameter is ignored. In
745 blocking mode, this parameter is ignored.
746 In non-blocking mode, if AP returns from
747 Procedure before the timeout expires, its
748 content is set to TRUE. Otherwise, the
749 value is set to FALSE. The caller can
750 determine if the AP returned from Procedure
751 by evaluating this value.
753 @retval EFI_SUCCESS In blocking mode, specified AP finished before
755 @retval EFI_SUCCESS In non-blocking mode, the function has been
756 dispatched to specified AP.
757 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
758 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
760 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
762 @retval EFI_DEVICE_ERROR The calling processor is an AP.
763 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
764 the specified AP has finished.
765 @retval EFI_NOT_READY The specified AP is busy.
766 @retval EFI_NOT_READY MP Initialize Library is not initialized.
767 @retval EFI_NOT_FOUND The processor with the handle specified by
768 ProcessorNumber does not exist.
769 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
770 @retval EFI_INVALID_PARAMETER Procedure is NULL.
775 MpInitLibStartupThisAP (
776 IN EFI_AP_PROCEDURE Procedure
,
777 IN UINTN ProcessorNumber
,
778 IN EFI_EVENT WaitEvent OPTIONAL
,
779 IN UINTN TimeoutInMicroseconds
,
780 IN VOID
*ProcedureArgument OPTIONAL
,
781 OUT BOOLEAN
*Finished OPTIONAL
787 // temporarily stop checkAllApsStatus for avoid resource dead-lock.
789 mStopCheckAllApsStatus
= TRUE
;
791 Status
= StartupThisAPWorker (
795 TimeoutInMicroseconds
,
800 mStopCheckAllApsStatus
= FALSE
;
806 This service switches the requested AP to be the BSP from that point onward.
807 This service changes the BSP for all purposes. This call can only be performed
810 @param[in] ProcessorNumber The handle number of AP that is to become the new
811 BSP. The range is from 0 to the total number of
812 logical processors minus 1. The total number of
813 logical processors can be retrieved by
814 MpInitLibGetNumberOfProcessors().
815 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
816 enabled AP. Otherwise, it will be disabled.
818 @retval EFI_SUCCESS BSP successfully switched.
819 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
820 this service returning.
821 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
822 @retval EFI_DEVICE_ERROR The calling processor is an AP.
823 @retval EFI_NOT_FOUND The processor with the handle specified by
824 ProcessorNumber does not exist.
825 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
827 @retval EFI_NOT_READY The specified AP is busy.
828 @retval EFI_NOT_READY MP Initialize Library is not initialized.
834 IN UINTN ProcessorNumber
,
835 IN BOOLEAN EnableOldBSP
839 EFI_TIMER_ARCH_PROTOCOL
*Timer
;
844 // Locate Timer Arch Protocol
846 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**) &Timer
);
847 if (EFI_ERROR (Status
)) {
853 // Save current rate of DXE Timer
855 Timer
->GetTimerPeriod (Timer
, &TimerPeriod
);
857 // Disable DXE Timer and drain pending interrupts
859 Timer
->SetTimerPeriod (Timer
, 0);
862 Status
= SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
866 // Enable and restore rate of DXE Timer
868 Timer
->SetTimerPeriod (Timer
, TimerPeriod
);
875 This service lets the caller enable or disable an AP from this point onward.
876 This service may only be called from the BSP.
878 @param[in] ProcessorNumber The handle number of AP.
879 The range is from 0 to the total number of
880 logical processors minus 1. The total number of
881 logical processors can be retrieved by
882 MpInitLibGetNumberOfProcessors().
883 @param[in] EnableAP Specifies the new state for the processor for
884 enabled, FALSE for disabled.
885 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
886 the new health status of the AP. This flag
887 corresponds to StatusFlag defined in
888 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
889 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
890 bits are ignored. If it is NULL, this parameter
893 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
894 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
895 prior to this service returning.
896 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
897 @retval EFI_DEVICE_ERROR The calling processor is an AP.
898 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
900 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
901 @retval EFI_NOT_READY MP Initialize Library is not initialized.
906 MpInitLibEnableDisableAP (
907 IN UINTN ProcessorNumber
,
909 IN UINT32
*HealthFlag OPTIONAL
913 BOOLEAN TempStopCheckState
;
915 TempStopCheckState
= FALSE
;
917 // temporarily stop checkAllAPsStatus for initialize parameters.
919 if (!mStopCheckAllApsStatus
) {
920 mStopCheckAllApsStatus
= TRUE
;
921 TempStopCheckState
= TRUE
;
924 Status
= EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
926 if (TempStopCheckState
) {
927 mStopCheckAllApsStatus
= FALSE
;
934 This funtion will try to invoke platform specific microcode shadow logic to
935 relocate microcode update patches into memory.
937 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
939 @retval EFI_SUCCESS Shadow microcode success.
940 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
941 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
945 PlatformShadowMicrocode (
946 IN OUT CPU_MP_DATA
*CpuMpData
950 // There is no DXE version of platform shadow microcode protocol so far.
951 // A platform which only uses DxeMpInitLib instance could only supports
952 // the PCD based microcode shadowing.
954 return EFI_UNSUPPORTED
;