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 Get available system memory below 1MB by specified size.
80 @param[in] WakeupBufferSize Wakeup buffer size required
82 @retval other Return wakeup buffer address below 1MB.
83 @retval -1 Cannot find free memory below 1MB.
87 IN UINTN WakeupBufferSize
91 EFI_PHYSICAL_ADDRESS StartAddress
;
93 StartAddress
= BASE_1MB
;
94 Status
= gBS
->AllocatePages (
97 EFI_SIZE_TO_PAGES (WakeupBufferSize
),
100 ASSERT_EFI_ERROR (Status
);
101 if (!EFI_ERROR (Status
)) {
102 Status
= gBS
->FreePages(
104 EFI_SIZE_TO_PAGES (WakeupBufferSize
)
106 ASSERT_EFI_ERROR (Status
);
107 DEBUG ((DEBUG_INFO
, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
108 (UINTN
) StartAddress
, WakeupBufferSize
));
110 StartAddress
= (EFI_PHYSICAL_ADDRESS
) -1;
112 return (UINTN
) StartAddress
;
116 Checks APs status and updates APs status if needed.
120 CheckAndUpdateApsStatus (
124 UINTN ProcessorNumber
;
126 CPU_MP_DATA
*CpuMpData
;
128 CpuMpData
= GetCpuMpData ();
131 // First, check whether pending StartupAllAPs() exists.
133 if (CpuMpData
->WaitEvent
!= NULL
) {
135 Status
= CheckAllAPs ();
137 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
139 if (Status
!= EFI_NOT_READY
) {
140 Status
= gBS
->SignalEvent (CpuMpData
->WaitEvent
);
141 CpuMpData
->WaitEvent
= NULL
;
146 // Second, check whether pending StartupThisAPs() callings exist.
148 for (ProcessorNumber
= 0; ProcessorNumber
< CpuMpData
->CpuCount
; ProcessorNumber
++) {
150 if (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
== NULL
) {
154 Status
= CheckThisAP (ProcessorNumber
);
156 if (Status
!= EFI_NOT_READY
) {
157 gBS
->SignalEvent (CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
);
158 CpuMpData
->CpuData
[ProcessorNumber
].WaitEvent
= NULL
;
164 Checks APs' status periodically.
166 This function is triggered by timer periodically to check the
167 state of APs for StartupAllAPs() and StartupThisAP() executed
168 in non-blocking mode.
170 @param[in] Event Event triggered.
171 @param[in] Context Parameter passed with the event.
182 // If CheckApsStatus() is not stopped, otherwise return immediately.
184 if (!mStopCheckAllApsStatus
) {
185 CheckAndUpdateApsStatus ();
190 Get Protected mode code segment from current GDT table.
192 @return Protected mode code segment value.
199 IA32_DESCRIPTOR GdtrDesc
;
200 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
205 AsmReadGdtr (&GdtrDesc
);
206 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
207 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
208 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
209 if (GdtEntry
->Bits
.L
== 0) {
210 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.L
== 0) {
216 ASSERT (Index
!= -1);
223 @param[in, out] Buffer Pointer to private data buffer.
231 CPU_MP_DATA
*CpuMpData
;
232 BOOLEAN MwaitSupport
;
233 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc
;
234 UINTN ProcessorNumber
;
236 MpInitLibWhoAmI (&ProcessorNumber
);
237 CpuMpData
= GetCpuMpData ();
238 MwaitSupport
= IsMwaitSupport ();
239 AsmRelocateApLoopFunc
= (ASM_RELOCATE_AP_LOOP
) (UINTN
) mReservedApLoopFunc
;
240 AsmRelocateApLoopFunc (
242 CpuMpData
->ApTargetCState
,
243 CpuMpData
->PmCodeSegment
,
244 mReservedTopOfApStack
- ProcessorNumber
* AP_SAFE_STACK_SIZE
,
245 (UINTN
) &mNumberToFinish
248 // It should never reach here
254 Callback function for ExitBootServices.
256 @param[in] Event Event whose notification function is being invoked.
257 @param[in] Context The pointer to the notification function's context,
258 which is implementation-dependent.
263 MpInitChangeApLoopCallback (
268 CPU_MP_DATA
*CpuMpData
;
270 CpuMpData
= GetCpuMpData ();
271 CpuMpData
->PmCodeSegment
= GetProtectedModeCS ();
272 CpuMpData
->ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
273 mNumberToFinish
= CpuMpData
->CpuCount
- 1;
274 WakeUpAP (CpuMpData
, TRUE
, 0, RelocateApLoop
, NULL
);
275 while (mNumberToFinish
> 0) {
278 DEBUG ((DEBUG_INFO
, "%a() done!\n", __FUNCTION__
));
282 Initialize global data for MP support.
284 @param[in] CpuMpData The pointer to CPU MP Data structure.
288 IN CPU_MP_DATA
*CpuMpData
292 EFI_PHYSICAL_ADDRESS Address
;
293 UINTN ApSafeBufferSize
;
295 SaveCpuMpData (CpuMpData
);
297 if (CpuMpData
->CpuCount
== 1) {
299 // If only BSP exists, return
305 // Avoid APs access invalid buffer data which allocated by BootServices,
306 // so we will allocate reserved data for AP loop code. We also need to
307 // allocate this buffer below 4GB due to APs may be transferred to 32bit
308 // protected mode on long mode DXE.
309 // Allocating it in advance since memory services are not available in
310 // Exit Boot Services callback function.
312 ApSafeBufferSize
= CpuMpData
->AddressMap
.RelocateApLoopFuncSize
;
313 ApSafeBufferSize
+= CpuMpData
->CpuCount
* AP_SAFE_STACK_SIZE
;
315 Address
= BASE_4GB
- 1;
316 Status
= gBS
->AllocatePages (
318 EfiReservedMemoryType
,
319 EFI_SIZE_TO_PAGES (ApSafeBufferSize
),
322 ASSERT_EFI_ERROR (Status
);
323 mReservedApLoopFunc
= (VOID
*) (UINTN
) Address
;
324 ASSERT (mReservedApLoopFunc
!= NULL
);
325 mReservedTopOfApStack
= (UINTN
) Address
+ EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ApSafeBufferSize
));
326 ASSERT ((mReservedTopOfApStack
& (UINTN
)(CPU_STACK_ALIGNMENT
- 1)) == 0);
329 CpuMpData
->AddressMap
.RelocateApLoopFuncAddress
,
330 CpuMpData
->AddressMap
.RelocateApLoopFuncSize
333 Status
= gBS
->CreateEvent (
334 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
340 ASSERT_EFI_ERROR (Status
);
343 // Set timer to check all APs status.
345 Status
= gBS
->SetTimer (
350 ASSERT_EFI_ERROR (Status
);
352 Status
= gBS
->CreateEvent (
353 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
355 MpInitChangeApLoopCallback
,
357 &mMpInitExitBootServicesEvent
359 ASSERT_EFI_ERROR (Status
);
361 Status
= gBS
->CreateEventEx (
364 MpInitChangeApLoopCallback
,
366 &gEfiEventLegacyBootGuid
,
369 ASSERT_EFI_ERROR (Status
);
373 This service executes a caller provided function on all enabled APs.
375 @param[in] Procedure A pointer to the function to be run on
376 enabled APs of the system. See type
378 @param[in] SingleThread If TRUE, then all the enabled APs execute
379 the function specified by Procedure one by
380 one, in ascending order of processor handle
381 number. If FALSE, then all the enabled APs
382 execute the function specified by Procedure
384 @param[in] WaitEvent The event created by the caller with CreateEvent()
385 service. If it is NULL, then execute in
386 blocking mode. BSP waits until all APs finish
387 or TimeoutInMicroSeconds expires. If it's
388 not NULL, then execute in non-blocking mode.
389 BSP requests the function specified by
390 Procedure to be started on all the enabled
391 APs, and go on executing immediately. If
392 all return from Procedure, or TimeoutInMicroSeconds
393 expires, this event is signaled. The BSP
394 can use the CheckEvent() or WaitForEvent()
395 services to check the state of event. Type
396 EFI_EVENT is defined in CreateEvent() in
397 the Unified Extensible Firmware Interface
399 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
400 APs to return from Procedure, either for
401 blocking or non-blocking mode. Zero means
402 infinity. If the timeout expires before
403 all APs return from Procedure, then Procedure
404 on the failed APs is terminated. All enabled
405 APs are available for next function assigned
406 by MpInitLibStartupAllAPs() or
407 MPInitLibStartupThisAP().
408 If the timeout expires in blocking mode,
409 BSP returns EFI_TIMEOUT. If the timeout
410 expires in non-blocking mode, WaitEvent
411 is signaled with SignalEvent().
412 @param[in] ProcedureArgument The parameter passed into Procedure for
414 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
415 if all APs finish successfully, then its
416 content is set to NULL. If not all APs
417 finish before timeout expires, then its
418 content is set to address of the buffer
419 holding handle numbers of the failed APs.
420 The buffer is allocated by MP Initialization
421 library, and it's the caller's responsibility to
422 free the buffer with FreePool() service.
423 In blocking mode, it is ready for consumption
424 when the call returns. In non-blocking mode,
425 it is ready when WaitEvent is signaled. The
426 list of failed CPU is terminated by
429 @retval EFI_SUCCESS In blocking mode, all APs have finished before
431 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
433 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
434 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
436 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
438 @retval EFI_DEVICE_ERROR Caller processor is AP.
439 @retval EFI_NOT_STARTED No enabled APs exist in the system.
440 @retval EFI_NOT_READY Any enabled APs are busy.
441 @retval EFI_NOT_READY MP Initialize Library is not initialized.
442 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
443 all enabled APs have finished.
444 @retval EFI_INVALID_PARAMETER Procedure is NULL.
449 MpInitLibStartupAllAPs (
450 IN EFI_AP_PROCEDURE Procedure
,
451 IN BOOLEAN SingleThread
,
452 IN EFI_EVENT WaitEvent OPTIONAL
,
453 IN UINTN TimeoutInMicroseconds
,
454 IN VOID
*ProcedureArgument OPTIONAL
,
455 OUT UINTN
**FailedCpuList OPTIONAL
461 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
463 mStopCheckAllApsStatus
= TRUE
;
465 Status
= StartupAllAPsWorker (
469 TimeoutInMicroseconds
,
475 // Start checkAllApsStatus
477 mStopCheckAllApsStatus
= FALSE
;
483 This service lets the caller get one enabled AP to execute a caller-provided
486 @param[in] Procedure A pointer to the function to be run on the
487 designated AP of the system. See type
489 @param[in] ProcessorNumber The handle number of the AP. The range is
490 from 0 to the total number of logical
491 processors minus 1. The total number of
492 logical processors can be retrieved by
493 MpInitLibGetNumberOfProcessors().
494 @param[in] WaitEvent The event created by the caller with CreateEvent()
495 service. If it is NULL, then execute in
496 blocking mode. BSP waits until this AP finish
497 or TimeoutInMicroSeconds expires. If it's
498 not NULL, then execute in non-blocking mode.
499 BSP requests the function specified by
500 Procedure to be started on this AP,
501 and go on executing immediately. If this AP
502 return from Procedure or TimeoutInMicroSeconds
503 expires, this event is signaled. The BSP
504 can use the CheckEvent() or WaitForEvent()
505 services to check the state of event. Type
506 EFI_EVENT is defined in CreateEvent() in
507 the Unified Extensible Firmware Interface
509 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
510 this AP to finish this Procedure, either for
511 blocking or non-blocking mode. Zero means
512 infinity. If the timeout expires before
513 this AP returns from Procedure, then Procedure
514 on the AP is terminated. The
515 AP is available for next function assigned
516 by MpInitLibStartupAllAPs() or
517 MpInitLibStartupThisAP().
518 If the timeout expires in blocking mode,
519 BSP returns EFI_TIMEOUT. If the timeout
520 expires in non-blocking mode, WaitEvent
521 is signaled with SignalEvent().
522 @param[in] ProcedureArgument The parameter passed into Procedure on the
524 @param[out] Finished If NULL, this parameter is ignored. In
525 blocking mode, this parameter is ignored.
526 In non-blocking mode, if AP returns from
527 Procedure before the timeout expires, its
528 content is set to TRUE. Otherwise, the
529 value is set to FALSE. The caller can
530 determine if the AP returned from Procedure
531 by evaluating this value.
533 @retval EFI_SUCCESS In blocking mode, specified AP finished before
535 @retval EFI_SUCCESS In non-blocking mode, the function has been
536 dispatched to specified AP.
537 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
538 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
540 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
542 @retval EFI_DEVICE_ERROR The calling processor is an AP.
543 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
544 the specified AP has finished.
545 @retval EFI_NOT_READY The specified AP is busy.
546 @retval EFI_NOT_READY MP Initialize Library is not initialized.
547 @retval EFI_NOT_FOUND The processor with the handle specified by
548 ProcessorNumber does not exist.
549 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
550 @retval EFI_INVALID_PARAMETER Procedure is NULL.
555 MpInitLibStartupThisAP (
556 IN EFI_AP_PROCEDURE Procedure
,
557 IN UINTN ProcessorNumber
,
558 IN EFI_EVENT WaitEvent OPTIONAL
,
559 IN UINTN TimeoutInMicroseconds
,
560 IN VOID
*ProcedureArgument OPTIONAL
,
561 OUT BOOLEAN
*Finished OPTIONAL
567 // temporarily stop checkAllApsStatus for avoid resource dead-lock.
569 mStopCheckAllApsStatus
= TRUE
;
571 Status
= StartupThisAPWorker (
575 TimeoutInMicroseconds
,
580 mStopCheckAllApsStatus
= FALSE
;
586 This service switches the requested AP to be the BSP from that point onward.
587 This service changes the BSP for all purposes. This call can only be performed
590 @param[in] ProcessorNumber The handle number of AP that is to become the new
591 BSP. The range is from 0 to the total number of
592 logical processors minus 1. The total number of
593 logical processors can be retrieved by
594 MpInitLibGetNumberOfProcessors().
595 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
596 enabled AP. Otherwise, it will be disabled.
598 @retval EFI_SUCCESS BSP successfully switched.
599 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
600 this service returning.
601 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
602 @retval EFI_DEVICE_ERROR The calling processor is an AP.
603 @retval EFI_NOT_FOUND The processor with the handle specified by
604 ProcessorNumber does not exist.
605 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
607 @retval EFI_NOT_READY The specified AP is busy.
608 @retval EFI_NOT_READY MP Initialize Library is not initialized.
614 IN UINTN ProcessorNumber
,
615 IN BOOLEAN EnableOldBSP
619 EFI_TIMER_ARCH_PROTOCOL
*Timer
;
624 // Locate Timer Arch Protocol
626 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**) &Timer
);
627 if (EFI_ERROR (Status
)) {
633 // Save current rate of DXE Timer
635 Timer
->GetTimerPeriod (Timer
, &TimerPeriod
);
637 // Disable DXE Timer and drain pending interrupts
639 Timer
->SetTimerPeriod (Timer
, 0);
642 Status
= SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
646 // Enable and restore rate of DXE Timer
648 Timer
->SetTimerPeriod (Timer
, TimerPeriod
);
655 This service lets the caller enable or disable an AP from this point onward.
656 This service may only be called from the BSP.
658 @param[in] ProcessorNumber The handle number of AP.
659 The range is from 0 to the total number of
660 logical processors minus 1. The total number of
661 logical processors can be retrieved by
662 MpInitLibGetNumberOfProcessors().
663 @param[in] EnableAP Specifies the new state for the processor for
664 enabled, FALSE for disabled.
665 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
666 the new health status of the AP. This flag
667 corresponds to StatusFlag defined in
668 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
669 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
670 bits are ignored. If it is NULL, this parameter
673 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
674 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
675 prior to this service returning.
676 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
677 @retval EFI_DEVICE_ERROR The calling processor is an AP.
678 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
680 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
681 @retval EFI_NOT_READY MP Initialize Library is not initialized.
686 MpInitLibEnableDisableAP (
687 IN UINTN ProcessorNumber
,
689 IN UINT32
*HealthFlag OPTIONAL
693 BOOLEAN TempStopCheckState
;
695 TempStopCheckState
= FALSE
;
697 // temporarily stop checkAllAPsStatus for initialize parameters.
699 if (!mStopCheckAllApsStatus
) {
700 mStopCheckAllApsStatus
= TRUE
;
701 TempStopCheckState
= TRUE
;
704 Status
= EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
706 if (TempStopCheckState
) {
707 mStopCheckAllApsStatus
= FALSE
;