• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   MP initialize support functions for DXE phase.
3 
4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
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 "MpLib.h"
16 
17 #include <Library/UefiLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Library/DebugAgentLib.h>
20 
21 #include <Protocol/Timer.h>
22 
23 #define  AP_CHECK_INTERVAL     (EFI_TIMER_PERIOD_MILLISECONDS (100))
24 #define  AP_SAFE_STACK_SIZE    128
25 
26 CPU_MP_DATA      *mCpuMpData = NULL;
27 EFI_EVENT        mCheckAllApsEvent = NULL;
28 EFI_EVENT        mMpInitExitBootServicesEvent = NULL;
29 EFI_EVENT        mLegacyBootEvent = NULL;
30 volatile BOOLEAN mStopCheckAllApsStatus = TRUE;
31 VOID             *mReservedApLoopFunc = NULL;
32 UINTN            mReservedTopOfApStack;
33 volatile UINT32  mNumberToFinish = 0;
34 
35 /**
36   Enable Debug Agent to support source debugging on AP function.
37 
38 **/
39 VOID
EnableDebugAgent(VOID)40 EnableDebugAgent (
41   VOID
42   )
43 {
44   //
45   // Initialize Debug Agent to support source level debug in DXE phase
46   //
47   InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);
48 }
49 
50 /**
51   Get the pointer to CPU MP Data structure.
52 
53   @return  The pointer to CPU MP Data structure.
54 **/
55 CPU_MP_DATA *
GetCpuMpData(VOID)56 GetCpuMpData (
57   VOID
58   )
59 {
60   ASSERT (mCpuMpData != NULL);
61   return mCpuMpData;
62 }
63 
64 /**
65   Save the pointer to CPU MP Data structure.
66 
67   @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.
68 **/
69 VOID
SaveCpuMpData(IN CPU_MP_DATA * CpuMpData)70 SaveCpuMpData (
71   IN CPU_MP_DATA   *CpuMpData
72   )
73 {
74   mCpuMpData = CpuMpData;
75 }
76 
77 /**
78   Allocate reset vector buffer.
79 
80   @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.
81 **/
82 VOID
AllocateResetVector(IN OUT CPU_MP_DATA * CpuMpData)83 AllocateResetVector (
84   IN OUT CPU_MP_DATA          *CpuMpData
85   )
86 {
87   EFI_STATUS            Status;
88   UINTN                 ApResetVectorSize;
89   EFI_PHYSICAL_ADDRESS  StartAddress;
90 
91   if (CpuMpData->SaveRestoreFlag) {
92     BackupAndPrepareWakeupBuffer (CpuMpData);
93   } else {
94     ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +
95                         sizeof (MP_CPU_EXCHANGE_INFO);
96 
97     StartAddress = BASE_1MB;
98     Status = gBS->AllocatePages (
99                     AllocateMaxAddress,
100                     EfiACPIMemoryNVS,
101                     EFI_SIZE_TO_PAGES (ApResetVectorSize),
102                     &StartAddress
103                     );
104     ASSERT_EFI_ERROR (Status);
105 
106     CpuMpData->WakeupBuffer      = (UINTN) StartAddress;
107     CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)
108                   (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);
109     //
110     // copy AP reset code in it
111     //
112     CopyMem (
113       (VOID *) CpuMpData->WakeupBuffer,
114       (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
115       CpuMpData->AddressMap.RendezvousFunnelSize
116       );
117   }
118 }
119 
120 /**
121   Free AP reset vector buffer.
122 
123   @param[in]  CpuMpData  The pointer to CPU MP Data structure.
124 **/
125 VOID
FreeResetVector(IN CPU_MP_DATA * CpuMpData)126 FreeResetVector (
127   IN CPU_MP_DATA              *CpuMpData
128   )
129 {
130   EFI_STATUS            Status;
131   UINTN                 ApResetVectorSize;
132 
133   if (CpuMpData->SaveRestoreFlag) {
134     RestoreWakeupBuffer (CpuMpData);
135   } else {
136     ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +
137                         sizeof (MP_CPU_EXCHANGE_INFO);
138     Status = gBS->FreePages(
139                (EFI_PHYSICAL_ADDRESS)CpuMpData->WakeupBuffer,
140                EFI_SIZE_TO_PAGES (ApResetVectorSize)
141                );
142     ASSERT_EFI_ERROR (Status);
143   }
144 }
145 
146 /**
147   Checks APs status and updates APs status if needed.
148 
149 **/
150 VOID
CheckAndUpdateApsStatus(VOID)151 CheckAndUpdateApsStatus (
152   VOID
153   )
154 {
155   UINTN                   ProcessorNumber;
156   EFI_STATUS              Status;
157   CPU_MP_DATA             *CpuMpData;
158 
159   CpuMpData = GetCpuMpData ();
160 
161   //
162   // First, check whether pending StartupAllAPs() exists.
163   //
164   if (CpuMpData->WaitEvent != NULL) {
165 
166     Status = CheckAllAPs ();
167     //
168     // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
169     //
170     if (Status != EFI_NOT_READY) {
171       Status = gBS->SignalEvent (CpuMpData->WaitEvent);
172       CpuMpData->WaitEvent = NULL;
173     }
174   }
175 
176   //
177   // Second, check whether pending StartupThisAPs() callings exist.
178   //
179   for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
180 
181     if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {
182       continue;
183     }
184 
185     Status = CheckThisAP (ProcessorNumber);
186 
187     if (Status != EFI_NOT_READY) {
188       gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);
189      CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;
190     }
191   }
192 }
193 
194 /**
195   Checks APs' status periodically.
196 
197   This function is triggered by timer periodically to check the
198   state of APs for StartupAllAPs() and StartupThisAP() executed
199   in non-blocking mode.
200 
201   @param[in]  Event    Event triggered.
202   @param[in]  Context  Parameter passed with the event.
203 
204 **/
205 VOID
206 EFIAPI
CheckApsStatus(IN EFI_EVENT Event,IN VOID * Context)207 CheckApsStatus (
208   IN  EFI_EVENT                           Event,
209   IN  VOID                                *Context
210   )
211 {
212   //
213   // If CheckApsStatus() is not stopped, otherwise return immediately.
214   //
215   if (!mStopCheckAllApsStatus) {
216     CheckAndUpdateApsStatus ();
217   }
218 }
219 
220 /**
221   Get Protected mode code segment from current GDT table.
222 
223   @return  Protected mode code segment value.
224 **/
225 UINT16
GetProtectedModeCS(VOID)226 GetProtectedModeCS (
227   VOID
228   )
229 {
230   IA32_DESCRIPTOR          GdtrDesc;
231   IA32_SEGMENT_DESCRIPTOR  *GdtEntry;
232   UINTN                    GdtEntryCount;
233   UINT16                   Index;
234 
235   Index = (UINT16) -1;
236   AsmReadGdtr (&GdtrDesc);
237   GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
238   GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
239   for (Index = 0; Index < GdtEntryCount; Index++) {
240     if (GdtEntry->Bits.L == 0) {
241       if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {
242         break;
243       }
244     }
245     GdtEntry++;
246   }
247   ASSERT (Index != -1);
248   return Index * 8;
249 }
250 
251 /**
252   Do sync on APs.
253 
254   @param[in, out] Buffer  Pointer to private data buffer.
255 **/
256 VOID
257 EFIAPI
RelocateApLoop(IN OUT VOID * Buffer)258 RelocateApLoop (
259   IN OUT VOID  *Buffer
260   )
261 {
262   CPU_MP_DATA            *CpuMpData;
263   BOOLEAN                MwaitSupport;
264   ASM_RELOCATE_AP_LOOP   AsmRelocateApLoopFunc;
265   UINTN                  ProcessorNumber;
266 
267   MpInitLibWhoAmI (&ProcessorNumber);
268   CpuMpData    = GetCpuMpData ();
269   MwaitSupport = IsMwaitSupport ();
270   AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;
271   AsmRelocateApLoopFunc (
272     MwaitSupport,
273     CpuMpData->ApTargetCState,
274     CpuMpData->PmCodeSegment,
275     mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,
276     (UINTN) &mNumberToFinish
277     );
278   //
279   // It should never reach here
280   //
281   ASSERT (FALSE);
282 }
283 
284 /**
285   Callback function for ExitBootServices.
286 
287   @param[in]  Event             Event whose notification function is being invoked.
288   @param[in]  Context           The pointer to the notification function's context,
289                                 which is implementation-dependent.
290 
291 **/
292 VOID
293 EFIAPI
MpInitChangeApLoopCallback(IN EFI_EVENT Event,IN VOID * Context)294 MpInitChangeApLoopCallback (
295   IN EFI_EVENT                Event,
296   IN VOID                     *Context
297   )
298 {
299   CPU_MP_DATA               *CpuMpData;
300 
301   CpuMpData = GetCpuMpData ();
302   CpuMpData->SaveRestoreFlag = TRUE;
303   CpuMpData->PmCodeSegment = GetProtectedModeCS ();
304   CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
305   mNumberToFinish = CpuMpData->CpuCount - 1;
306   WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL);
307   while (mNumberToFinish > 0) {
308     CpuPause ();
309   }
310   DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));
311 }
312 
313 /**
314   Initialize global data for MP support.
315 
316   @param[in] CpuMpData  The pointer to CPU MP Data structure.
317 **/
318 VOID
InitMpGlobalData(IN CPU_MP_DATA * CpuMpData)319 InitMpGlobalData (
320   IN CPU_MP_DATA               *CpuMpData
321   )
322 {
323   EFI_STATUS                 Status;
324   EFI_PHYSICAL_ADDRESS       Address;
325   UINTN                      ApSafeBufferSize;
326 
327   SaveCpuMpData (CpuMpData);
328 
329   if (CpuMpData->CpuCount == 1) {
330     //
331     // If only BSP exists, return
332     //
333     return;
334   }
335 
336   //
337   // Avoid APs access invalid buffer data which allocated by BootServices,
338   // so we will allocate reserved data for AP loop code. We also need to
339   // allocate this buffer below 4GB due to APs may be transferred to 32bit
340   // protected mode on long mode DXE.
341   // Allocating it in advance since memory services are not available in
342   // Exit Boot Services callback function.
343   //
344   ApSafeBufferSize  = CpuMpData->AddressMap.RelocateApLoopFuncSize;
345   ApSafeBufferSize += CpuMpData->CpuCount * AP_SAFE_STACK_SIZE;
346 
347   Address = BASE_4GB - 1;
348   Status  = gBS->AllocatePages (
349                    AllocateMaxAddress,
350                    EfiReservedMemoryType,
351                    EFI_SIZE_TO_PAGES (ApSafeBufferSize),
352                    &Address
353                    );
354   ASSERT_EFI_ERROR (Status);
355   mReservedApLoopFunc = (VOID *) (UINTN) Address;
356   ASSERT (mReservedApLoopFunc != NULL);
357   mReservedTopOfApStack = (UINTN) Address + EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ApSafeBufferSize));
358   ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);
359   CopyMem (
360     mReservedApLoopFunc,
361     CpuMpData->AddressMap.RelocateApLoopFuncAddress,
362     CpuMpData->AddressMap.RelocateApLoopFuncSize
363     );
364 
365   Status = gBS->CreateEvent (
366                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
367                   TPL_NOTIFY,
368                   CheckApsStatus,
369                   NULL,
370                   &mCheckAllApsEvent
371                   );
372   ASSERT_EFI_ERROR (Status);
373 
374   //
375   // Set timer to check all APs status.
376   //
377   Status = gBS->SetTimer (
378                   mCheckAllApsEvent,
379                   TimerPeriodic,
380                   AP_CHECK_INTERVAL
381                   );
382   ASSERT_EFI_ERROR (Status);
383 
384   Status = gBS->CreateEvent (
385                   EVT_SIGNAL_EXIT_BOOT_SERVICES,
386                   TPL_CALLBACK,
387                   MpInitChangeApLoopCallback,
388                   NULL,
389                   &mMpInitExitBootServicesEvent
390                   );
391   ASSERT_EFI_ERROR (Status);
392 
393   Status = gBS->CreateEventEx (
394                   EVT_NOTIFY_SIGNAL,
395                   TPL_CALLBACK,
396                   MpInitChangeApLoopCallback,
397                   NULL,
398                   &gEfiEventLegacyBootGuid,
399                   &mLegacyBootEvent
400                   );
401   ASSERT_EFI_ERROR (Status);
402 }
403 
404 /**
405   This service executes a caller provided function on all enabled APs.
406 
407   @param[in]  Procedure               A pointer to the function to be run on
408                                       enabled APs of the system. See type
409                                       EFI_AP_PROCEDURE.
410   @param[in]  SingleThread            If TRUE, then all the enabled APs execute
411                                       the function specified by Procedure one by
412                                       one, in ascending order of processor handle
413                                       number.  If FALSE, then all the enabled APs
414                                       execute the function specified by Procedure
415                                       simultaneously.
416   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
417                                       service.  If it is NULL, then execute in
418                                       blocking mode. BSP waits until all APs finish
419                                       or TimeoutInMicroSeconds expires.  If it's
420                                       not NULL, then execute in non-blocking mode.
421                                       BSP requests the function specified by
422                                       Procedure to be started on all the enabled
423                                       APs, and go on executing immediately. If
424                                       all return from Procedure, or TimeoutInMicroSeconds
425                                       expires, this event is signaled. The BSP
426                                       can use the CheckEvent() or WaitForEvent()
427                                       services to check the state of event.  Type
428                                       EFI_EVENT is defined in CreateEvent() in
429                                       the Unified Extensible Firmware Interface
430                                       Specification.
431   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
432                                       APs to return from Procedure, either for
433                                       blocking or non-blocking mode. Zero means
434                                       infinity.  If the timeout expires before
435                                       all APs return from Procedure, then Procedure
436                                       on the failed APs is terminated. All enabled
437                                       APs are available for next function assigned
438                                       by MpInitLibStartupAllAPs() or
439                                       MPInitLibStartupThisAP().
440                                       If the timeout expires in blocking mode,
441                                       BSP returns EFI_TIMEOUT.  If the timeout
442                                       expires in non-blocking mode, WaitEvent
443                                       is signaled with SignalEvent().
444   @param[in]  ProcedureArgument       The parameter passed into Procedure for
445                                       all APs.
446   @param[out] FailedCpuList           If NULL, this parameter is ignored. Otherwise,
447                                       if all APs finish successfully, then its
448                                       content is set to NULL. If not all APs
449                                       finish before timeout expires, then its
450                                       content is set to address of the buffer
451                                       holding handle numbers of the failed APs.
452                                       The buffer is allocated by MP Initialization
453                                       library, and it's the caller's responsibility to
454                                       free the buffer with FreePool() service.
455                                       In blocking mode, it is ready for consumption
456                                       when the call returns. In non-blocking mode,
457                                       it is ready when WaitEvent is signaled.  The
458                                       list of failed CPU is terminated by
459                                       END_OF_CPU_LIST.
460 
461   @retval EFI_SUCCESS             In blocking mode, all APs have finished before
462                                   the timeout expired.
463   @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
464                                   to all enabled APs.
465   @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
466                                   UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
467                                   signaled.
468   @retval EFI_UNSUPPORTED         WaitEvent is not NULL if non-blocking mode is not
469                                   supported.
470   @retval EFI_DEVICE_ERROR        Caller processor is AP.
471   @retval EFI_NOT_STARTED         No enabled APs exist in the system.
472   @retval EFI_NOT_READY           Any enabled APs are busy.
473   @retval EFI_NOT_READY           MP Initialize Library is not initialized.
474   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
475                                   all enabled APs have finished.
476   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
477 
478 **/
479 EFI_STATUS
480 EFIAPI
MpInitLibStartupAllAPs(IN EFI_AP_PROCEDURE Procedure,IN BOOLEAN SingleThread,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT UINTN ** FailedCpuList OPTIONAL)481 MpInitLibStartupAllAPs (
482   IN  EFI_AP_PROCEDURE          Procedure,
483   IN  BOOLEAN                   SingleThread,
484   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
485   IN  UINTN                     TimeoutInMicroseconds,
486   IN  VOID                      *ProcedureArgument      OPTIONAL,
487   OUT UINTN                     **FailedCpuList         OPTIONAL
488   )
489 {
490   EFI_STATUS              Status;
491 
492   //
493   // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
494   //
495   mStopCheckAllApsStatus = TRUE;
496 
497   Status = StartupAllAPsWorker (
498              Procedure,
499              SingleThread,
500              WaitEvent,
501              TimeoutInMicroseconds,
502              ProcedureArgument,
503              FailedCpuList
504              );
505 
506   //
507   // Start checkAllApsStatus
508   //
509   mStopCheckAllApsStatus = FALSE;
510 
511   return Status;
512 }
513 
514 /**
515   This service lets the caller get one enabled AP to execute a caller-provided
516   function.
517 
518   @param[in]  Procedure               A pointer to the function to be run on the
519                                       designated AP of the system. See type
520                                       EFI_AP_PROCEDURE.
521   @param[in]  ProcessorNumber         The handle number of the AP. The range is
522                                       from 0 to the total number of logical
523                                       processors minus 1. The total number of
524                                       logical processors can be retrieved by
525                                       MpInitLibGetNumberOfProcessors().
526   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
527                                       service.  If it is NULL, then execute in
528                                       blocking mode. BSP waits until this AP finish
529                                       or TimeoutInMicroSeconds expires.  If it's
530                                       not NULL, then execute in non-blocking mode.
531                                       BSP requests the function specified by
532                                       Procedure to be started on this AP,
533                                       and go on executing immediately. If this AP
534                                       return from Procedure or TimeoutInMicroSeconds
535                                       expires, this event is signaled. The BSP
536                                       can use the CheckEvent() or WaitForEvent()
537                                       services to check the state of event.  Type
538                                       EFI_EVENT is defined in CreateEvent() in
539                                       the Unified Extensible Firmware Interface
540                                       Specification.
541   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
542                                       this AP to finish this Procedure, either for
543                                       blocking or non-blocking mode. Zero means
544                                       infinity.  If the timeout expires before
545                                       this AP returns from Procedure, then Procedure
546                                       on the AP is terminated. The
547                                       AP is available for next function assigned
548                                       by MpInitLibStartupAllAPs() or
549                                       MpInitLibStartupThisAP().
550                                       If the timeout expires in blocking mode,
551                                       BSP returns EFI_TIMEOUT.  If the timeout
552                                       expires in non-blocking mode, WaitEvent
553                                       is signaled with SignalEvent().
554   @param[in]  ProcedureArgument       The parameter passed into Procedure on the
555                                       specified AP.
556   @param[out] Finished                If NULL, this parameter is ignored.  In
557                                       blocking mode, this parameter is ignored.
558                                       In non-blocking mode, if AP returns from
559                                       Procedure before the timeout expires, its
560                                       content is set to TRUE. Otherwise, the
561                                       value is set to FALSE. The caller can
562                                       determine if the AP returned from Procedure
563                                       by evaluating this value.
564 
565   @retval EFI_SUCCESS             In blocking mode, specified AP finished before
566                                   the timeout expires.
567   @retval EFI_SUCCESS             In non-blocking mode, the function has been
568                                   dispatched to specified AP.
569   @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
570                                   UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
571                                   signaled.
572   @retval EFI_UNSUPPORTED         WaitEvent is not NULL if non-blocking mode is not
573                                   supported.
574   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
575   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
576                                   the specified AP has finished.
577   @retval EFI_NOT_READY           The specified AP is busy.
578   @retval EFI_NOT_READY           MP Initialize Library is not initialized.
579   @retval EFI_NOT_FOUND           The processor with the handle specified by
580                                   ProcessorNumber does not exist.
581   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
582   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
583 
584 **/
585 EFI_STATUS
586 EFIAPI
MpInitLibStartupThisAP(IN EFI_AP_PROCEDURE Procedure,IN UINTN ProcessorNumber,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT BOOLEAN * Finished OPTIONAL)587 MpInitLibStartupThisAP (
588   IN  EFI_AP_PROCEDURE          Procedure,
589   IN  UINTN                     ProcessorNumber,
590   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
591   IN  UINTN                     TimeoutInMicroseconds,
592   IN  VOID                      *ProcedureArgument      OPTIONAL,
593   OUT BOOLEAN                   *Finished               OPTIONAL
594   )
595 {
596   EFI_STATUS              Status;
597 
598   //
599   // temporarily stop checkAllApsStatus for avoid resource dead-lock.
600   //
601   mStopCheckAllApsStatus = TRUE;
602 
603   Status = StartupThisAPWorker (
604              Procedure,
605              ProcessorNumber,
606              WaitEvent,
607              TimeoutInMicroseconds,
608              ProcedureArgument,
609              Finished
610              );
611 
612   mStopCheckAllApsStatus = FALSE;
613 
614   return Status;
615 }
616 
617 /**
618   This service switches the requested AP to be the BSP from that point onward.
619   This service changes the BSP for all purposes. This call can only be performed
620   by the current BSP.
621 
622   @param[in] ProcessorNumber   The handle number of AP that is to become the new
623                                BSP. The range is from 0 to the total number of
624                                logical processors minus 1. The total number of
625                                logical processors can be retrieved by
626                                MpInitLibGetNumberOfProcessors().
627   @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
628                                enabled AP. Otherwise, it will be disabled.
629 
630   @retval EFI_SUCCESS             BSP successfully switched.
631   @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to
632                                   this service returning.
633   @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
634   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
635   @retval EFI_NOT_FOUND           The processor with the handle specified by
636                                   ProcessorNumber does not exist.
637   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or
638                                   a disabled AP.
639   @retval EFI_NOT_READY           The specified AP is busy.
640   @retval EFI_NOT_READY           MP Initialize Library is not initialized.
641 
642 **/
643 EFI_STATUS
644 EFIAPI
MpInitLibSwitchBSP(IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)645 MpInitLibSwitchBSP (
646   IN UINTN                     ProcessorNumber,
647   IN BOOLEAN                   EnableOldBSP
648   )
649 {
650   EFI_STATUS                   Status;
651   EFI_TIMER_ARCH_PROTOCOL      *Timer;
652   UINT64                       TimerPeriod;
653 
654   TimerPeriod = 0;
655   //
656   // Locate Timer Arch Protocol
657   //
658   Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer);
659   if (EFI_ERROR (Status)) {
660     Timer = NULL;
661   }
662 
663   if (Timer != NULL) {
664     //
665     // Save current rate of DXE Timer
666     //
667     Timer->GetTimerPeriod (Timer, &TimerPeriod);
668     //
669     // Disable DXE Timer and drain pending interrupts
670     //
671     Timer->SetTimerPeriod (Timer, 0);
672   }
673 
674   Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
675 
676   if (Timer != NULL) {
677     //
678     // Enable and restore rate of DXE Timer
679     //
680     Timer->SetTimerPeriod (Timer, TimerPeriod);
681   }
682 
683   return Status;
684 }
685 
686 /**
687   This service lets the caller enable or disable an AP from this point onward.
688   This service may only be called from the BSP.
689 
690   @param[in] ProcessorNumber   The handle number of AP.
691                                The range is from 0 to the total number of
692                                logical processors minus 1. The total number of
693                                logical processors can be retrieved by
694                                MpInitLibGetNumberOfProcessors().
695   @param[in] EnableAP          Specifies the new state for the processor for
696                                enabled, FALSE for disabled.
697   @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
698                                the new health status of the AP. This flag
699                                corresponds to StatusFlag defined in
700                                EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
701                                the PROCESSOR_HEALTH_STATUS_BIT is used. All other
702                                bits are ignored.  If it is NULL, this parameter
703                                is ignored.
704 
705   @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
706   @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed
707                                   prior to this service returning.
708   @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
709   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
710   @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
711                                   does not exist.
712   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
713   @retval EFI_NOT_READY           MP Initialize Library is not initialized.
714 
715 **/
716 EFI_STATUS
717 EFIAPI
MpInitLibEnableDisableAP(IN UINTN ProcessorNumber,IN BOOLEAN EnableAP,IN UINT32 * HealthFlag OPTIONAL)718 MpInitLibEnableDisableAP (
719   IN  UINTN                     ProcessorNumber,
720   IN  BOOLEAN                   EnableAP,
721   IN  UINT32                    *HealthFlag OPTIONAL
722   )
723 {
724   EFI_STATUS     Status;
725   BOOLEAN        TempStopCheckState;
726 
727   TempStopCheckState = FALSE;
728   //
729   // temporarily stop checkAllAPsStatus for initialize parameters.
730   //
731   if (!mStopCheckAllApsStatus) {
732     mStopCheckAllApsStatus = TRUE;
733     TempStopCheckState     = TRUE;
734   }
735 
736   Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
737 
738   if (TempStopCheckState) {
739     mStopCheckAllApsStatus = FALSE;
740   }
741 
742   return Status;
743 }
744