1 /** @file
2   CPU DXE Module.
3 
4   Copyright (c) 2008 - 2015, 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
9 
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.
12 
13 **/
14 
15 #include "CpuDxe.h"
16 #include "CpuMp.h"
17 
18 UINTN gMaxLogicalProcessorNumber;
19 UINTN gApStackSize;
20 UINTN gPollInterval = 100; // 100 microseconds
21 
22 MP_SYSTEM_DATA mMpSystemData;
23 EFI_HANDLE     mMpServiceHandle       = NULL;
24 EFI_EVENT      mExitBootServicesEvent = (EFI_EVENT)NULL;
25 
26 VOID *mCommonStack = 0;
27 VOID *mTopOfApCommonStack = 0;
28 VOID *mApStackStart = 0;
29 
30 volatile BOOLEAN mAPsAlreadyInitFinished = FALSE;
31 volatile BOOLEAN mStopCheckAllAPsStatus = TRUE;
32 
33 EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate = {
34   GetNumberOfProcessors,
35   GetProcessorInfo,
36   StartupAllAPs,
37   StartupThisAP,
38   SwitchBSP,
39   EnableDisableAP,
40   WhoAmI
41 };
42 
43 /**
44    Get Mp Service Lock.
45 
46   @param   CpuData    the pointer to CPU_DATA_BLOCK of specified processor
47 
48 **/
49 VOID
GetMpSpinLock(IN CPU_DATA_BLOCK * CpuData)50 GetMpSpinLock (
51   IN  CPU_DATA_BLOCK  *CpuData
52   )
53 {
54   while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {
55     CpuPause ();
56   }
57   CpuData->LockSelf = GetApicId ();
58 }
59 
60 /**
61    Release Mp Service Lock.
62 
63   @param   CpuData    the pointer to CPU_DATA_BLOCK of specified processor
64 
65 **/
66 VOID
ReleaseMpSpinLock(IN CPU_DATA_BLOCK * CpuData)67 ReleaseMpSpinLock (
68   IN  CPU_DATA_BLOCK  *CpuData
69   )
70 {
71   ReleaseSpinLock (&CpuData->CpuDataLock);
72 }
73 
74 /**
75   Check whether caller processor is BSP.
76 
77   @retval  TRUE       the caller is BSP
78   @retval  FALSE      the caller is AP
79 
80 **/
81 BOOLEAN
IsBSP(VOID)82 IsBSP (
83   VOID
84   )
85 {
86   UINTN           CpuIndex;
87   CPU_DATA_BLOCK  *CpuData;
88 
89   CpuData = NULL;
90 
91   WhoAmI (&mMpServicesTemplate, &CpuIndex);
92   CpuData = &mMpSystemData.CpuDatas[CpuIndex];
93 
94   return CpuData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT ? TRUE : FALSE;
95 }
96 
97 /**
98   Get the Application Processors state.
99 
100   @param   CpuData    the pointer to CPU_DATA_BLOCK of specified AP
101 
102   @retval  CPU_STATE  the AP status
103 
104 **/
105 CPU_STATE
GetApState(IN CPU_DATA_BLOCK * CpuData)106 GetApState (
107   IN  CPU_DATA_BLOCK  *CpuData
108   )
109 {
110   CPU_STATE State;
111 
112   GetMpSpinLock (CpuData);
113   State = CpuData->State;
114   ReleaseMpSpinLock (CpuData);
115 
116   return State;
117 }
118 
119 /**
120   Set the Application Processors state.
121 
122   @param   CpuData    The pointer to CPU_DATA_BLOCK of specified AP
123   @param   State      The AP status
124 
125 **/
126 VOID
SetApState(IN CPU_DATA_BLOCK * CpuData,IN CPU_STATE State)127 SetApState (
128   IN  CPU_DATA_BLOCK   *CpuData,
129   IN  CPU_STATE        State
130   )
131 {
132   GetMpSpinLock (CpuData);
133   CpuData->State = State;
134   ReleaseMpSpinLock (CpuData);
135 }
136 
137 /**
138   Set the Application Processor prepare to run a function specified
139   by Params.
140 
141   @param CpuData           the pointer to CPU_DATA_BLOCK of specified AP
142   @param Procedure         A pointer to the function to be run on enabled APs of the system
143   @param ProcedureArgument Pointer to the optional parameter of the assigned function
144 
145 **/
146 VOID
SetApProcedure(IN CPU_DATA_BLOCK * CpuData,IN EFI_AP_PROCEDURE Procedure,IN VOID * ProcedureArgument)147 SetApProcedure (
148   IN   CPU_DATA_BLOCK        *CpuData,
149   IN   EFI_AP_PROCEDURE      Procedure,
150   IN   VOID                  *ProcedureArgument
151   )
152 {
153   GetMpSpinLock (CpuData);
154   CpuData->Parameter  = ProcedureArgument;
155   CpuData->Procedure  = Procedure;
156   ReleaseMpSpinLock (CpuData);
157 }
158 
159 /**
160   Check the Application Processors Status whether contains the Flags.
161 
162   @param     CpuData  the pointer to CPU_DATA_BLOCK of specified AP
163   @param     Flags    the StatusFlag describing in EFI_PROCESSOR_INFORMATION
164 
165   @retval    TRUE     the AP status includes the StatusFlag
166   @retval    FALSE    the AP status excludes the StatusFlag
167 
168 **/
169 BOOLEAN
TestCpuStatusFlag(IN CPU_DATA_BLOCK * CpuData,IN UINT32 Flags)170 TestCpuStatusFlag (
171   IN  CPU_DATA_BLOCK  *CpuData,
172   IN  UINT32          Flags
173   )
174 {
175   UINT32 Ret;
176 
177   GetMpSpinLock (CpuData);
178   Ret = CpuData->Info.StatusFlag & Flags;
179   ReleaseMpSpinLock (CpuData);
180 
181   return (BOOLEAN) (Ret != 0);
182 }
183 
184 /**
185   Bitwise-Or of the Application Processors Status with the Flags.
186 
187   @param     CpuData  the pointer to CPU_DATA_BLOCK of specified AP
188   @param     Flags    the StatusFlag describing in EFI_PROCESSOR_INFORMATION
189 
190 **/
191 VOID
CpuStatusFlagOr(IN CPU_DATA_BLOCK * CpuData,IN UINT32 Flags)192 CpuStatusFlagOr (
193   IN  CPU_DATA_BLOCK  *CpuData,
194   IN  UINT32          Flags
195   )
196 {
197   GetMpSpinLock (CpuData);
198   CpuData->Info.StatusFlag |= Flags;
199   ReleaseMpSpinLock (CpuData);
200 }
201 
202 /**
203   Bitwise-AndNot of the Application Processors Status with the Flags.
204 
205   @param     CpuData  the pointer to CPU_DATA_BLOCK of specified AP
206   @param     Flags    the StatusFlag describing in EFI_PROCESSOR_INFORMATION
207 
208 **/
209 VOID
CpuStatusFlagAndNot(IN CPU_DATA_BLOCK * CpuData,IN UINT32 Flags)210 CpuStatusFlagAndNot (
211   IN  CPU_DATA_BLOCK  *CpuData,
212   IN  UINT32          Flags
213   )
214 {
215   GetMpSpinLock (CpuData);
216   CpuData->Info.StatusFlag &= ~Flags;
217   ReleaseMpSpinLock (CpuData);
218 }
219 
220 /**
221   Searches for the next blocking AP.
222 
223   Search for the next AP that is put in blocking state by single-threaded StartupAllAPs().
224 
225   @param  NextNumber           Pointer to the processor number of the next blocking AP.
226 
227   @retval EFI_SUCCESS          The next blocking AP has been found.
228   @retval EFI_NOT_FOUND        No blocking AP exists.
229 
230 **/
231 EFI_STATUS
GetNextBlockedNumber(OUT UINTN * NextNumber)232 GetNextBlockedNumber (
233   OUT UINTN  *NextNumber
234   )
235 {
236   UINTN                 Number;
237   CPU_STATE             CpuState;
238   CPU_DATA_BLOCK        *CpuData;
239 
240   for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
241     CpuData = &mMpSystemData.CpuDatas[Number];
242     if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
243       //
244       // Skip BSP
245       //
246       continue;
247     }
248 
249     CpuState = GetApState (CpuData);
250     if (CpuState == CpuStateBlocked) {
251       *NextNumber = Number;
252       return EFI_SUCCESS;
253     }
254   }
255 
256   return EFI_NOT_FOUND;
257 }
258 
259 /**
260   Check if the APs state are finished, and update them to idle state
261   by StartupAllAPs().
262 
263 **/
264 VOID
CheckAndUpdateAllAPsToIdleState(VOID)265 CheckAndUpdateAllAPsToIdleState (
266   VOID
267   )
268 {
269   UINTN                 ProcessorNumber;
270   UINTN                 NextNumber;
271   CPU_DATA_BLOCK        *CpuData;
272   EFI_STATUS            Status;
273   CPU_STATE             CpuState;
274 
275   for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
276     CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
277     if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
278       //
279       // Skip BSP
280       //
281       continue;
282     }
283 
284     if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
285       //
286       // Skip Disabled processors
287       //
288       continue;
289     }
290 
291     CpuState = GetApState (CpuData);
292     if (CpuState == CpuStateFinished) {
293       mMpSystemData.FinishCount++;
294       if (mMpSystemData.SingleThread) {
295         Status = GetNextBlockedNumber (&NextNumber);
296         if (!EFI_ERROR (Status)) {
297           SetApState (&mMpSystemData.CpuDatas[NextNumber], CpuStateReady);
298           SetApProcedure (&mMpSystemData.CpuDatas[NextNumber],
299                           mMpSystemData.Procedure,
300                           mMpSystemData.ProcedureArgument);
301           //
302           // If this AP previous state is blocked, we should
303           // wake up this AP by sent a SIPI. and avoid
304           // re-involve the sleeping state. we must call
305           // SetApProcedure() first.
306           //
307           ResetProcessorToIdleState (&mMpSystemData.CpuDatas[NextNumber]);
308         }
309       }
310       SetApState (CpuData, CpuStateIdle);
311     }
312   }
313 }
314 
315 /**
316   Check if all APs are in state CpuStateSleeping.
317 
318   Return TRUE if all APs are in the CpuStateSleeping state.  Do not
319   check the state of the BSP or any disabled APs.
320 
321   @retval TRUE   All APs are in CpuStateSleeping state.
322   @retval FALSE  One or more APs are not in CpuStateSleeping state.
323 
324 **/
325 BOOLEAN
CheckAllAPsSleeping(VOID)326 CheckAllAPsSleeping (
327   VOID
328   )
329 {
330   UINTN           ProcessorNumber;
331   CPU_DATA_BLOCK  *CpuData;
332 
333   for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
334     CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
335     if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
336       //
337       // Skip BSP
338       //
339       continue;
340     }
341 
342     if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
343       //
344       // Skip Disabled processors
345       //
346       continue;
347     }
348 
349     if (GetApState (CpuData) != CpuStateSleeping) {
350       return FALSE;
351     }
352   }
353   return TRUE;
354 }
355 
356 /**
357   If the timeout expires before all APs returns from Procedure,
358   we should forcibly terminate the executing AP and fill FailedList back
359   by StartupAllAPs().
360 
361 **/
362 VOID
ResetAllFailedAPs(VOID)363 ResetAllFailedAPs (
364   VOID
365   )
366 {
367   CPU_DATA_BLOCK        *CpuData;
368   UINTN                 Number;
369   CPU_STATE             CpuState;
370 
371   if (mMpSystemData.FailedList != NULL) {
372      *mMpSystemData.FailedList = AllocatePool ((mMpSystemData.StartCount - mMpSystemData.FinishCount + 1) * sizeof(UINTN));
373      ASSERT (*mMpSystemData.FailedList != NULL);
374   }
375 
376   for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
377     CpuData = &mMpSystemData.CpuDatas[Number];
378     if (TestCpuStatusFlag (CpuData,  PROCESSOR_AS_BSP_BIT)) {
379       //
380       // Skip BSP
381       //
382       continue;
383     }
384 
385     if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
386       //
387       // Skip Disabled processors
388       //
389       continue;
390     }
391 
392     CpuState = GetApState (CpuData);
393     if (CpuState != CpuStateIdle &&
394         CpuState != CpuStateSleeping) {
395       if (mMpSystemData.FailedList != NULL) {
396         (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex++] = Number;
397       }
398       ResetProcessorToIdleState (CpuData);
399     }
400   }
401 
402   if (mMpSystemData.FailedList != NULL) {
403     (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex] = END_OF_CPU_LIST;
404   }
405 }
406 
407 /**
408   This service retrieves the number of logical processor in the platform
409   and the number of those logical processors that are enabled on this boot.
410   This service may only be called from the BSP.
411 
412   This function is used to retrieve the following information:
413     - The number of logical processors that are present in the system.
414     - The number of enabled logical processors in the system at the instant
415       this call is made.
416 
417   Because MP Service Protocol provides services to enable and disable processors
418   dynamically, the number of enabled logical processors may vary during the
419   course of a boot session.
420 
421   If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
422   If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
423   EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
424   is returned in NumberOfProcessors, the number of currently enabled processor
425   is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
426 
427   @param[in]  This                        A pointer to the EFI_MP_SERVICES_PROTOCOL
428                                           instance.
429   @param[out] NumberOfProcessors          Pointer to the total number of logical
430                                           processors in the system, including the BSP
431                                           and disabled APs.
432   @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled logical
433                                           processors that exist in system, including
434                                           the BSP.
435 
436   @retval EFI_SUCCESS             The number of logical processors and enabled
437                                   logical processors was retrieved.
438   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
439   @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL.
440   @retval EFI_INVALID_PARAMETER   NumberOfEnabledProcessors is NULL.
441 
442 **/
443 EFI_STATUS
444 EFIAPI
GetNumberOfProcessors(IN EFI_MP_SERVICES_PROTOCOL * This,OUT UINTN * NumberOfProcessors,OUT UINTN * NumberOfEnabledProcessors)445 GetNumberOfProcessors (
446   IN  EFI_MP_SERVICES_PROTOCOL  *This,
447   OUT UINTN                     *NumberOfProcessors,
448   OUT UINTN                     *NumberOfEnabledProcessors
449   )
450 {
451   if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
452     return EFI_INVALID_PARAMETER;
453   }
454 
455   if (!IsBSP ()) {
456     return EFI_DEVICE_ERROR;
457   }
458 
459   *NumberOfProcessors        = mMpSystemData.NumberOfProcessors;
460   *NumberOfEnabledProcessors = mMpSystemData.NumberOfEnabledProcessors;
461   return EFI_SUCCESS;
462 }
463 
464 /**
465   Gets detailed MP-related information on the requested processor at the
466   instant this call is made. This service may only be called from the BSP.
467 
468   This service retrieves detailed MP-related information about any processor
469   on the platform. Note the following:
470     - The processor information may change during the course of a boot session.
471     - The information presented here is entirely MP related.
472 
473   Information regarding the number of caches and their sizes, frequency of operation,
474   slot numbers is all considered platform-related information and is not provided
475   by this service.
476 
477   @param[in]  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL
478                                     instance.
479   @param[in]  ProcessorNumber       The handle number of processor.
480   @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
481                                     the requested processor is deposited.
482 
483   @retval EFI_SUCCESS             Processor information was returned.
484   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
485   @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
486   @retval EFI_NOT_FOUND           The processor with the handle specified by
487                                   ProcessorNumber does not exist in the platform.
488 
489 **/
490 EFI_STATUS
491 EFIAPI
GetProcessorInfo(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,OUT EFI_PROCESSOR_INFORMATION * ProcessorInfoBuffer)492 GetProcessorInfo (
493   IN  EFI_MP_SERVICES_PROTOCOL   *This,
494   IN  UINTN                      ProcessorNumber,
495   OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer
496   )
497 {
498   if (ProcessorInfoBuffer == NULL) {
499     return EFI_INVALID_PARAMETER;
500   }
501 
502   if (!IsBSP ()) {
503     return EFI_DEVICE_ERROR;
504   }
505 
506   if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
507     return EFI_NOT_FOUND;
508   }
509 
510   CopyMem (ProcessorInfoBuffer, &mMpSystemData.CpuDatas[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));
511   return EFI_SUCCESS;
512 }
513 
514 /**
515   This service executes a caller provided function on all enabled APs. APs can
516   run either simultaneously or one at a time in sequence. This service supports
517   both blocking and non-blocking requests. The non-blocking requests use EFI
518   events so the BSP can detect when the APs have finished. This service may only
519   be called from the BSP.
520 
521   This function is used to dispatch all the enabled APs to the function specified
522   by Procedure.  If any enabled AP is busy, then EFI_NOT_READY is returned
523   immediately and Procedure is not started on any AP.
524 
525   If SingleThread is TRUE, all the enabled APs execute the function specified by
526   Procedure one by one, in ascending order of processor handle number. Otherwise,
527   all the enabled APs execute the function specified by Procedure simultaneously.
528 
529   If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
530   APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
531   mode, and the BSP returns from this service without waiting for APs. If a
532   non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
533   is signaled, then EFI_UNSUPPORTED must be returned.
534 
535   If the timeout specified by TimeoutInMicroseconds expires before all APs return
536   from Procedure, then Procedure on the failed APs is terminated. All enabled APs
537   are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
538   and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
539   content points to the list of processor handle numbers in which Procedure was
540   terminated.
541 
542   Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
543   to make sure that the nature of the code that is executed on the BSP and the
544   dispatched APs is well controlled. The MP Services Protocol does not guarantee
545   that the Procedure function is MP-safe. Hence, the tasks that can be run in
546   parallel are limited to certain independent tasks and well-controlled exclusive
547   code. EFI services and protocols may not be called by APs unless otherwise
548   specified.
549 
550   In blocking execution mode, BSP waits until all APs finish or
551   TimeoutInMicroseconds expires.
552 
553   In non-blocking execution mode, BSP is freed to return to the caller and then
554   proceed to the next task without having to wait for APs. The following
555   sequence needs to occur in a non-blocking execution mode:
556 
557     -# The caller that intends to use this MP Services Protocol in non-blocking
558        mode creates WaitEvent by calling the EFI CreateEvent() service.  The caller
559        invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
560        is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
561        the function specified by Procedure to be started on all the enabled APs,
562        and releases the BSP to continue with other tasks.
563     -# The caller can use the CheckEvent() and WaitForEvent() services to check
564        the state of the WaitEvent created in step 1.
565     -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
566        Service signals WaitEvent by calling the EFI SignalEvent() function. If
567        FailedCpuList is not NULL, its content is available when WaitEvent is
568        signaled. If all APs returned from Procedure prior to the timeout, then
569        FailedCpuList is set to NULL. If not all APs return from Procedure before
570        the timeout, then FailedCpuList is filled in with the list of the failed
571        APs. The buffer is allocated by MP Service Protocol using AllocatePool().
572        It is the caller's responsibility to free the buffer with FreePool() service.
573     -# This invocation of SignalEvent() function informs the caller that invoked
574        EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
575        the specified task or a timeout occurred. The contents of FailedCpuList
576        can be examined to determine which APs did not complete the specified task
577        prior to the timeout.
578 
579   @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
580                                       instance.
581   @param[in]  Procedure               A pointer to the function to be run on
582                                       enabled APs of the system. See type
583                                       EFI_AP_PROCEDURE.
584   @param[in]  SingleThread            If TRUE, then all the enabled APs execute
585                                       the function specified by Procedure one by
586                                       one, in ascending order of processor handle
587                                       number.  If FALSE, then all the enabled APs
588                                       execute the function specified by Procedure
589                                       simultaneously.
590   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
591                                       service.  If it is NULL, then execute in
592                                       blocking mode. BSP waits until all APs finish
593                                       or TimeoutInMicroseconds expires.  If it's
594                                       not NULL, then execute in non-blocking mode.
595                                       BSP requests the function specified by
596                                       Procedure to be started on all the enabled
597                                       APs, and go on executing immediately. If
598                                       all return from Procedure, or TimeoutInMicroseconds
599                                       expires, this event is signaled. The BSP
600                                       can use the CheckEvent() or WaitForEvent()
601                                       services to check the state of event.  Type
602                                       EFI_EVENT is defined in CreateEvent() in
603                                       the Unified Extensible Firmware Interface
604                                       Specification.
605   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
606                                       APs to return from Procedure, either for
607                                       blocking or non-blocking mode. Zero means
608                                       infinity.  If the timeout expires before
609                                       all APs return from Procedure, then Procedure
610                                       on the failed APs is terminated. All enabled
611                                       APs are available for next function assigned
612                                       by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
613                                       or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
614                                       If the timeout expires in blocking mode,
615                                       BSP returns EFI_TIMEOUT.  If the timeout
616                                       expires in non-blocking mode, WaitEvent
617                                       is signaled with SignalEvent().
618   @param[in]  ProcedureArgument       The parameter passed into Procedure for
619                                       all APs.
620   @param[out] FailedCpuList           If NULL, this parameter is ignored. Otherwise,
621                                       if all APs finish successfully, then its
622                                       content is set to NULL. If not all APs
623                                       finish before timeout expires, then its
624                                       content is set to address of the buffer
625                                       holding handle numbers of the failed APs.
626                                       The buffer is allocated by MP Service Protocol,
627                                       and it's the caller's responsibility to
628                                       free the buffer with FreePool() service.
629                                       In blocking mode, it is ready for consumption
630                                       when the call returns. In non-blocking mode,
631                                       it is ready when WaitEvent is signaled.  The
632                                       list of failed CPU is terminated by
633                                       END_OF_CPU_LIST.
634 
635   @retval EFI_SUCCESS             In blocking mode, all APs have finished before
636                                   the timeout expired.
637   @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
638                                   to all enabled APs.
639   @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
640                                   UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
641                                   signaled.
642   @retval EFI_DEVICE_ERROR        Caller processor is AP.
643   @retval EFI_NOT_STARTED         No enabled APs exist in the system.
644   @retval EFI_NOT_READY           Any enabled APs are busy.
645   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
646                                   all enabled APs have finished.
647   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
648 
649 **/
650 EFI_STATUS
651 EFIAPI
StartupAllAPs(IN EFI_MP_SERVICES_PROTOCOL * This,IN EFI_AP_PROCEDURE Procedure,IN BOOLEAN SingleThread,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT UINTN ** FailedCpuList OPTIONAL)652 StartupAllAPs (
653   IN  EFI_MP_SERVICES_PROTOCOL  *This,
654   IN  EFI_AP_PROCEDURE          Procedure,
655   IN  BOOLEAN                   SingleThread,
656   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
657   IN  UINTN                     TimeoutInMicroseconds,
658   IN  VOID                      *ProcedureArgument      OPTIONAL,
659   OUT UINTN                     **FailedCpuList         OPTIONAL
660   )
661 {
662   EFI_STATUS            Status;
663   CPU_DATA_BLOCK        *CpuData;
664   UINTN                 Number;
665   CPU_STATE             APInitialState;
666   CPU_STATE             CpuState;
667 
668   CpuData = NULL;
669 
670   if (FailedCpuList != NULL) {
671     *FailedCpuList = NULL;
672   }
673 
674   if (!IsBSP ()) {
675     return EFI_DEVICE_ERROR;
676   }
677 
678   if (mMpSystemData.NumberOfProcessors == 1) {
679     return EFI_NOT_STARTED;
680   }
681 
682   if (Procedure == NULL) {
683     return EFI_INVALID_PARAMETER;
684   }
685 
686   //
687   // temporarily stop checkAllAPsStatus for avoid resource dead-lock.
688   //
689   mStopCheckAllAPsStatus = TRUE;
690 
691   for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
692     CpuData = &mMpSystemData.CpuDatas[Number];
693     if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
694       //
695       // Skip BSP
696       //
697       continue;
698     }
699 
700     if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
701       //
702       // Skip Disabled processors
703       //
704       continue;
705     }
706 
707     CpuState = GetApState (CpuData);
708     if (CpuState != CpuStateIdle &&
709         CpuState != CpuStateSleeping) {
710       return EFI_NOT_READY;
711     }
712   }
713 
714   mMpSystemData.Procedure         = Procedure;
715   mMpSystemData.ProcedureArgument = ProcedureArgument;
716   mMpSystemData.WaitEvent         = WaitEvent;
717   mMpSystemData.Timeout           = TimeoutInMicroseconds;
718   mMpSystemData.TimeoutActive     = (BOOLEAN) (TimeoutInMicroseconds != 0);
719   mMpSystemData.FinishCount       = 0;
720   mMpSystemData.StartCount        = 0;
721   mMpSystemData.SingleThread      = SingleThread;
722   mMpSystemData.FailedList        = FailedCpuList;
723   mMpSystemData.FailedListIndex   = 0;
724   APInitialState                  = CpuStateReady;
725 
726   for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
727     CpuData = &mMpSystemData.CpuDatas[Number];
728     if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
729       //
730       // Skip BSP
731       //
732       continue;
733     }
734 
735     if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
736       //
737       // Skip Disabled processors
738       //
739       continue;
740     }
741 
742     //
743     // Get APs prepared, and put failing APs into FailedCpuList
744     // if "SingleThread", only 1 AP will put to ready state, other AP will be put to ready
745     // state 1 by 1, until the previous 1 finished its task
746     // if not "SingleThread", all APs are put to ready state from the beginning
747     //
748     CpuState = GetApState (CpuData);
749     if (CpuState == CpuStateIdle ||
750         CpuState == CpuStateSleeping) {
751       mMpSystemData.StartCount++;
752 
753       SetApState (CpuData, APInitialState);
754 
755       if (APInitialState == CpuStateReady) {
756         SetApProcedure (CpuData, Procedure, ProcedureArgument);
757         //
758         // If this AP previous state is Sleeping, we should
759         // wake up this AP by sent a SIPI. and avoid
760         // re-involve the sleeping state. we must call
761         // SetApProcedure() first.
762         //
763         if (CpuState == CpuStateSleeping) {
764           ResetProcessorToIdleState (CpuData);
765         }
766       }
767 
768       if (SingleThread) {
769         APInitialState = CpuStateBlocked;
770       }
771     }
772   }
773 
774   mStopCheckAllAPsStatus = FALSE;
775 
776   if (WaitEvent != NULL) {
777     //
778     // non blocking
779     //
780     return EFI_SUCCESS;
781   }
782 
783   //
784   // Blocking temporarily stop CheckAllAPsStatus()
785   //
786   mStopCheckAllAPsStatus = TRUE;
787 
788   while (TRUE) {
789     CheckAndUpdateAllAPsToIdleState ();
790     if (mMpSystemData.FinishCount == mMpSystemData.StartCount) {
791       Status = EFI_SUCCESS;
792       goto Done;
793     }
794 
795     //
796     // task timeout
797     //
798     if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
799       ResetAllFailedAPs();
800       Status = EFI_TIMEOUT;
801       goto Done;
802     }
803 
804     MicroSecondDelay (gPollInterval);
805     mMpSystemData.Timeout -= gPollInterval;
806   }
807 
808 Done:
809 
810   return Status;
811 }
812 
813 /**
814   This service lets the caller get one enabled AP to execute a caller-provided
815   function. The caller can request the BSP to either wait for the completion
816   of the AP or just proceed with the next task by using the EFI event mechanism.
817   See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
818   execution support.  This service may only be called from the BSP.
819 
820   This function is used to dispatch one enabled AP to the function specified by
821   Procedure passing in the argument specified by ProcedureArgument.  If WaitEvent
822   is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
823   TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
824   BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
825   is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
826   then EFI_UNSUPPORTED must be returned.
827 
828   If the timeout specified by TimeoutInMicroseconds expires before the AP returns
829   from Procedure, then execution of Procedure by the AP is terminated. The AP is
830   available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
831   EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
832 
833   @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
834                                       instance.
835   @param[in]  Procedure               A pointer to the function to be run on
836                                       enabled APs of the system. See type
837                                       EFI_AP_PROCEDURE.
838   @param[in]  ProcessorNumber         The handle number of the AP. The range is
839                                       from 0 to the total number of logical
840                                       processors minus 1. The total number of
841                                       logical processors can be retrieved by
842                                       EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
843   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
844                                       service.  If it is NULL, then execute in
845                                       blocking mode. BSP waits until all APs finish
846                                       or TimeoutInMicroseconds expires.  If it's
847                                       not NULL, then execute in non-blocking mode.
848                                       BSP requests the function specified by
849                                       Procedure to be started on all the enabled
850                                       APs, and go on executing immediately. If
851                                       all return from Procedure or TimeoutInMicroseconds
852                                       expires, this event is signaled. The BSP
853                                       can use the CheckEvent() or WaitForEvent()
854                                       services to check the state of event.  Type
855                                       EFI_EVENT is defined in CreateEvent() in
856                                       the Unified Extensible Firmware Interface
857                                       Specification.
858   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
859                                       APs to return from Procedure, either for
860                                       blocking or non-blocking mode. Zero means
861                                       infinity.  If the timeout expires before
862                                       all APs return from Procedure, then Procedure
863                                       on the failed APs is terminated. All enabled
864                                       APs are available for next function assigned
865                                       by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
866                                       or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
867                                       If the timeout expires in blocking mode,
868                                       BSP returns EFI_TIMEOUT.  If the timeout
869                                       expires in non-blocking mode, WaitEvent
870                                       is signaled with SignalEvent().
871   @param[in]  ProcedureArgument       The parameter passed into Procedure for
872                                       all APs.
873   @param[out] Finished                If NULL, this parameter is ignored.  In
874                                       blocking mode, this parameter is ignored.
875                                       In non-blocking mode, if AP returns from
876                                       Procedure before the timeout expires, its
877                                       content is set to TRUE. Otherwise, the
878                                       value is set to FALSE. The caller can
879                                       determine if the AP returned from Procedure
880                                       by evaluating this value.
881 
882   @retval EFI_SUCCESS             In blocking mode, specified AP finished before
883                                   the timeout expires.
884   @retval EFI_SUCCESS             In non-blocking mode, the function has been
885                                   dispatched to specified AP.
886   @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
887                                   UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
888                                   signaled.
889   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
890   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
891                                   the specified AP has finished.
892   @retval EFI_NOT_READY           The specified AP is busy.
893   @retval EFI_NOT_FOUND           The processor with the handle specified by
894                                   ProcessorNumber does not exist.
895   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
896   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
897 
898 **/
899 EFI_STATUS
900 EFIAPI
StartupThisAP(IN EFI_MP_SERVICES_PROTOCOL * This,IN EFI_AP_PROCEDURE Procedure,IN UINTN ProcessorNumber,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT BOOLEAN * Finished OPTIONAL)901 StartupThisAP (
902   IN  EFI_MP_SERVICES_PROTOCOL  *This,
903   IN  EFI_AP_PROCEDURE          Procedure,
904   IN  UINTN                     ProcessorNumber,
905   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
906   IN  UINTN                     TimeoutInMicroseconds,
907   IN  VOID                      *ProcedureArgument      OPTIONAL,
908   OUT BOOLEAN                   *Finished               OPTIONAL
909   )
910 {
911   CPU_DATA_BLOCK        *CpuData;
912   CPU_STATE             CpuState;
913 
914   CpuData = NULL;
915 
916   if (Finished != NULL) {
917     *Finished = FALSE;
918   }
919 
920   if (!IsBSP ()) {
921     return EFI_DEVICE_ERROR;
922   }
923 
924   if (Procedure == NULL) {
925     return EFI_INVALID_PARAMETER;
926   }
927 
928   if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
929     return EFI_NOT_FOUND;
930   }
931 
932   //
933   // temporarily stop checkAllAPsStatus for avoid resource dead-lock.
934   //
935   mStopCheckAllAPsStatus = TRUE;
936 
937   CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
938   if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT) ||
939       !TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
940     return EFI_INVALID_PARAMETER;
941   }
942 
943   CpuState = GetApState (CpuData);
944   if (CpuState != CpuStateIdle &&
945       CpuState != CpuStateSleeping) {
946     return EFI_NOT_READY;
947   }
948 
949   SetApState (CpuData, CpuStateReady);
950 
951   SetApProcedure (CpuData, Procedure, ProcedureArgument);
952   //
953   // If this AP previous state is Sleeping, we should
954   // wake up this AP by sent a SIPI. and avoid
955   // re-involve the sleeping state. we must call
956   // SetApProcedure() first.
957   //
958   if (CpuState == CpuStateSleeping) {
959     ResetProcessorToIdleState (CpuData);
960   }
961 
962   CpuData->Timeout = TimeoutInMicroseconds;
963   CpuData->WaitEvent = WaitEvent;
964   CpuData->TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);
965   CpuData->Finished = Finished;
966 
967   mStopCheckAllAPsStatus = FALSE;
968 
969   if (WaitEvent != NULL) {
970     //
971     // Non Blocking
972     //
973     return EFI_SUCCESS;
974   }
975 
976   //
977   // Blocking
978   //
979   while (TRUE) {
980     if (GetApState (CpuData) == CpuStateFinished) {
981       SetApState (CpuData, CpuStateIdle);
982       break;
983     }
984 
985     if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
986       ResetProcessorToIdleState (CpuData);
987       return EFI_TIMEOUT;
988     }
989 
990     MicroSecondDelay (gPollInterval);
991     CpuData->Timeout -= gPollInterval;
992   }
993 
994   return EFI_SUCCESS;
995 }
996 
997 /**
998   This service switches the requested AP to be the BSP from that point onward.
999   This service changes the BSP for all purposes.   This call can only be performed
1000   by the current BSP.
1001 
1002   This service switches the requested AP to be the BSP from that point onward.
1003   This service changes the BSP for all purposes. The new BSP can take over the
1004   execution of the old BSP and continue seamlessly from where the old one left
1005   off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
1006   is signaled.
1007 
1008   If the BSP cannot be switched prior to the return from this service, then
1009   EFI_UNSUPPORTED must be returned.
1010 
1011   @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
1012   @param[in] ProcessorNumber   The handle number of AP that is to become the new
1013                                BSP. The range is from 0 to the total number of
1014                                logical processors minus 1. The total number of
1015                                logical processors can be retrieved by
1016                                EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
1017   @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
1018                                enabled AP. Otherwise, it will be disabled.
1019 
1020   @retval EFI_SUCCESS             BSP successfully switched.
1021   @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to
1022                                   this service returning.
1023   @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
1024   @retval EFI_SUCCESS             The calling processor is an AP.
1025   @retval EFI_NOT_FOUND           The processor with the handle specified by
1026                                   ProcessorNumber does not exist.
1027   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or
1028                                   a disabled AP.
1029   @retval EFI_NOT_READY           The specified AP is busy.
1030 
1031 **/
1032 EFI_STATUS
1033 EFIAPI
SwitchBSP(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)1034 SwitchBSP (
1035   IN EFI_MP_SERVICES_PROTOCOL  *This,
1036   IN  UINTN                    ProcessorNumber,
1037   IN  BOOLEAN                  EnableOldBSP
1038   )
1039 {
1040    //
1041    // Current always return unsupported.
1042    //
1043    return EFI_UNSUPPORTED;
1044 }
1045 
1046 /**
1047   This service lets the caller enable or disable an AP from this point onward.
1048   This service may only be called from the BSP.
1049 
1050   This service allows the caller enable or disable an AP from this point onward.
1051   The caller can optionally specify the health status of the AP by Health. If
1052   an AP is being disabled, then the state of the disabled AP is implementation
1053   dependent. If an AP is enabled, then the implementation must guarantee that a
1054   complete initialization sequence is performed on the AP, so the AP is in a state
1055   that is compatible with an MP operating system. This service may not be supported
1056   after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
1057 
1058   If the enable or disable AP operation cannot be completed prior to the return
1059   from this service, then EFI_UNSUPPORTED must be returned.
1060 
1061   @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
1062   @param[in] ProcessorNumber   The handle number of AP that is to become the new
1063                                BSP. The range is from 0 to the total number of
1064                                logical processors minus 1. The total number of
1065                                logical processors can be retrieved by
1066                                EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
1067   @param[in] EnableAP          Specifies the new state for the processor for
1068                                enabled, FALSE for disabled.
1069   @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
1070                                the new health status of the AP. This flag
1071                                corresponds to StatusFlag defined in
1072                                EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
1073                                the PROCESSOR_HEALTH_STATUS_BIT is used. All other
1074                                bits are ignored.  If it is NULL, this parameter
1075                                is ignored.
1076 
1077   @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
1078   @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed
1079                                   prior to this service returning.
1080   @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
1081   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
1082   @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
1083                                   does not exist.
1084   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
1085 
1086 **/
1087 EFI_STATUS
1088 EFIAPI
EnableDisableAP(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableAP,IN UINT32 * HealthFlag OPTIONAL)1089 EnableDisableAP (
1090   IN  EFI_MP_SERVICES_PROTOCOL  *This,
1091   IN  UINTN                     ProcessorNumber,
1092   IN  BOOLEAN                   EnableAP,
1093   IN  UINT32                    *HealthFlag OPTIONAL
1094   )
1095 {
1096   CPU_DATA_BLOCK *CpuData;
1097   BOOLEAN        TempStopCheckState;
1098   CPU_STATE      CpuState;
1099 
1100   CpuData = NULL;
1101   TempStopCheckState = FALSE;
1102 
1103   if (!IsBSP ()) {
1104     return EFI_DEVICE_ERROR;
1105   }
1106 
1107   if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
1108     return EFI_NOT_FOUND;
1109   }
1110 
1111   //
1112   // temporarily stop checkAllAPsStatus for initialize parameters.
1113   //
1114   if (!mStopCheckAllAPsStatus) {
1115     mStopCheckAllAPsStatus = TRUE;
1116     TempStopCheckState = TRUE;
1117   }
1118 
1119   CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1120   if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
1121     return EFI_INVALID_PARAMETER;
1122   }
1123 
1124   CpuState = GetApState (CpuData);
1125   if (CpuState != CpuStateIdle &&
1126       CpuState != CpuStateSleeping) {
1127     return EFI_UNSUPPORTED;
1128   }
1129 
1130   if (EnableAP) {
1131     if (!(TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT))) {
1132       mMpSystemData.NumberOfEnabledProcessors++;
1133     }
1134     CpuStatusFlagOr (CpuData, PROCESSOR_ENABLED_BIT);
1135   } else {
1136     if (TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
1137       mMpSystemData.NumberOfEnabledProcessors--;
1138     }
1139     CpuStatusFlagAndNot (CpuData, PROCESSOR_ENABLED_BIT);
1140   }
1141 
1142   if (HealthFlag != NULL) {
1143     CpuStatusFlagAndNot (CpuData, (UINT32)~PROCESSOR_HEALTH_STATUS_BIT);
1144     CpuStatusFlagOr (CpuData, (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT));
1145   }
1146 
1147   if (TempStopCheckState) {
1148     mStopCheckAllAPsStatus = FALSE;
1149   }
1150 
1151   return EFI_SUCCESS;
1152 }
1153 
1154 /**
1155   This return the handle number for the calling processor.  This service may be
1156   called from the BSP and APs.
1157 
1158   This service returns the processor handle number for the calling processor.
1159   The returned value is in the range from 0 to the total number of logical
1160   processors minus 1. The total number of logical processors can be retrieved
1161   with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
1162   called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
1163   is returned. Otherwise, the current processors handle number is returned in
1164   ProcessorNumber, and EFI_SUCCESS is returned.
1165 
1166   @param[in]  This             A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
1167   @param[out] ProcessorNumber  The handle number of AP that is to become the new
1168                                BSP. The range is from 0 to the total number of
1169                                logical processors minus 1. The total number of
1170                                logical processors can be retrieved by
1171                                EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
1172 
1173   @retval EFI_SUCCESS             The current processor handle number was returned
1174                                   in ProcessorNumber.
1175   @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.
1176 
1177 **/
1178 EFI_STATUS
1179 EFIAPI
WhoAmI(IN EFI_MP_SERVICES_PROTOCOL * This,OUT UINTN * ProcessorNumber)1180 WhoAmI (
1181   IN EFI_MP_SERVICES_PROTOCOL  *This,
1182   OUT UINTN                    *ProcessorNumber
1183   )
1184 {
1185   UINTN   Index;
1186   UINT32  ProcessorId;
1187 
1188   if (ProcessorNumber == NULL) {
1189     return EFI_INVALID_PARAMETER;
1190   }
1191 
1192   ProcessorId = GetApicId ();
1193   for (Index = 0; Index < mMpSystemData.NumberOfProcessors; Index++) {
1194     if (mMpSystemData.CpuDatas[Index].Info.ProcessorId == ProcessorId) {
1195       break;
1196     }
1197   }
1198 
1199   *ProcessorNumber = Index;
1200   return EFI_SUCCESS;
1201 }
1202 
1203 /**
1204   Terminate AP's task and set it to idle state.
1205 
1206   This function terminates AP's task due to timeout by sending INIT-SIPI,
1207   and sends it to idle state.
1208 
1209   @param CpuData           the pointer to CPU_DATA_BLOCK of specified AP
1210 
1211 **/
1212 VOID
ResetProcessorToIdleState(IN CPU_DATA_BLOCK * CpuData)1213 ResetProcessorToIdleState (
1214   IN CPU_DATA_BLOCK  *CpuData
1215   )
1216 {
1217   ResetApStackless ((UINT32)CpuData->Info.ProcessorId);
1218 }
1219 
1220 /**
1221   Application Processors do loop routine
1222   after switch to its own stack.
1223 
1224   @param  Context1    A pointer to the context to pass into the function.
1225   @param  Context2    A pointer to the context to pass into the function.
1226 
1227 **/
1228 VOID
ProcessorToIdleState(IN VOID * Context1,OPTIONAL IN VOID * Context2 OPTIONAL)1229 ProcessorToIdleState (
1230   IN      VOID                      *Context1,  OPTIONAL
1231   IN      VOID                      *Context2   OPTIONAL
1232   )
1233 {
1234   UINTN                 ProcessorNumber;
1235   CPU_DATA_BLOCK        *CpuData;
1236   EFI_AP_PROCEDURE      Procedure;
1237   volatile VOID         *ProcedureArgument;
1238 
1239   AsmApDoneWithCommonStack ();
1240 
1241   while (!mAPsAlreadyInitFinished) {
1242     CpuPause ();
1243   }
1244 
1245   WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
1246   CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1247 
1248   //
1249   // Avoid forcibly reset AP caused the AP got lock not release.
1250   //
1251   if (CpuData->LockSelf == (INTN) GetApicId ()) {
1252     ReleaseSpinLock (&CpuData->CpuDataLock);
1253   }
1254 
1255   //
1256   // Avoid forcibly reset AP caused the timeout AP State is not
1257   // updated.
1258   //
1259   GetMpSpinLock (CpuData);
1260   if (CpuData->State == CpuStateBusy) {
1261     CpuData->Procedure = NULL;
1262   }
1263   CpuData->State = CpuStateIdle;
1264   ReleaseMpSpinLock (CpuData);
1265 
1266   while (TRUE) {
1267     GetMpSpinLock (CpuData);
1268     ProcedureArgument = CpuData->Parameter;
1269     Procedure = CpuData->Procedure;
1270     ReleaseMpSpinLock (CpuData);
1271 
1272     if (Procedure != NULL) {
1273       SetApState (CpuData, CpuStateBusy);
1274 
1275       Procedure ((VOID*) ProcedureArgument);
1276 
1277       GetMpSpinLock (CpuData);
1278       CpuData->Procedure = NULL;
1279       CpuData->State = CpuStateFinished;
1280       ReleaseMpSpinLock (CpuData);
1281     } else {
1282       //
1283       // if no procedure to execution, we simply put AP
1284       // into sleeping state, and waiting BSP sent SIPI.
1285       //
1286       GetMpSpinLock (CpuData);
1287       if (CpuData->State == CpuStateIdle) {
1288           CpuData->State = CpuStateSleeping;
1289       }
1290       ReleaseMpSpinLock (CpuData);
1291     }
1292 
1293     if (GetApState (CpuData) == CpuStateSleeping) {
1294       CpuSleep ();
1295     }
1296 
1297     CpuPause ();
1298   }
1299 
1300   CpuSleep ();
1301   CpuDeadLoop ();
1302 }
1303 
1304 /**
1305   Checks AP' status periodically.
1306 
1307   This function is triggerred by timer perodically to check the
1308   state of AP forStartupThisAP() executed in non-blocking mode.
1309 
1310   @param  Event    Event triggered.
1311   @param  Context  Parameter passed with the event.
1312 
1313 **/
1314 VOID
1315 EFIAPI
CheckThisAPStatus(IN EFI_EVENT Event,IN VOID * Context)1316 CheckThisAPStatus (
1317   IN  EFI_EVENT        Event,
1318   IN  VOID             *Context
1319   )
1320 {
1321   CPU_DATA_BLOCK  *CpuData;
1322   CPU_STATE       CpuState;
1323 
1324   CpuData = (CPU_DATA_BLOCK *) Context;
1325   if (CpuData->TimeoutActive) {
1326     CpuData->Timeout -= gPollInterval;
1327   }
1328 
1329   CpuState = GetApState (CpuData);
1330 
1331   if (CpuState == CpuStateFinished) {
1332     if (CpuData->Finished) {
1333       *CpuData->Finished = TRUE;
1334     }
1335     SetApState (CpuData, CpuStateIdle);
1336     goto out;
1337   }
1338 
1339   if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
1340     if (CpuState != CpuStateIdle &&
1341         CpuData->Finished) {
1342       *CpuData->Finished = FALSE;
1343     }
1344     ResetProcessorToIdleState (CpuData);
1345     goto out;
1346   }
1347 
1348   return;
1349 
1350 out:
1351   CpuData->TimeoutActive = FALSE;
1352   gBS->SignalEvent (CpuData->WaitEvent);
1353   CpuData->WaitEvent = NULL;
1354 }
1355 
1356 /**
1357   Checks APs' status periodically.
1358 
1359   This function is triggerred by timer perodically to check the
1360   state of APs for StartupAllAPs() executed in non-blocking mode.
1361 
1362   @param  Event    Event triggered.
1363   @param  Context  Parameter passed with the event.
1364 
1365 **/
1366 VOID
1367 EFIAPI
CheckAllAPsStatus(IN EFI_EVENT Event,IN VOID * Context)1368 CheckAllAPsStatus (
1369   IN  EFI_EVENT        Event,
1370   IN  VOID             *Context
1371   )
1372 {
1373   CPU_DATA_BLOCK *CpuData;
1374   UINTN          Number;
1375   EFI_STATUS     Status;
1376 
1377   if (mMpSystemData.TimeoutActive) {
1378     mMpSystemData.Timeout -= gPollInterval;
1379   }
1380 
1381   if (mStopCheckAllAPsStatus) {
1382     return;
1383   }
1384 
1385   //
1386   // avoid next timer enter.
1387   //
1388   Status = gBS->SetTimer (
1389                   mMpSystemData.CheckAllAPsEvent,
1390                   TimerCancel,
1391                   0
1392                   );
1393   ASSERT_EFI_ERROR (Status);
1394 
1395   if (mMpSystemData.WaitEvent != NULL) {
1396     CheckAndUpdateAllAPsToIdleState ();
1397     //
1398     // task timeout
1399     //
1400     if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
1401       ResetAllFailedAPs();
1402       //
1403       // force exit
1404       //
1405       mMpSystemData.FinishCount = mMpSystemData.StartCount;
1406     }
1407 
1408     if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {
1409       goto EXIT;
1410     }
1411 
1412     mMpSystemData.TimeoutActive = FALSE;
1413     gBS->SignalEvent (mMpSystemData.WaitEvent);
1414     mMpSystemData.WaitEvent = NULL;
1415     mStopCheckAllAPsStatus = TRUE;
1416 
1417     goto EXIT;
1418   }
1419 
1420   //
1421   // check each AP status for StartupThisAP
1422   //
1423   for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
1424     CpuData = &mMpSystemData.CpuDatas[Number];
1425     if (CpuData->WaitEvent) {
1426       CheckThisAPStatus (NULL, (VOID *)CpuData);
1427     }
1428   }
1429 
1430 EXIT:
1431   Status = gBS->SetTimer (
1432                   mMpSystemData.CheckAllAPsEvent,
1433                   TimerPeriodic,
1434                   EFI_TIMER_PERIOD_MICROSECONDS (100)
1435                   );
1436   ASSERT_EFI_ERROR (Status);
1437 }
1438 
1439 /**
1440   Application Processor C code entry point.
1441 
1442 **/
1443 VOID
1444 EFIAPI
ApEntryPointInC(VOID)1445 ApEntryPointInC (
1446   VOID
1447   )
1448 {
1449   VOID*           TopOfApStack;
1450   UINTN           ProcessorNumber;
1451 
1452   if (!mAPsAlreadyInitFinished) {
1453     FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);
1454     TopOfApStack  = (UINT8*)mApStackStart + gApStackSize;
1455     mApStackStart = TopOfApStack;
1456 
1457     //
1458     // Store the Stack address, when reset the AP, We can found the original address.
1459     //
1460     mMpSystemData.CpuDatas[mMpSystemData.NumberOfProcessors].TopOfStack = TopOfApStack;
1461     mMpSystemData.NumberOfProcessors++;
1462     mMpSystemData.NumberOfEnabledProcessors++;
1463   } else {
1464     WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
1465     //
1466     // Get the original stack address.
1467     //
1468     TopOfApStack = mMpSystemData.CpuDatas[ProcessorNumber].TopOfStack;
1469   }
1470 
1471   SwitchStack (
1472     (SWITCH_STACK_ENTRY_POINT)(UINTN)ProcessorToIdleState,
1473     NULL,
1474     NULL,
1475     TopOfApStack);
1476 }
1477 
1478 /**
1479   This function is called by all processors (both BSP and AP) once and collects MP related data.
1480 
1481   @param Bsp             TRUE if the CPU is BSP
1482   @param ProcessorNumber The specific processor number
1483 
1484   @retval EFI_SUCCESS    Data for the processor collected and filled in
1485 
1486 **/
1487 EFI_STATUS
FillInProcessorInformation(IN BOOLEAN Bsp,IN UINTN ProcessorNumber)1488 FillInProcessorInformation (
1489   IN     BOOLEAN              Bsp,
1490   IN     UINTN                ProcessorNumber
1491   )
1492 {
1493   CPU_DATA_BLOCK  *CpuData;
1494   UINT32          ProcessorId;
1495 
1496   CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1497   ProcessorId  = GetApicId ();
1498   CpuData->Info.ProcessorId  = ProcessorId;
1499   CpuData->Info.StatusFlag   = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
1500   if (Bsp) {
1501     CpuData->Info.StatusFlag |= PROCESSOR_AS_BSP_BIT;
1502   }
1503   CpuData->Info.Location.Package = ProcessorId;
1504   CpuData->Info.Location.Core    = 0;
1505   CpuData->Info.Location.Thread  = 0;
1506   CpuData->State = Bsp ? CpuStateBusy : CpuStateIdle;
1507 
1508   CpuData->Procedure        = NULL;
1509   CpuData->Parameter        = NULL;
1510   InitializeSpinLock (&CpuData->CpuDataLock);
1511   CpuData->LockSelf         = -1;
1512 
1513   return EFI_SUCCESS;
1514 }
1515 
1516 /**
1517   Prepare the System Data.
1518 
1519   @retval EFI_SUCCESS     the System Data finished initilization.
1520 
1521 **/
1522 EFI_STATUS
InitMpSystemData(VOID)1523 InitMpSystemData (
1524   VOID
1525   )
1526 {
1527   EFI_STATUS     Status;
1528 
1529   ZeroMem (&mMpSystemData, sizeof (MP_SYSTEM_DATA));
1530 
1531   mMpSystemData.NumberOfProcessors = 1;
1532   mMpSystemData.NumberOfEnabledProcessors = 1;
1533 
1534   mMpSystemData.CpuDatas = AllocateZeroPool (sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber);
1535   ASSERT(mMpSystemData.CpuDatas != NULL);
1536 
1537   Status = gBS->CreateEvent (
1538                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
1539                   TPL_CALLBACK,
1540                   CheckAllAPsStatus,
1541                   NULL,
1542                   &mMpSystemData.CheckAllAPsEvent
1543                   );
1544   ASSERT_EFI_ERROR (Status);
1545 
1546   //
1547   // Set timer to check all APs status.
1548   //
1549   Status = gBS->SetTimer (
1550                   mMpSystemData.CheckAllAPsEvent,
1551                   TimerPeriodic,
1552                   EFI_TIMER_PERIOD_MICROSECONDS (100)
1553                   );
1554   ASSERT_EFI_ERROR (Status);
1555 
1556   //
1557   // BSP
1558   //
1559   FillInProcessorInformation (TRUE, 0);
1560 
1561   return EFI_SUCCESS;
1562 }
1563 
1564 /**
1565   Collects BIST data from HOB.
1566 
1567   This function collects BIST data from HOB built from Sec Platform Information
1568   PPI or SEC Platform Information2 PPI.
1569 
1570 **/
1571 VOID
CollectBistDataFromHob(VOID)1572 CollectBistDataFromHob (
1573   VOID
1574   )
1575 {
1576   EFI_HOB_GUID_TYPE                     *GuidHob;
1577   EFI_SEC_PLATFORM_INFORMATION_RECORD2  *SecPlatformInformation2;
1578   EFI_SEC_PLATFORM_INFORMATION_RECORD   *SecPlatformInformation;
1579   UINTN                                 NumberOfData;
1580   EFI_SEC_PLATFORM_INFORMATION_CPU      *CpuInstance;
1581   EFI_SEC_PLATFORM_INFORMATION_CPU      BspCpuInstance;
1582   UINTN                                 ProcessorNumber;
1583   UINT32                                InitialLocalApicId;
1584   CPU_DATA_BLOCK                        *CpuData;
1585 
1586   SecPlatformInformation2 = NULL;
1587   SecPlatformInformation  = NULL;
1588 
1589   //
1590   // Get gEfiSecPlatformInformation2PpiGuid Guided HOB firstly
1591   //
1592   GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformation2PpiGuid);
1593   if (GuidHob != NULL) {
1594     //
1595     // Sec Platform Information2 PPI includes BSP/APs' BIST information
1596     //
1597     SecPlatformInformation2 = GET_GUID_HOB_DATA (GuidHob);
1598     NumberOfData = SecPlatformInformation2->NumberOfCpus;
1599     CpuInstance  = SecPlatformInformation2->CpuInstance;
1600   } else {
1601     //
1602     // Otherwise, get gEfiSecPlatformInformationPpiGuid Guided HOB
1603     //
1604     GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformationPpiGuid);
1605     if (GuidHob != NULL) {
1606       SecPlatformInformation = GET_GUID_HOB_DATA (GuidHob);
1607       NumberOfData = 1;
1608       //
1609       // SEC Platform Information only includes BSP's BIST information
1610       // does not have BSP's APIC ID
1611       //
1612       BspCpuInstance.CpuLocation = GetApicId ();
1613       BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32  = SecPlatformInformation->IA32HealthFlags.Uint32;
1614       CpuInstance = &BspCpuInstance;
1615     } else {
1616       DEBUG ((EFI_D_INFO, "Does not find any HOB stored CPU BIST information!\n"));
1617       //
1618       // Does not find any HOB stored BIST information
1619       //
1620       return;
1621     }
1622   }
1623 
1624   while ((NumberOfData--) > 0) {
1625     for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
1626       CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1627       InitialLocalApicId = (UINT32) CpuData->Info.ProcessorId;
1628       if (InitialLocalApicId == CpuInstance[NumberOfData].CpuLocation) {
1629         //
1630         // Update CPU health status for MP Services Protocol according to BIST data.
1631         //
1632         if (CpuInstance[NumberOfData].InfoRecord.IA32HealthFlags.Uint32 != 0) {
1633           CpuData->Info.StatusFlag &= ~PROCESSOR_HEALTH_STATUS_BIT;
1634           //
1635           // Report Status Code that self test is failed
1636           //
1637           REPORT_STATUS_CODE (
1638             EFI_ERROR_CODE | EFI_ERROR_MAJOR,
1639             (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
1640             );
1641         }
1642       }
1643     }
1644   }
1645 }
1646 
1647 /**
1648   Callback function for ExitBootServices.
1649 
1650   @param  Event                 Event whose notification function is being invoked.
1651   @param  Context               The pointer to the notification function's context,
1652                                 which is implementation-dependent.
1653 
1654 **/
1655 VOID
1656 EFIAPI
ExitBootServicesCallback(IN EFI_EVENT Event,IN VOID * Context)1657 ExitBootServicesCallback (
1658   IN EFI_EVENT                Event,
1659   IN VOID                     *Context
1660   )
1661 {
1662   //
1663   // Avoid APs access invalid buff datas which allocated by BootServices,
1664   // so we send INIT IPI to APs to let them wait for SIPI state.
1665   //
1666   SendInitIpiAllExcludingSelf ();
1667 }
1668 
1669 /**
1670   A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to
1671   EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.
1672 
1673   @param[in] Buffer  Pointer to an MTRR_SETTINGS object, to be passed to
1674                      MtrrSetAllMtrrs().
1675 **/
1676 VOID
1677 EFIAPI
SetMtrrsFromBuffer(IN VOID * Buffer)1678 SetMtrrsFromBuffer (
1679   IN VOID *Buffer
1680   )
1681 {
1682   MtrrSetAllMtrrs (Buffer);
1683 }
1684 
1685 /**
1686   Initialize Multi-processor support.
1687 
1688 **/
1689 VOID
InitializeMpSupport(VOID)1690 InitializeMpSupport (
1691   VOID
1692   )
1693 {
1694   EFI_STATUS     Status;
1695   MTRR_SETTINGS  MtrrSettings;
1696   UINTN          Timeout;
1697 
1698   gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
1699   if (gMaxLogicalProcessorNumber < 1) {
1700     DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));
1701     return;
1702   }
1703 
1704 
1705 
1706   InitMpSystemData ();
1707 
1708   //
1709   // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
1710   //
1711   if (gMaxLogicalProcessorNumber > 1) {
1712 
1713     gApStackSize = (UINTN) PcdGet32 (PcdCpuApStackSize);
1714     ASSERT ((gApStackSize & (SIZE_4KB - 1)) == 0);
1715 
1716     mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
1717     ASSERT (mApStackStart != NULL);
1718 
1719     //
1720     // the first buffer of stack size used for common stack, when the amount of AP
1721     // more than 1, we should never free the common stack which maybe used for AP reset.
1722     //
1723     mCommonStack = mApStackStart;
1724     mTopOfApCommonStack = (UINT8*) mApStackStart + gApStackSize;
1725     mApStackStart = mTopOfApCommonStack;
1726 
1727     PrepareAPStartupCode ();
1728 
1729     StartApsStackless ();
1730   }
1731 
1732   DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mMpSystemData.NumberOfProcessors));
1733   if (mMpSystemData.NumberOfProcessors == 1) {
1734     FreeApStartupCode ();
1735     if (mCommonStack != NULL) {
1736       FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
1737     }
1738   }
1739 
1740   mMpSystemData.CpuDatas = ReallocatePool (
1741                              sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber,
1742                              sizeof (CPU_DATA_BLOCK) * mMpSystemData.NumberOfProcessors,
1743                              mMpSystemData.CpuDatas);
1744 
1745   //
1746   // Release all APs to complete initialization and enter idle loop
1747   //
1748   mAPsAlreadyInitFinished = TRUE;
1749 
1750   //
1751   // Wait for all APs to enter idle loop.
1752   //
1753   Timeout = 0;
1754   do {
1755     if (CheckAllAPsSleeping ()) {
1756       break;
1757     }
1758     MicroSecondDelay (gPollInterval);
1759     Timeout += gPollInterval;
1760   } while (Timeout <= PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
1761   ASSERT (Timeout <= PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
1762 
1763   //
1764   // Update CPU healthy information from Guided HOB
1765   //
1766   CollectBistDataFromHob ();
1767 
1768   //
1769   // Synchronize MTRR settings to APs.
1770   //
1771   MtrrGetAllMtrrs (&MtrrSettings);
1772   Status = mMpServicesTemplate.StartupAllAPs (
1773                                  &mMpServicesTemplate, // This
1774                                  SetMtrrsFromBuffer,   // Procedure
1775                                  TRUE,                 // SingleThread
1776                                  NULL,                 // WaitEvent
1777                                  0,                    // TimeoutInMicrosecsond
1778                                  &MtrrSettings,        // ProcedureArgument
1779                                  NULL                  // FailedCpuList
1780                                  );
1781   ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_STARTED);
1782 
1783   Status = gBS->InstallMultipleProtocolInterfaces (
1784                   &mMpServiceHandle,
1785                   &gEfiMpServiceProtocolGuid,  &mMpServicesTemplate,
1786                   NULL
1787                   );
1788   ASSERT_EFI_ERROR (Status);
1789 
1790   if (mMpSystemData.NumberOfProcessors > 1 && mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) {
1791     if (mApStackStart != NULL) {
1792       FreePages (mApStackStart, EFI_SIZE_TO_PAGES (
1793                                   (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) *
1794                                   gApStackSize));
1795     }
1796   }
1797 
1798   Status = gBS->CreateEvent (
1799                   EVT_SIGNAL_EXIT_BOOT_SERVICES,
1800                   TPL_CALLBACK,
1801                   ExitBootServicesCallback,
1802                   NULL,
1803                   &mExitBootServicesEvent
1804                   );
1805   ASSERT_EFI_ERROR (Status);
1806 }
1807