1 /** @file
2 Library that helps implement monolithic PEI
3
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5
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 <PrePi.h>
17 #include <Library/ReportStatusCodeLib.h>
18 #include <Library/SerialPortLib.h>
19 #include <Library/PrintLib.h>
20
21 #include <Protocol/StatusCode.h>
22 #include <Guid/StatusCodeDataTypeId.h>
23 #include <Guid/StatusCodeDataTypeDebug.h>
24 #include <FrameworkPei.h>
25
26 EFI_STATUS
27 EFIAPI
28 SerialReportStatusCode (
29 IN EFI_STATUS_CODE_TYPE CodeType,
30 IN EFI_STATUS_CODE_VALUE Value,
31 IN UINT32 Instance,
32 IN CONST EFI_GUID *CallerId,
33 IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
34 );
35
36
37 EFI_STATUS_CODE_PROTOCOL gStatusCode = {
38 (EFI_REPORT_STATUS_CODE)SerialReportStatusCode
39 };
40
41 /**
42 Extracts ASSERT() information from a status code structure.
43
44 Converts the status code specified by CodeType, Value, and Data to the ASSERT()
45 arguments specified by Filename, Description, and LineNumber. If CodeType is
46 an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
47 Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
48 Filename, Description, and LineNumber from the optional data area of the
49 status code buffer specified by Data. The optional data area of Data contains
50 a Null-terminated ASCII string for the FileName, followed by a Null-terminated
51 ASCII string for the Description, followed by a 32-bit LineNumber. If the
52 ASSERT() information could be extracted from Data, then return TRUE.
53 Otherwise, FALSE is returned.
54
55 If Data is NULL, then ASSERT().
56 If Filename is NULL, then ASSERT().
57 If Description is NULL, then ASSERT().
58 If LineNumber is NULL, then ASSERT().
59
60 @param CodeType The type of status code being converted.
61 @param Value The status code value being converted.
62 @param Data Pointer to status code data buffer.
63 @param Filename Pointer to the source file name that generated the ASSERT().
64 @param Description Pointer to the description of the ASSERT().
65 @param LineNumber Pointer to source line number that generated the ASSERT().
66
67 @retval TRUE The status code specified by CodeType, Value, and Data was
68 converted ASSERT() arguments specified by Filename, Description,
69 and LineNumber.
70 @retval FALSE The status code specified by CodeType, Value, and Data could
71 not be converted to ASSERT() arguments.
72
73 **/
74 BOOLEAN
75 EFIAPI
ReportStatusCodeExtractAssertInfo(IN EFI_STATUS_CODE_TYPE CodeType,IN EFI_STATUS_CODE_VALUE Value,IN CONST EFI_STATUS_CODE_DATA * Data,OUT CHAR8 ** Filename,OUT CHAR8 ** Description,OUT UINT32 * LineNumber)76 ReportStatusCodeExtractAssertInfo (
77 IN EFI_STATUS_CODE_TYPE CodeType,
78 IN EFI_STATUS_CODE_VALUE Value,
79 IN CONST EFI_STATUS_CODE_DATA *Data,
80 OUT CHAR8 **Filename,
81 OUT CHAR8 **Description,
82 OUT UINT32 *LineNumber
83 )
84 {
85 EFI_DEBUG_ASSERT_DATA *AssertData;
86
87 ASSERT (Data != NULL);
88 ASSERT (Filename != NULL);
89 ASSERT (Description != NULL);
90 ASSERT (LineNumber != NULL);
91
92 if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
93 ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&
94 ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
95 AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
96 *Filename = (CHAR8 *)(AssertData + 1);
97 *Description = *Filename + AsciiStrLen (*Filename) + 1;
98 *LineNumber = AssertData->LineNumber;
99 return TRUE;
100 }
101 return FALSE;
102 }
103
104
105 /**
106 Extracts DEBUG() information from a status code structure.
107
108 Converts the status code specified by Data to the DEBUG() arguments specified
109 by ErrorLevel, Marker, and Format. If type GUID in Data is
110 EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
111 Format from the optional data area of the status code buffer specified by Data.
112 The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
113 which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
114 the Format. If the DEBUG() information could be extracted from Data, then
115 return TRUE. Otherwise, FALSE is returned.
116
117 If Data is NULL, then ASSERT().
118 If ErrorLevel is NULL, then ASSERT().
119 If Marker is NULL, then ASSERT().
120 If Format is NULL, then ASSERT().
121
122 @param Data Pointer to status code data buffer.
123 @param ErrorLevel Pointer to error level mask for a debug message.
124 @param Marker Pointer to the variable argument list associated with Format.
125 @param Format Pointer to a Null-terminated ASCII format string of a
126 debug message.
127
128 @retval TRUE The status code specified by Data was converted DEBUG() arguments
129 specified by ErrorLevel, Marker, and Format.
130 @retval FALSE The status code specified by Data could not be converted to
131 DEBUG() arguments.
132
133 **/
134 BOOLEAN
135 EFIAPI
ReportStatusCodeExtractDebugInfo(IN CONST EFI_STATUS_CODE_DATA * Data,OUT UINT32 * ErrorLevel,OUT BASE_LIST * Marker,OUT CHAR8 ** Format)136 ReportStatusCodeExtractDebugInfo (
137 IN CONST EFI_STATUS_CODE_DATA *Data,
138 OUT UINT32 *ErrorLevel,
139 OUT BASE_LIST *Marker,
140 OUT CHAR8 **Format
141 )
142 {
143 EFI_DEBUG_INFO *DebugInfo;
144
145 ASSERT (Data != NULL);
146 ASSERT (ErrorLevel != NULL);
147 ASSERT (Marker != NULL);
148 ASSERT (Format != NULL);
149
150 //
151 // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
152 //
153 if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
154 return FALSE;
155 }
156
157 //
158 // Retrieve the debug information from the status code record
159 //
160 DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
161
162 *ErrorLevel = DebugInfo->ErrorLevel;
163
164 //
165 // The first 12 * UINTN bytes of the string are really an
166 // argument stack to support varargs on the Format string.
167 //
168 *Marker = (BASE_LIST) (DebugInfo + 1);
169 *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
170
171 return TRUE;
172 }
173
174
175
176
177 EFI_STATUS
178 EFIAPI
SerialReportStatusCode(IN EFI_STATUS_CODE_TYPE CodeType,IN EFI_STATUS_CODE_VALUE Value,IN UINT32 Instance,IN CONST EFI_GUID * CallerId,IN CONST EFI_STATUS_CODE_DATA * Data OPTIONAL)179 SerialReportStatusCode (
180 IN EFI_STATUS_CODE_TYPE CodeType,
181 IN EFI_STATUS_CODE_VALUE Value,
182 IN UINT32 Instance,
183 IN CONST EFI_GUID *CallerId,
184 IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
185 )
186 {
187 CHAR8 *Filename;
188 CHAR8 *Description;
189 CHAR8 *Format;
190 CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE];
191 UINT32 ErrorLevel;
192 UINT32 LineNumber;
193 UINTN CharCount;
194 BASE_LIST Marker;
195 EFI_DEBUG_INFO *DebugInfo;
196
197 Buffer[0] = '\0';
198
199
200 if (Data != NULL &&
201 ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
202
203 //
204 // Print ASSERT() information into output buffer.
205 //
206 CharCount = AsciiSPrint (
207 Buffer,
208 EFI_STATUS_CODE_DATA_MAX_SIZE,
209 "\n\rASSERT!: %a (%d): %a\n\r",
210 Filename,
211 LineNumber,
212 Description
213 );
214
215
216 //
217 // Callout to standard output.
218 //
219 SerialPortWrite ((UINT8 *)Buffer, CharCount);
220 return EFI_SUCCESS;
221
222 } else if (Data != NULL &&
223 ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
224
225 //
226 // Print DEBUG() information into output buffer.
227 //
228 CharCount = AsciiBSPrint (
229 Buffer,
230 EFI_STATUS_CODE_DATA_MAX_SIZE,
231 Format,
232 Marker
233 );
234
235 } else if (Data != NULL &&
236 CompareGuid (&Data->Type, &gEfiStatusCodeSpecificDataGuid) &&
237 (CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
238
239 //
240 // Print specific data into output buffer.
241 //
242 DebugInfo = (EFI_DEBUG_INFO *) (Data + 1);
243 Marker = (BASE_LIST) (DebugInfo + 1);
244 Format = (CHAR8 *) (((UINT64 *) (DebugInfo + 1)) + 12);
245
246 CharCount = AsciiBSPrint (Buffer, EFI_STATUS_CODE_DATA_MAX_SIZE, Format, Marker);
247
248 } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
249 //
250 // Print ERROR information into output buffer.
251 //
252
253 CharCount = AsciiSPrint (
254 Buffer,
255 EFI_STATUS_CODE_DATA_MAX_SIZE,
256 "ERROR: C%x:V%x I%x",
257 CodeType,
258 Value,
259 Instance
260 );
261
262 //
263 // Make sure we don't try to print values that weren't intended to be printed, especially NULL GUID pointers.
264 //
265 if (CallerId != NULL) {
266 CharCount += AsciiSPrint (
267 &Buffer[CharCount - 1],
268 (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
269 " %g",
270 CallerId
271 );
272 }
273
274 if (Data != NULL) {
275 CharCount += AsciiSPrint (
276 &Buffer[CharCount - 1],
277 (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
278 " %x",
279 Data
280 );
281
282 }
283
284
285 CharCount += AsciiSPrint (
286 &Buffer[CharCount - 1],
287 (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
288 "\n\r"
289 );
290
291 } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
292 CharCount = AsciiSPrint (
293 Buffer,
294 EFI_STATUS_CODE_DATA_MAX_SIZE,
295 "PROGRESS CODE: V%x I%x\n\r",
296 Value,
297 Instance
298 );
299 } else {
300 CharCount = AsciiSPrint (
301 Buffer,
302 EFI_STATUS_CODE_DATA_MAX_SIZE,
303 "Undefined: C%x:V%x I%x\n\r",
304 CodeType,
305 Value,
306 Instance
307 );
308
309 }
310
311 SerialPortWrite ((UINT8 *)Buffer, CharCount);
312 return EFI_SUCCESS;
313
314 }
315
316
317 VOID
318 EFIAPI
AddDxeCoreReportStatusCodeCallback(VOID)319 AddDxeCoreReportStatusCodeCallback (
320 VOID
321 )
322 {
323 BuildGuidDataHob (&gEfiStatusCodeRuntimeProtocolGuid, &gStatusCode, sizeof(VOID *));
324 }
325
326