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 // Begin wakeup buffer allocation below 0x88000
35 STATIC EFI_PHYSICAL_ADDRESS mSevEsDxeWakeupBuffer
= 0x88000;
38 Enable Debug Agent to support source debugging on AP function.
47 // Initialize Debug Agent to support source level debug in DXE phase
49 InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP
, NULL
, NULL
);
53 Get the pointer to CPU MP Data structure.
55 @return The pointer to CPU MP Data structure.
62 ASSERT (mCpuMpData
!= NULL
);
67 Save the pointer to CPU MP Data structure.
69 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
73 IN CPU_MP_DATA
*CpuMpData
76 mCpuMpData
= CpuMpData
;
80 Get available system memory below 0x88000 by specified size.
82 @param[in] WakeupBufferSize Wakeup buffer size required
84 @retval other Return wakeup buffer address below 1MB.
85 @retval -1 Cannot find free memory below 1MB.
89 IN UINTN WakeupBufferSize
93 EFI_PHYSICAL_ADDRESS StartAddress
;
94 EFI_MEMORY_TYPE MemoryType
;
96 if (PcdGetBool (PcdSevEsIsEnabled
)) {
97 MemoryType
= EfiReservedMemoryType
;
99 MemoryType
= EfiBootServicesData
;
103 // Try to allocate buffer below 1M for waking vector.
104 // LegacyBios driver only reports warning when page allocation in range
105 // [0x60000, 0x88000) fails.
106 // This library is consumed by CpuDxe driver to produce CPU Arch protocol.
107 // LagacyBios driver depends on CPU Arch protocol which guarantees below
108 // allocation runs earlier than LegacyBios driver.
110 if (PcdGetBool (PcdSevEsIsEnabled
)) {
112 // SEV-ES Wakeup buffer should be under 0x88000 and under any previous one
114 StartAddress
= mSevEsDxeWakeupBuffer
;
116 StartAddress
= 0x88000;
118 Status
= gBS
->AllocatePages (
121 EFI_SIZE_TO_PAGES (WakeupBufferSize
),
124 ASSERT_EFI_ERROR (Status
);
125 if (EFI_ERROR (Status
)) {
126 StartAddress
= (EFI_PHYSICAL_ADDRESS
) -1;
127 } else if (PcdGetBool (PcdSevEsIsEnabled
)) {
129 // Next SEV-ES wakeup buffer allocation must be below this allocation
131 mSevEsDxeWakeupBuffer
= StartAddress
;
134 DEBUG ((DEBUG_INFO
, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
135 (UINTN
) StartAddress
, WakeupBufferSize
));
137 return (UINTN
) StartAddress
;
141 Get available EfiBootServicesCode memory below 4GB by specified size.
143 This buffer is required to safely transfer AP from real address mode to
144 protected mode or long mode, due to the fact that the buffer returned by
145 GetWakeupBuffer() may be marked as non-executable.
147 @param[in] BufferSize Wakeup transition buffer size.
149 @retval other Return wakeup transition buffer address below 4GB.
150 @retval 0 Cannot find free memory below 4GB.
153 GetModeTransitionBuffer (
158 EFI_PHYSICAL_ADDRESS StartAddress
;
160 StartAddress
= BASE_4GB
- 1;
161 Status
= gBS
->AllocatePages (
164 EFI_SIZE_TO_PAGES (BufferSize
),
167 if (EFI_ERROR (Status
)) {
171 return (UINTN
)StartAddress
;
175 Return the address of the SEV-ES AP jump table.
177 This buffer is required in order for an SEV-ES guest to transition from
180 @return Return SEV-ES AP jump table buffer
188 EFI_PHYSICAL_ADDRESS StartAddress
;
189 MSR_SEV_ES_GHCB_REGISTER Msr
;
191 BOOLEAN InterruptState
;
194 // Allocate 1 page for AP jump table page
196 StartAddress
= BASE_4GB
- 1;
197 Status
= gBS
->AllocatePages (
199 EfiReservedMemoryType
,
203 ASSERT_EFI_ERROR (Status
);
205 DEBUG ((DEBUG_INFO
, "Dxe: SevEsAPMemory = %lx\n", (UINTN
) StartAddress
));
208 // Save the SevEsAPMemory as the AP jump table.
210 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
213 VmgInit (Ghcb
, &InterruptState
);
214 VmgExit (Ghcb
, SVM_EXIT_AP_JUMP_TABLE
, 0, (UINT64
) (UINTN
) StartAddress
);
215 VmgDone (Ghcb
, InterruptState
);
217 return (UINTN
) StartAddress
;
221 Checks APs status and updates APs status if needed.
225 CheckAndUpdateApsStatus (
229 UINTN ProcessorNumber
;
231 CPU_MP_DATA
*CpuMpData
;
233 CpuMpData
= GetCpuMpData ();
236 // First, check whether pending StartupAllAPs() exists.
238 if (CpuMpData
->WaitEvent
!= NULL
) {
240 Status
= CheckAllAPs ();
242 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
244 if (Status
!= EFI_NOT_READY
) {
245 Status
= gBS
->SignalEvent (CpuMpData
->WaitEvent
);
246 CpuMpData
->WaitEvent
= NULL
;
251 // Second, check whether pending StartupThisAPs() callings exist.
253 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
255 if (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
== NULL
) {
259 Status
= CheckThisAP (ProcessorNumber
);
261 if (Status
!= EFI_NOT_READY
) {
262 gBS
->SignalEvent (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
);
263 CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
= NULL
;
269 Checks APs' status periodically.
271 This function is triggered by timer periodically to check the
272 state of APs for StartupAllAPs() and StartupThisAP() executed
273 in non-blocking mode.
275 @param[in] Event Event triggered.
276 @param[in] Context Parameter passed with the event.
287 // If CheckApsStatus() is not stopped, otherwise return immediately.
289 if (!mStopCheckAllApsStatus
) {
290 CheckAndUpdateApsStatus ();
295 Get Protected mode code segment with 16-bit default addressing
296 from current GDT table.
298 @return Protected mode 16-bit code segment value.
301 GetProtectedMode16CS (
305 IA32_DESCRIPTOR GdtrDesc
;
306 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
311 AsmReadGdtr (&GdtrDesc
);
312 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
313 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
314 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
315 if (GdtEntry
->Bits
.L
== 0) {
316 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.DB
== 0) {
322 ASSERT (Index
!= GdtEntryCount
);
327 Get Protected mode code segment from current GDT table.
329 @return Protected mode code segment value.
336 IA32_DESCRIPTOR GdtrDesc
;
337 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
341 AsmReadGdtr (&GdtrDesc
);
342 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
343 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
344 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
345 if (GdtEntry
->Bits
.L
== 0) {
346 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.DB
== 1) {
352 ASSERT (Index
!= GdtEntryCount
);
359 @param[in, out] Buffer Pointer to private data buffer.
367 CPU_MP_DATA
*CpuMpData
;
368 BOOLEAN MwaitSupport
;
369 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc
;
370 UINTN ProcessorNumber
;
373 MpInitLibWhoAmI (&ProcessorNumber
);
374 CpuMpData
= GetCpuMpData ();
375 MwaitSupport
= IsMwaitSupport ();
376 if (CpuMpData
->SevEsIsEnabled
) {
377 StackStart
= CpuMpData
->SevEsAPResetStackStart
;
379 StackStart
= mReservedTopOfApStack
;
381 AsmRelocateApLoopFunc
= (ASM_RELOCATE_AP_LOOP
) (UINTN
) mReservedApLoopFunc
;
382 AsmRelocateApLoopFunc (
384 CpuMpData
->ApTargetCState
,
385 CpuMpData
->PmCodeSegment
,
386 StackStart
- ProcessorNumber
* AP_SAFE_STACK_SIZE
,
387 (UINTN
) &mNumberToFinish
,
388 CpuMpData
->Pm16CodeSegment
,
389 CpuMpData
->SevEsAPBuffer
,
390 CpuMpData
->WakeupBuffer
393 // It should never reach here
399 Callback function for ExitBootServices.
401 @param[in] Event Event whose notification function is being invoked.
402 @param[in] Context The pointer to the notification function's context,
403 which is implementation-dependent.
408 MpInitChangeApLoopCallback (
413 CPU_MP_DATA
*CpuMpData
;
415 CpuMpData
= GetCpuMpData ();
416 CpuMpData
->PmCodeSegment
= GetProtectedModeCS ();
417 CpuMpData
->Pm16CodeSegment
= GetProtectedMode16CS ();
418 CpuMpData
->ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
419 mNumberToFinish
= CpuMpData
->CpuCount
- 1;
420 WakeUpAP (CpuMpData
, TRUE
, 0, RelocateApLoop
, NULL
, TRUE
);
421 while (mNumberToFinish
> 0) {
425 if (CpuMpData
->SevEsIsEnabled
&& (CpuMpData
->WakeupBuffer
!= (UINTN
) -1)) {
427 // There are APs present. Re-use reserved memory area below 1MB from
428 // WakeupBuffer as the area to be used for transitioning to 16-bit mode
429 // in support of booting of the AP by an OS.
432 (VOID
*) CpuMpData
->WakeupBuffer
,
433 (VOID
*) (CpuMpData
->AddressMap
.RendezvousFunnelAddress
+
434 CpuMpData
->AddressMap
.SwitchToRealPM16ModeOffset
),
435 CpuMpData
->AddressMap
.SwitchToRealPM16ModeSize
439 DEBUG ((DEBUG_INFO
, "%a() done!\n", __FUNCTION__
));
443 Initialize global data for MP support.
445 @param[in] CpuMpData The pointer to CPU MP Data structure.
449 IN CPU_MP_DATA
*CpuMpData
453 EFI_PHYSICAL_ADDRESS Address
;
454 UINTN ApSafeBufferSize
;
456 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc
;
458 CPU_INFO_IN_HOB
*CpuInfoInHob
;
460 SaveCpuMpData (CpuMpData
);
462 if (CpuMpData
->CpuCount
== 1) {
464 // If only BSP exists, return
469 if (PcdGetBool (PcdCpuStackGuard
)) {
471 // One extra page at the bottom of the stack is needed for Guard page.
473 if (CpuMpData
->CpuApStackSize
<= EFI_PAGE_SIZE
) {
474 DEBUG ((DEBUG_ERROR
, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
479 // DXE will reuse stack allocated for APs at PEI phase if it's available.
480 // Let's check it here.
482 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of
483 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be
486 CpuInfoInHob
= (CPU_INFO_IN_HOB
*)(UINTN
)CpuMpData
->CpuInfoInHob
;
487 for (Index
= 0; Index
< CpuMpData
->CpuCount
; ++Index
) {
488 if (CpuInfoInHob
!= NULL
&& CpuInfoInHob
[Index
].ApTopOfStack
!= 0) {
489 StackBase
= (UINTN
)CpuInfoInHob
[Index
].ApTopOfStack
- CpuMpData
->CpuApStackSize
;
491 StackBase
= CpuMpData
->Buffer
+ Index
* CpuMpData
->CpuApStackSize
;
494 Status
= gDS
->GetMemorySpaceDescriptor (StackBase
, &MemDesc
);
495 ASSERT_EFI_ERROR (Status
);
497 Status
= gDS
->SetMemorySpaceAttributes (
499 EFI_PAGES_TO_SIZE (1),
500 MemDesc
.Attributes
| EFI_MEMORY_RP
502 ASSERT_EFI_ERROR (Status
);
504 DEBUG ((DEBUG_INFO
, "Stack Guard set at %lx [cpu%lu]!\n",
505 (UINT64
)StackBase
, (UINT64
)Index
));
510 // Avoid APs access invalid buffer data which allocated by BootServices,
511 // so we will allocate reserved data for AP loop code. We also need to
512 // allocate this buffer below 4GB due to APs may be transferred to 32bit
513 // protected mode on long mode DXE.
514 // Allocating it in advance since memory services are not available in
515 // Exit Boot Services callback function.
517 ApSafeBufferSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (
518 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
520 Address
= BASE_4GB
- 1;
521 Status
= gBS
->AllocatePages (
523 EfiReservedMemoryType
,
524 EFI_SIZE_TO_PAGES (ApSafeBufferSize
),
527 ASSERT_EFI_ERROR (Status
);
529 mReservedApLoopFunc
= (VOID
*) (UINTN
) Address
;
530 ASSERT (mReservedApLoopFunc
!= NULL
);
533 // Make sure that the buffer memory is executable if NX protection is enabled
534 // for EfiReservedMemoryType.
536 // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD
539 Status
= gDS
->GetMemorySpaceDescriptor (Address
, &MemDesc
);
540 if (!EFI_ERROR (Status
)) {
541 gDS
->SetMemorySpaceAttributes (
544 MemDesc
.Attributes
& (~EFI_MEMORY_XP
)
548 ApSafeBufferSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (
549 CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
551 Address
= BASE_4GB
- 1;
552 Status
= gBS
->AllocatePages (
554 EfiReservedMemoryType
,
555 EFI_SIZE_TO_PAGES (ApSafeBufferSize
),
558 ASSERT_EFI_ERROR (Status
);
560 mReservedTopOfApStack
= (UINTN
) Address
+ ApSafeBufferSize
;
561 ASSERT ((mReservedTopOfApStack
& (UINTN
)(CPU_STACK_ALIGNMENT
- 1)) == 0);
564 CpuMpData
->AddressMap
.RelocateApLoopFuncAddress
,
565 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
568 Status
= gBS
->CreateEvent (
569 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
575 ASSERT_EFI_ERROR (Status
);
578 // Set timer to check all APs status.
580 Status
= gBS
->SetTimer (
583 EFI_TIMER_PERIOD_MICROSECONDS (
584 PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds
)
587 ASSERT_EFI_ERROR (Status
);
589 Status
= gBS
->CreateEvent (
590 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
592 MpInitChangeApLoopCallback
,
594 &mMpInitExitBootServicesEvent
596 ASSERT_EFI_ERROR (Status
);
598 Status
= gBS
->CreateEventEx (
601 MpInitChangeApLoopCallback
,
603 &gEfiEventLegacyBootGuid
,
606 ASSERT_EFI_ERROR (Status
);
610 This service executes a caller provided function on all enabled APs.
612 @param[in] Procedure A pointer to the function to be run on
613 enabled APs of the system. See type
615 @param[in] SingleThread If TRUE, then all the enabled APs execute
616 the function specified by Procedure one by
617 one, in ascending order of processor handle
618 number. If FALSE, then all the enabled APs
619 execute the function specified by Procedure
621 @param[in] WaitEvent The event created by the caller with CreateEvent()
622 service. If it is NULL, then execute in
623 blocking mode. BSP waits until all APs finish
624 or TimeoutInMicroSeconds expires. If it's
625 not NULL, then execute in non-blocking mode.
626 BSP requests the function specified by
627 Procedure to be started on all the enabled
628 APs, and go on executing immediately. If
629 all return from Procedure, or TimeoutInMicroSeconds
630 expires, this event is signaled. The BSP
631 can use the CheckEvent() or WaitForEvent()
632 services to check the state of event. Type
633 EFI_EVENT is defined in CreateEvent() in
634 the Unified Extensible Firmware Interface
636 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
637 APs to return from Procedure, either for
638 blocking or non-blocking mode. Zero means
639 infinity. If the timeout expires before
640 all APs return from Procedure, then Procedure
641 on the failed APs is terminated. All enabled
642 APs are available for next function assigned
643 by MpInitLibStartupAllAPs() or
644 MPInitLibStartupThisAP().
645 If the timeout expires in blocking mode,
646 BSP returns EFI_TIMEOUT. If the timeout
647 expires in non-blocking mode, WaitEvent
648 is signaled with SignalEvent().
649 @param[in] ProcedureArgument The parameter passed into Procedure for
651 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
652 if all APs finish successfully, then its
653 content is set to NULL. If not all APs
654 finish before timeout expires, then its
655 content is set to address of the buffer
656 holding handle numbers of the failed APs.
657 The buffer is allocated by MP Initialization
658 library, and it's the caller's responsibility to
659 free the buffer with FreePool() service.
660 In blocking mode, it is ready for consumption
661 when the call returns. In non-blocking mode,
662 it is ready when WaitEvent is signaled. The
663 list of failed CPU is terminated by
666 @retval EFI_SUCCESS In blocking mode, all APs have finished before
668 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
670 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
671 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
673 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
675 @retval EFI_DEVICE_ERROR Caller processor is AP.
676 @retval EFI_NOT_STARTED No enabled APs exist in the system.
677 @retval EFI_NOT_READY Any enabled APs are busy.
678 @retval EFI_NOT_READY MP Initialize Library is not initialized.
679 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
680 all enabled APs have finished.
681 @retval EFI_INVALID_PARAMETER Procedure is NULL.
686 MpInitLibStartupAllAPs (
687 IN EFI_AP_PROCEDURE Procedure
,
688 IN BOOLEAN SingleThread
,
689 IN EFI_EVENT WaitEvent OPTIONAL
,
690 IN UINTN TimeoutInMicroseconds
,
691 IN VOID
*ProcedureArgument OPTIONAL
,
692 OUT UINTN
**FailedCpuList OPTIONAL
698 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
700 mStopCheckAllApsStatus
= TRUE
;
702 Status
= StartupAllCPUsWorker (
707 TimeoutInMicroseconds
,
713 // Start checkAllApsStatus
715 mStopCheckAllApsStatus
= FALSE
;
721 This service lets the caller get one enabled AP to execute a caller-provided
724 @param[in] Procedure A pointer to the function to be run on the
725 designated AP of the system. See type
727 @param[in] ProcessorNumber The handle number of the AP. The range is
728 from 0 to the total number of logical
729 processors minus 1. The total number of
730 logical processors can be retrieved by
731 MpInitLibGetNumberOfProcessors().
732 @param[in] WaitEvent The event created by the caller with CreateEvent()
733 service. If it is NULL, then execute in
734 blocking mode. BSP waits until this AP finish
735 or TimeoutInMicroSeconds expires. If it's
736 not NULL, then execute in non-blocking mode.
737 BSP requests the function specified by
738 Procedure to be started on this AP,
739 and go on executing immediately. If this AP
740 return from Procedure or TimeoutInMicroSeconds
741 expires, this event is signaled. The BSP
742 can use the CheckEvent() or WaitForEvent()
743 services to check the state of event. Type
744 EFI_EVENT is defined in CreateEvent() in
745 the Unified Extensible Firmware Interface
747 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
748 this AP to finish this Procedure, either for
749 blocking or non-blocking mode. Zero means
750 infinity. If the timeout expires before
751 this AP returns from Procedure, then Procedure
752 on the AP is terminated. The
753 AP is available for next function assigned
754 by MpInitLibStartupAllAPs() or
755 MpInitLibStartupThisAP().
756 If the timeout expires in blocking mode,
757 BSP returns EFI_TIMEOUT. If the timeout
758 expires in non-blocking mode, WaitEvent
759 is signaled with SignalEvent().
760 @param[in] ProcedureArgument The parameter passed into Procedure on the
762 @param[out] Finished If NULL, this parameter is ignored. In
763 blocking mode, this parameter is ignored.
764 In non-blocking mode, if AP returns from
765 Procedure before the timeout expires, its
766 content is set to TRUE. Otherwise, the
767 value is set to FALSE. The caller can
768 determine if the AP returned from Procedure
769 by evaluating this value.
771 @retval EFI_SUCCESS In blocking mode, specified AP finished before
773 @retval EFI_SUCCESS In non-blocking mode, the function has been
774 dispatched to specified AP.
775 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
776 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
778 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
780 @retval EFI_DEVICE_ERROR The calling processor is an AP.
781 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
782 the specified AP has finished.
783 @retval EFI_NOT_READY The specified AP is busy.
784 @retval EFI_NOT_READY MP Initialize Library is not initialized.
785 @retval EFI_NOT_FOUND The processor with the handle specified by
786 ProcessorNumber does not exist.
787 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
788 @retval EFI_INVALID_PARAMETER Procedure is NULL.
793 MpInitLibStartupThisAP (
794 IN EFI_AP_PROCEDURE Procedure
,
795 IN UINTN ProcessorNumber
,
796 IN EFI_EVENT WaitEvent OPTIONAL
,
797 IN UINTN TimeoutInMicroseconds
,
798 IN VOID
*ProcedureArgument OPTIONAL
,
799 OUT BOOLEAN
*Finished OPTIONAL
805 // temporarily stop checkAllApsStatus for avoid resource dead-lock.
807 mStopCheckAllApsStatus
= TRUE
;
809 Status
= StartupThisAPWorker (
813 TimeoutInMicroseconds
,
818 mStopCheckAllApsStatus
= FALSE
;
824 This service switches the requested AP to be the BSP from that point onward.
825 This service changes the BSP for all purposes. This call can only be performed
828 @param[in] ProcessorNumber The handle number of AP that is to become the new
829 BSP. The range is from 0 to the total number of
830 logical processors minus 1. The total number of
831 logical processors can be retrieved by
832 MpInitLibGetNumberOfProcessors().
833 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
834 enabled AP. Otherwise, it will be disabled.
836 @retval EFI_SUCCESS BSP successfully switched.
837 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
838 this service returning.
839 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
840 @retval EFI_DEVICE_ERROR The calling processor is an AP.
841 @retval EFI_NOT_FOUND The processor with the handle specified by
842 ProcessorNumber does not exist.
843 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
845 @retval EFI_NOT_READY The specified AP is busy.
846 @retval EFI_NOT_READY MP Initialize Library is not initialized.
852 IN UINTN ProcessorNumber
,
853 IN BOOLEAN EnableOldBSP
857 EFI_TIMER_ARCH_PROTOCOL
*Timer
;
862 // Locate Timer Arch Protocol
864 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**) &Timer
);
865 if (EFI_ERROR (Status
)) {
871 // Save current rate of DXE Timer
873 Timer
->GetTimerPeriod (Timer
, &TimerPeriod
);
875 // Disable DXE Timer and drain pending interrupts
877 Timer
->SetTimerPeriod (Timer
, 0);
880 Status
= SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
884 // Enable and restore rate of DXE Timer
886 Timer
->SetTimerPeriod (Timer
, TimerPeriod
);
893 This service lets the caller enable or disable an AP from this point onward.
894 This service may only be called from the BSP.
896 @param[in] ProcessorNumber The handle number of AP.
897 The range is from 0 to the total number of
898 logical processors minus 1. The total number of
899 logical processors can be retrieved by
900 MpInitLibGetNumberOfProcessors().
901 @param[in] EnableAP Specifies the new state for the processor for
902 enabled, FALSE for disabled.
903 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
904 the new health status of the AP. This flag
905 corresponds to StatusFlag defined in
906 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
907 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
908 bits are ignored. If it is NULL, this parameter
911 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
912 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
913 prior to this service returning.
914 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
915 @retval EFI_DEVICE_ERROR The calling processor is an AP.
916 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
918 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
919 @retval EFI_NOT_READY MP Initialize Library is not initialized.
924 MpInitLibEnableDisableAP (
925 IN UINTN ProcessorNumber
,
927 IN UINT32
*HealthFlag OPTIONAL
931 BOOLEAN TempStopCheckState
;
933 TempStopCheckState
= FALSE
;
935 // temporarily stop checkAllAPsStatus for initialize parameters.
937 if (!mStopCheckAllApsStatus
) {
938 mStopCheckAllApsStatus
= TRUE
;
939 TempStopCheckState
= TRUE
;
942 Status
= EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
944 if (TempStopCheckState
) {
945 mStopCheckAllApsStatus
= FALSE
;
952 This funtion will try to invoke platform specific microcode shadow logic to
953 relocate microcode update patches into memory.
955 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
957 @retval EFI_SUCCESS Shadow microcode success.
958 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
959 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
963 PlatformShadowMicrocode (
964 IN OUT CPU_MP_DATA
*CpuMpData
968 // There is no DXE version of platform shadow microcode protocol so far.
969 // A platform which only uses DxeMpInitLib instance could only supports
970 // the PCD based microcode shadowing.
972 return EFI_UNSUPPORTED
;