2 MP initialize support functions for DXE phase.
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Library/UefiLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Library/DebugAgentLib.h>
21 #include <Protocol/Timer.h>
23 #define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100))
24 #define AP_SAFE_STACK_SIZE 128
26 CPU_MP_DATA
*mCpuMpData
= NULL
;
27 EFI_EVENT mCheckAllApsEvent
= NULL
;
28 EFI_EVENT mMpInitExitBootServicesEvent
= NULL
;
29 EFI_EVENT mLegacyBootEvent
= NULL
;
30 volatile BOOLEAN mStopCheckAllApsStatus
= TRUE
;
31 VOID
*mReservedApLoopFunc
= NULL
;
32 UINTN mReservedTopOfApStack
;
33 volatile UINT32 mNumberToFinish
= 0;
36 Enable Debug Agent to support source debugging on AP function.
45 // Initialize Debug Agent to support source level debug in DXE phase
47 InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP
, NULL
, NULL
);
51 Get the pointer to CPU MP Data structure.
53 @return The pointer to CPU MP Data structure.
60 ASSERT (mCpuMpData
!= NULL
);
65 Save the pointer to CPU MP Data structure.
67 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
71 IN CPU_MP_DATA
*CpuMpData
74 mCpuMpData
= CpuMpData
;
78 Allocate reset vector buffer.
80 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
84 IN OUT CPU_MP_DATA
*CpuMpData
88 UINTN ApResetVectorSize
;
89 EFI_PHYSICAL_ADDRESS StartAddress
;
91 if (CpuMpData
->SaveRestoreFlag
) {
92 BackupAndPrepareWakeupBuffer (CpuMpData
);
94 ApResetVectorSize
= CpuMpData
->AddressMap
.RendezvousFunnelSize
+
95 sizeof (MP_CPU_EXCHANGE_INFO
);
97 StartAddress
= BASE_1MB
;
98 Status
= gBS
->AllocatePages (
101 EFI_SIZE_TO_PAGES (ApResetVectorSize
),
104 ASSERT_EFI_ERROR (Status
);
106 CpuMpData
->WakeupBuffer
= (UINTN
) StartAddress
;
107 CpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
)
108 (CpuMpData
->WakeupBuffer
+ CpuMpData
->AddressMap
.RendezvousFunnelSize
);
110 // copy AP reset code in it
113 (VOID
*) CpuMpData
->WakeupBuffer
,
114 (VOID
*) CpuMpData
->AddressMap
.RendezvousFunnelAddress
,
115 CpuMpData
->AddressMap
.RendezvousFunnelSize
121 Free AP reset vector buffer.
123 @param[in] CpuMpData The pointer to CPU MP Data structure.
127 IN CPU_MP_DATA
*CpuMpData
131 UINTN ApResetVectorSize
;
133 if (CpuMpData
->SaveRestoreFlag
) {
134 RestoreWakeupBuffer (CpuMpData
);
136 ApResetVectorSize
= CpuMpData
->AddressMap
.RendezvousFunnelSize
+
137 sizeof (MP_CPU_EXCHANGE_INFO
);
138 Status
= gBS
->FreePages(
139 (EFI_PHYSICAL_ADDRESS
)CpuMpData
->WakeupBuffer
,
140 EFI_SIZE_TO_PAGES (ApResetVectorSize
)
142 ASSERT_EFI_ERROR (Status
);
147 Checks APs status and updates APs status if needed.
151 CheckAndUpdateApsStatus (
155 UINTN ProcessorNumber
;
157 CPU_MP_DATA
*CpuMpData
;
159 CpuMpData
= GetCpuMpData ();
162 // First, check whether pending StartupAllAPs() exists.
164 if (CpuMpData
->WaitEvent
!= NULL
) {
166 Status
= CheckAllAPs ();
168 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
170 if (Status
!= EFI_NOT_READY
) {
171 Status
= gBS
->SignalEvent (CpuMpData
->WaitEvent
);
172 CpuMpData
->WaitEvent
= NULL
;
177 // Second, check whether pending StartupThisAPs() callings exist.
179 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
181 if (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
== NULL
) {
185 Status
= CheckThisAP (ProcessorNumber
);
187 if (Status
!= EFI_NOT_READY
) {
188 gBS
->SignalEvent (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
);
189 CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
= NULL
;
195 Checks APs' status periodically.
197 This function is triggered by timer periodically to check the
198 state of APs for StartupAllAPs() and StartupThisAP() executed
199 in non-blocking mode.
201 @param[in] Event Event triggered.
202 @param[in] Context Parameter passed with the event.
213 // If CheckApsStatus() is not stopped, otherwise return immediately.
215 if (!mStopCheckAllApsStatus
) {
216 CheckAndUpdateApsStatus ();
221 Get Protected mode code segment from current GDT table.
223 @return Protected mode code segment value.
230 IA32_DESCRIPTOR GdtrDesc
;
231 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
236 AsmReadGdtr (&GdtrDesc
);
237 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
238 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
239 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
240 if (GdtEntry
->Bits
.L
== 0) {
241 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.L
== 0) {
247 ASSERT (Index
!= -1);
254 @param[in, out] Buffer Pointer to private data buffer.
262 CPU_MP_DATA
*CpuMpData
;
263 BOOLEAN MwaitSupport
;
264 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc
;
265 UINTN ProcessorNumber
;
267 MpInitLibWhoAmI (&ProcessorNumber
);
268 CpuMpData
= GetCpuMpData ();
269 MwaitSupport
= IsMwaitSupport ();
270 AsmRelocateApLoopFunc
= (ASM_RELOCATE_AP_LOOP
) (UINTN
) mReservedApLoopFunc
;
271 AsmRelocateApLoopFunc (
273 CpuMpData
->ApTargetCState
,
274 CpuMpData
->PmCodeSegment
,
275 mReservedTopOfApStack
- ProcessorNumber
* AP_SAFE_STACK_SIZE
,
276 (UINTN
) &mNumberToFinish
279 // It should never reach here
285 Callback function for ExitBootServices.
287 @param[in] Event Event whose notification function is being invoked.
288 @param[in] Context The pointer to the notification function's context,
289 which is implementation-dependent.
294 MpInitChangeApLoopCallback (
299 CPU_MP_DATA
*CpuMpData
;
301 CpuMpData
= GetCpuMpData ();
302 CpuMpData
->SaveRestoreFlag
= TRUE
;
303 CpuMpData
->PmCodeSegment
= GetProtectedModeCS ();
304 CpuMpData
->ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
305 mNumberToFinish
= CpuMpData
->CpuCount
- 1;
306 WakeUpAP (CpuMpData
, TRUE
, 0, RelocateApLoop
, NULL
);
307 while (mNumberToFinish
> 0) {
310 DEBUG ((DEBUG_INFO
, "%a() done!\n", __FUNCTION__
));
314 Initialize global data for MP support.
316 @param[in] CpuMpData The pointer to CPU MP Data structure.
320 IN CPU_MP_DATA
*CpuMpData
324 EFI_PHYSICAL_ADDRESS Address
;
325 UINTN ApSafeBufferSize
;
327 SaveCpuMpData (CpuMpData
);
329 if (CpuMpData
->CpuCount
== 1) {
331 // If only BSP exists, return
337 // Avoid APs access invalid buffer data which allocated by BootServices,
338 // so we will allocate reserved data for AP loop code. We also need to
339 // allocate this buffer below 4GB due to APs may be transferred to 32bit
340 // protected mode on long mode DXE.
341 // Allocating it in advance since memory services are not available in
342 // Exit Boot Services callback function.
344 ApSafeBufferSize
= CpuMpData
->AddressMap
.RelocateApLoopFuncSize
;
345 ApSafeBufferSize
+= CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
;
347 Address
= BASE_4GB
- 1;
348 Status
= gBS
->AllocatePages (
350 EfiReservedMemoryType
,
351 EFI_SIZE_TO_PAGES (ApSafeBufferSize
),
354 ASSERT_EFI_ERROR (Status
);
355 mReservedApLoopFunc
= (VOID
*) (UINTN
) Address
;
356 ASSERT (mReservedApLoopFunc
!= NULL
);
357 mReservedTopOfApStack
= (UINTN
) Address
+ EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ApSafeBufferSize
));
358 ASSERT ((mReservedTopOfApStack
& (UINTN
)(CPU_STACK_ALIGNMENT
- 1)) == 0);
361 CpuMpData
->AddressMap
.RelocateApLoopFuncAddress
,
362 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
365 Status
= gBS
->CreateEvent (
366 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
372 ASSERT_EFI_ERROR (Status
);
375 // Set timer to check all APs status.
377 Status
= gBS
->SetTimer (
382 ASSERT_EFI_ERROR (Status
);
384 Status
= gBS
->CreateEvent (
385 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
387 MpInitChangeApLoopCallback
,
389 &mMpInitExitBootServicesEvent
391 ASSERT_EFI_ERROR (Status
);
393 Status
= gBS
->CreateEventEx (
396 MpInitChangeApLoopCallback
,
398 &gEfiEventLegacyBootGuid
,
401 ASSERT_EFI_ERROR (Status
);
405 This service executes a caller provided function on all enabled APs.
407 @param[in] Procedure A pointer to the function to be run on
408 enabled APs of the system. See type
410 @param[in] SingleThread If TRUE, then all the enabled APs execute
411 the function specified by Procedure one by
412 one, in ascending order of processor handle
413 number. If FALSE, then all the enabled APs
414 execute the function specified by Procedure
416 @param[in] WaitEvent The event created by the caller with CreateEvent()
417 service. If it is NULL, then execute in
418 blocking mode. BSP waits until all APs finish
419 or TimeoutInMicroSeconds expires. If it's
420 not NULL, then execute in non-blocking mode.
421 BSP requests the function specified by
422 Procedure to be started on all the enabled
423 APs, and go on executing immediately. If
424 all return from Procedure, or TimeoutInMicroSeconds
425 expires, this event is signaled. The BSP
426 can use the CheckEvent() or WaitForEvent()
427 services to check the state of event. Type
428 EFI_EVENT is defined in CreateEvent() in
429 the Unified Extensible Firmware Interface
431 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
432 APs to return from Procedure, either for
433 blocking or non-blocking mode. Zero means
434 infinity. If the timeout expires before
435 all APs return from Procedure, then Procedure
436 on the failed APs is terminated. All enabled
437 APs are available for next function assigned
438 by MpInitLibStartupAllAPs() or
439 MPInitLibStartupThisAP().
440 If the timeout expires in blocking mode,
441 BSP returns EFI_TIMEOUT. If the timeout
442 expires in non-blocking mode, WaitEvent
443 is signaled with SignalEvent().
444 @param[in] ProcedureArgument The parameter passed into Procedure for
446 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
447 if all APs finish successfully, then its
448 content is set to NULL. If not all APs
449 finish before timeout expires, then its
450 content is set to address of the buffer
451 holding handle numbers of the failed APs.
452 The buffer is allocated by MP Initialization
453 library, and it's the caller's responsibility to
454 free the buffer with FreePool() service.
455 In blocking mode, it is ready for consumption
456 when the call returns. In non-blocking mode,
457 it is ready when WaitEvent is signaled. The
458 list of failed CPU is terminated by
461 @retval EFI_SUCCESS In blocking mode, all APs have finished before
463 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
465 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
466 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
468 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
470 @retval EFI_DEVICE_ERROR Caller processor is AP.
471 @retval EFI_NOT_STARTED No enabled APs exist in the system.
472 @retval EFI_NOT_READY Any enabled APs are busy.
473 @retval EFI_NOT_READY MP Initialize Library is not initialized.
474 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
475 all enabled APs have finished.
476 @retval EFI_INVALID_PARAMETER Procedure is NULL.
481 MpInitLibStartupAllAPs (
482 IN EFI_AP_PROCEDURE Procedure
,
483 IN BOOLEAN SingleThread
,
484 IN EFI_EVENT WaitEvent OPTIONAL
,
485 IN UINTN TimeoutInMicroseconds
,
486 IN VOID
*ProcedureArgument OPTIONAL
,
487 OUT UINTN
**FailedCpuList OPTIONAL
493 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
495 mStopCheckAllApsStatus
= TRUE
;
497 Status
= StartupAllAPsWorker (
501 TimeoutInMicroseconds
,
507 // Start checkAllApsStatus
509 mStopCheckAllApsStatus
= FALSE
;
515 This service lets the caller get one enabled AP to execute a caller-provided
518 @param[in] Procedure A pointer to the function to be run on the
519 designated AP of the system. See type
521 @param[in] ProcessorNumber The handle number of the AP. The range is
522 from 0 to the total number of logical
523 processors minus 1. The total number of
524 logical processors can be retrieved by
525 MpInitLibGetNumberOfProcessors().
526 @param[in] WaitEvent The event created by the caller with CreateEvent()
527 service. If it is NULL, then execute in
528 blocking mode. BSP waits until this AP finish
529 or TimeoutInMicroSeconds expires. If it's
530 not NULL, then execute in non-blocking mode.
531 BSP requests the function specified by
532 Procedure to be started on this AP,
533 and go on executing immediately. If this AP
534 return from Procedure or TimeoutInMicroSeconds
535 expires, this event is signaled. The BSP
536 can use the CheckEvent() or WaitForEvent()
537 services to check the state of event. Type
538 EFI_EVENT is defined in CreateEvent() in
539 the Unified Extensible Firmware Interface
541 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
542 this AP to finish this Procedure, either for
543 blocking or non-blocking mode. Zero means
544 infinity. If the timeout expires before
545 this AP returns from Procedure, then Procedure
546 on the AP is terminated. The
547 AP is available for next function assigned
548 by MpInitLibStartupAllAPs() or
549 MpInitLibStartupThisAP().
550 If the timeout expires in blocking mode,
551 BSP returns EFI_TIMEOUT. If the timeout
552 expires in non-blocking mode, WaitEvent
553 is signaled with SignalEvent().
554 @param[in] ProcedureArgument The parameter passed into Procedure on the
556 @param[out] Finished If NULL, this parameter is ignored. In
557 blocking mode, this parameter is ignored.
558 In non-blocking mode, if AP returns from
559 Procedure before the timeout expires, its
560 content is set to TRUE. Otherwise, the
561 value is set to FALSE. The caller can
562 determine if the AP returned from Procedure
563 by evaluating this value.
565 @retval EFI_SUCCESS In blocking mode, specified AP finished before
567 @retval EFI_SUCCESS In non-blocking mode, the function has been
568 dispatched to specified AP.
569 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
570 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
572 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
574 @retval EFI_DEVICE_ERROR The calling processor is an AP.
575 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
576 the specified AP has finished.
577 @retval EFI_NOT_READY The specified AP is busy.
578 @retval EFI_NOT_READY MP Initialize Library is not initialized.
579 @retval EFI_NOT_FOUND The processor with the handle specified by
580 ProcessorNumber does not exist.
581 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
582 @retval EFI_INVALID_PARAMETER Procedure is NULL.
587 MpInitLibStartupThisAP (
588 IN EFI_AP_PROCEDURE Procedure
,
589 IN UINTN ProcessorNumber
,
590 IN EFI_EVENT WaitEvent OPTIONAL
,
591 IN UINTN TimeoutInMicroseconds
,
592 IN VOID
*ProcedureArgument OPTIONAL
,
593 OUT BOOLEAN
*Finished OPTIONAL
599 // temporarily stop checkAllApsStatus for avoid resource dead-lock.
601 mStopCheckAllApsStatus
= TRUE
;
603 Status
= StartupThisAPWorker (
607 TimeoutInMicroseconds
,
612 mStopCheckAllApsStatus
= FALSE
;
618 This service switches the requested AP to be the BSP from that point onward.
619 This service changes the BSP for all purposes. This call can only be performed
622 @param[in] ProcessorNumber The handle number of AP that is to become the new
623 BSP. The range is from 0 to the total number of
624 logical processors minus 1. The total number of
625 logical processors can be retrieved by
626 MpInitLibGetNumberOfProcessors().
627 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
628 enabled AP. Otherwise, it will be disabled.
630 @retval EFI_SUCCESS BSP successfully switched.
631 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
632 this service returning.
633 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
634 @retval EFI_DEVICE_ERROR The calling processor is an AP.
635 @retval EFI_NOT_FOUND The processor with the handle specified by
636 ProcessorNumber does not exist.
637 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
639 @retval EFI_NOT_READY The specified AP is busy.
640 @retval EFI_NOT_READY MP Initialize Library is not initialized.
646 IN UINTN ProcessorNumber
,
647 IN BOOLEAN EnableOldBSP
651 EFI_TIMER_ARCH_PROTOCOL
*Timer
;
655 // Locate Timer Arch Protocol
657 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**) &Timer
);
658 if (EFI_ERROR (Status
)) {
664 // Save current rate of DXE Timer
666 Timer
->GetTimerPeriod (Timer
, &TimerPeriod
);
668 // Disable DXE Timer and drain pending interrupts
670 Timer
->SetTimerPeriod (Timer
, 0);
673 Status
= SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
677 // Enable and restore rate of DXE Timer
679 Timer
->SetTimerPeriod (Timer
, TimerPeriod
);
686 This service lets the caller enable or disable an AP from this point onward.
687 This service may only be called from the BSP.
689 @param[in] ProcessorNumber The handle number of AP.
690 The range is from 0 to the total number of
691 logical processors minus 1. The total number of
692 logical processors can be retrieved by
693 MpInitLibGetNumberOfProcessors().
694 @param[in] EnableAP Specifies the new state for the processor for
695 enabled, FALSE for disabled.
696 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
697 the new health status of the AP. This flag
698 corresponds to StatusFlag defined in
699 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
700 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
701 bits are ignored. If it is NULL, this parameter
704 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
705 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
706 prior to this service returning.
707 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
708 @retval EFI_DEVICE_ERROR The calling processor is an AP.
709 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
711 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
712 @retval EFI_NOT_READY MP Initialize Library is not initialized.
717 MpInitLibEnableDisableAP (
718 IN UINTN ProcessorNumber
,
720 IN UINT32
*HealthFlag OPTIONAL
724 BOOLEAN TempStopCheckState
;
726 TempStopCheckState
= FALSE
;
728 // temporarily stop checkAllAPsStatus for initialize parameters.
730 if (!mStopCheckAllApsStatus
) {
731 mStopCheckAllApsStatus
= TRUE
;
732 TempStopCheckState
= TRUE
;
735 Status
= EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
737 if (TempStopCheckState
) {
738 mStopCheckAllApsStatus
= FALSE
;