1/*++
2
3Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
4This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution.  The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12
13Module Name:
14
15  ReportStatusCodeLib.c
16
17Abstract:
18
19  Report Status Code Library for SMM Runtime driver.
20
21--*/
22
23#include "ReportStatusCodeLibInternal.h"
24
25
26EFI_REPORT_STATUS_CODE  mReportStatusCode = NULL;
27
28/**
29  Internal worker function that reports a status code through the Status Code Protocol
30
31  This function checks to see if a Status Code Protocol is present in the handle
32  database.  If a Status Code Protocol is not present, then EFI_UNSUPPORTED is
33  returned.  If a Status Code Protocol is present, then it is cached in gStatusCode,
34  and the ReportStatusCode() service of the Status Code Protocol is called passing in
35  Type, Value, Instance, CallerId, and Data.  The result of this call is returned.
36
37  @param  Type              Status code type.
38  @param  Value             Status code value.
39  @param  Instance          Status code instance number.
40  @param  CallerId          Pointer to a GUID that identifies the caller of this
41                            function.  This is an optional parameter that may be
42                            NULL.
43  @param  Data              Pointer to the extended data buffer.  This is an
44                            optional parameter that may be NULL.
45
46  @retval  EFI_SUCCESS           The status code was reported.
47  @retval  EFI_OUT_OF_RESOURCES  There were not enough resources to report the status code.
48  @retval  EFI_UNSUPPORTED       Status Code Protocol is not available.
49
50**/
51EFI_STATUS
52InternalReportStatusCode (
53  IN EFI_STATUS_CODE_TYPE     Type,
54  IN EFI_STATUS_CODE_VALUE    Value,
55  IN UINT32                   Instance,
56  IN CONST EFI_GUID           *CallerId OPTIONAL,
57  IN EFI_STATUS_CODE_DATA     *Data     OPTIONAL
58  )
59{
60  //
61  // If gStatusCode is NULL, then see if a Status Code Protocol instance is present
62  // in the handle database.
63  //
64  if (mReportStatusCode == NULL) {
65    mReportStatusCode = InternalGetReportStatusCode ();
66    if (mReportStatusCode == NULL) {
67      return EFI_UNSUPPORTED;
68    }
69  }
70
71  //
72  // A Status Code Protocol is present in the handle database, so pass in all the
73  // parameters to the ReportStatusCode() service of the Status Code Protocol
74  //
75  return (*mReportStatusCode) (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
76}
77
78
79/**
80  Computes and returns the size, in bytes, of a device path.
81
82  @param  DevicePath  A pointer to a device path.
83
84  @return  The size, in bytes, of DevicePath.
85
86**/
87UINTN
88InternalReportStatusCodeDevicePathSize (
89  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
90  )
91{
92  CONST EFI_DEVICE_PATH_PROTOCOL  *Start;
93
94  //
95  // Search for the end of the device path structure
96  //
97  Start = DevicePath;
98  while (!IsDevicePathEnd (DevicePath)) {
99    DevicePath = NextDevicePathNode (DevicePath);
100  }
101
102  //
103  // Subtract the start node from the end node and add in the size of the end node
104  //
105  return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath);
106}
107
108
109/**
110  Converts a status code to an 8-bit POST code value.
111
112  Converts the status code specified by CodeType and Value to an 8-bit POST code
113  and returns the 8-bit POST code in PostCode.  If CodeType is an
114  EFI_PROGRESS_CODE or CodeType is an EFI_ERROR_CODE, then bits 0..4 of PostCode
115  are set to bits 16..20 of Value, and bits 5..7 of PostCode are set to bits
116  24..26 of Value., and TRUE is returned.  Otherwise, FALSE is returned.
117
118  If PostCode is NULL, then ASSERT().
119
120  @param  CodeType  The type of status code being converted.
121  @param  Value     The status code value being converted.
122  @param  PostCode  A pointer to the 8-bit POST code value to return.
123
124  @retval  TRUE   The status code specified by CodeType and Value was converted
125                  to an 8-bit POST code and returned in  PostCode.
126  @retval  FALSE  The status code specified by CodeType and Value could not be
127                  converted to an 8-bit POST code value.
128
129**/
130BOOLEAN
131EFIAPI
132GlueCodeTypeToPostCode (
133  IN  EFI_STATUS_CODE_TYPE   CodeType,
134  IN  EFI_STATUS_CODE_VALUE  Value,
135  OUT UINT8                  *PostCode
136  )
137{
138  //
139  // If PostCode is NULL, then ASSERT()
140  //
141  ASSERT (PostCode != NULL);
142
143  //
144  // Convert Value to an 8 bit post code
145  //
146  if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
147      ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)       ) {
148    *PostCode  = (UINT8) ((((Value & EFI_STATUS_CODE_CLASS_MASK) >> 24) << 5) |
149                          (((Value & EFI_STATUS_CODE_SUBCLASS_MASK) >> 16) & 0x1f));
150    return TRUE;
151  }
152  return FALSE;
153}
154
155
156/**
157  Extracts ASSERT() information from a status code structure.
158
159  Converts the status code specified by CodeType, Value, and Data to the ASSERT()
160  arguments specified by Filename, Description, and LineNumber.  If CodeType is
161  an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
162  Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
163  Filename, Description, and LineNumber from the optional data area of the
164  status code buffer specified by Data.  The optional data area of Data contains
165  a Null-terminated ASCII string for the FileName, followed by a Null-terminated
166  ASCII string for the Description, followed by a 32-bit LineNumber.  If the
167  ASSERT() information could be extracted from Data, then return TRUE.
168  Otherwise, FALSE is returned.
169
170  If Data is NULL, then ASSERT().
171  If Filename is NULL, then ASSERT().
172  If Description is NULL, then ASSERT().
173  If LineNumber is NULL, then ASSERT().
174
175  @param  CodeType     The type of status code being converted.
176  @param  Value        The status code value being converted.
177  @param  Data         Pointer to status code data buffer.
178  @param  Filename     Pointer to the source file name that generated the ASSERT().
179  @param  Description  Pointer to the description of the ASSERT().
180  @param  LineNumber   Pointer to source line number that generated the ASSERT().
181
182  @retval  TRUE   The status code specified by CodeType, Value, and Data was
183                  converted ASSERT() arguments specified by Filename, Description,
184                  and LineNumber.
185  @retval  FALSE  The status code specified by CodeType, Value, and Data could
186                  not be converted to ASSERT() arguments.
187
188**/
189BOOLEAN
190EFIAPI
191GlueReportStatusCodeExtractAssertInfo (
192  IN EFI_STATUS_CODE_TYPE        CodeType,
193  IN EFI_STATUS_CODE_VALUE       Value,
194  IN CONST EFI_STATUS_CODE_DATA  *Data,
195  OUT CHAR8                      **Filename,
196  OUT CHAR8                      **Description,
197  OUT UINT32                     *LineNumber
198  )
199{
200  EFI_DEBUG_ASSERT_DATA  *AssertData;
201
202  ASSERT (Data        != NULL);
203  ASSERT (Filename    != NULL);
204  ASSERT (Description != NULL);
205  ASSERT (LineNumber  != NULL);
206
207  if (((CodeType & EFI_STATUS_CODE_TYPE_MASK)      == EFI_ERROR_CODE) &&
208      ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK)  == EFI_ERROR_UNRECOVERED) &&
209      ((Value    & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
210    AssertData   = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
211    *Filename    = (CHAR8 *)(AssertData + 1);
212    *Description = *Filename + AsciiStrLen (*Filename) + 1;
213    *LineNumber  = AssertData->LineNumber;
214    return TRUE;
215  }
216  return FALSE;
217}
218
219
220/**
221  Extracts DEBUG() information from a status code structure.
222
223  Converts the status code specified by Data to the DEBUG() arguments specified
224  by ErrorLevel, Marker, and Format.  If type GUID in Data is
225  EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
226  Format from the optional data area of the status code buffer specified by Data.
227  The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
228  which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
229  the Format.  If the DEBUG() information could be extracted from Data, then
230  return TRUE.  Otherwise, FALSE is returned.
231
232  If Data is NULL, then ASSERT().
233  If ErrorLevel is NULL, then ASSERT().
234  If Marker is NULL, then ASSERT().
235  If Format is NULL, then ASSERT().
236
237  @param  Data        Pointer to status code data buffer.
238  @param  ErrorLevel  Pointer to error level mask for a debug message.
239  @param  Marker      Pointer to the variable argument list associated with Format.
240  @param  Format      Pointer to a Null-terminated ASCII format string of a
241                      debug message.
242
243  @retval  TRUE   The status code specified by Data was converted DEBUG() arguments
244                  specified by ErrorLevel, Marker, and Format.
245  @retval  FALSE  The status code specified by Data could not be converted to
246                  DEBUG() arguments.
247
248**/
249BOOLEAN
250EFIAPI
251GlueReportStatusCodeExtractDebugInfo (
252  IN CONST EFI_STATUS_CODE_DATA  *Data,
253  OUT UINT32                     *ErrorLevel,
254  OUT VA_LIST                    *Marker,
255  OUT CHAR8                      **Format
256  )
257{
258  EFI_DEBUG_INFO  *DebugInfo;
259
260  ASSERT (Data       != NULL);
261  ASSERT (ErrorLevel != NULL);
262  ASSERT (Marker     != NULL);
263  ASSERT (Format     != NULL);
264
265  //
266  // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
267  //
268  if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
269    return FALSE;
270  }
271
272  //
273  // Retrieve the debug information from the status code record
274  //
275  DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
276
277  *ErrorLevel = DebugInfo->ErrorLevel;
278
279  //
280  // The first 12 * UINTN bytes of the string are really an
281  // argument stack to support varargs on the Format string.
282  //
283#ifdef __APPLE__
284  // This is non portable C code you can't assume VA_LIST is pointer
285  return FALSE;
286#else
287  *Marker = (VA_LIST) (DebugInfo + 1);
288#endif
289  *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
290
291  return TRUE;
292}
293
294
295/**
296  Reports a status code.
297
298  Reports the status code specified by the parameters Type and Value.  Status
299  code also require an instance, caller ID, and extended data.  This function
300  passed in a zero instance, NULL extended data, and a caller ID of
301  gEfiCallerIdGuid, which is the GUID for the module.
302
303  ReportStatusCode()must actively prevent recusrsion.  If ReportStatusCode()
304  is called while processing another any other Report Status Code Library function,
305  then ReportStatusCode() must return immediately.
306
307  @param  Type   Status code type.
308  @param  Value  Status code value.
309
310  @retval  EFI_SUCCESS       The status code was reported.
311  @retval  EFI_DEVICE_ERROR  There status code could not be reported due to a
312                             device error.
313  @retval  EFI_UNSUPPORTED   Report status code is not supported
314
315**/
316EFI_STATUS
317EFIAPI
318GlueReportStatusCode (
319  IN EFI_STATUS_CODE_TYPE   Type,
320  IN EFI_STATUS_CODE_VALUE  Value
321  )
322{
323  return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
324}
325
326
327/**
328  Reports a status code with a Device Path Protocol as the extended data.
329
330  Allocates and fills in the extended data section of a status code with the
331  Device Path Protocol specified by DevicePath.  This function is responsible
332  for allocating a buffer large enough for the standard header and the device
333  path.  The standard header is filled in with a GUID of
334  gEfiStatusCodeSpecificDataGuid.  The status code is reported with a zero
335  instance and a caller ID of gEfiCallerIdGuid.
336
337  ReportStatusCodeWithDevicePath()must actively prevent recursion.  If
338  ReportStatusCodeWithDevicePath() is called while processing another any other
339  Report Status Code Library function, then ReportStatusCodeWithDevicePath()
340  must return EFI_DEVICE_ERROR immediately.
341
342  If DevicePath is NULL, then ASSERT().
343
344  @param  Type        Status code type.
345  @param  Value       Status code value.
346  @param  DevicePath  Pointer to the Device Path Protocol to be reported.
347
348  @retval  EFI_SUCCESS           The status code was reported with the extended
349                                 data specified by DevicePath.
350  @retval  EFI_OUT_OF_RESOURCES  There were not enough resources to allocate the
351                                 extended data section.
352  @retval  EFI_UNSUPPORTED       Report status code is not supported
353
354**/
355EFI_STATUS
356EFIAPI
357GlueReportStatusCodeWithDevicePath (
358  IN EFI_STATUS_CODE_TYPE            Type,
359  IN EFI_STATUS_CODE_VALUE           Value,
360  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
361  )
362{
363  ASSERT (DevicePath != NULL);
364  return ReportStatusCodeWithExtendedData (
365           Type,
366           Value,
367           (VOID *)DevicePath,
368           InternalReportStatusCodeDevicePathSize (DevicePath)
369           );
370}
371
372
373/**
374  Reports a status code with an extended data buffer.
375
376  Allocates and fills in the extended data section of a status code with the
377  extended data specified by ExtendedData and ExtendedDataSize.  ExtendedData
378  is assumed to be one of the data structures specified in Related Definitions.
379  These data structure do not have the standard header, so this function is
380  responsible for allocating a buffer large enough for the standard header and
381  the extended data passed into this function.  The standard header is filled
382  in with a GUID of  gEfiStatusCodeSpecificDataGuid.  The status code is reported
383  with a zero instance and a caller ID of gEfiCallerIdGuid.
384
385  ReportStatusCodeWithExtendedData()must actively prevent recursion.  If
386  ReportStatusCodeWithExtendedData() is called while processing another any other
387  Report Status Code Library function, then ReportStatusCodeWithExtendedData()
388  must return EFI_DEVICE_ERROR immediately.
389
390  If ExtendedData is NULL, then ASSERT().
391  If ExtendedDataSize is 0, then ASSERT().
392
393  @param  Type              Status code type.
394  @param  Value             Status code value.
395  @param  ExtendedData      Pointer to the extended data buffer to be reported.
396  @param  ExtendedDataSize  The size, in bytes, of the extended data buffer to
397                            be reported.
398
399  @retval  EFI_SUCCESS           The status code was reported with the extended
400                                 data specified by ExtendedData and ExtendedDataSize.
401  @retval  EFI_OUT_OF_RESOURCES  There were not enough resources to allocate the
402                                 extended data section.
403  @retval  EFI_UNSUPPORTED       Report status code is not supported
404
405**/
406EFI_STATUS
407EFIAPI
408GlueReportStatusCodeWithExtendedData (
409  IN EFI_STATUS_CODE_TYPE   Type,
410  IN EFI_STATUS_CODE_VALUE  Value,
411  IN CONST VOID             *ExtendedData,
412  IN UINTN                  ExtendedDataSize
413  )
414{
415  ASSERT (ExtendedData     != NULL);
416  ASSERT (ExtendedDataSize != 0);
417  return ReportStatusCodeEx (
418           Type,
419           Value,
420           0,
421           NULL,
422           NULL,
423           ExtendedData,
424           ExtendedDataSize
425           );
426}
427
428
429/**
430  Reports a status code with full parameters.
431
432  The function reports a status code.  If ExtendedData is NULL and ExtendedDataSize
433  is 0, then an extended data buffer is not reported.  If ExtendedData is not
434  NULL and ExtendedDataSize is not 0, then an extended data buffer is allocated.
435  ExtendedData is assumed not have the standard status code header, so this function
436  is responsible for allocating a buffer large enough for the standard header and
437  the extended data passed into this function.  The standard header is filled in
438  with a GUID specified by ExtendedDataGuid.  If ExtendedDataGuid is NULL, then a
439  GUID of gEfiStatusCodeSpecificDatauid is used.  The status code is reported with
440  an instance specified by Instance and a caller ID specified by CallerId.  If
441  CallerId is NULL, then a caller ID of gEfiCallerIdGuid is used.
442
443  ReportStatusCodeEx()must actively prevent recursion. If
444  ReportStatusCodeEx() is called while processing another any
445  other Report Status Code Library function, then
446  ReportStatusCodeEx() must return EFI_DEVICE_ERROR immediately.
447
448  If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
449  If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
450
451  @param  Type              Status code type.
452  @param  Value             Status code value.
453  @param  Instance          Status code instance number.
454  @param  CallerId          Pointer to a GUID that identifies the caller of this
455                            function.  If this parameter is NULL, then a caller
456                            ID of gEfiCallerIdGuid is used.
457  @param  ExtendedDataGuid  Pointer to the GUID for the extended data buffer.
458                            If this parameter is NULL, then a the status code
459                            standard header is filled in with
460                            gEfiStatusCodeSpecificDataGuid.
461  @param  ExtendedData      Pointer to the extended data buffer.  This is an
462                            optional parameter that may be NULL.
463  @param  ExtendedDataSize  The size, in bytes, of the extended data buffer.
464
465  @retval  EFI_SUCCESS           The status code was reported.
466  @retval  EFI_OUT_OF_RESOURCES  There were not enough resources to allocate
467                                 the extended data section if it was specified.
468  @retval  EFI_UNSUPPORTED       Report status code is not supported
469
470**/
471EFI_STATUS
472EFIAPI
473GlueReportStatusCodeEx (
474  IN EFI_STATUS_CODE_TYPE   Type,
475  IN EFI_STATUS_CODE_VALUE  Value,
476  IN UINT32                 Instance,
477  IN CONST EFI_GUID         *CallerId          OPTIONAL,
478  IN CONST EFI_GUID         *ExtendedDataGuid  OPTIONAL,
479  IN CONST VOID             *ExtendedData      OPTIONAL,
480  IN UINTN                  ExtendedDataSize
481  )
482{
483  EFI_STATUS  Status;
484
485  Status = InternalReportStatusCodeEx (
486             Type,
487             Value,
488             Instance,
489             CallerId,
490             ExtendedDataGuid,
491             ExtendedData,
492             ExtendedDataSize
493             );
494
495  return Status;
496}
497
498
499/**
500  Returns TRUE if status codes of type EFI_PROGRESS_CODE are enabled
501
502  This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED
503  bit of PcdReportStatusCodeProperyMask is set.  Otherwise FALSE is returned.
504
505  @retval  TRUE   The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
506                  PcdReportStatusCodeProperyMask is set.
507  @retval  FALSE  The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
508                  PcdReportStatusCodeProperyMask is clear.
509
510**/
511BOOLEAN
512EFIAPI
513GlueReportProgressCodeEnabled (
514  VOID
515  )
516{
517  return (BOOLEAN) ((PcdGet8(PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
518}
519
520
521/**
522  Returns TRUE if status codes of type EFI_ERROR_CODE are enabled
523
524  This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED
525  bit of PcdReportStatusCodeProperyMask is set.  Otherwise FALSE is returned.
526
527  @retval  TRUE   The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
528                  PcdReportStatusCodeProperyMask is set.
529  @retval  FALSE  The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
530                  PcdReportStatusCodeProperyMask is clear.
531
532**/
533BOOLEAN
534EFIAPI
535GlueReportErrorCodeEnabled (
536  VOID
537  )
538{
539  return (BOOLEAN) ((PcdGet8(PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED) != 0);
540}
541
542
543/**
544  Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
545
546  This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
547  bit of PcdReportStatusCodeProperyMask is set.  Otherwise FALSE is returned.
548
549  @retval  TRUE   The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
550                  PcdReportStatusCodeProperyMask is set.
551  @retval  FALSE  The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
552                  PcdReportStatusCodeProperyMask is clear.
553
554**/
555BOOLEAN
556EFIAPI
557GlueReportDebugCodeEnabled (
558  VOID
559  )
560{
561  return (BOOLEAN) ((PcdGet8(PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
562}
563