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