SmmRuntimeDxeSupport.c revision 3c28a7280b3f724d4b106d55e2efca37f65b0d2e
1/** @file
2  Library constructor & destructor, event handlers, and other internal worker functions.
3
4  Copyright (c) 2006 - 2011, 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 "ReportStatusCodeLibInternal.h"
16
17EFI_EVENT                     mVirtualAddressChangeEvent;
18EFI_EVENT                     mExitBootServicesEvent;
19EFI_STATUS_CODE_DATA          *mStatusCodeData;
20BOOLEAN                       mInSmm;
21EFI_SMM_BASE_PROTOCOL         *mSmmBase;
22EFI_RUNTIME_SERVICES          *mInternalRT;
23BOOLEAN                       mHaveExitedBootServices = FALSE;
24EFI_REPORT_STATUS_CODE        mReportStatusCode = NULL;
25EFI_SMM_STATUS_CODE_PROTOCOL  *mSmmStatusCodeProtocol;
26
27/**
28  Locates and caches SMM Status Code Protocol.
29
30**/
31VOID
32SmmStatusCodeInitialize (
33  VOID
34  )
35{
36  EFI_STATUS Status;
37
38  Status = gBS->LocateProtocol (&gEfiSmmStatusCodeProtocolGuid, NULL, (VOID **) &mSmmStatusCodeProtocol);
39  if (EFI_ERROR (Status)) {
40    mSmmStatusCodeProtocol = NULL;
41  }
42}
43
44/**
45  Report status code via SMM Status Code Protocol.
46
47  @param  Type          Indicates the type of status code being reported.
48  @param  Value         Describes the current status of a hardware or software entity.
49                        This included information about the class and subclass that is used to classify the entity
50                        as well as an operation.  For progress codes, the operation is the current activity.
51                        For error codes, it is the exception.  For debug codes, it is not defined at this time.
52  @param  Instance      The enumeration of a hardware or software entity within the system.
53                        A system may contain multiple entities that match a class/subclass pairing.
54                        The instance differentiates between them.  An instance of 0 indicates that instance information is unavailable,
55                        not meaningful, or not relevant.  Valid instance numbers start with 1.
56  @param  CallerId      This optional parameter may be used to identify the caller.
57                        This parameter allows the status code driver to apply different rules to different callers.
58  @param  Data          This optional parameter may be used to pass additional data
59
60  @retval EFI_SUCCESS   Always return EFI_SUCCESS.
61
62**/
63EFI_STATUS
64SmmStatusCodeReport (
65  IN EFI_STATUS_CODE_TYPE     Type,
66  IN EFI_STATUS_CODE_VALUE    Value,
67  IN UINT32                   Instance,
68  IN EFI_GUID                 *CallerId OPTIONAL,
69  IN EFI_STATUS_CODE_DATA     *Data     OPTIONAL
70  )
71{
72  if (mSmmStatusCodeProtocol != NULL) {
73    (mSmmStatusCodeProtocol->ReportStatusCode) (mSmmStatusCodeProtocol, Type, Value, Instance, CallerId, Data);
74  }
75  return EFI_SUCCESS;
76}
77
78/**
79  Locate the report status code service.
80
81  In SMM, it tries to retrieve SMM Status Code Protocol.
82  Otherwise, it first tries to retrieve ReportStatusCode() in Runtime Services Table.
83  If not found, it then tries to retrieve ReportStatusCode() API of Report Status Code Protocol.
84
85  @return   Function pointer to the report status code service.
86            NULL is returned if no status code service is available.
87
88**/
89EFI_REPORT_STATUS_CODE
90InternalGetReportStatusCode (
91  VOID
92  )
93{
94  EFI_STATUS_CODE_PROTOCOL  *StatusCodeProtocol;
95  EFI_STATUS                Status;
96
97  if (mInSmm) {
98    return (EFI_REPORT_STATUS_CODE) SmmStatusCodeReport;
99  } else if (mInternalRT != NULL && mInternalRT->Hdr.Revision < 0x20000) {
100    return ((FRAMEWORK_EFI_RUNTIME_SERVICES*)mInternalRT)->ReportStatusCode;
101  } else if (!mHaveExitedBootServices) {
102  	//
103  	// Check gBS just in case. ReportStatusCode is called before gBS is initialized.
104  	//
105    if (gBS != NULL) {
106      Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**)&StatusCodeProtocol);
107      if (!EFI_ERROR (Status) && StatusCodeProtocol != NULL) {
108        return StatusCodeProtocol->ReportStatusCode;
109      }
110    }
111  }
112
113  return NULL;
114}
115
116/**
117  Internal worker function that reports a status code through the status code service.
118
119  If status code service is not cached, then this function checks if status code service is
120  available in system.  If status code service is not available, then EFI_UNSUPPORTED is
121  returned.  If status code service is present, then it is cached in mReportStatusCode.
122  Finally this function reports status code through the status code service.
123
124  @param  Type              Status code type.
125  @param  Value             Status code value.
126  @param  Instance          Status code instance number.
127  @param  CallerId          Pointer to a GUID that identifies the caller of this
128                            function.  This is an optional parameter that may be
129                            NULL.
130  @param  Data              Pointer to the extended data buffer.  This is an
131                            optional parameter that may be NULL.
132
133  @retval EFI_SUCCESS       The status code was reported.
134  @retval EFI_UNSUPPORTED   Status code service is not available.
135  @retval EFI_UNSUPPORTED   Status code type is not supported.
136
137**/
138EFI_STATUS
139InternalReportStatusCode (
140  IN EFI_STATUS_CODE_TYPE     Type,
141  IN EFI_STATUS_CODE_VALUE    Value,
142  IN UINT32                   Instance,
143  IN CONST EFI_GUID           *CallerId OPTIONAL,
144  IN EFI_STATUS_CODE_DATA     *Data     OPTIONAL
145  )
146{
147  if ((ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
148      (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ||
149      (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)) {
150    //
151    // If mReportStatusCode is NULL, then check if status code service is available in system.
152    //
153    if (mReportStatusCode == NULL) {
154      mReportStatusCode = InternalGetReportStatusCode ();
155      if (mReportStatusCode == NULL) {
156        return EFI_UNSUPPORTED;
157      }
158    }
159
160    //
161    // A status code service is present in system, so pass in all the parameters to the service.
162    //
163    return (*mReportStatusCode) (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
164  }
165
166  return EFI_UNSUPPORTED;
167}
168
169/**
170  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
171
172  @param  Event        Event whose notification function is being invoked.
173  @param  Context      Pointer to the notification function's context
174
175**/
176VOID
177EFIAPI
178ReportStatusCodeLibVirtualAddressChange (
179  IN EFI_EVENT        Event,
180  IN VOID             *Context
181  )
182{
183  if (mReportStatusCode != NULL) {
184    mInternalRT->ConvertPointer (0, (VOID **) &mReportStatusCode);
185  }
186  mInternalRT->ConvertPointer (0, (VOID **) &mStatusCodeData);
187  mInternalRT->ConvertPointer (0, (VOID **) &mInternalRT);
188}
189
190/**
191  Notification function of EVT_SIGNAL_EXIT_BOOT_SERVICES.
192
193  @param  Event        Event whose notification function is being invoked.
194  @param  Context      Pointer to the notification function's context
195
196**/
197VOID
198EFIAPI
199ReportStatusCodeLibExitBootServices (
200  IN EFI_EVENT        Event,
201  IN VOID             *Context
202  )
203{
204  //
205  // If mReportStatusCode is NULL, then see if a Status Code Protocol instance is present
206  // in the handle database.
207  //
208  if (mReportStatusCode == NULL) {
209    mReportStatusCode = InternalGetReportStatusCode ();
210  }
211
212  mHaveExitedBootServices = TRUE;
213}
214
215/**
216  The constructor function of SMM Runtime DXE Report Status Code Lib.
217
218  This function allocates memory for extended status code data, caches
219  the report status code service, and registers events.
220
221  @param  ImageHandle   The firmware allocated handle for the EFI image.
222  @param  SystemTable   A pointer to the EFI System Table.
223
224  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
225
226**/
227EFI_STATUS
228EFIAPI
229ReportStatusCodeLibConstruct (
230  IN EFI_HANDLE           ImageHandle,
231  IN EFI_SYSTEM_TABLE     *SystemTable
232  )
233{
234  EFI_STATUS     Status;
235
236  //
237  // If in SMM mode, then allocates memory from SMRAM for extended status code data.
238  //
239  Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &mSmmBase);
240  if (!EFI_ERROR (Status)) {
241    mSmmBase->InSmm (mSmmBase, &mInSmm);
242    if (mInSmm) {
243      Status = mSmmBase->SmmAllocatePool (
244                           mSmmBase,
245                           EfiRuntimeServicesData,
246                           sizeof (EFI_STATUS_CODE_DATA) + EFI_STATUS_CODE_DATA_MAX_SIZE,
247                           (VOID **) &mStatusCodeData
248                           );
249      ASSERT_EFI_ERROR (Status);
250      SmmStatusCodeInitialize ();
251      return EFI_SUCCESS;
252    }
253  }
254
255
256  //
257  // If not in SMM mode, then allocate runtime memory for extended status code data.
258  //
259  // Library should not use the gRT directly, for it may be converted by other library instance.
260  //
261  mInternalRT = gRT;
262  mInSmm      = FALSE;
263
264  mStatusCodeData = AllocateRuntimePool (sizeof (EFI_STATUS_CODE_DATA) + EFI_STATUS_CODE_DATA_MAX_SIZE);
265  ASSERT (mStatusCodeData != NULL);
266  //
267  // Cache the report status code service
268  //
269  mReportStatusCode = InternalGetReportStatusCode ();
270
271  //
272  // Register notify function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
273  //
274  Status = gBS->CreateEventEx (
275                  EVT_NOTIFY_SIGNAL,
276                  TPL_NOTIFY,
277                  ReportStatusCodeLibVirtualAddressChange,
278                  NULL,
279                  &gEfiEventVirtualAddressChangeGuid,
280                  &mVirtualAddressChangeEvent
281                  );
282  ASSERT_EFI_ERROR (Status);
283
284  //
285  // Register notify function for EVT_SIGNAL_EXIT_BOOT_SERVICES
286  //
287  Status = gBS->CreateEventEx (
288                  EVT_NOTIFY_SIGNAL,
289                  TPL_NOTIFY,
290                  ReportStatusCodeLibExitBootServices,
291                  NULL,
292                  &gEfiEventExitBootServicesGuid,
293                  &mExitBootServicesEvent
294                  );
295  ASSERT_EFI_ERROR (Status);
296
297  return EFI_SUCCESS;
298}
299
300/**
301  The destructor function of SMM Runtime DXE Report Status Code Lib.
302
303  The destructor function frees memory allocated by constructor, and closes related events.
304  It will ASSERT() if that related operation fails and it will always return EFI_SUCCESS.
305
306  @param  ImageHandle   The firmware allocated handle for the EFI image.
307  @param  SystemTable   A pointer to the EFI System Table.
308
309  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
310
311**/
312EFI_STATUS
313EFIAPI
314ReportStatusCodeLibDestruct (
315  IN EFI_HANDLE        ImageHandle,
316  IN EFI_SYSTEM_TABLE  *SystemTable
317  )
318{
319  EFI_STATUS  Status;
320
321  if (!mInSmm) {
322    ASSERT (gBS != NULL);
323    Status = gBS->CloseEvent (mVirtualAddressChangeEvent);
324    ASSERT_EFI_ERROR (Status);
325    Status = gBS->CloseEvent (mExitBootServicesEvent);
326    ASSERT_EFI_ERROR (Status);
327
328    FreePool (mStatusCodeData);
329  } else {
330    mSmmBase->SmmFreePool (mSmmBase, mStatusCodeData);
331  }
332
333  return EFI_SUCCESS;
334}
335
336