1 /*++
2 
3 Copyright (c) 2004, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   ReportStatusCode.c
15 
16 Abstract:
17 
18   Worker functions for ReportStatusCode
19 
20 --*/
21 
22 #include "TianoCommon.h"
23 #include "EfiCommonLib.h"
24 #include EFI_GUID_DEFINITION (StatusCodeCallerId)
25 #include EFI_GUID_DEFINITION (StatusCodeDataTypeId)
26 
27 
28 VOID *
EfiConstructStatusCodeData(IN UINT16 DataSize,IN EFI_GUID * TypeGuid,IN OUT EFI_STATUS_CODE_DATA * Data)29 EfiConstructStatusCodeData (
30   IN  UINT16                    DataSize,
31   IN  EFI_GUID                  *TypeGuid,
32   IN OUT  EFI_STATUS_CODE_DATA  *Data
33   )
34 /*++
35 
36 Routine Description:
37 
38   Construct stanader header for optional data passed into ReportStatusCode
39 
40 Arguments:
41 
42   DataSize - Size of optional data. Does not include EFI_STATUS_CODE_DATA header
43   TypeGuid - GUID to place in EFI_STATUS_CODE_DATA
44   Data     - Buffer to use.
45 
46 Returns:
47 
48   Return pointer to Data buffer pointing past the end of EFI_STATUS_CODE_DATA
49 
50 --*/
51 {
52   Data->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
53   Data->Size = (UINT16)(DataSize - sizeof (EFI_STATUS_CODE_DATA));
54   EfiCommonLibCopyMem (&Data->Type, TypeGuid, sizeof (EFI_GUID));
55 
56   return (VOID *)(Data + 1);
57 }
58 
59 EFI_STATUS
EfiDebugVPrintWorker(IN UINTN ErrorLevel,IN CHAR8 * Format,IN VA_LIST Marker,IN UINTN BufferSize,IN OUT VOID * Buffer)60 EfiDebugVPrintWorker (
61   IN  UINTN                   ErrorLevel,
62   IN  CHAR8                   *Format,
63   IN  VA_LIST                 Marker,
64   IN  UINTN                   BufferSize,
65   IN OUT VOID                 *Buffer
66   )
67 /*++
68 
69 Routine Description:
70 
71   Worker function for DEBUG(). If Error Logging hub is loaded log ASSERT
72   information. If Error Logging hub is not loaded do nothing.
73 
74   The Format string might be truncated to fit into the status code struture
75   which has the max size of EFI_STATUS_CODE_DATA_MAX_SIZE.
76 
77   We use UINT64 buffers due to IPF alignment concerns.
78 
79 Arguments:
80 
81   ErrorLevel - If error level is set do the debug print.
82 
83   Format     - String to use for the print, followed by Print arguments.
84 
85   Marker     - VarArgs
86 
87   BufferSize - Size of Buffer.
88 
89   Buffer     - Caller allocated buffer, contains ReportStatusCode extended data
90 
91 Returns:
92 
93   Status code
94 
95   EFI_SUCCESS             - Successfully printed
96 
97 --*/
98 {
99   UINTN                   Index;
100   UINTN                   FormatStrLen;
101   UINTN                   RemainingStrLen;
102   UINT64                  *Ptr;
103   EFI_DEBUG_INFO          *EfiDebug;
104 
105 
106   //
107   // Build the type specific EFI_STATUS_CODE_DATA in order
108   //
109 
110   //
111   // Fill in EFI_STATUS_CODE_DATA to Buffer.
112   //
113   EfiDebug = (EFI_DEBUG_INFO *)EfiConstructStatusCodeData (
114                                 (UINT16)BufferSize,
115                                 &gEfiStatusCodeDataTypeDebugGuid,
116                                 Buffer
117                                 );
118 
119   //
120   // Then EFI_DEBUG_INFO
121   //
122   EfiDebug->ErrorLevel = (UINT32)ErrorLevel;
123 
124   //
125   // 12 * sizeof (UINT64) byte mini Var Arg stack.
126   // That is followed by the format string.
127   //
128   for (Index = 0, Ptr = (UINT64 *)(EfiDebug + 1); Index < 12; Index++, Ptr++) {
129     *Ptr = VA_ARG (Marker, UINT64);
130   }
131 
132   //
133   // Place Ascii Format string at the end
134   // Truncate it to fit into the status code structure
135   //
136   FormatStrLen    = EfiAsciiStrLen (Format);
137   RemainingStrLen = EFI_STATUS_CODE_DATA_MAX_SIZE
138     - sizeof (EFI_STATUS_CODE_DATA)
139     - sizeof (EFI_DEBUG_INFO)
140     - 12 * sizeof (UINT64) - 1;
141   if (FormatStrLen > RemainingStrLen) {
142     FormatStrLen = RemainingStrLen;
143   }
144   EfiCommonLibCopyMem (Ptr, Format, FormatStrLen);
145   *((CHAR8 *) Ptr + FormatStrLen) = '\0';
146 
147   return EFI_SUCCESS;
148 }
149 
150 
151 
152 EFI_STATUS
EfiDebugAssertWorker(IN CHAR8 * Filename,IN INTN LineNumber,IN CHAR8 * Description,IN UINTN BufferSize,IN OUT VOID * Buffer)153 EfiDebugAssertWorker (
154   IN CHAR8                    *Filename,
155   IN INTN                     LineNumber,
156   IN CHAR8                    *Description,
157   IN UINTN                    BufferSize,
158   IN OUT VOID                 *Buffer
159   )
160 /*++
161 
162 Routine Description:
163 
164   Worker function for ASSERT (). If Error Logging hub is loaded log ASSERT
165   information. If Error Logging hub is not loaded DEADLOOP ().
166 
167   We use UINT64 buffers due to IPF alignment concerns.
168 
169 Arguments:
170 
171   Filename    - File name of failing routine.
172 
173   LineNumber  - Line number of failing ASSERT().
174 
175   Description - Description, usually the assertion,
176 
177   BufferSize - Size of Buffer.
178 
179   Buffer     - Caller allocated buffer, contains ReportStatusCode extendecd data
180 
181 Returns:
182 
183   Status code
184 
185   EFI_BUFFER_TOO_SMALL      - Buffer not large enough
186 
187   EFI_SUCCESS               - Function successfully done.
188 
189 --*/
190 {
191   EFI_DEBUG_ASSERT_DATA   *AssertData;
192   UINTN                   TotalSize;
193   CHAR8                   *EndOfStr;
194 
195   //
196   // Make sure it will all fit in the passed in buffer
197   //
198   TotalSize = sizeof (EFI_STATUS_CODE_DATA) + sizeof (EFI_DEBUG_ASSERT_DATA);
199   TotalSize += EfiAsciiStrLen (Filename);
200   TotalSize += EfiAsciiStrLen (Description);
201   if (TotalSize > BufferSize) {
202     return EFI_BUFFER_TOO_SMALL;
203   }
204 
205   //
206   // Fill in EFI_STATUS_CODE_DATA
207   //
208   AssertData =  (EFI_DEBUG_ASSERT_DATA *)
209                 EfiConstructStatusCodeData (
210                   (UINT16)(TotalSize - sizeof (EFI_STATUS_CODE_DATA)),
211                   &gEfiStatusCodeDataTypeAssertGuid,
212                   Buffer
213                   );
214 
215   //
216   // Fill in EFI_DEBUG_ASSERT_DATA
217   //
218   AssertData->LineNumber = (UINT32)LineNumber;
219 
220   //
221   // Copy Ascii FileName including NULL.
222   //
223   EndOfStr = EfiAsciiStrCpy ((CHAR8 *)(AssertData + 1), Filename);
224 
225   //
226   // Copy Ascii Description
227   //
228   EfiAsciiStrCpy (EndOfStr, Description);
229   return EFI_SUCCESS;
230 }
231 
232 
233 
234 BOOLEAN
ReportStatusCodeExtractAssertInfo(IN EFI_STATUS_CODE_TYPE CodeType,IN EFI_STATUS_CODE_VALUE Value,IN EFI_STATUS_CODE_DATA * Data,OUT CHAR8 ** Filename,OUT CHAR8 ** Description,OUT UINT32 * LineNumber)235 ReportStatusCodeExtractAssertInfo (
236   IN EFI_STATUS_CODE_TYPE     CodeType,
237   IN EFI_STATUS_CODE_VALUE    Value,
238   IN EFI_STATUS_CODE_DATA     *Data,
239   OUT CHAR8                   **Filename,
240   OUT CHAR8                   **Description,
241   OUT UINT32                  *LineNumber
242   )
243 /*++
244 
245 Routine Description:
246 
247   Extract assert information from status code data.
248 
249 Arguments:
250 
251   CodeType    - Code type
252   Value       - Code value
253   Data        - Optional data associated with this status code.
254   Filename    - Filename extracted from Data
255   Description - Description extracted from Data
256   LineNumber  - Line number extracted from Data
257 
258 Returns:
259 
260   TRUE      - Successfully extracted
261 
262   FALSE     - Extraction failed
263 
264 --*/
265 {
266   EFI_DEBUG_ASSERT_DATA   *AssertData;
267 
268   if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
269         ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED)) {
270     //
271     // Assume if we have an uncontained unrecoverable error that the data hub
272     // may not work. So we will print out data here. If we had an IPMI controller,
273     // or error log we could wack the hardware here.
274     //
275     if ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE && (Data != NULL)) {
276       //
277       // ASSERT (Expresion) -
278       // ExtendedData == FileName
279       // Instance     == Line Nuber
280       // NULL         == String of Expresion
281       //
282       AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
283       *Filename = (CHAR8 *)(AssertData + 1);
284       *Description = *Filename + EfiAsciiStrLen (*Filename) + 1;
285       *LineNumber = AssertData->LineNumber;
286       return TRUE;
287     }
288   }
289   return FALSE;
290 }
291 
292 
293 BOOLEAN
ReportStatusCodeExtractDebugInfo(IN EFI_STATUS_CODE_DATA * Data,OUT UINT32 * ErrorLevel,OUT VA_LIST * Marker,OUT CHAR8 ** Format)294 ReportStatusCodeExtractDebugInfo (
295   IN EFI_STATUS_CODE_DATA     *Data,
296   OUT UINT32                  *ErrorLevel,
297   OUT VA_LIST                 *Marker,
298   OUT CHAR8                   **Format
299   )
300 /*++
301 
302 Routine Description:
303 
304   Extract debug information from status code data.
305 
306 Arguments:
307 
308   Data        - Optional data associated with status code.
309   ErrorLevel  - Error level extracted from Data
310   Marker      - VA_LIST extracted from Data
311   Format      - Format string extracted from Data
312 
313 Returns:
314 
315   TRUE      - Successfully extracted
316 
317   FALSE     - Extraction failed
318 
319 --*/
320 {
321   EFI_DEBUG_INFO      *DebugInfo;
322 
323   if ((Data == NULL) || (!EfiCompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid))) {
324     return FALSE;
325   }
326 
327   DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
328 
329   *ErrorLevel = DebugInfo->ErrorLevel;
330 
331   //
332   // The first 12 * UINTN bytes of the string are really an
333   // arguement stack to support varargs on the Format string.
334   //
335 #if (defined (EFIARM) || defined(__APPLE__))
336   // It is not legal C code to case VA_LIST to a pointer. VA_LIST can
337   // be a structure.
338   return FALSE;
339 #else
340   *Marker = (VA_LIST) (DebugInfo + 1);
341   *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
342   return TRUE;
343 #endif
344 }
345