Home | History | Annotate | Download | only in PiSmmCpuDxeSmm
      1 /** @file
      2 Implementation of SMM CPU Services Protocol.
      3 
      4 Copyright (c) 2011 - 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 "PiSmmCpuDxeSmm.h"
     16 
     17 //
     18 // SMM CPU Service Protocol instance
     19 //
     20 EFI_SMM_CPU_SERVICE_PROTOCOL  mSmmCpuService = {
     21   SmmGetProcessorInfo,
     22   SmmSwitchBsp,
     23   SmmAddProcessor,
     24   SmmRemoveProcessor,
     25   SmmWhoAmI,
     26   SmmRegisterExceptionHandler
     27 };
     28 
     29 /**
     30   Gets processor information on the requested processor at the instant this call is made.
     31 
     32   @param[in]  This                 A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
     33   @param[in]  ProcessorNumber      The handle number of processor.
     34   @param[out] ProcessorInfoBuffer  A pointer to the buffer where information for
     35                                    the requested processor is deposited.
     36 
     37   @retval EFI_SUCCESS             Processor information was returned.
     38   @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
     39   @retval EFI_INVALID_PARAMETER   ProcessorNumber is invalid.
     40   @retval EFI_NOT_FOUND           The processor with the handle specified by
     41                                   ProcessorNumber does not exist in the platform.
     42 
     43 **/
     44 EFI_STATUS
     45 EFIAPI
     46 SmmGetProcessorInfo (
     47   IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
     48   IN       UINTN                        ProcessorNumber,
     49   OUT      EFI_PROCESSOR_INFORMATION    *ProcessorInfoBuffer
     50   )
     51 {
     52   //
     53   // Check parameter
     54   //
     55   if (ProcessorNumber >= mMaxNumberOfCpus || ProcessorInfoBuffer == NULL) {
     56     return EFI_INVALID_PARAMETER;
     57   }
     58 
     59   if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
     60     return EFI_NOT_FOUND;
     61   }
     62 
     63   //
     64   // Fill in processor information
     65   //
     66   CopyMem (ProcessorInfoBuffer, &gSmmCpuPrivate->ProcessorInfo[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));
     67   return EFI_SUCCESS;
     68 }
     69 
     70 /**
     71   This service switches the requested AP to be the BSP since the next SMI.
     72 
     73   @param[in] This             A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
     74   @param[in] ProcessorNumber  The handle number of AP that is to become the new BSP.
     75 
     76   @retval EFI_SUCCESS             BSP will be switched in next SMI.
     77   @retval EFI_UNSUPPORTED         Switching the BSP or a processor to be hot-removed is not supported.
     78   @retval EFI_NOT_FOUND           The processor with the handle specified by ProcessorNumber does not exist.
     79   @retval EFI_INVALID_PARAMETER   ProcessorNumber is invalid.
     80 **/
     81 EFI_STATUS
     82 EFIAPI
     83 SmmSwitchBsp (
     84   IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
     85   IN       UINTN                        ProcessorNumber
     86   )
     87 {
     88   //
     89   // Check parameter
     90   //
     91   if (ProcessorNumber >= mMaxNumberOfCpus) {
     92     return EFI_INVALID_PARAMETER;
     93   }
     94 
     95   if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
     96     return EFI_NOT_FOUND;
     97   }
     98 
     99   if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone ||
    100       gSmst->CurrentlyExecutingCpu == ProcessorNumber) {
    101     return EFI_UNSUPPORTED;
    102   }
    103 
    104   //
    105   // Setting of the BSP for next SMI is pending until all SMI handlers are finished
    106   //
    107   gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuSwitchBsp;
    108   return EFI_SUCCESS;
    109 }
    110 
    111 /**
    112   Notify that a processor was hot-added.
    113 
    114   @param[in] This                A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
    115   @param[in] ProcessorId         Local APIC ID of the hot-added processor.
    116   @param[out] ProcessorNumber    The handle number of the hot-added processor.
    117 
    118   @retval EFI_SUCCESS            The hot-addition of the specified processors was successfully notified.
    119   @retval EFI_UNSUPPORTED        Hot addition of processor is not supported.
    120   @retval EFI_NOT_FOUND          The processor with the handle specified by ProcessorNumber does not exist.
    121   @retval EFI_INVALID_PARAMETER  ProcessorNumber is invalid.
    122   @retval EFI_ALREADY_STARTED    The processor is already online in the system.
    123 **/
    124 EFI_STATUS
    125 EFIAPI
    126 SmmAddProcessor (
    127   IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL  *This,
    128   IN       UINT64                        ProcessorId,
    129   OUT      UINTN                         *ProcessorNumber
    130   )
    131 {
    132   UINTN  Index;
    133 
    134   if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {
    135     return EFI_UNSUPPORTED;
    136   }
    137 
    138   //
    139   // Check parameter
    140   //
    141   if (ProcessorNumber == NULL || ProcessorId == INVALID_APIC_ID) {
    142     return EFI_INVALID_PARAMETER;
    143   }
    144 
    145   //
    146   // Check if the processor already exists
    147   //
    148 
    149   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
    150     if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ProcessorId) {
    151       return EFI_ALREADY_STARTED;
    152     }
    153   }
    154 
    155   //
    156   // Check CPU hot plug data. The CPU RAS handler should have created the mapping
    157   // of the APIC ID to SMBASE.
    158   //
    159   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
    160     if (mCpuHotPlugData.ApicId[Index] == ProcessorId &&
    161         gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == INVALID_APIC_ID) {
    162       gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = ProcessorId;
    163       gSmmCpuPrivate->ProcessorInfo[Index].StatusFlag = 0;
    164       GetProcessorLocationByApicId (
    165         (UINT32)ProcessorId,
    166         &gSmmCpuPrivate->ProcessorInfo[Index].Location.Package,
    167         &gSmmCpuPrivate->ProcessorInfo[Index].Location.Core,
    168         &gSmmCpuPrivate->ProcessorInfo[Index].Location.Thread
    169         );
    170 
    171       *ProcessorNumber = Index;
    172       gSmmCpuPrivate->Operation[Index] = SmmCpuAdd;
    173       return EFI_SUCCESS;
    174     }
    175   }
    176 
    177   return EFI_INVALID_PARAMETER;
    178 }
    179 
    180 /**
    181   Notify that a processor was hot-removed.
    182 
    183   @param[in] This                A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
    184   @param[in] ProcessorNumber     The handle number of the hot-added processor.
    185 
    186   @retval EFI_SUCCESS            The hot-removal of the specified processors was successfully notified.
    187   @retval EFI_UNSUPPORTED        Hot removal of processor is not supported.
    188   @retval EFI_UNSUPPORTED        Hot removal of BSP is not supported.
    189   @retval EFI_UNSUPPORTED        Hot removal of a processor with pending hot-plug operation is not supported.
    190   @retval EFI_INVALID_PARAMETER  ProcessorNumber is invalid.
    191 **/
    192 EFI_STATUS
    193 EFIAPI
    194 SmmRemoveProcessor (
    195   IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL  *This,
    196   IN       UINTN                         ProcessorNumber
    197   )
    198 {
    199   if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {
    200     return EFI_UNSUPPORTED;
    201   }
    202 
    203   //
    204   // Check parameter
    205   //
    206   if (ProcessorNumber >= mMaxNumberOfCpus ||
    207       gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
    208     return EFI_INVALID_PARAMETER;
    209   }
    210 
    211   //
    212   // Can't remove BSP
    213   //
    214   if (ProcessorNumber == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {
    215     return EFI_UNSUPPORTED;
    216   }
    217 
    218   if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone) {
    219     return EFI_UNSUPPORTED;
    220   }
    221 
    222   gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId = INVALID_APIC_ID;
    223   mCpuHotPlugData.ApicId[ProcessorNumber] = INVALID_APIC_ID;
    224 
    225   //
    226   // Removal of the processor from the CPU list is pending until all SMI handlers are finished
    227   //
    228   gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuRemove;
    229   return EFI_SUCCESS;
    230 }
    231 
    232 /**
    233   This return the handle number for the calling processor.
    234 
    235   @param[in] This                 A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
    236   @param[out] ProcessorNumber      The handle number of currently executing processor.
    237 
    238   @retval EFI_SUCCESS             The current processor handle number was returned
    239                                   in ProcessorNumber.
    240   @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.
    241 
    242 **/
    243 EFI_STATUS
    244 EFIAPI
    245 SmmWhoAmI (
    246   IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
    247   OUT      UINTN                        *ProcessorNumber
    248   )
    249 {
    250   UINTN  Index;
    251   UINT64 ApicId;
    252 
    253   //
    254   // Check parameter
    255   //
    256   if (ProcessorNumber == NULL) {
    257     return EFI_INVALID_PARAMETER;
    258   }
    259 
    260   ApicId = GetApicId ();
    261 
    262   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
    263     if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) {
    264       *ProcessorNumber = Index;
    265       return EFI_SUCCESS;
    266     }
    267   }
    268   //
    269   // This should not happen
    270   //
    271   ASSERT (FALSE);
    272   return EFI_NOT_FOUND;
    273 }
    274 
    275 /**
    276   Update the SMM CPU list per the pending operation.
    277 
    278   This function is called after return from SMI handlers.
    279 **/
    280 VOID
    281 SmmCpuUpdate (
    282   VOID
    283   )
    284 {
    285   UINTN   Index;
    286 
    287   //
    288   // Handle pending BSP switch operations
    289   //
    290   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
    291     if (gSmmCpuPrivate->Operation[Index] == SmmCpuSwitchBsp) {
    292       gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
    293       mSmmMpSyncData->SwitchBsp = TRUE;
    294       mSmmMpSyncData->CandidateBsp[Index] = TRUE;
    295     }
    296   }
    297 
    298   //
    299   // Handle pending hot-add operations
    300   //
    301   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
    302     if (gSmmCpuPrivate->Operation[Index] == SmmCpuAdd) {
    303       gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
    304       mNumberOfCpus++;
    305     }
    306   }
    307 
    308   //
    309   // Handle pending hot-remove operations
    310   //
    311   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
    312     if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {
    313       gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
    314       mNumberOfCpus--;
    315     }
    316   }
    317 }
    318 
    319 /**
    320   Register exception handler.
    321 
    322   @param  This                  A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.
    323   @param  ExceptionType         Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and
    324                                 the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL
    325                                 of the UEFI 2.0 specification.
    326   @param  InterruptHandler      A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER
    327                                 that is called when a processor interrupt occurs.
    328                                 If this parameter is NULL, then the handler will be uninstalled.
    329 
    330   @retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.
    331   @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was previously installed.
    332   @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.
    333   @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.
    334 
    335 **/
    336 EFI_STATUS
    337 EFIAPI
    338 SmmRegisterExceptionHandler (
    339     IN EFI_SMM_CPU_SERVICE_PROTOCOL  *This,
    340     IN EFI_EXCEPTION_TYPE            ExceptionType,
    341     IN EFI_CPU_INTERRUPT_HANDLER     InterruptHandler
    342     )
    343 {
    344   return RegisterCpuInterruptHandler (ExceptionType, InterruptHandler);
    345 }
    346 
    347 /**
    348   Initialize SMM CPU Services.
    349 
    350   It installs EFI SMM CPU Services Protocol.
    351 
    352   @param ImageHandle The firmware allocated handle for the EFI image.
    353 
    354   @retval EFI_SUCCESS    EFI SMM CPU Services Protocol was installed successfully.
    355 **/
    356 EFI_STATUS
    357 InitializeSmmCpuServices (
    358   IN EFI_HANDLE  Handle
    359   )
    360 {
    361   EFI_STATUS Status;
    362 
    363   Status = gSmst->SmmInstallProtocolInterface (
    364                     &Handle,
    365                     &gEfiSmmCpuServiceProtocolGuid,
    366                     EFI_NATIVE_INTERFACE,
    367                     &mSmmCpuService
    368                     );
    369   ASSERT_EFI_ERROR (Status);
    370   return Status;
    371 }
    372 
    373