]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c
recalculate the total size of format string printed by DebugPrint().
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / PeiDxeDebugLibReportStatusCode / DebugLib.c
1 /** @file
2 Debug Library based on report status code library.
3
4 Copyright (c) 2006 - 2009, Intel Corporation<BR>
5 All rights reserved. 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 <FrameworkPei.h>
16
17 #include <Guid/StatusCodeDataTypeId.h>
18 #include <Guid/StatusCodeDataTypeDebug.h>
19
20 #include <Library/DebugLib.h>
21 #include <Library/BaseLib.h>
22 #include <Library/BaseMemoryLib.h>
23 #include <Library/ReportStatusCodeLib.h>
24 #include <Library/PcdLib.h>
25
26 /**
27 Prints a debug message to the debug output device if the specified error level is enabled.
28
29 If any bit in ErrorLevel is also set in PcdDebugPrintErrorLevel, then print
30 the message specified by Format and the associated variable argument list to
31 the debug output device.
32
33 If Format is NULL, then ASSERT().
34
35 @param ErrorLevel The error level of the debug message.
36 @param Format Format string for the debug message to print.
37 @param ... Variable argument list whose contents are accessed
38 based on the format string specified by Format.
39
40 **/
41 VOID
42 EFIAPI
43 DebugPrint (
44 IN UINTN ErrorLevel,
45 IN CONST CHAR8 *Format,
46 ...
47 )
48 {
49 UINT64 Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1];
50 EFI_DEBUG_INFO *DebugInfo;
51 UINTN TotalSize;
52 VA_LIST VaListMarker;
53 BASE_LIST BaseListMarker;
54 CHAR8 *FormatString;
55 BOOLEAN Long;
56 BOOLEAN Done;
57
58 //
59 // If Format is NULL, then ASSERT().
60 //
61 ASSERT (Format != NULL);
62
63 //
64 // Check driver Debug Level value and global debug level
65 //
66 if ((ErrorLevel & PcdGet32 (PcdDebugPrintErrorLevel)) == 0) {
67 return;
68 }
69
70 //
71 // Compute the total size of the record.
72 // Note that the passing-in format string and variable parameters will be constructed to
73 // the following layout:
74 //
75 // Buffer->|------------------------|
76 // | Pading | 4 bytes
77 // DebugInfo->|------------------------|
78 // | EFI_DEBUG_INFO | sizeof(EFI_DEBUG_INFO)
79 // BaseListMarker->|------------------------|
80 // | ... |
81 // | variable arguments | 12 * sizeof (UINT64)
82 // | ... |
83 // |------------------------|
84 // | Format String |
85 // |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer)
86 //
87 TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format);
88
89 //
90 // If the TotalSize is larger than the maximum record size, then return
91 //
92 if (TotalSize > sizeof (Buffer)) {
93 return;
94 }
95
96 //
97 // Fill in EFI_DEBUG_INFO
98 //
99 // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarker is
100 // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarker will cause
101 // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO))
102 // just makes addess of BaseListMarker, which follows DebugInfo, 64-bit aligned.
103 //
104 DebugInfo = (EFI_DEBUG_INFO *)(Buffer) + 1;
105 DebugInfo->ErrorLevel = (UINT32)ErrorLevel;
106 BaseListMarker = (BASE_LIST)(DebugInfo + 1);
107 FormatString = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12);
108
109 //
110 // Copy the Format string into the record
111 //
112 AsciiStrCpy (FormatString, Format);
113
114 //
115 // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
116 // of format in DEBUG string, which is followed by the DEBUG format string.
117 // Here we will process the variable arguments and pack them in this area.
118 //
119 VA_START (VaListMarker, Format);
120 for (; *Format != '\0'; Format++) {
121 //
122 // Only format with prefix % is processed.
123 //
124 if (*Format != '%') {
125 continue;
126 }
127 Long = FALSE;
128 //
129 // Parse Flags and Width
130 //
131 for (Done = FALSE; !Done; ) {
132 Format++;
133 switch (*Format) {
134 case '.':
135 case '-':
136 case '+':
137 case ' ':
138 case ',':
139 case '0':
140 case '1':
141 case '2':
142 case '3':
143 case '4':
144 case '5':
145 case '6':
146 case '7':
147 case '8':
148 case '9':
149 //
150 // These characters in format field are omitted.
151 //
152 break;
153 case 'L':
154 case 'l':
155 //
156 // 'L" or "l" in format field means the number being printed is a UINT64
157 //
158 Long = TRUE;
159 break;
160 case '*':
161 //
162 // '*' in format field means the precision of the field is specified by
163 // a UINTN argument in the argument list.
164 //
165 BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
166 break;
167 case '\0':
168 //
169 // Make no output if Format string terminates unexpectedly when
170 // looking up for flag, width, precision and type.
171 //
172 Format--;
173 //
174 // break skipped on purpose.
175 //
176 default:
177 //
178 // When valid argument type detected or format string terminates unexpectedly,
179 // the inner loop is done.
180 //
181 Done = TRUE;
182 break;
183 }
184 }
185
186 //
187 // Pack variable arguments into the storage area following EFI_DEBUG_INFO.
188 //
189 switch (*Format) {
190 case 'p':
191 if (sizeof (VOID *) > 4) {
192 Long = TRUE;
193 }
194 case 'X':
195 case 'x':
196 case 'd':
197 if (Long) {
198 BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64);
199 } else {
200 BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int);
201 }
202 break;
203 case 's':
204 case 'S':
205 case 'a':
206 case 'g':
207 case 't':
208 BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *);
209 break;
210 case 'c':
211 BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
212 break;
213 case 'r':
214 BASE_ARG (BaseListMarker, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);
215 break;
216 }
217
218 //
219 // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then ASSERT()
220 // This indicates that the DEBUG() macro is passing in more argument than can be handled by
221 // the EFI_DEBUG_INFO record
222 //
223 ASSERT ((CHAR8 *)BaseListMarker <= FormatString);
224
225 //
226 // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return
227 //
228 if ((CHAR8 *)BaseListMarker > FormatString) {
229 return;
230 }
231 }
232 VA_END (VaListMarker);
233
234 //
235 // Send the DebugInfo record
236 //
237 REPORT_STATUS_CODE_EX (
238 EFI_DEBUG_CODE,
239 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED),
240 0,
241 NULL,
242 &gEfiStatusCodeDataTypeDebugGuid,
243 DebugInfo,
244 TotalSize
245 );
246 }
247
248 /**
249 Prints an assert message containing a filename, line number, and description.
250 This may be followed by a breakpoint or a dead loop.
251
252 Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
253 to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
254 PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if
255 DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then
256 CpuDeadLoop() is called. If neither of these bits are set, then this function
257 returns immediately after the message is printed to the debug output device.
258 DebugAssert() must actively prevent recursion. If DebugAssert() is called while
259 processing another DebugAssert(), then DebugAssert() must return immediately.
260
261 If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
262 If Description is NULL, then a <Description> string of "(NULL) Description" is printed.
263
264 @param FileName Pointer to the name of the source file that generated the assert condition.
265 @param LineNumber The line number in the source file that generated the assert condition
266 @param Description Pointer to the description of the assert condition.
267
268 **/
269 VOID
270 EFIAPI
271 DebugAssert (
272 IN CONST CHAR8 *FileName,
273 IN UINTN LineNumber,
274 IN CONST CHAR8 *Description
275 )
276 {
277 UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof(UINT64)];
278 EFI_DEBUG_ASSERT_DATA *AssertData;
279 UINTN TotalSize;
280 CHAR8 *Temp;
281 UINTN FileNameSize;
282 UINTN DescriptionSize;
283
284 //
285 // Make sure it will all fit in the passed in buffer
286 //
287 FileNameSize = AsciiStrSize (FileName);
288 DescriptionSize = AsciiStrSize (Description);
289 TotalSize = sizeof (EFI_DEBUG_ASSERT_DATA) + FileNameSize + DescriptionSize;
290 if (TotalSize <= sizeof (Buffer)) {
291 //
292 // Fill in EFI_DEBUG_ASSERT_DATA
293 //
294 AssertData = (EFI_DEBUG_ASSERT_DATA *)Buffer;
295 AssertData->LineNumber = (UINT32)LineNumber;
296
297 //
298 // Copy Ascii FileName including NULL.
299 //
300 Temp = AsciiStrCpy ((CHAR8 *)(AssertData + 1), FileName);
301
302 //
303 // Copy Ascii Description
304 //
305 AsciiStrCpy (Temp + FileNameSize, Description);
306
307 REPORT_STATUS_CODE_EX (
308 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
309 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE),
310 0,
311 NULL,
312 NULL,
313 AssertData,
314 TotalSize
315 );
316 }
317
318 //
319 // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
320 //
321 if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
322 CpuBreakpoint ();
323 } else if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
324 CpuDeadLoop ();
325 }
326 }
327
328
329 /**
330 Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.
331
332 This function fills Length bytes of Buffer with the value specified by
333 PcdDebugClearMemoryValue, and returns Buffer.
334
335 If Buffer is NULL, then ASSERT().
336 If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
337
338 @param Buffer Pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
339 @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
340
341 @return Buffer Pointer to the target buffer filled with PcdDebugClearMemoryValue.
342
343 **/
344 VOID *
345 EFIAPI
346 DebugClearMemory (
347 OUT VOID *Buffer,
348 IN UINTN Length
349 )
350 {
351 ASSERT (Buffer != NULL);
352
353 return SetMem (Buffer, Length, PcdGet8 (PcdDebugClearMemoryValue));
354 }
355
356
357 /**
358 Returns TRUE if ASSERT() macros are enabled.
359
360 This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
361 PcdDebugProperyMask is set. Otherwise FALSE is returned.
362
363 @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set.
364 @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear.
365
366 **/
367 BOOLEAN
368 EFIAPI
369 DebugAssertEnabled (
370 VOID
371 )
372 {
373 return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
374 }
375
376
377 /**
378 Returns TRUE if DEBUG() macros are enabled.
379
380 This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
381 PcdDebugProperyMask is set. Otherwise FALSE is returned.
382
383 @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
384 @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.
385
386 **/
387 BOOLEAN
388 EFIAPI
389 DebugPrintEnabled (
390 VOID
391 )
392 {
393 return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
394 }
395
396
397 /**
398 Returns TRUE if DEBUG_CODE() macros are enabled.
399
400 This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
401 PcdDebugProperyMask is set. Otherwise FALSE is returned.
402
403 @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set.
404 @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear.
405
406 **/
407 BOOLEAN
408 EFIAPI
409 DebugCodeEnabled (
410 VOID
411 )
412 {
413 return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);
414 }
415
416
417 /**
418 Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.
419
420 This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
421 PcdDebugProperyMask is set. Otherwise FALSE is returned.
422
423 @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set.
424 @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear.
425
426 **/
427 BOOLEAN
428 EFIAPI
429 DebugClearMemoryEnabled (
430 VOID
431 )
432 {
433 return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
434 }