2 Construct MP Services Protocol.
4 The MP Services Protocol provides a generalized way of performing following tasks:
5 - Retrieving information of multi-processor environment and MP-related status of
7 - Dispatching user-provided function to APs.
8 - Maintain MP-related processor status.
10 The MP Services Protocol must be produced on any system with more than one logical
13 The Protocol is available only during boot time.
15 MP Services Protocol is hardware-independent. Most of the logic of this protocol
16 is architecturally neutral. It abstracts the multi-processor environment and
17 status of processors, and provides interfaces to retrieve information, maintain,
20 MP Services Protocol may be consumed by ACPI module. The ACPI module may use this
21 protocol to retrieve data that are needed for an MP platform and report them to OS.
22 MP Services Protocol may also be used to program and configure processors, such
23 as MTRR synchronization for memory space attributes setting in DXE Services.
24 MP Services Protocol may be used by non-CPU DXE drivers to speed up platform boot
25 by taking advantage of the processing capabilities of the APs, for example, using
26 APs to help test system memory in parallel with other device initialization.
27 Diagnostics applications may also use this protocol for multi-processor.
29 Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
30 SPDX-License-Identifier: BSD-2-Clause-Patent
36 #include <Library/ArmLib.h>
37 #include <Library/ArmMmuLib.h>
38 #include <Library/ArmPlatformLib.h>
39 #include <Library/ArmSmcLib.h>
40 #include <Library/BaseMemoryLib.h>
41 #include <Library/CacheMaintenanceLib.h>
42 #include <Library/CpuExceptionHandlerLib.h>
43 #include <Library/DebugLib.h>
44 #include <Library/HobLib.h>
45 #include <Library/MemoryAllocationLib.h>
46 #include <Library/UefiBootServicesTableLib.h>
47 #include <Library/UefiLib.h>
48 #include <IndustryStandard/ArmStdSmc.h>
49 #include <Ppi/ArmMpCoreInfo.h>
50 #include <Protocol/LoadedImage.h>
52 #include "MpServicesInternal.h"
54 #define POLL_INTERVAL_US 50000
56 STATIC CPU_MP_DATA mCpuMpData
;
57 STATIC BOOLEAN mNonBlockingModeAllowed
;
58 UINT64
*gApStacksBase
;
59 UINT64
*gProcessorIDs
;
60 CONST UINT64 gApStackSize
= AP_STACK_SIZE
;
67 IsCurrentProcessorBSP (
71 /** Turns on the specified core using PSCI and executes the user-supplied
72 function that's been configured via a previous call to SetApProcedure.
74 @param ProcessorIndex The index of the core to turn on.
76 @retval EFI_SUCCESS Success.
77 @retval EFI_DEVICE_ERROR The processor could not be turned on.
84 IN UINTN ProcessorIndex
92 mCpuMpData
.CpuData
[ProcessorIndex
].State
= CpuStateBusy
;
95 if (sizeof (Args
.Arg0
) == sizeof (UINT32
)) {
96 Args
.Arg0
= ARM_SMC_ID_PSCI_CPU_ON_AARCH32
;
98 Args
.Arg0
= ARM_SMC_ID_PSCI_CPU_ON_AARCH64
;
101 Args
.Arg1
= gProcessorIDs
[ProcessorIndex
];
102 Args
.Arg2
= (UINTN
)ApEntryPoint
;
106 if (Args
.Arg0
!= ARM_SMC_PSCI_RET_SUCCESS
) {
107 DEBUG ((DEBUG_ERROR
, "PSCI_CPU_ON call failed: %d\n", Args
.Arg0
));
108 Status
= EFI_DEVICE_ERROR
;
114 /** Returns whether the specified processor is the BSP.
116 @param[in] ProcessorIndex The index the processor to check.
118 @return TRUE if the processor is the BSP, FALSE otherwise.
126 EFI_PROCESSOR_INFORMATION
*CpuInfo
;
128 CpuInfo
= &mCpuMpData
.CpuData
[ProcessorIndex
].Info
;
130 return (CpuInfo
->StatusFlag
& PROCESSOR_AS_BSP_BIT
) != 0;
133 /** Get the Application Processors state.
135 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP.
137 @return The AP status.
141 IN CPU_AP_DATA
*CpuData
144 return CpuData
->State
;
147 /** Configures the processor context with the user-supplied procedure and
150 @param CpuData The processor context.
151 @param Procedure The user-supplied procedure.
152 @param ProcedureArgument The user-supplied procedure argument.
158 IN CPU_AP_DATA
*CpuData
,
159 IN EFI_AP_PROCEDURE Procedure
,
160 IN VOID
*ProcedureArgument
163 ASSERT (CpuData
!= NULL
);
164 ASSERT (Procedure
!= NULL
);
166 CpuData
->Parameter
= ProcedureArgument
;
167 CpuData
->Procedure
= Procedure
;
170 /** Returns the index of the next processor that is blocked.
172 @param[out] NextNumber The index of the next blocked processor.
174 @retval EFI_SUCCESS Successfully found the next blocked processor.
175 @retval EFI_NOT_FOUND There are no blocked processors.
180 GetNextBlockedNumber (
181 OUT UINTN
*NextNumber
186 CPU_AP_DATA
*CpuData
;
188 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
189 CpuData
= &mCpuMpData
.CpuData
[Index
];
190 if (IsProcessorBSP (Index
)) {
195 State
= CpuData
->State
;
197 if (State
== CpuStateBlocked
) {
203 return EFI_NOT_FOUND
;
206 /** Stalls the BSP for the minimum of POLL_INTERVAL_US and Timeout.
208 @param[in] Timeout The time limit in microseconds remaining for
209 APs to return from Procedure.
211 @retval StallTime Time of execution stall.
215 CalculateAndStallInterval (
221 if ((Timeout
< POLL_INTERVAL_US
) && (Timeout
!= 0)) {
224 StallTime
= POLL_INTERVAL_US
;
227 gBS
->Stall (StallTime
);
233 This service retrieves the number of logical processor in the platform
234 and the number of those logical processors that are enabled on this boot.
235 This service may only be called from the BSP.
237 This function is used to retrieve the following information:
238 - The number of logical processors that are present in the system.
239 - The number of enabled logical processors in the system at the instant
242 Because MP Service Protocol provides services to enable and disable processors
243 dynamically, the number of enabled logical processors may vary during the
244 course of a boot session.
246 If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
247 If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
248 EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
249 is returned in NumberOfProcessors, the number of currently enabled processor
250 is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
252 @param[in] This A pointer to the
253 EFI_MP_SERVICES_PROTOCOL instance.
254 @param[out] NumberOfProcessors Pointer to the total number of logical
255 processors in the system, including
256 the BSP and disabled APs.
257 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled
258 logical processors that exist in the
259 system, including the BSP.
261 @retval EFI_SUCCESS The number of logical processors and enabled
262 logical processors was retrieved.
263 @retval EFI_DEVICE_ERROR The calling processor is an AP.
264 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
265 @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
271 GetNumberOfProcessors (
272 IN EFI_MP_SERVICES_PROTOCOL
*This
,
273 OUT UINTN
*NumberOfProcessors
,
274 OUT UINTN
*NumberOfEnabledProcessors
277 if ((NumberOfProcessors
== NULL
) || (NumberOfEnabledProcessors
== NULL
)) {
278 return EFI_INVALID_PARAMETER
;
281 if (!IsCurrentProcessorBSP ()) {
282 return EFI_DEVICE_ERROR
;
285 *NumberOfProcessors
= mCpuMpData
.NumberOfProcessors
;
286 *NumberOfEnabledProcessors
= mCpuMpData
.NumberOfEnabledProcessors
;
291 Gets detailed MP-related information on the requested processor at the
292 instant this call is made. This service may only be called from the BSP.
294 This service retrieves detailed MP-related information about any processor
295 on the platform. Note the following:
296 - The processor information may change during the course of a boot session.
297 - The information presented here is entirely MP related.
299 Information regarding the number of caches and their sizes, frequency of
300 operation, slot numbers is all considered platform-related information and is
301 not provided by this service.
303 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
305 @param[in] ProcessorIndex The index of the processor.
306 @param[out] ProcessorInfoBuffer A pointer to the buffer where information
307 for the requested processor is deposited.
309 @retval EFI_SUCCESS Processor information was returned.
310 @retval EFI_DEVICE_ERROR The calling processor is an AP.
311 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
312 @retval EFI_NOT_FOUND The processor with the handle specified by
313 ProcessorNumber does not exist in the platform.
320 IN EFI_MP_SERVICES_PROTOCOL
*This
,
321 IN UINTN ProcessorIndex
,
322 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
325 if (ProcessorInfoBuffer
== NULL
) {
326 return EFI_INVALID_PARAMETER
;
329 if (!IsCurrentProcessorBSP ()) {
330 return EFI_DEVICE_ERROR
;
333 ProcessorIndex
&= ~CPU_V2_EXTENDED_TOPOLOGY
;
335 if (ProcessorIndex
>= mCpuMpData
.NumberOfProcessors
) {
336 return EFI_NOT_FOUND
;
341 &mCpuMpData
.CpuData
[ProcessorIndex
],
342 sizeof (EFI_PROCESSOR_INFORMATION
)
348 This service executes a caller provided function on all enabled APs. APs can
349 run either simultaneously or one at a time in sequence. This service supports
350 both blocking and non-blocking requests. The non-blocking requests use EFI
351 events so the BSP can detect when the APs have finished. This service may only
352 be called from the BSP.
354 This function is used to dispatch all the enabled APs to the function
355 specified by Procedure. If any enabled AP is busy, then EFI_NOT_READY is
356 returned immediately and Procedure is not started on any AP.
358 If SingleThread is TRUE, all the enabled APs execute the function specified by
359 Procedure one by one, in ascending order of processor handle number.
360 Otherwise, all the enabled APs execute the function specified by Procedure
363 If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
364 APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in
365 non-blocking mode, and the BSP returns from this service without waiting for
366 APs. If a non-blocking mode is requested after the UEFI Event
367 EFI_EVENT_GROUP_READY_TO_BOOT is signaled, then EFI_UNSUPPORTED must be
370 If the timeout specified by TimeoutInMicroseconds expires before all APs
371 return from Procedure, then Procedure on the failed APs is terminated.
372 All enabled APs are always available for further calls to
373 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
374 EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
375 content points to the list of processor handle numbers in which Procedure was
378 Note: It is the responsibility of the consumer of the
379 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() to make sure that the nature of the
380 code that is executed on the BSP and the dispatched APs is well controlled.
381 The MP Services Protocol does not guarantee that the Procedure function is
382 MP-safe. Hence, the tasks that can be run in parallel are limited to certain
383 independent tasks and well-controlled exclusive code. EFI services and
384 protocols may not be called by APs unless otherwise specified.
386 In blocking execution mode, BSP waits until all APs finish or
387 TimeoutInMicroseconds expires.
389 In non-blocking execution mode, BSP is freed to return to the caller and then
390 proceed to the next task without having to wait for APs. The following
391 sequence needs to occur in a non-blocking execution mode:
393 -# The caller that intends to use this MP Services Protocol in non-blocking
394 mode creates WaitEvent by calling the EFI CreateEvent() service. The
395 caller invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter
396 WaitEvent is not NULL, then StartupAllAPs() executes in non-blocking
397 mode. It requests the function specified by Procedure to be started on
398 all the enabled APs, and releases the BSP to continue with other tasks.
399 -# The caller can use the CheckEvent() and WaitForEvent() services to check
400 the state of the WaitEvent created in step 1.
401 -# When the APs complete their task or TimeoutInMicroSecondss expires, the
402 MP Service signals WaitEvent by calling the EFI SignalEvent() function.
403 If FailedCpuList is not NULL, its content is available when WaitEvent is
404 signaled. If all APs returned from Procedure prior to the timeout, then
405 FailedCpuList is set to NULL. If not all APs return from Procedure before
406 the timeout, then FailedCpuList is filled in with the list of the failed
407 APs. The buffer is allocated by MP Service Protocol using AllocatePool().
408 It is the caller's responsibility to free the buffer with FreePool()
410 -# This invocation of SignalEvent() function informs the caller that invoked
411 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs
412 completed the specified task or a timeout occurred. The contents of
413 FailedCpuList can be examined to determine which APs did not complete the
414 specified task prior to the timeout.
416 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
418 @param[in] Procedure A pointer to the function to be run on
419 enabled APs of the system. See type
421 @param[in] SingleThread If TRUE, then all the enabled APs execute
422 the function specified by Procedure one by
423 one, in ascending order of processor
424 handle number. If FALSE, then all the
425 enabled APs execute the function specified
426 by Procedure simultaneously.
427 @param[in] WaitEvent The event created by the caller with
428 CreateEvent() service. If it is NULL,
429 then execute in blocking mode. BSP waits
430 until all APs finish or
431 TimeoutInMicroseconds expires. If it's
432 not NULL, then execute in non-blocking
433 mode. BSP requests the function specified
434 by Procedure to be started on all the
435 enabled APs, and go on executing
436 immediately. If all return from Procedure,
437 or TimeoutInMicroseconds expires, this
438 event is signaled. The BSP can use the
439 CheckEvent() or WaitForEvent()
440 services to check the state of event. Type
441 EFI_EVENT is defined in CreateEvent() in
442 the Unified Extensible Firmware Interface
444 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds
445 for APs to return from Procedure, either
446 for blocking or non-blocking mode. Zero
447 means infinity. If the timeout expires
448 before all APs return from Procedure, then
449 Procedure on the failed APs is terminated.
450 All enabled APs are available for next
452 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
453 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
454 If the timeout expires in blocking mode,
455 BSP returns EFI_TIMEOUT. If the timeout
456 expires in non-blocking mode, WaitEvent
457 is signaled with SignalEvent().
458 @param[in] ProcedureArgument The parameter passed into Procedure for
460 @param[out] FailedCpuList If NULL, this parameter is ignored.
461 Otherwise, if all APs finish successfully,
462 then its content is set to NULL. If not
463 all APs finish before timeout expires,
464 then its content is set to address of the
465 buffer holding handle numbers of the
467 The buffer is allocated by MP Service
468 Protocol, and it's the caller's
469 responsibility to free the buffer with
471 In blocking mode, it is ready for
472 consumption when the call returns. In
473 non-blocking mode, it is ready when
474 WaitEvent is signaled. The list of failed
475 CPU is terminated by END_OF_CPU_LIST.
477 @retval EFI_SUCCESS In blocking mode, all APs have finished before
479 @retval EFI_SUCCESS In non-blocking mode, function has been
480 dispatched to all enabled APs.
481 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
482 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
484 @retval EFI_DEVICE_ERROR Caller processor is AP.
485 @retval EFI_NOT_STARTED No enabled APs exist in the system.
486 @retval EFI_NOT_READY Any enabled APs are busy.
487 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
488 all enabled APs have finished.
489 @retval EFI_INVALID_PARAMETER Procedure is NULL.
496 IN EFI_MP_SERVICES_PROTOCOL
*This
,
497 IN EFI_AP_PROCEDURE Procedure
,
498 IN BOOLEAN SingleThread
,
499 IN EFI_EVENT WaitEvent OPTIONAL
,
500 IN UINTN TimeoutInMicroseconds
,
501 IN VOID
*ProcedureArgument OPTIONAL
,
502 OUT UINTN
**FailedCpuList OPTIONAL
507 if (!IsCurrentProcessorBSP ()) {
508 return EFI_DEVICE_ERROR
;
511 if ((mCpuMpData
.NumberOfProcessors
== 1) || (mCpuMpData
.NumberOfEnabledProcessors
== 1)) {
512 return EFI_NOT_STARTED
;
515 if (Procedure
== NULL
) {
516 return EFI_INVALID_PARAMETER
;
519 if ((WaitEvent
!= NULL
) && !mNonBlockingModeAllowed
) {
520 return EFI_UNSUPPORTED
;
523 if (FailedCpuList
!= NULL
) {
524 mCpuMpData
.FailedList
= AllocateZeroPool (
525 (mCpuMpData
.NumberOfProcessors
+ 1) *
528 if (mCpuMpData
.FailedList
== NULL
) {
529 return EFI_OUT_OF_RESOURCES
;
533 mCpuMpData
.FailedList
,
534 (mCpuMpData
.NumberOfProcessors
+ 1) *
538 mCpuMpData
.FailedListIndex
= 0;
539 *FailedCpuList
= mCpuMpData
.FailedList
;
542 StartupAllAPsPrepareState (SingleThread
);
544 // If any enabled APs are busy (ignoring the BSP), return EFI_NOT_READY
545 if (mCpuMpData
.StartCount
!= (mCpuMpData
.NumberOfEnabledProcessors
- 1)) {
546 return EFI_NOT_READY
;
549 if (WaitEvent
!= NULL
) {
550 Status
= StartupAllAPsWithWaitEvent (
554 TimeoutInMicroseconds
,
559 if (EFI_ERROR (Status
) && (FailedCpuList
!= NULL
)) {
560 if (mCpuMpData
.FailedListIndex
== 0) {
561 FreePool (*FailedCpuList
);
562 *FailedCpuList
= NULL
;
566 Status
= StartupAllAPsNoWaitEvent (
569 TimeoutInMicroseconds
,
574 if (FailedCpuList
!= NULL
) {
575 if (mCpuMpData
.FailedListIndex
== 0) {
576 FreePool (*FailedCpuList
);
577 *FailedCpuList
= NULL
;
586 This service lets the caller get one enabled AP to execute a caller-provided
587 function. The caller can request the BSP to either wait for the completion
588 of the AP or just proceed with the next task by using the EFI event mechanism.
589 See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
590 execution support. This service may only be called from the BSP.
592 This function is used to dispatch one enabled AP to the function specified by
593 Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
594 is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
595 TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
596 BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
597 is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
598 then EFI_UNSUPPORTED must be returned.
600 If the timeout specified by TimeoutInMicroseconds expires before the AP returns
601 from Procedure, then execution of Procedure by the AP is terminated. The AP is
602 available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
603 EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
605 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
607 @param[in] Procedure A pointer to the function to be run on
608 enabled APs of the system. See type
610 @param[in] ProcessorNumber The handle number of the AP. The range is
611 from 0 to the total number of logical
612 processors minus 1. The total number of
613 logical processors can be retrieved by
614 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
615 @param[in] WaitEvent The event created by the caller with CreateEvent()
616 service. If it is NULL, then execute in
617 blocking mode. BSP waits until all APs finish
618 or TimeoutInMicroseconds expires. If it's
619 not NULL, then execute in non-blocking mode.
620 BSP requests the function specified by
621 Procedure to be started on all the enabled
622 APs, and go on executing immediately. If
623 all return from Procedure or TimeoutInMicroseconds
624 expires, this event is signaled. The BSP
625 can use the CheckEvent() or WaitForEvent()
626 services to check the state of event. Type
627 EFI_EVENT is defined in CreateEvent() in
628 the Unified Extensible Firmware Interface
630 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
631 APs to return from Procedure, either for
632 blocking or non-blocking mode. Zero means
633 infinity. If the timeout expires before
634 all APs return from Procedure, then Procedure
635 on the failed APs is terminated. All enabled
636 APs are available for next function assigned
637 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
638 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
639 If the timeout expires in blocking mode,
640 BSP returns EFI_TIMEOUT. If the timeout
641 expires in non-blocking mode, WaitEvent
642 is signaled with SignalEvent().
643 @param[in] ProcedureArgument The parameter passed into Procedure for
645 @param[out] Finished If NULL, this parameter is ignored. In
646 blocking mode, this parameter is ignored.
647 In non-blocking mode, if AP returns from
648 Procedure before the timeout expires, its
649 content is set to TRUE. Otherwise, the
650 value is set to FALSE. The caller can
651 determine if the AP returned from Procedure
652 by evaluating this value.
654 @retval EFI_SUCCESS In blocking mode, specified AP finished before
656 @retval EFI_SUCCESS In non-blocking mode, the function has been
657 dispatched to specified AP.
658 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
659 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
661 @retval EFI_DEVICE_ERROR The calling processor is an AP.
662 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
663 the specified AP has finished.
664 @retval EFI_NOT_READY The specified AP is busy.
665 @retval EFI_NOT_FOUND The processor with the handle specified by
666 ProcessorNumber does not exist.
667 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
668 @retval EFI_INVALID_PARAMETER Procedure is NULL.
675 IN EFI_MP_SERVICES_PROTOCOL
*This
,
676 IN EFI_AP_PROCEDURE Procedure
,
677 IN UINTN ProcessorNumber
,
678 IN EFI_EVENT WaitEvent OPTIONAL
,
679 IN UINTN TimeoutInMicroseconds
,
680 IN VOID
*ProcedureArgument OPTIONAL
,
681 OUT BOOLEAN
*Finished OPTIONAL
686 CPU_AP_DATA
*CpuData
;
688 if (!IsCurrentProcessorBSP ()) {
689 return EFI_DEVICE_ERROR
;
692 if (Procedure
== NULL
) {
693 return EFI_INVALID_PARAMETER
;
696 if (ProcessorNumber
>= mCpuMpData
.NumberOfProcessors
) {
697 return EFI_NOT_FOUND
;
700 CpuData
= &mCpuMpData
.CpuData
[ProcessorNumber
];
702 if (IsProcessorBSP (ProcessorNumber
)) {
703 return EFI_INVALID_PARAMETER
;
706 if (!IsProcessorEnabled (ProcessorNumber
)) {
707 return EFI_INVALID_PARAMETER
;
710 if ((GetApState (CpuData
) != CpuStateIdle
) &&
711 (GetApState (CpuData
) != CpuStateFinished
))
713 return EFI_NOT_READY
;
716 if ((WaitEvent
!= NULL
) && !mNonBlockingModeAllowed
) {
717 return EFI_UNSUPPORTED
;
720 Timeout
= TimeoutInMicroseconds
;
722 CpuData
->Timeout
= TimeoutInMicroseconds
;
723 CpuData
->TimeTaken
= 0;
724 CpuData
->TimeoutActive
= (BOOLEAN
)(TimeoutInMicroseconds
!= 0);
732 Status
= DispatchCpu (ProcessorNumber
);
733 if (EFI_ERROR (Status
)) {
734 CpuData
->State
= CpuStateIdle
;
735 return EFI_NOT_READY
;
738 if (WaitEvent
!= NULL
) {
740 if (Finished
!= NULL
) {
741 CpuData
->SingleApFinished
= Finished
;
745 CpuData
->WaitEvent
= WaitEvent
;
746 Status
= gBS
->SetTimer (
747 CpuData
->CheckThisAPEvent
,
757 if (GetApState (CpuData
) == CpuStateFinished
) {
758 CpuData
->State
= CpuStateIdle
;
762 if ((TimeoutInMicroseconds
!= 0) && (Timeout
== 0)) {
766 Timeout
-= CalculateAndStallInterval (Timeout
);
773 This service switches the requested AP to be the BSP from that point onward.
774 This service changes the BSP for all purposes. This call can only be
775 performed by the current BSP.
777 This service switches the requested AP to be the BSP from that point onward.
778 This service changes the BSP for all purposes. The new BSP can take over the
779 execution of the old BSP and continue seamlessly from where the old one left
780 off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
783 If the BSP cannot be switched prior to the return from this service, then
784 EFI_UNSUPPORTED must be returned.
786 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
787 @param[in] ProcessorNumber The handle number of AP that is to become the new
788 BSP. The range is from 0 to the total number of
789 logical processors minus 1. The total number of
790 logical processors can be retrieved by
791 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
792 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
793 enabled AP. Otherwise, it will be disabled.
795 @retval EFI_SUCCESS BSP successfully switched.
796 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
797 this service returning.
798 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
799 @retval EFI_SUCCESS The calling processor is an AP.
800 @retval EFI_NOT_FOUND The processor with the handle specified by
801 ProcessorNumber does not exist.
802 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
804 @retval EFI_NOT_READY The specified AP is busy.
811 IN EFI_MP_SERVICES_PROTOCOL
*This
,
812 IN UINTN ProcessorNumber
,
813 IN BOOLEAN EnableOldBSP
816 return EFI_UNSUPPORTED
;
820 This service lets the caller enable or disable an AP from this point onward.
821 This service may only be called from the BSP.
823 This service allows the caller enable or disable an AP from this point onward.
824 The caller can optionally specify the health status of the AP by Health. If
825 an AP is being disabled, then the state of the disabled AP is implementation
826 dependent. If an AP is enabled, then the implementation must guarantee that a
827 complete initialization sequence is performed on the AP, so the AP is in a state
828 that is compatible with an MP operating system. This service may not be supported
829 after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
831 If the enable or disable AP operation cannot be completed prior to the return
832 from this service, then EFI_UNSUPPORTED must be returned.
834 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
835 @param[in] ProcessorNumber The handle number of AP that is to become the new
836 BSP. The range is from 0 to the total number of
837 logical processors minus 1. The total number of
838 logical processors can be retrieved by
839 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
840 @param[in] EnableAP Specifies the new state for the processor for
841 enabled, FALSE for disabled.
842 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
843 the new health status of the AP. This flag
844 corresponds to StatusFlag defined in
845 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
846 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
847 bits are ignored. If it is NULL, this parameter
850 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
851 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
852 prior to this service returning.
853 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
854 @retval EFI_DEVICE_ERROR The calling processor is an AP.
855 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
857 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
864 IN EFI_MP_SERVICES_PROTOCOL
*This
,
865 IN UINTN ProcessorNumber
,
867 IN UINT32
*HealthFlag OPTIONAL
871 CPU_AP_DATA
*CpuData
;
873 StatusFlag
= mCpuMpData
.CpuData
[ProcessorNumber
].Info
.StatusFlag
;
874 CpuData
= &mCpuMpData
.CpuData
[ProcessorNumber
];
876 if (!IsCurrentProcessorBSP ()) {
877 return EFI_DEVICE_ERROR
;
880 if (ProcessorNumber
>= mCpuMpData
.NumberOfProcessors
) {
881 return EFI_NOT_FOUND
;
884 if (IsProcessorBSP (ProcessorNumber
)) {
885 return EFI_INVALID_PARAMETER
;
888 if (GetApState (CpuData
) != CpuStateIdle
) {
889 return EFI_UNSUPPORTED
;
893 if (!IsProcessorEnabled (ProcessorNumber
)) {
894 mCpuMpData
.NumberOfEnabledProcessors
++;
897 StatusFlag
|= PROCESSOR_ENABLED_BIT
;
899 if (IsProcessorEnabled (ProcessorNumber
) && !IsProcessorBSP (ProcessorNumber
)) {
900 mCpuMpData
.NumberOfEnabledProcessors
--;
903 StatusFlag
&= ~PROCESSOR_ENABLED_BIT
;
906 if ((HealthFlag
!= NULL
) && !IsProcessorBSP (ProcessorNumber
)) {
907 StatusFlag
&= ~PROCESSOR_HEALTH_STATUS_BIT
;
908 StatusFlag
|= (*HealthFlag
& PROCESSOR_HEALTH_STATUS_BIT
);
911 mCpuMpData
.CpuData
[ProcessorNumber
].Info
.StatusFlag
= StatusFlag
;
916 This return the handle number for the calling processor. This service may be
917 called from the BSP and APs.
919 This service returns the processor handle number for the calling processor.
920 The returned value is in the range from 0 to the total number of logical
921 processors minus 1. The total number of logical processors can be retrieved
922 with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
923 called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
924 is returned. Otherwise, the current processors handle number is returned in
925 ProcessorNumber, and EFI_SUCCESS is returned.
927 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
928 @param[out] ProcessorNumber The handle number of AP that is to become the new
929 BSP. The range is from 0 to the total number of
930 logical processors minus 1. The total number of
931 logical processors can be retrieved by
932 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
934 @retval EFI_SUCCESS The current processor handle number was returned
936 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
943 IN EFI_MP_SERVICES_PROTOCOL
*This
,
944 OUT UINTN
*ProcessorNumber
950 if (ProcessorNumber
== NULL
) {
951 return EFI_INVALID_PARAMETER
;
954 ProcessorId
= GET_MPIDR_AFFINITY_BITS (ArmReadMpidr ());
955 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
956 if (ProcessorId
== gProcessorIDs
[Index
]) {
957 *ProcessorNumber
= Index
;
965 STATIC EFI_MP_SERVICES_PROTOCOL mMpServicesProtocol
= {
966 GetNumberOfProcessors
,
975 /** Adds the specified processor the list of failed processors.
977 @param ProcessorIndex The processor index to add.
978 @param ApState Processor state.
983 AddProcessorToFailedList (
984 UINTN ProcessorIndex
,
993 if ((mCpuMpData
.FailedList
== NULL
) ||
994 (ApState
== CpuStateIdle
) ||
995 (ApState
== CpuStateFinished
) ||
996 IsProcessorBSP (ProcessorIndex
))
1001 // If we are retrying make sure we don't double count
1002 for (Index
= 0; Index
< mCpuMpData
.FailedListIndex
; Index
++) {
1003 if (mCpuMpData
.FailedList
[Index
] == ProcessorIndex
) {
1009 /* If the CPU isn't already in the FailedList, add it */
1011 mCpuMpData
.FailedList
[mCpuMpData
.FailedListIndex
++] = ProcessorIndex
;
1015 /** Handles the StartupAllAPs case where the timeout has occurred.
1020 ProcessStartupAllAPsTimeout (
1024 CPU_AP_DATA
*CpuData
;
1027 if (mCpuMpData
.FailedList
== NULL
) {
1031 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
1032 CpuData
= &mCpuMpData
.CpuData
[Index
];
1033 if (IsProcessorBSP (Index
)) {
1038 if (!IsProcessorEnabled (Index
)) {
1039 // Skip Disabled processors
1043 CpuData
= &mCpuMpData
.CpuData
[Index
];
1044 AddProcessorToFailedList (Index
, GetApState (CpuData
));
1048 /** Updates the status of the APs.
1050 @param[in] ProcessorIndex The index of the AP to update.
1055 IN UINTN ProcessorIndex
1059 CPU_AP_DATA
*CpuData
;
1060 CPU_AP_DATA
*NextCpuData
;
1064 CpuData
= &mCpuMpData
.CpuData
[ProcessorIndex
];
1066 if (IsProcessorBSP (ProcessorIndex
)) {
1071 if (!IsProcessorEnabled (ProcessorIndex
)) {
1072 // Skip Disabled processors
1076 State
= GetApState (CpuData
);
1079 case CpuStateFinished
:
1080 if (mCpuMpData
.SingleThread
) {
1081 Status
= GetNextBlockedNumber (&NextNumber
);
1082 if (!EFI_ERROR (Status
)) {
1083 NextCpuData
= &mCpuMpData
.CpuData
[NextNumber
];
1085 NextCpuData
->State
= CpuStateReady
;
1089 mCpuMpData
.Procedure
,
1090 mCpuMpData
.ProcedureArgument
1093 Status
= DispatchCpu (NextNumber
);
1094 if (!EFI_ERROR (Status
)) {
1095 mCpuMpData
.StartCount
++;
1097 AddProcessorToFailedList (NextNumber
, NextCpuData
->State
);
1102 CpuData
->State
= CpuStateIdle
;
1103 mCpuMpData
.FinishCount
++;
1112 If a timeout is specified in StartupAllAps(), a timer is set, which invokes
1113 this procedure periodically to check whether all APs have finished.
1115 @param[in] Event The WaitEvent the user supplied.
1116 @param[in] Context The event context.
1129 mCpuMpData
.AllTimeTaken
+= POLL_INTERVAL_US
;
1131 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
1132 UpdateApStatus (Index
);
1135 if (mCpuMpData
.AllTimeoutActive
&& (mCpuMpData
.AllTimeTaken
> mCpuMpData
.AllTimeout
)) {
1136 ProcessStartupAllAPsTimeout ();
1138 // Force terminal exit
1139 mCpuMpData
.FinishCount
= mCpuMpData
.StartCount
;
1142 if (mCpuMpData
.FinishCount
!= mCpuMpData
.StartCount
) {
1147 mCpuMpData
.CheckAllAPsEvent
,
1152 if (mCpuMpData
.FailedListIndex
== 0) {
1153 if (mCpuMpData
.FailedList
!= NULL
) {
1154 // Since we don't have the original `FailedCpuList`
1155 // pointer here to set to NULL, don't free the
1160 Status
= gBS
->SignalEvent (mCpuMpData
.AllWaitEvent
);
1161 ASSERT_EFI_ERROR (Status
);
1162 mCpuMpData
.AllWaitEvent
= NULL
;
1165 /** Invoked periodically via a timer to check the state of the processor.
1167 @param Event The event supplied by the timer expiration.
1168 @param Context The processor context.
1180 CPU_AP_DATA
*CpuData
;
1185 CpuData
->TimeTaken
+= POLL_INTERVAL_US
;
1187 State
= GetApState (CpuData
);
1189 if (State
== CpuStateFinished
) {
1190 Status
= gBS
->SetTimer (CpuData
->CheckThisAPEvent
, TimerCancel
, 0);
1191 ASSERT_EFI_ERROR (Status
);
1193 if (CpuData
->SingleApFinished
!= NULL
) {
1194 *(CpuData
->SingleApFinished
) = TRUE
;
1197 if (CpuData
->WaitEvent
!= NULL
) {
1198 Status
= gBS
->SignalEvent (CpuData
->WaitEvent
);
1199 ASSERT_EFI_ERROR (Status
);
1202 CpuData
->State
= CpuStateIdle
;
1205 if (CpuData
->TimeoutActive
&& (CpuData
->TimeTaken
> CpuData
->Timeout
)) {
1206 Status
= gBS
->SetTimer (CpuData
->CheckThisAPEvent
, TimerCancel
, 0);
1207 if (CpuData
->WaitEvent
!= NULL
) {
1208 Status
= gBS
->SignalEvent (CpuData
->WaitEvent
);
1209 ASSERT_EFI_ERROR (Status
);
1210 CpuData
->WaitEvent
= NULL
;
1216 This function is called by all processors (both BSP and AP) once and collects
1219 @param BSP TRUE if the processor is the BSP.
1220 @param Mpidr The MPIDR for the specified processor. This should be
1221 the full MPIDR and not only the affinity bits.
1222 @param ProcessorIndex The index of the processor.
1224 @return EFI_SUCCESS if the data for the processor collected and filled in.
1229 FillInProcessorInformation (
1232 IN UINTN ProcessorIndex
1235 EFI_PROCESSOR_INFORMATION
*CpuInfo
;
1237 CpuInfo
= &mCpuMpData
.CpuData
[ProcessorIndex
].Info
;
1239 CpuInfo
->ProcessorId
= GET_MPIDR_AFFINITY_BITS (Mpidr
);
1240 CpuInfo
->StatusFlag
= PROCESSOR_ENABLED_BIT
| PROCESSOR_HEALTH_STATUS_BIT
;
1243 CpuInfo
->StatusFlag
|= PROCESSOR_AS_BSP_BIT
;
1246 if ((Mpidr
& MPIDR_MT_BIT
) > 0) {
1247 CpuInfo
->Location
.Package
= GET_MPIDR_AFF2 (Mpidr
);
1248 CpuInfo
->Location
.Core
= GET_MPIDR_AFF1 (Mpidr
);
1249 CpuInfo
->Location
.Thread
= GET_MPIDR_AFF0 (Mpidr
);
1251 CpuInfo
->ExtendedInformation
.Location2
.Package
= GET_MPIDR_AFF3 (Mpidr
);
1252 CpuInfo
->ExtendedInformation
.Location2
.Die
= GET_MPIDR_AFF2 (Mpidr
);
1253 CpuInfo
->ExtendedInformation
.Location2
.Core
= GET_MPIDR_AFF1 (Mpidr
);
1254 CpuInfo
->ExtendedInformation
.Location2
.Thread
= GET_MPIDR_AFF0 (Mpidr
);
1256 CpuInfo
->Location
.Package
= GET_MPIDR_AFF1 (Mpidr
);
1257 CpuInfo
->Location
.Core
= GET_MPIDR_AFF0 (Mpidr
);
1258 CpuInfo
->Location
.Thread
= 0;
1260 CpuInfo
->ExtendedInformation
.Location2
.Package
= GET_MPIDR_AFF2 (Mpidr
);
1261 CpuInfo
->ExtendedInformation
.Location2
.Die
= GET_MPIDR_AFF1 (Mpidr
);
1262 CpuInfo
->ExtendedInformation
.Location2
.Core
= GET_MPIDR_AFF0 (Mpidr
);
1263 CpuInfo
->ExtendedInformation
.Location2
.Thread
= 0;
1266 mCpuMpData
.CpuData
[ProcessorIndex
].State
= BSP
? CpuStateBusy
: CpuStateIdle
;
1268 mCpuMpData
.CpuData
[ProcessorIndex
].Procedure
= NULL
;
1269 mCpuMpData
.CpuData
[ProcessorIndex
].Parameter
= NULL
;
1274 /** Initializes the MP Services system data
1276 @param NumberOfProcessors The number of processors, both BSP and AP.
1277 @param CoreInfo CPU information gathered earlier during boot.
1282 MpServicesInitialize (
1283 IN UINTN NumberOfProcessors
,
1284 IN CONST ARM_CORE_INFO
*CoreInfo
1289 EFI_EVENT ReadyToBootEvent
;
1293 // Clear the data structure area first.
1295 ZeroMem (&mCpuMpData
, sizeof (CPU_MP_DATA
));
1297 // First BSP fills and inits all known values, including its own records.
1299 mCpuMpData
.NumberOfProcessors
= NumberOfProcessors
;
1300 mCpuMpData
.NumberOfEnabledProcessors
= NumberOfProcessors
;
1302 mCpuMpData
.CpuData
= AllocateZeroPool (
1303 mCpuMpData
.NumberOfProcessors
* sizeof (CPU_AP_DATA
)
1306 if (mCpuMpData
.CpuData
== NULL
) {
1307 return EFI_OUT_OF_RESOURCES
;
1310 /* Allocate one extra for the sentinel entry at the end */
1311 gProcessorIDs
= AllocateZeroPool ((mCpuMpData
.NumberOfProcessors
+ 1) * sizeof (UINT64
));
1312 ASSERT (gProcessorIDs
!= NULL
);
1314 Status
= gBS
->CreateEvent (
1315 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1319 &mCpuMpData
.CheckAllAPsEvent
1321 ASSERT_EFI_ERROR (Status
);
1323 gApStacksBase
= AllocatePages (
1325 mCpuMpData
.NumberOfProcessors
*
1329 ASSERT (gApStacksBase
!= NULL
);
1331 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
1332 if (GET_MPIDR_AFFINITY_BITS (ArmReadMpidr ()) == CoreInfo
[Index
].Mpidr
) {
1338 FillInProcessorInformation (IsBsp
, CoreInfo
[Index
].Mpidr
, Index
);
1340 gProcessorIDs
[Index
] = mCpuMpData
.CpuData
[Index
].Info
.ProcessorId
;
1342 Status
= gBS
->CreateEvent (
1343 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1346 (VOID
*)&mCpuMpData
.CpuData
[Index
],
1347 &mCpuMpData
.CpuData
[Index
].CheckThisAPEvent
1349 ASSERT_EFI_ERROR (Status
);
1352 gProcessorIDs
[Index
] = MAX_UINT64
;
1354 gTcr
= ArmGetTCR ();
1355 gMair
= ArmGetMAIR ();
1356 gTtbr0
= ArmGetTTBR0BaseAddress ();
1359 // The global pointer variables as well as the gProcessorIDs array contents
1360 // are accessed by the other cores so we must clean them to the PoC
1362 WriteBackDataCacheRange (&gProcessorIDs
, sizeof (UINT64
*));
1363 WriteBackDataCacheRange (&gApStacksBase
, sizeof (UINT64
*));
1365 WriteBackDataCacheRange (
1367 (mCpuMpData
.NumberOfProcessors
+ 1) * sizeof (UINT64
)
1370 mNonBlockingModeAllowed
= TRUE
;
1372 Status
= EfiCreateEventReadyToBootEx (
1374 ReadyToBootSignaled
,
1378 ASSERT_EFI_ERROR (Status
);
1384 Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is
1385 signaled. After this point, non-blocking mode is no longer allowed.
1387 @param Event Event whose notification function is being invoked.
1388 @param Context The pointer to the notification function's context,
1389 which is implementation-dependent.
1395 ReadyToBootSignaled (
1400 mNonBlockingModeAllowed
= FALSE
;
1403 /** Initialize multi-processor support.
1405 @param ImageHandle Image handle.
1406 @param SystemTable System table.
1408 @return EFI_SUCCESS on success, or an error code.
1413 ArmPsciMpServicesDxeInitialize (
1414 IN EFI_HANDLE ImageHandle
,
1415 IN EFI_SYSTEM_TABLE
*SystemTable
1421 EFI_LOADED_IMAGE_PROTOCOL
*Image
;
1422 EFI_HOB_GENERIC_HEADER
*Hob
;
1425 CONST ARM_CORE_INFO
*CoreInfo
;
1429 Status
= gBS
->HandleProtocol (
1431 &gEfiLoadedImageProtocolGuid
,
1434 ASSERT_EFI_ERROR (Status
);
1437 // Parts of the code in this driver may be executed by other cores running
1438 // with the MMU off so we need to ensure that everything is clean to the
1439 // point of coherency (PoC)
1441 WriteBackDataCacheRange (Image
->ImageBase
, Image
->ImageSize
);
1443 Hob
= GetFirstGuidHob (&gArmMpCoreInfoGuid
);
1445 HobData
= GET_GUID_HOB_DATA (Hob
);
1446 HobDataSize
= GET_GUID_HOB_DATA_SIZE (Hob
);
1447 CoreInfo
= (ARM_CORE_INFO
*)HobData
;
1448 MaxCpus
= HobDataSize
/ sizeof (ARM_CORE_INFO
);
1452 DEBUG ((DEBUG_WARN
, "Trying to use EFI_MP_SERVICES_PROTOCOL on a UP system"));
1453 // We are not MP so nothing to do
1454 return EFI_NOT_FOUND
;
1457 Status
= MpServicesInitialize (MaxCpus
, CoreInfo
);
1458 if (Status
!= EFI_SUCCESS
) {
1459 ASSERT_EFI_ERROR (Status
);
1464 // Now install the MP services protocol.
1467 Status
= gBS
->InstallMultipleProtocolInterfaces (
1469 &gEfiMpServiceProtocolGuid
,
1470 &mMpServicesProtocol
,
1473 ASSERT_EFI_ERROR (Status
);
1478 /** AP exception handler.
1480 @param InterruptType The AArch64 CPU exception type.
1481 @param SystemContext System context.
1487 ApExceptionHandler (
1488 IN CONST EFI_EXCEPTION_TYPE InterruptType
,
1489 IN CONST EFI_SYSTEM_CONTEXT SystemContext
1495 UINTN ProcessorIndex
;
1497 Mpidr
= GET_MPIDR_AFFINITY_BITS (ArmReadMpidr ());
1500 ProcessorIndex
= MAX_UINT64
;
1503 if (gProcessorIDs
[Index
] == Mpidr
) {
1504 ProcessorIndex
= Index
;
1509 } while (gProcessorIDs
[Index
] != MAX_UINT64
);
1511 if (ProcessorIndex
!= MAX_UINT64
) {
1512 mCpuMpData
.CpuData
[ProcessorIndex
].State
= CpuStateFinished
;
1513 ArmDataMemoryBarrier ();
1516 Args
.Arg0
= ARM_SMC_ID_PSCI_CPU_OFF
;
1519 /* Should never be reached */
1524 /** C entry-point for the AP.
1525 This function gets called from the assembly function ApEntryPoint.
1534 EFI_AP_PROCEDURE UserApProcedure
;
1535 VOID
*UserApParameter
;
1536 UINTN ProcessorIndex
;
1540 WhoAmI (&mMpServicesProtocol
, &ProcessorIndex
);
1542 /* Fetch the user-supplied procedure and parameter to execute */
1543 UserApProcedure
= mCpuMpData
.CpuData
[ProcessorIndex
].Procedure
;
1544 UserApParameter
= mCpuMpData
.CpuData
[ProcessorIndex
].Parameter
;
1546 InitializeCpuExceptionHandlers (NULL
);
1547 RegisterCpuInterruptHandler (EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
, ApExceptionHandler
);
1548 RegisterCpuInterruptHandler (EXCEPT_AARCH64_IRQ
, ApExceptionHandler
);
1549 RegisterCpuInterruptHandler (EXCEPT_AARCH64_FIQ
, ApExceptionHandler
);
1550 RegisterCpuInterruptHandler (EXCEPT_AARCH64_SERROR
, ApExceptionHandler
);
1552 UserApProcedure (UserApParameter
);
1554 mCpuMpData
.CpuData
[ProcessorIndex
].State
= CpuStateFinished
;
1556 ArmDataMemoryBarrier ();
1558 /* Since we're finished with this AP, turn it off */
1559 Args
.Arg0
= ARM_SMC_ID_PSCI_CPU_OFF
;
1562 /* Should never be reached */
1567 /** Returns whether the processor executing this function is the BSP.
1569 @return Whether the current processor is the BSP.
1573 IsCurrentProcessorBSP (
1578 UINTN ProcessorIndex
;
1580 Status
= WhoAmI (&mMpServicesProtocol
, &ProcessorIndex
);
1581 if (EFI_ERROR (Status
)) {
1582 ASSERT_EFI_ERROR (Status
);
1586 return IsProcessorBSP (ProcessorIndex
);
1589 /** Returns whether the specified processor is enabled.
1591 @param[in] ProcessorIndex The index of the processor to check.
1593 @return TRUE if the processor is enabled, FALSE otherwise.
1597 IsProcessorEnabled (
1598 UINTN ProcessorIndex
1601 EFI_PROCESSOR_INFORMATION
*CpuInfo
;
1603 CpuInfo
= &mCpuMpData
.CpuData
[ProcessorIndex
].Info
;
1605 return (CpuInfo
->StatusFlag
& PROCESSOR_ENABLED_BIT
) != 0;
1608 /** Sets up the state for the StartupAllAPs function.
1610 @param SingleThread Whether the APs will execute sequentially.
1615 StartupAllAPsPrepareState (
1616 IN BOOLEAN SingleThread
1620 CPU_STATE APInitialState
;
1621 CPU_AP_DATA
*CpuData
;
1623 mCpuMpData
.FinishCount
= 0;
1624 mCpuMpData
.StartCount
= 0;
1625 mCpuMpData
.SingleThread
= SingleThread
;
1627 APInitialState
= CpuStateReady
;
1629 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
1630 CpuData
= &mCpuMpData
.CpuData
[Index
];
1633 // Get APs prepared, and put failing APs into FailedCpuList.
1634 // If "SingleThread", only 1 AP will put into ready state, other AP will be
1635 // put into ready state 1 by 1, until the previous 1 finished its task.
1636 // If not "SingleThread", all APs are put into ready state from the
1640 if (IsProcessorBSP (Index
)) {
1645 if (!IsProcessorEnabled (Index
)) {
1646 // Skip Disabled processors
1647 if (mCpuMpData
.FailedList
!= NULL
) {
1648 mCpuMpData
.FailedList
[mCpuMpData
.FailedListIndex
++] = Index
;
1654 // If any APs finished after timing out, reset state to Idle
1655 if (GetApState (CpuData
) == CpuStateFinished
) {
1656 CpuData
->State
= CpuStateIdle
;
1659 if (GetApState (CpuData
) != CpuStateIdle
) {
1660 // Skip busy processors
1661 if (mCpuMpData
.FailedList
!= NULL
) {
1662 mCpuMpData
.FailedList
[mCpuMpData
.FailedListIndex
++] = Index
;
1666 CpuData
->State
= APInitialState
;
1668 mCpuMpData
.StartCount
++;
1670 APInitialState
= CpuStateBlocked
;
1675 /** Handles execution of StartupAllAPs when a WaitEvent has been specified.
1677 @param Procedure The user-supplied procedure.
1678 @param ProcedureArgument The user-supplied procedure argument.
1679 @param WaitEvent The wait event to be signaled when the work is
1680 complete or a timeout has occurred.
1681 @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
1682 indicates an infinite timeout.
1683 @param SingleThread Whether the APs will execute sequentially.
1684 @param FailedCpuList User-supplied pointer for list of failed CPUs.
1686 @return EFI_SUCCESS on success.
1690 StartupAllAPsWithWaitEvent (
1691 IN EFI_AP_PROCEDURE Procedure
,
1692 IN VOID
*ProcedureArgument
,
1693 IN EFI_EVENT WaitEvent
,
1694 IN UINTN TimeoutInMicroseconds
,
1695 IN BOOLEAN SingleThread
,
1696 IN UINTN
**FailedCpuList
1701 CPU_AP_DATA
*CpuData
;
1703 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
1704 CpuData
= &mCpuMpData
.CpuData
[Index
];
1705 if (IsProcessorBSP (Index
)) {
1710 if (!IsProcessorEnabled (Index
)) {
1711 // Skip Disabled processors
1715 if (GetApState (CpuData
) == CpuStateReady
) {
1716 SetApProcedure (CpuData
, Procedure
, ProcedureArgument
);
1717 if ((mCpuMpData
.StartCount
== 0) || !SingleThread
) {
1718 Status
= DispatchCpu (Index
);
1719 if (EFI_ERROR (Status
)) {
1720 AddProcessorToFailedList (Index
, CpuData
->State
);
1727 if (EFI_ERROR (Status
)) {
1728 return EFI_NOT_READY
;
1732 // Save data into private data structure, and create timer to poll AP state
1735 mCpuMpData
.Procedure
= Procedure
;
1736 mCpuMpData
.ProcedureArgument
= ProcedureArgument
;
1737 mCpuMpData
.AllWaitEvent
= WaitEvent
;
1738 mCpuMpData
.AllTimeout
= TimeoutInMicroseconds
;
1739 mCpuMpData
.AllTimeTaken
= 0;
1740 mCpuMpData
.AllTimeoutActive
= (BOOLEAN
)(TimeoutInMicroseconds
!= 0);
1741 Status
= gBS
->SetTimer (
1742 mCpuMpData
.CheckAllAPsEvent
,
1750 /** Handles execution of StartupAllAPs when no wait event has been specified.
1752 @param Procedure The user-supplied procedure.
1753 @param ProcedureArgument The user-supplied procedure argument.
1754 @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
1755 indicates an infinite timeout.
1756 @param SingleThread Whether the APs will execute sequentially.
1757 @param FailedCpuList User-supplied pointer for list of failed CPUs.
1759 @return EFI_SUCCESS on success.
1763 StartupAllAPsNoWaitEvent (
1764 IN EFI_AP_PROCEDURE Procedure
,
1765 IN VOID
*ProcedureArgument
,
1766 IN UINTN TimeoutInMicroseconds
,
1767 IN BOOLEAN SingleThread
,
1768 IN UINTN
**FailedCpuList
1775 CPU_AP_DATA
*CpuData
;
1776 BOOLEAN DispatchError
;
1778 Timeout
= TimeoutInMicroseconds
;
1779 DispatchError
= FALSE
;
1782 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
1783 CpuData
= &mCpuMpData
.CpuData
[Index
];
1784 if (IsProcessorBSP (Index
)) {
1789 if (!IsProcessorEnabled (Index
)) {
1790 // Skip Disabled processors
1794 switch (GetApState (CpuData
)) {
1796 SetApProcedure (CpuData
, Procedure
, ProcedureArgument
);
1797 Status
= DispatchCpu (Index
);
1798 if (EFI_ERROR (Status
)) {
1799 AddProcessorToFailedList (Index
, CpuData
->State
);
1800 CpuData
->State
= CpuStateIdle
;
1801 mCpuMpData
.StartCount
--;
1802 DispatchError
= TRUE
;
1805 // Dispatch the next available AP
1806 Status
= GetNextBlockedNumber (&NextIndex
);
1807 if (!EFI_ERROR (Status
)) {
1808 mCpuMpData
.CpuData
[NextIndex
].State
= CpuStateReady
;
1815 case CpuStateFinished
:
1816 mCpuMpData
.FinishCount
++;
1818 Status
= GetNextBlockedNumber (&NextIndex
);
1819 if (!EFI_ERROR (Status
)) {
1820 mCpuMpData
.CpuData
[NextIndex
].State
= CpuStateReady
;
1824 CpuData
->State
= CpuStateIdle
;
1832 if (mCpuMpData
.FinishCount
== mCpuMpData
.StartCount
) {
1833 Status
= EFI_SUCCESS
;
1837 if ((TimeoutInMicroseconds
!= 0) && (Timeout
== 0)) {
1838 Status
= EFI_TIMEOUT
;
1842 Timeout
-= CalculateAndStallInterval (Timeout
);
1845 if (Status
== EFI_TIMEOUT
) {
1846 // Add any remaining CPUs to the FailedCpuList
1847 if (FailedCpuList
!= NULL
) {
1848 for (Index
= 0; Index
< mCpuMpData
.NumberOfProcessors
; Index
++) {
1849 AddProcessorToFailedList (Index
, mCpuMpData
.CpuData
[Index
].State
);
1854 if (DispatchError
) {
1855 Status
= EFI_NOT_READY
;