Home | History | Annotate | Download | only in SmmBaseOnSmmBase2Thunk
      1 /** @file
      2   SMM Base Protocol on SMM Base2 Protocol Thunk driver.
      3 
      4   This driver co-operates with SMM Base Helper SMM driver to provide SMM Base Protocol
      5   based on SMM Base2 Protocol.
      6 
      7   This thunk driver is expected to be loaded before PI SMM IPL driver so that
      8   SMM BASE Protocol can be published immediately after SMM Base2 Protocol is installed to
      9   make SMM Base Protocol.InSmm() as early as possible.
     10 
     11   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
     12   This program and the accompanying materials
     13   are licensed and made available under the terms and conditions of the BSD License
     14   which accompanies this distribution.  The full text of the license may be found at
     15   http://opensource.org/licenses/bsd-license.php
     16 
     17   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.
     19 
     20 **/
     21 
     22 #include <PiDxe.h>
     23 #include <FrameworkSmm.h>
     24 
     25 #include <Protocol/SmmBase2.h>
     26 #include <Protocol/SmmCommunication.h>
     27 #include <Protocol/SmmBaseHelperReady.h>
     28 
     29 #include <Guid/SmmBaseThunkCommunication.h>
     30 #include <Guid/EventGroup.h>
     31 
     32 #include <Library/DebugLib.h>
     33 #include <Library/UefiBootServicesTableLib.h>
     34 #include <Library/UefiDriverEntryPoint.h>
     35 #include <Library/UefiLib.h>
     36 #include <Library/UefiRuntimeLib.h>
     37 
     38 SMMBASETHUNK_COMMUNICATION_DATA  mCommunicationData = {
     39   EFI_SMM_BASE_THUNK_COMMUNICATION_GUID,
     40   sizeof (SMMBASE_FUNCTION_DATA)
     41 };
     42 
     43 EFI_HANDLE                         mSmmBaseHandle = NULL;
     44 EFI_SMM_BASE2_PROTOCOL             *mSmmBase2 = NULL;
     45 EFI_SMM_COMMUNICATION_PROTOCOL     *mSmmCommunication = NULL;
     46 EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady = NULL;
     47 BOOLEAN                            mAtRuntime = FALSE;
     48 
     49 /**
     50   Determine if in SMM mode.
     51 
     52   @retval TRUE   In SMM mode.
     53   @retval FALSE  Not in SMM mode.
     54 **/
     55 BOOLEAN
     56 IsInSmm (
     57   VOID
     58   )
     59 {
     60   EFI_STATUS Status;
     61   BOOLEAN    InSmm;
     62 
     63   Status = mSmmBase2->InSmm (mSmmBase2, &InSmm);
     64   ASSERT_EFI_ERROR (Status);
     65   return InSmm;
     66 }
     67 
     68 /**
     69   Invoke services provided by SMM Base Helper SMM driver.
     70 **/
     71 VOID
     72 SmmBaseHelperService (
     73   VOID
     74   )
     75 {
     76   UINTN DataSize;
     77 
     78   mCommunicationData.FunctionData.Status = EFI_UNSUPPORTED;
     79   mCommunicationData.FunctionData.SmmBaseImageHandle = mSmmBaseHandle;
     80 
     81   if ((mCommunicationData.FunctionData.Function != SmmBaseFunctionCommunicate) && IsInSmm()) {
     82     ///
     83     /// If in SMM mode, directly call services in SMM Base Helper.
     84     ///
     85     DataSize = (UINTN)(sizeof (SMMBASE_FUNCTION_DATA));
     86     mSmmBaseHelperReady->ServiceEntry (
     87                            NULL,
     88                            NULL,
     89                            &mCommunicationData.FunctionData,
     90                            &DataSize
     91                            );
     92   } else {
     93     ///
     94     /// Call services in SMM Base Helper via SMM Communication Protocol.
     95     ///
     96     DataSize = (UINTN)(sizeof (mCommunicationData));
     97     mSmmCommunication->Communicate (
     98                          mSmmCommunication,
     99                          &mCommunicationData,
    100                          &DataSize
    101                          );
    102   }
    103 }
    104 
    105 /**
    106   Register a given driver into SMRAM. This is the equivalent of performing
    107   the LoadImage/StartImage into System Management Mode.
    108 
    109   @param[in]   This                  Protocol instance pointer.
    110   @param[in]   FilePath              Location of the image to be installed as the handler.
    111   @param[in]   SourceBuffer          Optional source buffer in case the image file
    112                                      is in memory.
    113   @param[in]   SourceSize            Size of the source image file, if in memory.
    114   @param[out]  ImageHandle           The handle that the base driver uses to decode
    115                                      the handler. Unique among SMM handlers only,
    116                                      not unique across DXE/EFI.
    117   @param[in]   LegacyIA32Binary      An optional parameter specifying that the associated
    118                                      file is a real-mode IA-32 binary.
    119 
    120   @retval      EFI_SUCCESS           The operation was successful.
    121   @retval      EFI_OUT_OF_RESOURCES  There were no additional SMRAM resources to load the handler
    122   @retval      EFI_UNSUPPORTED       This platform does not support 16-bit handlers.
    123   @retval      EFI_UNSUPPORTED       Platform is in runtime.
    124   @retval      EFI_INVALID_PARAMETER The handlers was not the correct image type
    125 **/
    126 EFI_STATUS
    127 EFIAPI
    128 SmmBaseRegister (
    129   IN      EFI_SMM_BASE_PROTOCOL     *This,
    130   IN      EFI_DEVICE_PATH_PROTOCOL  *FilePath,
    131   IN      VOID                      *SourceBuffer,
    132   IN      UINTN                     SourceSize,
    133   OUT     EFI_HANDLE                *ImageHandle,
    134   IN      BOOLEAN                   LegacyIA32Binary
    135   )
    136 {
    137   if (mAtRuntime || LegacyIA32Binary) {
    138     return EFI_UNSUPPORTED;
    139   }
    140 
    141   mCommunicationData.FunctionData.Function = SmmBaseFunctionRegister;
    142   mCommunicationData.FunctionData.Args.Register.FilePath = FilePath;
    143   mCommunicationData.FunctionData.Args.Register.SourceBuffer = SourceBuffer;
    144   mCommunicationData.FunctionData.Args.Register.SourceSize = SourceSize;
    145   mCommunicationData.FunctionData.Args.Register.ImageHandle = ImageHandle;
    146   mCommunicationData.FunctionData.Args.Register.LegacyIA32Binary = LegacyIA32Binary;
    147 
    148   SmmBaseHelperService ();
    149   return mCommunicationData.FunctionData.Status;
    150 }
    151 
    152 /**
    153   Removes a handler from execution within SMRAM.  This is the equivalent of performing
    154   the UnloadImage in System Management Mode.
    155 
    156   @param[in]  This                  Protocol instance pointer.
    157   @param[in]  ImageHandle           The handler to be removed.
    158 
    159   @retval     EFI_SUCCESS           The operation was successful
    160   @retval     EFI_INVALID_PARAMETER The handler did not exist
    161   @retval     EFI_UNSUPPORTED       Platform is in runtime.
    162 **/
    163 EFI_STATUS
    164 EFIAPI
    165 SmmBaseUnregister (
    166   IN      EFI_SMM_BASE_PROTOCOL     *This,
    167   IN      EFI_HANDLE                ImageHandle
    168   )
    169 {
    170   if (mAtRuntime) {
    171     return EFI_UNSUPPORTED;
    172   }
    173 
    174   mCommunicationData.FunctionData.Function = SmmBaseFunctionUnregister;
    175   mCommunicationData.FunctionData.Args.UnRegister.ImageHandle = ImageHandle;
    176 
    177   SmmBaseHelperService ();
    178   return mCommunicationData.FunctionData.Status;
    179 }
    180 
    181 /**
    182   The SMM Inter-module Communicate Service Communicate() function
    183   provides a service to send/receive messages from a registered
    184   EFI service.  The BASE protocol driver is responsible for doing
    185   any of the copies such that the data lives in boot-service-accessible RAM.
    186 
    187   @param[in]      This                  Protocol instance pointer.
    188   @param[in]      ImageHandle           The handle of the registered driver.
    189   @param[in, out]  CommunicationBuffer   Pointer to the buffer to convey into SMRAM.
    190   @param[in, out]  BufferSize            The size of the data buffer being passed in.
    191                                         On exit, the size of data being returned.
    192                                         Zero if the handler does not wish to reply with any data.
    193 
    194   @retval         EFI_SUCCESS           The message was successfully posted
    195   @retval         EFI_INVALID_PARAMETER The buffer was NULL
    196 **/
    197 EFI_STATUS
    198 EFIAPI
    199 SmmBaseCommunicate (
    200   IN      EFI_SMM_BASE_PROTOCOL     *This,
    201   IN      EFI_HANDLE                ImageHandle,
    202   IN OUT  VOID                      *CommunicationBuffer,
    203   IN OUT  UINTN                     *BufferSize
    204   )
    205 {
    206   ///
    207   /// Note this is a runtime interface
    208   ///
    209 
    210   if (CommunicationBuffer == NULL || BufferSize == NULL) {
    211     return EFI_INVALID_PARAMETER;
    212   }
    213 
    214   mCommunicationData.FunctionData.Function = SmmBaseFunctionCommunicate;
    215   mCommunicationData.FunctionData.Args.Communicate.ImageHandle = ImageHandle;
    216   mCommunicationData.FunctionData.Args.Communicate.CommunicationBuffer = CommunicationBuffer;
    217   mCommunicationData.FunctionData.Args.Communicate.SourceSize = BufferSize;
    218 
    219   SmmBaseHelperService ();
    220   return mCommunicationData.FunctionData.Status;
    221 }
    222 
    223 /**
    224   Register a callback to execute within SMM.
    225   This allows receipt of messages created with EFI_SMM_BASE_PROTOCOL.Communicate().
    226 
    227   @param[in]  This                  Protocol instance pointer.
    228   @param[in]  SmmImageHandle        Handle of the callback service.
    229   @param[in]  CallbackAddress       Address of the callback service.
    230   @param[in]  MakeLast              If present, will stipulate that the handler is posted to
    231                                     be executed last in the dispatch table.
    232   @param[in]  FloatingPointSave     An optional parameter that informs the
    233                                     EFI_SMM_ACCESS_PROTOCOL Driver core if it needs to save
    234                                     the floating point register state. If any handler
    235                                     require this, the state will be saved for all handlers.
    236 
    237   @retval     EFI_SUCCESS           The operation was successful
    238   @retval     EFI_OUT_OF_RESOURCES  Not enough space in the dispatch queue
    239   @retval     EFI_UNSUPPORTED       Platform is in runtime.
    240   @retval     EFI_UNSUPPORTED       The caller is not in SMM.
    241 **/
    242 EFI_STATUS
    243 EFIAPI
    244 SmmBaseRegisterCallback (
    245   IN      EFI_SMM_BASE_PROTOCOL         *This,
    246   IN      EFI_HANDLE                    SmmImageHandle,
    247   IN      EFI_SMM_CALLBACK_ENTRY_POINT  CallbackAddress,
    248   IN      BOOLEAN                       MakeLast,
    249   IN      BOOLEAN                       FloatingPointSave
    250   )
    251 {
    252   if (!IsInSmm()) {
    253     return EFI_UNSUPPORTED;
    254   }
    255 
    256   mCommunicationData.FunctionData.Function = SmmBaseFunctionRegisterCallback;
    257   mCommunicationData.FunctionData.Args.RegisterCallback.SmmImageHandle = SmmImageHandle;
    258   mCommunicationData.FunctionData.Args.RegisterCallback.CallbackAddress = CallbackAddress;
    259   mCommunicationData.FunctionData.Args.RegisterCallback.MakeLast = MakeLast;
    260   mCommunicationData.FunctionData.Args.RegisterCallback.FloatingPointSave = FloatingPointSave;
    261 
    262   SmmBaseHelperService();
    263   return mCommunicationData.FunctionData.Status;
    264 }
    265 
    266 /**
    267   This routine tells caller if execution context is SMM or not.
    268 
    269   @param[in]   This                   Protocol instance pointer.
    270   @param[out]  InSmm                  Whether the caller is inside SMM for IA-32
    271                                       or servicing a PMI for the Itanium processor
    272                                       family.
    273 
    274   @retval      EFI_SUCCESS            The operation was successful
    275   @retval      EFI_INVALID_PARAMETER  InSmm was NULL.
    276 **/
    277 EFI_STATUS
    278 EFIAPI
    279 SmmBaseInSmm (
    280   IN      EFI_SMM_BASE_PROTOCOL     *This,
    281   OUT     BOOLEAN                   *InSmm
    282   )
    283 {
    284   return mSmmBase2->InSmm (mSmmBase2, InSmm);
    285 }
    286 
    287 /**
    288   The SmmAllocatePool() function allocates a memory region of Size bytes from memory of
    289   type PoolType and returns the address of the allocated memory in the location referenced
    290   by Buffer.  This function allocates pages from EFI SMRAM Memory as needed to grow the
    291   requested pool type.  All allocations are eight-byte aligned.
    292 
    293   @param[in]   This                  Protocol instance pointer.
    294   @param[in]   PoolType              The type of pool to allocate.
    295                                      The only supported type is EfiRuntimeServicesData;
    296                                      the interface will internally map this runtime request to
    297                                      SMRAM for IA-32 and leave as this type for the Itanium
    298                                      processor family. Other types can be ignored.
    299   @param[in]   Size                  The number of bytes to allocate from the pool.
    300   @param[out]  Buffer                A pointer to a pointer to the allocated buffer if the call
    301                                      succeeds; undefined otherwise.
    302 
    303   @retval      EFI_SUCCESS           The requested number of bytes was allocated.
    304   @retval      EFI_OUT_OF_RESOURCES  The pool requested could not be allocated.
    305   @retval      EFI_UNSUPPORTED       Platform is in runtime.
    306 **/
    307 EFI_STATUS
    308 EFIAPI
    309 SmmBaseSmmAllocatePool (
    310   IN      EFI_SMM_BASE_PROTOCOL     *This,
    311   IN      EFI_MEMORY_TYPE           PoolType,
    312   IN      UINTN                     Size,
    313   OUT     VOID                      **Buffer
    314   )
    315 {
    316   if (mAtRuntime) {
    317     return EFI_UNSUPPORTED;
    318   }
    319 
    320   mCommunicationData.FunctionData.Function = SmmBaseFunctionAllocatePool;
    321   mCommunicationData.FunctionData.Args.AllocatePool.PoolType = PoolType;
    322   mCommunicationData.FunctionData.Args.AllocatePool.Size = Size;
    323   mCommunicationData.FunctionData.Args.AllocatePool.Buffer = Buffer;
    324 
    325   SmmBaseHelperService ();
    326   return mCommunicationData.FunctionData.Status;
    327 }
    328 
    329 /**
    330   The SmmFreePool() function returns the memory specified by Buffer to the system.
    331   On return, the memory's type is EFI SMRAM Memory.  The Buffer that is freed must
    332   have been allocated by SmmAllocatePool().
    333 
    334   @param[in]  This                  Protocol instance pointer.
    335   @param[in]  Buffer                Pointer to the buffer allocation.
    336 
    337   @retval     EFI_SUCCESS           The memory was returned to the system.
    338   @retval     EFI_INVALID_PARAMETER Buffer was invalid.
    339   @retval     EFI_UNSUPPORTED       Platform is in runtime.
    340 **/
    341 EFI_STATUS
    342 EFIAPI
    343 SmmBaseSmmFreePool (
    344   IN      EFI_SMM_BASE_PROTOCOL     *This,
    345   IN      VOID                      *Buffer
    346   )
    347 {
    348   if (mAtRuntime) {
    349     return EFI_UNSUPPORTED;
    350   }
    351 
    352   mCommunicationData.FunctionData.Function = SmmBaseFunctionFreePool;
    353   mCommunicationData.FunctionData.Args.FreePool.Buffer = Buffer;
    354 
    355   SmmBaseHelperService ();
    356   return mCommunicationData.FunctionData.Status;
    357 }
    358 
    359 /**
    360   The GetSmstLocation() function returns the location of the System Management
    361   Service Table.  The use of the API is such that a driver can discover the
    362   location of the SMST in its entry point and then cache it in some driver
    363   global variable so that the SMST can be invoked in subsequent callbacks.
    364 
    365   @param[in]  This                  Protocol instance pointer.
    366   @param[out] Smst                  Pointer to the SMST.
    367 
    368   @retval     EFI_SUCCESS           The operation was successful
    369   @retval     EFI_INVALID_PARAMETER Smst was invalid.
    370   @retval     EFI_UNSUPPORTED       Not in SMM.
    371 **/
    372 EFI_STATUS
    373 EFIAPI
    374 SmmBaseGetSmstLocation (
    375   IN      EFI_SMM_BASE_PROTOCOL     *This,
    376   OUT     EFI_SMM_SYSTEM_TABLE      **Smst
    377   )
    378 {
    379   if (!IsInSmm ()) {
    380     return EFI_UNSUPPORTED;
    381   }
    382 
    383   if (Smst == NULL) {
    384     return EFI_INVALID_PARAMETER;
    385   }
    386 
    387   *Smst = mSmmBaseHelperReady->FrameworkSmst;
    388   return EFI_SUCCESS;
    389 }
    390 
    391 /**
    392   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
    393 
    394   This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
    395   It convers pointer to new virtual address.
    396 
    397   @param  Event        Event whose notification function is being invoked
    398   @param  Context      Pointer to the notification function's context
    399 **/
    400 VOID
    401 EFIAPI
    402 SmmBaseAddressChangeEvent (
    403   IN EFI_EVENT        Event,
    404   IN VOID             *Context
    405   )
    406 {
    407   EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
    408 }
    409 
    410 ///
    411 /// SMM Base Protocol instance
    412 ///
    413 EFI_SMM_BASE_PROTOCOL  mSmmBase = {
    414   SmmBaseRegister,
    415   SmmBaseUnregister,
    416   SmmBaseCommunicate,
    417   SmmBaseRegisterCallback,
    418   SmmBaseInSmm,
    419   SmmBaseSmmAllocatePool,
    420   SmmBaseSmmFreePool,
    421   SmmBaseGetSmstLocation
    422 };
    423 
    424 /**
    425   Notification function on Exit Boot Services Event.
    426 
    427   This function sets a flag indicating it is in Runtime phase.
    428 
    429   @param  Event        Event whose notification function is being invoked
    430   @param  Context      Pointer to the notification function's context
    431 **/
    432 VOID
    433 EFIAPI
    434 SmmBaseExitBootServicesEventNotify (
    435   IN EFI_EVENT  Event,
    436   IN VOID       *Context
    437   )
    438 {
    439   mAtRuntime = TRUE;
    440 }
    441 
    442 /**
    443   Entry Point for SMM Base Protocol on SMM Base2 Protocol Thunk driver.
    444 
    445   @param[in] ImageHandle  Image handle of this driver.
    446   @param[in] SystemTable  A Pointer to the EFI System Table.
    447 
    448   @retval EFI_SUCCESS  The entry point is executed successfully.
    449 **/
    450 EFI_STATUS
    451 EFIAPI
    452 SmmBaseThunkMain (
    453   IN EFI_HANDLE        ImageHandle,
    454   IN EFI_SYSTEM_TABLE  *SystemTable
    455   )
    456 {
    457   EFI_STATUS  Status;
    458   EFI_EVENT   Event;
    459 
    460   mSmmBaseHandle = ImageHandle;
    461 
    462   //
    463   // Assume only one instance of SMM Base2 Protocol in the system
    464   // Locate SMM Base2 Protocol
    465   //
    466   Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **) &mSmmBase2);
    467   ASSERT_EFI_ERROR (Status);
    468 
    469   //
    470   // Assume only one instance of SMM Communication Protocol in the system
    471   // Locate SMM Communication Protocol
    472   //
    473   Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
    474   ASSERT_EFI_ERROR (Status);
    475 
    476   //
    477   // Assume only one instance of SMM Base Helper Ready Protocol in the system
    478   // Locate SMM Base Helper Ready Protocol
    479   //
    480   Status = gBS->LocateProtocol (&gEfiSmmBaseHelperReadyProtocolGuid, NULL, (VOID **) &mSmmBaseHelperReady);
    481   ASSERT_EFI_ERROR (Status);
    482 
    483   //
    484   // Create event notification on Exit Boot Services event.
    485   //
    486   Status = gBS->CreateEventEx (
    487                   EVT_NOTIFY_SIGNAL,
    488                   TPL_NOTIFY,
    489                   SmmBaseExitBootServicesEventNotify,
    490                   NULL,
    491                   &gEfiEventExitBootServicesGuid,
    492                   &Event
    493                   );
    494   ASSERT_EFI_ERROR (Status);
    495 
    496   //
    497   // Create event on SetVirtualAddressMap() to convert mSmmCommunication from a physical address to a virtual address
    498   //
    499   Status = gBS->CreateEventEx (
    500                   EVT_NOTIFY_SIGNAL,
    501                   TPL_NOTIFY,
    502                   SmmBaseAddressChangeEvent,
    503                   NULL,
    504                   &gEfiEventVirtualAddressChangeGuid,
    505                   &Event
    506                   );
    507   ASSERT_EFI_ERROR (Status);
    508 
    509   //
    510   // Publish Framework SMM BASE Protocol immediately after SMM Base2 Protocol is installed to
    511   // make SMM Base Protocol.InSmm() available as early as possible.
    512   //
    513   Status = gBS->InstallMultipleProtocolInterfaces (
    514                   &mSmmBaseHandle,
    515                   &gEfiSmmBaseProtocolGuid, &mSmmBase,
    516                   NULL
    517                   );
    518   ASSERT_EFI_ERROR (Status);
    519 
    520   return EFI_SUCCESS;
    521 }
    522