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