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
Register(IN EFI_SMM_RSC_HANDLER_CALLBACK Callback)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
Unregister(IN EFI_SMM_RSC_HANDLER_CALLBACK Callback)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
ReportDispatcher(IN CONST EFI_SMM_STATUS_CODE_PROTOCOL * This,IN EFI_STATUS_CODE_TYPE Type,IN EFI_STATUS_CODE_VALUE Value,IN UINT32 Instance,IN CONST EFI_GUID * CallerId OPTIONAL,IN EFI_STATUS_CODE_DATA * Data OPTIONAL)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
GenericStatusCodeSmmEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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