Home | History | Annotate | Download | only in SmmSwDispatch2OnSmmSwDispatchThunk
      1 /** @file
      2   SMM SwDispatch2 Protocol on SMM SwDispatch Protocol Thunk driver.
      3 
      4   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials are licensed and made available under
      8   the terms and conditions of the BSD License that accompanies this distribution.
     10   The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php.
     14 
     16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     20 
     22 
     24 **/
     25 
     26 #include <PiDxe.h>
     27 #include <FrameworkSmm.h>
     28 
     29 #include <Protocol/SmmSwDispatch2.h>
     30 #include <Protocol/SmmSwDispatch.h>
     31 #include <Protocol/SmmControl.h>
     32 #include <Protocol/SmmCpu.h>
     33 
     34 #include <Library/UefiBootServicesTableLib.h>
     35 #include <Library/UefiDriverEntryPoint.h>
     36 #include <Library/SmmServicesTableLib.h>
     37 #include <Library/BaseLib.h>
     38 #include <Library/IoLib.h>
     39 #include <Library/DebugLib.h>
     40 
     41 typedef struct {
     42   LIST_ENTRY                     Link;
     43   EFI_HANDLE                     DispatchHandle;
     44   UINTN                          SwSmiInputValue;
     45   UINTN                          DispatchFunction;
     46 } EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT;
     47 
     48 /**
     49   Register a child SMI source dispatch function for the specified software SMI.
     50 
     51   This service registers a function (DispatchFunction) which will be called when the software
     52   SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return,
     53   DispatchHandle contains a unique handle which may be used later to unregister the function
     54   using UnRegister().
     55 
     56   @param[in]  This                  Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
     57   @param[in]  DispatchFunction      Function to register for handler when the specified software
     58                                     SMI is generated.
     59   @param[in, out]  RegisterContext  Pointer to the dispatch function's context.
     60                                     The caller fills this context in before calling
     61                                     the register function to indicate to the register
     62                                     function which Software SMI input value the
     63                                     dispatch function should be invoked for.
     64   @param[out] DispatchHandle        Handle generated by the dispatcher to track the
     65                                     function instance.
     66 
     67   @retval EFI_SUCCESS            The dispatch function has been successfully
     68                                  registered and the SMI source has been enabled.
     69   @retval EFI_DEVICE_ERROR       The SW driver was unable to enable the SMI source.
     70   @retval EFI_INVALID_PARAMETER  RegisterContext is invalid. The SW SMI input value
     71                                  is not within valid range.
     72   @retval EFI_OUT_OF_RESOURCES   There is not enough memory (system or SMM) to manage this
     73                                  child.
     74   @retval EFI_OUT_OF_RESOURCES   A unique software SMI value could not be assigned
     75                                  for this dispatch.
     76 **/
     77 EFI_STATUS
     78 EFIAPI
     79 SmmSwDispatch2Register (
     80   IN  CONST EFI_SMM_SW_DISPATCH2_PROTOCOL  *This,
     81   IN        EFI_SMM_HANDLER_ENTRY_POINT2   DispatchFunction,
     82   IN  OUT   EFI_SMM_SW_REGISTER_CONTEXT    *RegisterContext,
     83   OUT       EFI_HANDLE                     *DispatchHandle
     84   );
     85 
     86 /**
     87   Unregister a child SMI source dispatch function for the specified software SMI.
     88 
     89   This service removes the handler associated with DispatchHandle so that it will no longer be
     90   called in response to a software SMI.
     91 
     92   @param[in] This                Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
     93   @param[in] DispatchHandle      Handle of dispatch function to deregister.
     94 
     95   @retval EFI_SUCCESS            The dispatch function has been successfully unregistered.
     96   @retval EFI_INVALID_PARAMETER  The DispatchHandle was not valid.
     97 **/
     98 EFI_STATUS
     99 EFIAPI
    100 SmmSwDispatch2UnRegister (
    101   IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL  *This,
    102   IN       EFI_HANDLE                     DispatchHandle
    103   );
    104 
    105 EFI_SMM_SW_DISPATCH2_PROTOCOL gSmmSwDispatch2 = {
    106   SmmSwDispatch2Register,
    107   SmmSwDispatch2UnRegister,
    108   0 // MaximumSwiValue
    109 };
    110 
    111 EFI_SMM_SW_DISPATCH_PROTOCOL  *mSmmSwDispatch;
    112 UINT8                         mSmiTriggerRegister;
    113 UINT8                         mSmiDataRegister;
    114 
    115 EFI_SMM_CPU_PROTOCOL          *mSmmCpuProtocol;
    116 LIST_ENTRY                    mSmmSwDispatch2ThunkQueue = INITIALIZE_LIST_HEAD_VARIABLE (mSmmSwDispatch2ThunkQueue);
    117 
    118 /**
    119   This function find SmmSwDispatch2Context by SwSmiInputValue.
    120 
    121   @param SwSmiInputValue The SwSmiInputValue to indentify the SmmSwDispatch2 context
    122 
    123   @return SmmSwDispatch2 context
    124 **/
    125 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *
    126 FindSmmSwDispatch2ContextBySwSmiInputValue (
    127   IN UINTN   SwSmiInputValue
    128   )
    129 {
    130   LIST_ENTRY                            *Link;
    131   EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT    *ThunkContext;
    132 
    133   for (Link = mSmmSwDispatch2ThunkQueue.ForwardLink;
    134     Link != &mSmmSwDispatch2ThunkQueue;
    135     Link = Link->ForwardLink) {
    136     ThunkContext = BASE_CR (
    137                      Link,
    138                      EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT,
    139                      Link
    140                      );
    141     if (ThunkContext->SwSmiInputValue == SwSmiInputValue) {
    142       return ThunkContext;
    143     }
    144   }
    145   return NULL;
    146 }
    147 
    148 /**
    149   This function find SmmSwDispatch2Context by DispatchHandle.
    150 
    151   @param DispatchHandle The DispatchHandle to indentify the SmmSwDispatch2Thunk context
    152 
    153   @return SmmSwDispatch2Thunk context
    154 **/
    155 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *
    156 FindSmmSwDispatch2ContextByDispatchHandle (
    157   IN EFI_HANDLE   DispatchHandle
    158   )
    159 {
    160   LIST_ENTRY                            *Link;
    161   EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT    *ThunkContext;
    162 
    163   for (Link = mSmmSwDispatch2ThunkQueue.ForwardLink;
    164        Link != &mSmmSwDispatch2ThunkQueue;
    165        Link = Link->ForwardLink) {
    166     ThunkContext = BASE_CR (
    167                      Link,
    168                      EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT,
    169                      Link
    170                      );
    171     if (ThunkContext->DispatchHandle == DispatchHandle) {
    172       return ThunkContext;
    173     }
    174   }
    175   return NULL;
    176 }
    177 
    178 /**
    179   Framework dispatch function for a Software SMI handler.
    180 
    181   @param  DispatchHandle        The handle of this dispatch function.
    182   @param  DispatchContext       The pointer to the dispatch function's context.
    183                                 The SwSmiInputValue field is filled in
    184                                 by the software dispatch driver prior to
    185                                 invoking this dispatch function.
    186                                 The dispatch function will only be called
    187                                 for input values for which it is registered.
    188 
    189   @return None
    190 
    191 **/
    192 VOID
    193 EFIAPI
    194 FrameworkDispatchFunction (
    195   IN  EFI_HANDLE                    DispatchHandle,
    196   IN  EFI_SMM_SW_DISPATCH_CONTEXT   *DispatchContext
    197   )
    198 {
    199   EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT    *ThunkContext;
    200   EFI_SMM_HANDLER_ENTRY_POINT2          DispatchFunction;
    201   EFI_SMM_SW_REGISTER_CONTEXT           RegisterContext;
    202   EFI_SMM_SW_CONTEXT                    SwContext;
    203   UINTN                                 Size;
    204   UINTN                                 Index;
    205   EFI_SMM_SAVE_STATE_IO_INFO            IoInfo;
    206   EFI_STATUS                            Status;
    207 
    208   //
    209   // Search context
    210   //
    211   ThunkContext = FindSmmSwDispatch2ContextBySwSmiInputValue (DispatchContext->SwSmiInputValue);
    212   ASSERT (ThunkContext != NULL);
    213   if (ThunkContext == NULL) {
    214     return ;
    215   }
    216 
    217   //
    218   // Construct new context
    219   //
    220   RegisterContext.SwSmiInputValue = DispatchContext->SwSmiInputValue;
    221   Size = sizeof(SwContext);
    222   SwContext.CommandPort = IoRead8 (mSmiTriggerRegister);
    223   SwContext.DataPort    = IoRead8 (mSmiDataRegister);
    224 
    225   //
    226   // Try to find which CPU trigger SWSMI
    227   //
    228   SwContext.SwSmiCpuIndex = 0;
    229   for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
    230     Status = mSmmCpuProtocol->ReadSaveState (
    231                                 mSmmCpuProtocol,
    232                                 sizeof(IoInfo),
    233                                 EFI_SMM_SAVE_STATE_REGISTER_IO,
    234                                 Index,
    235                                 &IoInfo
    236                                 );
    237     if (EFI_ERROR (Status)) {
    238       continue;
    239     }
    240     if (IoInfo.IoPort == mSmiTriggerRegister) {
    241       //
    242       // Great! Find it.
    243       //
    244       SwContext.SwSmiCpuIndex = Index;
    245       break;
    246     }
    247   }
    248 
    249   //
    250   // Dispatch
    251   //
    252   DispatchFunction = (EFI_SMM_HANDLER_ENTRY_POINT2)ThunkContext->DispatchFunction;
    253   DispatchFunction (
    254     DispatchHandle,
    255     &RegisterContext,
    256     &SwContext,
    257     &Size
    258     );
    259   return ;
    260 }
    261 
    262 /**
    263   Register a child SMI source dispatch function for the specified software SMI.
    264 
    265   This service registers a function (DispatchFunction) which will be called when the software
    266   SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return,
    267   DispatchHandle contains a unique handle which may be used later to unregister the function
    268   using UnRegister().
    269 
    270   @param[in]  This                  Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
    271   @param[in]  DispatchFunction      Function to register for handler when the specified software
    272                                     SMI is generated.
    273   @param[in, out]  RegisterContext  Pointer to the dispatch function's context.
    274                                     The caller fills this context in before calling
    275                                     the register function to indicate to the register
    276                                     function which Software SMI input value the
    277                                     dispatch function should be invoked for.
    278   @param[out] DispatchHandle        Handle generated by the dispatcher to track the
    279                                     function instance.
    280 
    281   @retval EFI_SUCCESS            The dispatch function has been successfully
    282                                  registered and the SMI source has been enabled.
    283   @retval EFI_DEVICE_ERROR       The SW driver was unable to enable the SMI source.
    284   @retval EFI_INVALID_PARAMETER  RegisterContext is invalid. The SW SMI input value
    285                                  is not within valid range.
    286   @retval EFI_OUT_OF_RESOURCES   There is not enough memory (system or SMM) to manage this
    287                                  child.
    288   @retval EFI_OUT_OF_RESOURCES   A unique software SMI value could not be assigned
    289                                  for this dispatch.
    290 **/
    291 EFI_STATUS
    292 EFIAPI
    293 SmmSwDispatch2Register (
    294   IN  CONST EFI_SMM_SW_DISPATCH2_PROTOCOL  *This,
    295   IN        EFI_SMM_HANDLER_ENTRY_POINT2   DispatchFunction,
    296   IN  OUT   EFI_SMM_SW_REGISTER_CONTEXT    *RegisterContext,
    297   OUT       EFI_HANDLE                     *DispatchHandle
    298   )
    299 {
    300   EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT    *ThunkContext;
    301   EFI_SMM_SW_DISPATCH_CONTEXT           DispatchContext;
    302   EFI_STATUS                            Status;
    303   UINTN                                 Index;
    304 
    305   if (RegisterContext->SwSmiInputValue == (UINTN)-1) {
    306     //
    307     // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.
    308     //
    309     Status = EFI_NOT_FOUND;
    310     for (Index = 1; Index < gSmmSwDispatch2.MaximumSwiValue; Index++) {
    311       DispatchContext.SwSmiInputValue = Index;
    312       Status = mSmmSwDispatch->Register (
    313                                  mSmmSwDispatch,
    314                                  FrameworkDispatchFunction,
    315                                  &DispatchContext,
    316                                  DispatchHandle
    317                                  );
    318       if (!EFI_ERROR (Status)) {
    319         RegisterContext->SwSmiInputValue = Index;
    320         break;
    321       }
    322     }
    323     if (RegisterContext->SwSmiInputValue == (UINTN)-1) {
    324       return EFI_OUT_OF_RESOURCES;
    325     }
    326   } else {
    327     DispatchContext.SwSmiInputValue = RegisterContext->SwSmiInputValue;
    328     Status = mSmmSwDispatch->Register (
    329                                mSmmSwDispatch,
    330                                FrameworkDispatchFunction,
    331                                &DispatchContext,
    332                                DispatchHandle
    333                                );
    334   }
    335   if (!EFI_ERROR (Status)) {
    336     //
    337     // Register
    338     //
    339     Status = gSmst->SmmAllocatePool (
    340                       EfiRuntimeServicesData,
    341                       sizeof(*ThunkContext),
    342                       (VOID **)&ThunkContext
    343                       );
    344     ASSERT_EFI_ERROR (Status);
    345     if (EFI_ERROR (Status)) {
    346       mSmmSwDispatch->UnRegister (mSmmSwDispatch, *DispatchHandle);
    347       return EFI_OUT_OF_RESOURCES;
    348     }
    349 
    350     ThunkContext->SwSmiInputValue  = RegisterContext->SwSmiInputValue;
    351     ThunkContext->DispatchFunction = (UINTN)DispatchFunction;
    352     ThunkContext->DispatchHandle   = *DispatchHandle;
    353     InsertTailList (&mSmmSwDispatch2ThunkQueue, &ThunkContext->Link);
    354   }
    355 
    356   return Status;
    357 }
    358 
    359 /**
    360   Unregister a child SMI source dispatch function for the specified software SMI.
    361 
    362   This service removes the handler associated with DispatchHandle so that it will no longer be
    363   called in response to a software SMI.
    364 
    365   @param[in] This                Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
    366   @param[in] DispatchHandle      Handle of dispatch function to deregister.
    367 
    368   @retval EFI_SUCCESS            The dispatch function has been successfully unregistered.
    369   @retval EFI_INVALID_PARAMETER  The DispatchHandle was not valid.
    370 **/
    371 EFI_STATUS
    372 EFIAPI
    373 SmmSwDispatch2UnRegister (
    374   IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL  *This,
    375   IN       EFI_HANDLE                     DispatchHandle
    376   )
    377 {
    378   EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT    *ThunkContext;
    379   EFI_STATUS                            Status;
    380 
    381   Status = mSmmSwDispatch->UnRegister (mSmmSwDispatch, DispatchHandle);
    382   if (!EFI_ERROR (Status)) {
    383     //
    384     // Unregister
    385     //
    386     ThunkContext = FindSmmSwDispatch2ContextByDispatchHandle (DispatchHandle);
    387     ASSERT (ThunkContext != NULL);
    388     if (ThunkContext != NULL) {
    389       RemoveEntryList (&ThunkContext->Link);
    390       gSmst->SmmFreePool (ThunkContext);
    391     }
    392   }
    393 
    394   return Status;
    395 }
    396 
    397 /**
    398   Entry Point for this thunk driver.
    399 
    400   @param[in] ImageHandle  Image handle of this driver.
    401   @param[in] SystemTable  A Pointer to the EFI System Table.
    402 
    403   @retval EFI_SUCCESS  The entry point is executed successfully.
    404   @retval other        Some error occurred when executing this entry point.
    405 **/
    406 EFI_STATUS
    407 EFIAPI
    408 SmmSwDispatch2ThunkMain (
    409   IN EFI_HANDLE        ImageHandle,
    410   IN EFI_SYSTEM_TABLE  *SystemTable
    411   )
    412 {
    413   EFI_STATUS               Status;
    414   EFI_SMM_CONTROL_PROTOCOL *SmmControl;
    415   EFI_SMM_CONTROL_REGISTER RegisterInfo;
    416 
    417   //
    418   // Locate Framework SMM SwDispatch Protocol
    419   //
    420   Status = gBS->LocateProtocol (
    421                   &gEfiSmmSwDispatchProtocolGuid,
    422                   NULL,
    423                   (VOID **)&mSmmSwDispatch
    424                   );
    425   ASSERT_EFI_ERROR (Status);
    426   gSmmSwDispatch2.MaximumSwiValue = mSmmSwDispatch->MaximumSwiValue;
    427   if (gSmmSwDispatch2.MaximumSwiValue == 0x0) {
    428     DEBUG ((EFI_D_ERROR, "BUGBUG: MaximumSwiValue is 0, work-around to make it 0xFF\n"));
    429     gSmmSwDispatch2.MaximumSwiValue = 0xFF;
    430   }
    431 
    432   //
    433   // Locate Framework SMM Control Protocol
    434   //
    435   Status = gBS->LocateProtocol (
    436                   &gEfiSmmControlProtocolGuid,
    437                   NULL,
    438                   (VOID **)&SmmControl
    439                   );
    440 
    441   ASSERT_EFI_ERROR (Status);
    442   Status = SmmControl->GetRegisterInfo (
    443                          SmmControl,
    444                          &RegisterInfo
    445                          );
    446   ASSERT_EFI_ERROR (Status);
    447   mSmiTriggerRegister = RegisterInfo.SmiTriggerRegister;
    448   mSmiDataRegister    = RegisterInfo.SmiDataRegister;
    449 
    450   //
    451   // Locate PI SMM CPU protocol
    452   //
    453   Status = gSmst->SmmLocateProtocol (
    454                     &gEfiSmmCpuProtocolGuid,
    455                     NULL,
    456                     (VOID **)&mSmmCpuProtocol
    457                     );
    458   ASSERT_EFI_ERROR (Status);
    459 
    460   //
    461   // Publish PI SMM SwDispatch2 Protocol
    462   //
    463   ImageHandle = NULL;
    464   Status = gSmst->SmmInstallProtocolInterface (
    465                     &ImageHandle,
    466                     &gEfiSmmSwDispatch2ProtocolGuid,
    467                     EFI_NATIVE_INTERFACE,
    468                     &gSmmSwDispatch2
    469                     );
    470   ASSERT_EFI_ERROR (Status);
    471   return Status;
    472 }
    473 
    474