Home | History | Annotate | Download | only in Smm
      1 /** @file
      2   Report Status Code Router Driver which produces SMM Report Stataus Code Handler Protocol
      3   and SMM Status Code Protocol.
      4 
      5   Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "ReportStatusCodeRouterSmm.h"
     17 
     18 LIST_ENTRY   mCallbackListHead          = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackListHead);
     19 
     20 //
     21 // Report operation nest status.
     22 // If it is set, then the report operation has nested.
     23 //
     24 UINT32       mStatusCodeNestStatus = 0;
     25 
     26 EFI_SMM_STATUS_CODE_PROTOCOL  mSmmStatusCodeProtocol  = {
     27   ReportDispatcher
     28 };
     29 
     30 EFI_SMM_RSC_HANDLER_PROTOCOL  mSmmRscHandlerProtocol = {
     31   Register,
     32   Unregister
     33   };
     34 
     35 /**
     36   Register the callback function for ReportStatusCode() notification.
     37 
     38   When this function is called the function pointer is added to an internal list and any future calls to
     39   ReportStatusCode() will be forwarded to the Callback function.
     40 
     41   @param[in] Callback           A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is called
     42                                 when a call to ReportStatusCode() occurs.
     43 
     44   @retval EFI_SUCCESS           Function was successfully registered.
     45   @retval EFI_INVALID_PARAMETER The callback function was NULL.
     46   @retval EFI_OUT_OF_RESOURCES  The internal buffer ran out of space. No more functions can be
     47                                 registered.
     48   @retval EFI_ALREADY_STARTED   The function was already registered. It can't be registered again.
     49 
     50 **/
     51 EFI_STATUS
     52 EFIAPI
     53 Register (
     54   IN EFI_SMM_RSC_HANDLER_CALLBACK   Callback
     55   )
     56 {
     57   LIST_ENTRY                      *Link;
     58   SMM_RSC_HANDLER_CALLBACK_ENTRY  *CallbackEntry;
     59 
     60   if (Callback == NULL) {
     61     return EFI_INVALID_PARAMETER;
     62   }
     63 
     64   for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
     65     CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
     66     if (CallbackEntry->RscHandlerCallback == Callback) {
     67       //
     68       // If the function was already registered. It can't be registered again.
     69       //
     70       return EFI_ALREADY_STARTED;
     71     }
     72   }
     73 
     74   CallbackEntry = (SMM_RSC_HANDLER_CALLBACK_ENTRY *)AllocatePool (sizeof (SMM_RSC_HANDLER_CALLBACK_ENTRY));
     75   ASSERT (CallbackEntry != NULL);
     76 
     77   CallbackEntry->Signature          = SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;
     78   CallbackEntry->RscHandlerCallback = Callback;
     79 
     80   InsertTailList (&mCallbackListHead, &CallbackEntry->Node);
     81 
     82   return EFI_SUCCESS;
     83 }
     84 
     85 /**
     86   Remove a previously registered callback function from the notification list.
     87 
     88   ReportStatusCode() messages will no longer be forwarded to the Callback function.
     89 
     90   @param[in] Callback           A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is to be
     91                                 unregistered.
     92 
     93   @retval EFI_SUCCESS           The function was successfully unregistered.
     94   @retval EFI_INVALID_PARAMETER The callback function was NULL.
     95   @retval EFI_NOT_FOUND         The callback function was not found to be unregistered.
     96 
     97 **/
     98 EFI_STATUS
     99 EFIAPI
    100 Unregister (
    101   IN EFI_SMM_RSC_HANDLER_CALLBACK Callback
    102   )
    103 {
    104   LIST_ENTRY                        *Link;
    105   SMM_RSC_HANDLER_CALLBACK_ENTRY    *CallbackEntry;
    106 
    107   if (Callback == NULL) {
    108     return EFI_INVALID_PARAMETER;
    109   }
    110 
    111   for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
    112     CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
    113     if (CallbackEntry->RscHandlerCallback == Callback) {
    114       //
    115       // If the function is found in list, delete it and return.
    116       //
    117       RemoveEntryList (&CallbackEntry->Node);
    118       FreePool (CallbackEntry);
    119       return EFI_SUCCESS;
    120     }
    121   }
    122 
    123   return EFI_NOT_FOUND;
    124 }
    125 
    126 
    127 /**
    128   Provides an interface that a software module can call to report a status code.
    129 
    130   @param  This             EFI_SMM_STATUS_CODE_PROTOCOL instance.
    131   @param  Type             Indicates the type of status code being reported.
    132   @param  Value            Describes the current status of a hardware or software entity.
    133                            This included information about the class and subclass that is used to
    134                            classify the entity as well as an operation.
    135   @param  Instance         The enumeration of a hardware or software entity within
    136                            the system. Valid instance numbers start with 1.
    137   @param  CallerId         This optional parameter may be used to identify the caller.
    138                            This parameter allows the status code driver to apply different rules to
    139                            different callers.
    140   @param  Data             This optional parameter may be used to pass additional data.
    141 
    142   @retval EFI_SUCCESS           The function completed successfully
    143   @retval EFI_DEVICE_ERROR      The function should not be completed due to a device error.
    144 
    145 **/
    146 EFI_STATUS
    147 EFIAPI
    148 ReportDispatcher (
    149   IN CONST EFI_SMM_STATUS_CODE_PROTOCOL  *This,
    150   IN EFI_STATUS_CODE_TYPE                Type,
    151   IN EFI_STATUS_CODE_VALUE               Value,
    152   IN UINT32                              Instance,
    153   IN CONST EFI_GUID                      *CallerId  OPTIONAL,
    154   IN EFI_STATUS_CODE_DATA                *Data      OPTIONAL
    155   )
    156 {
    157   LIST_ENTRY                        *Link;
    158   SMM_RSC_HANDLER_CALLBACK_ENTRY    *CallbackEntry;
    159 
    160   //
    161   // Use atom operation to avoid the reentant of report.
    162   // If current status is not zero, then the function is reentrancy.
    163   //
    164   if (InterlockedCompareExchange32 (&mStatusCodeNestStatus, 0, 1) == 1) {
    165     return EFI_DEVICE_ERROR;
    166   }
    167 
    168   for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link);) {
    169     CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
    170     //
    171     // The handler may remove itself, so get the next handler in advance.
    172     //
    173     Link = GetNextNode (&mCallbackListHead, Link);
    174     CallbackEntry->RscHandlerCallback (
    175                      Type,
    176                      Value,
    177                      Instance,
    178                      (EFI_GUID*)CallerId,
    179                      Data
    180                      );
    181 
    182   }
    183 
    184   //
    185   // Restore the nest status of report
    186   //
    187   InterlockedCompareExchange32 (&mStatusCodeNestStatus, 1, 0);
    188 
    189   return EFI_SUCCESS;
    190 }
    191 
    192 /**
    193   Entry point of Generic Status Code Driver.
    194 
    195   This function is the entry point of SMM Status Code Router .
    196   It produces SMM Report Stataus Code Handler and Status Code protocol.
    197 
    198   @param  ImageHandle       The firmware allocated handle for the EFI image.
    199   @param  SystemTable       A pointer to the EFI System Table.
    200 
    201   @retval EFI_SUCCESS       The entry point is executed successfully.
    202 
    203 **/
    204 EFI_STATUS
    205 EFIAPI
    206 GenericStatusCodeSmmEntry (
    207   IN EFI_HANDLE         ImageHandle,
    208   IN EFI_SYSTEM_TABLE   *SystemTable
    209   )
    210 {
    211   EFI_STATUS     Status;
    212   EFI_HANDLE     Handle;
    213 
    214   Handle     = NULL;
    215 
    216   //
    217   // Install SmmRscHandler Protocol
    218   //
    219   Status = gSmst->SmmInstallProtocolInterface (
    220                     &Handle,
    221                     &gEfiSmmRscHandlerProtocolGuid,
    222                     EFI_NATIVE_INTERFACE,
    223                     &mSmmRscHandlerProtocol
    224                     );
    225   ASSERT_EFI_ERROR (Status);
    226 
    227   //
    228   // Install SmmStatusCode Protocol
    229   //
    230   Status = gSmst->SmmInstallProtocolInterface (
    231                     &Handle,
    232                     &gEfiSmmStatusCodeProtocolGuid,
    233                     EFI_NATIVE_INTERFACE,
    234                     &mSmmStatusCodeProtocol
    235                     );
    236   ASSERT_EFI_ERROR (Status);
    237 
    238   return EFI_SUCCESS;
    239 }
    240