Home | History | Annotate | Download | only in MpInitLib
      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
     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 *
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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