1 /** @file
2   Debug Library based on report status code library.
3 
4   Note that if the debug message length is larger than the maximum allowable
5   record length, then the debug message will be ignored directly.
6 
7   Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
8   SPDX-License-Identifier: BSD-2-Clause-Patent
9 
10 **/
11 
12 #include <PiPei.h>
13 
14 #include <Guid/StatusCodeDataTypeId.h>
15 #include <Guid/StatusCodeDataTypeDebug.h>
16 
17 #include <Library/DebugLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/ReportStatusCodeLib.h>
21 #include <Library/PcdLib.h>
22 #include <Library/DebugPrintErrorLevelLib.h>
23 
24 //
25 // VA_LIST can not initialize to NULL for all compiler, so we use this to
26 // indicate a null VA_LIST
27 //
28 VA_LIST     mVaListNull;
29 
30 /**
31   Prints a debug message to the debug output device if the specified error level is enabled.
32 
33   If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
34   GetDebugPrintErrorLevel (), then print the message specified by Format and the
35   associated variable argument list to the debug output device.
36 
37   If Format is NULL, then ASSERT().
38 
39   If the length of the message string specificed by Format is larger than the maximum allowable
40   record length, then directly return and not print it.
41 
42   @param  ErrorLevel  The error level of the debug message.
43   @param  Format      Format string for the debug message to print.
44   @param  ...         Variable argument list whose contents are accessed
45                       based on the format string specified by Format.
46 
47 **/
48 VOID
49 EFIAPI
DebugPrint(IN UINTN ErrorLevel,IN CONST CHAR8 * Format,...)50 DebugPrint (
51   IN  UINTN        ErrorLevel,
52   IN  CONST CHAR8  *Format,
53   ...
54   )
55 {
56   VA_LIST         Marker;
57 
58   VA_START (Marker, Format);
59   DebugVPrint (ErrorLevel, Format, Marker);
60   VA_END (Marker);
61 }
62 
63 /**
64   Prints a debug message to the debug output device if the specified
65   error level is enabled base on Null-terminated format string and a
66   VA_LIST argument list or a BASE_LIST argument list.
67 
68   If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
69   GetDebugPrintErrorLevel (), then print the message specified by Format and
70   the associated variable argument list to the debug output device.
71 
72   Only one list type is used.
73   If BaseListMarker == NULL, then use VaListMarker.
74   Otherwise use BaseListMarker and the VaListMarker should be initilized as
75   mVaListNull.
76 
77   If Format is NULL, then ASSERT().
78 
79   @param  ErrorLevel      The error level of the debug message.
80   @param  Format          Format string for the debug message to print.
81   @param  VaListMarker    VA_LIST marker for the variable argument list.
82   @param  BaseListMarker  BASE_LIST marker for the variable argument list.
83 
84 **/
85 VOID
DebugPrintMarker(IN UINTN ErrorLevel,IN CONST CHAR8 * Format,IN VA_LIST VaListMarker,IN BASE_LIST BaseListMarker)86 DebugPrintMarker (
87   IN  UINTN         ErrorLevel,
88   IN  CONST CHAR8   *Format,
89   IN  VA_LIST       VaListMarker,
90   IN  BASE_LIST     BaseListMarker
91   )
92 {
93   UINT64          Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1];
94   EFI_DEBUG_INFO  *DebugInfo;
95   UINTN           TotalSize;
96   BASE_LIST       BaseListMarkerPointer;
97   CHAR8           *FormatString;
98   BOOLEAN         Long;
99 
100   //
101   // If Format is NULL, then ASSERT().
102   //
103   ASSERT (Format != NULL);
104 
105   //
106   // Check driver Debug Level value and global debug level
107   //
108   if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
109     return;
110   }
111 
112   //
113   // Compute the total size of the record.
114   // Note that the passing-in format string and variable parameters will be constructed to
115   // the following layout:
116   //
117   //                Buffer->|------------------------|
118   //                        |         Padding        | 4 bytes
119   //             DebugInfo->|------------------------|
120   //                        |      EFI_DEBUG_INFO    | sizeof(EFI_DEBUG_INFO)
121   // BaseListMarkerPointer->|------------------------|
122   //                        |           ...          |
123   //                        |   variable arguments   | 12 * sizeof (UINT64)
124   //                        |           ...          |
125   //                        |------------------------|
126   //                        |       Format String    |
127   //                        |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer)
128   //
129   TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format);
130 
131   //
132   // If the TotalSize is larger than the maximum record size, then truncate it.
133   //
134   if (TotalSize > sizeof (Buffer)) {
135     TotalSize = sizeof (Buffer);
136   }
137 
138   //
139   // Fill in EFI_DEBUG_INFO
140   //
141   // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarkerPointer is
142   // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarkerPointer will cause
143   // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO))
144   // just makes address of BaseListMarkerPointer, which follows DebugInfo, 64-bit aligned.
145   //
146   DebugInfo             = (EFI_DEBUG_INFO *)(Buffer) + 1;
147   DebugInfo->ErrorLevel = (UINT32)ErrorLevel;
148   BaseListMarkerPointer = (BASE_LIST)(DebugInfo + 1);
149   FormatString          = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12);
150 
151   //
152   // Copy the Format string into the record. It will be truncated if it's too long.
153   //
154   AsciiStrnCpyS (
155     FormatString, sizeof(Buffer) - (4 + sizeof(EFI_DEBUG_INFO) + 12 * sizeof(UINT64)),
156     Format,       sizeof(Buffer) - (4 + sizeof(EFI_DEBUG_INFO) + 12 * sizeof(UINT64)) - 1
157     );
158 
159   //
160   // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
161   // of format in DEBUG string, which is followed by the DEBUG format string.
162   // Here we will process the variable arguments and pack them in this area.
163   //
164 
165   //
166   // Use the actual format string.
167   //
168   Format = FormatString;
169   for (; *Format != '\0'; Format++) {
170     //
171     // Only format with prefix % is processed.
172     //
173     if (*Format != '%') {
174       continue;
175     }
176     Long = FALSE;
177     //
178     // Parse Flags and Width
179     //
180     for (Format++; TRUE; Format++) {
181       if (*Format == '.' || *Format == '-' || *Format == '+' || *Format == ' ') {
182         //
183         // These characters in format field are omitted.
184         //
185         continue;
186       }
187       if (*Format >= '0' && *Format <= '9') {
188         //
189         // These characters in format field are omitted.
190         //
191         continue;
192       }
193       if (*Format == 'L' || *Format == 'l') {
194         //
195         // 'L" or "l" in format field means the number being printed is a UINT64
196         //
197         Long = TRUE;
198         continue;
199       }
200       if (*Format == '*') {
201         //
202         // '*' in format field means the precision of the field is specified by
203         // a UINTN argument in the argument list.
204         //
205         if (BaseListMarker == NULL) {
206           BASE_ARG (BaseListMarkerPointer, UINTN) = VA_ARG (VaListMarker, UINTN);
207         } else {
208           BASE_ARG (BaseListMarkerPointer, UINTN) = BASE_ARG (BaseListMarker, UINTN);
209         }
210         continue;
211       }
212       if (*Format == '\0') {
213         //
214         // Make no output if Format string terminates unexpectedly when
215         // looking up for flag, width, precision and type.
216         //
217         Format--;
218       }
219       //
220       // When valid argument type detected or format string terminates unexpectedly,
221       // the inner loop is done.
222       //
223       break;
224     }
225 
226     //
227     // Pack variable arguments into the storage area following EFI_DEBUG_INFO.
228     //
229     if ((*Format == 'p') && (sizeof (VOID *) > 4)) {
230       Long = TRUE;
231     }
232     if (*Format == 'p' || *Format == 'X' || *Format == 'x' || *Format == 'd' || *Format == 'u') {
233       if (Long) {
234         if (BaseListMarker == NULL) {
235           BASE_ARG (BaseListMarkerPointer, INT64) = VA_ARG (VaListMarker, INT64);
236         } else {
237           BASE_ARG (BaseListMarkerPointer, INT64) = BASE_ARG (BaseListMarker, INT64);
238         }
239       } else {
240         if (BaseListMarker == NULL) {
241           BASE_ARG (BaseListMarkerPointer, int) = VA_ARG (VaListMarker, int);
242         } else {
243           BASE_ARG (BaseListMarkerPointer, int) = BASE_ARG (BaseListMarker, int);
244         }
245       }
246     } else if (*Format == 's' || *Format == 'S' || *Format == 'a' || *Format == 'g' || *Format == 't') {
247       if (BaseListMarker == NULL) {
248         BASE_ARG (BaseListMarkerPointer, VOID *) = VA_ARG (VaListMarker, VOID *);
249       } else {
250         BASE_ARG (BaseListMarkerPointer, VOID *) = BASE_ARG (BaseListMarker, VOID *);
251       }
252     } else if (*Format == 'c') {
253       if (BaseListMarker == NULL) {
254         BASE_ARG (BaseListMarkerPointer, UINTN) = VA_ARG (VaListMarker, UINTN);
255       } else {
256         BASE_ARG (BaseListMarkerPointer, UINTN) = BASE_ARG (BaseListMarker, UINTN);
257       }
258     } else if (*Format == 'r') {
259       if (BaseListMarker == NULL) {
260         BASE_ARG (BaseListMarkerPointer, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);
261       } else {
262         BASE_ARG (BaseListMarkerPointer, RETURN_STATUS) = BASE_ARG (BaseListMarker, RETURN_STATUS);
263       }
264     }
265 
266     //
267     // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then ASSERT()
268     // This indicates that the DEBUG() macro is passing in more argument than can be handled by
269     // the EFI_DEBUG_INFO record
270     //
271     ASSERT ((CHAR8 *)BaseListMarkerPointer <= FormatString);
272 
273     //
274     // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return
275     //
276     if ((CHAR8 *)BaseListMarkerPointer > FormatString) {
277       return;
278     }
279   }
280 
281   //
282   // Send the DebugInfo record
283   //
284   REPORT_STATUS_CODE_EX (
285     EFI_DEBUG_CODE,
286     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED),
287     0,
288     NULL,
289     &gEfiStatusCodeDataTypeDebugGuid,
290     DebugInfo,
291     TotalSize
292     );
293 }
294 
295 /**
296   Prints a debug message to the debug output device if the specified
297   error level is enabled.
298 
299   If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
300   GetDebugPrintErrorLevel (), then print the message specified by Format and
301   the associated variable argument list to the debug output device.
302 
303   If Format is NULL, then ASSERT().
304 
305   @param  ErrorLevel    The error level of the debug message.
306   @param  Format        Format string for the debug message to print.
307   @param  VaListMarker  VA_LIST marker for the variable argument list.
308 
309 **/
310 VOID
311 EFIAPI
DebugVPrint(IN UINTN ErrorLevel,IN CONST CHAR8 * Format,IN VA_LIST VaListMarker)312 DebugVPrint (
313   IN  UINTN         ErrorLevel,
314   IN  CONST CHAR8   *Format,
315   IN  VA_LIST       VaListMarker
316   )
317 {
318   DebugPrintMarker (ErrorLevel, Format, VaListMarker, NULL);
319 }
320 
321 /**
322   Prints a debug message to the debug output device if the specified
323   error level is enabled.
324   This function use BASE_LIST which would provide a more compatible
325   service than VA_LIST.
326 
327   If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
328   GetDebugPrintErrorLevel (), then print the message specified by Format and
329   the associated variable argument list to the debug output device.
330 
331   If Format is NULL, then ASSERT().
332 
333   @param  ErrorLevel      The error level of the debug message.
334   @param  Format          Format string for the debug message to print.
335   @param  BaseListMarker  BASE_LIST marker for the variable argument list.
336 
337 **/
338 VOID
339 EFIAPI
DebugBPrint(IN UINTN ErrorLevel,IN CONST CHAR8 * Format,IN BASE_LIST BaseListMarker)340 DebugBPrint (
341   IN  UINTN         ErrorLevel,
342   IN  CONST CHAR8   *Format,
343   IN  BASE_LIST     BaseListMarker
344   )
345 {
346   DebugPrintMarker (ErrorLevel, Format, mVaListNull, BaseListMarker);
347 }
348 
349 /**
350   Prints an assert message containing a filename, line number, and description.
351   This may be followed by a breakpoint or a dead loop.
352 
353   Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
354   to the debug output device.  If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
355   PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if
356   DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then
357   CpuDeadLoop() is called.  If neither of these bits are set, then this function
358   returns immediately after the message is printed to the debug output device.
359   DebugAssert() must actively prevent recursion.  If DebugAssert() is called while
360   processing another DebugAssert(), then DebugAssert() must return immediately.
361 
362   If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
363   If Description is NULL, then a <Description> string of "(NULL) Description" is printed.
364 
365   @param  FileName     Pointer to the name of the source file that generated the assert condition.
366   @param  LineNumber   The line number in the source file that generated the assert condition
367   @param  Description  Pointer to the description of the assert condition.
368 
369 **/
370 VOID
371 EFIAPI
DebugAssert(IN CONST CHAR8 * FileName,IN UINTN LineNumber,IN CONST CHAR8 * Description)372 DebugAssert (
373   IN CONST CHAR8  *FileName,
374   IN UINTN        LineNumber,
375   IN CONST CHAR8  *Description
376   )
377 {
378   UINT64                 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof(UINT64)];
379   EFI_DEBUG_ASSERT_DATA  *AssertData;
380   UINTN                  HeaderSize;
381   UINTN                  TotalSize;
382   CHAR8                  *Temp;
383   UINTN                  ModuleNameSize;
384   UINTN                  FileNameSize;
385   UINTN                  DescriptionSize;
386 
387   //
388   // Get string size
389   //
390   HeaderSize       = sizeof (EFI_DEBUG_ASSERT_DATA);
391   //
392   // Compute string size of module name enclosed by []
393   //
394   ModuleNameSize   = 2 + AsciiStrSize (gEfiCallerBaseName);
395   FileNameSize     = AsciiStrSize (FileName);
396   DescriptionSize  = AsciiStrSize (Description);
397 
398   //
399   // Make sure it will all fit in the passed in buffer.
400   //
401   if (HeaderSize + ModuleNameSize + FileNameSize + DescriptionSize > sizeof (Buffer)) {
402     //
403     // remove module name if it's too long to be filled into buffer
404     //
405     ModuleNameSize = 0;
406     if (HeaderSize + FileNameSize + DescriptionSize > sizeof (Buffer)) {
407       //
408       // FileName + Description is too long to be filled into buffer.
409       //
410       if (HeaderSize + FileNameSize < sizeof (Buffer)) {
411         //
412         // Description has enough buffer to be truncated.
413         //
414         DescriptionSize = sizeof (Buffer) - HeaderSize - FileNameSize;
415       } else {
416         //
417         // FileName is too long to be filled into buffer.
418         // FileName will be truncated. Reserved one byte for Description NULL terminator.
419         //
420         DescriptionSize = 1;
421         FileNameSize    = sizeof (Buffer) - HeaderSize - DescriptionSize;
422       }
423     }
424   }
425   //
426   // Fill in EFI_DEBUG_ASSERT_DATA
427   //
428   AssertData = (EFI_DEBUG_ASSERT_DATA *)Buffer;
429   AssertData->LineNumber = (UINT32)LineNumber;
430   TotalSize  = sizeof (EFI_DEBUG_ASSERT_DATA);
431 
432   Temp = (CHAR8 *)(AssertData + 1);
433 
434   //
435   // Copy Ascii [ModuleName].
436   //
437   if (ModuleNameSize != 0) {
438     CopyMem(Temp, "[", 1);
439     CopyMem(Temp + 1, gEfiCallerBaseName, ModuleNameSize - 3);
440     CopyMem(Temp + ModuleNameSize - 2, "] ", 2);
441   }
442 
443   //
444   // Copy Ascii FileName including NULL terminator.
445   //
446   Temp = CopyMem (Temp + ModuleNameSize, FileName, FileNameSize);
447   Temp[FileNameSize - 1] = 0;
448   TotalSize += (ModuleNameSize + FileNameSize);
449 
450   //
451   // Copy Ascii Description include NULL terminator.
452   //
453   Temp = CopyMem (Temp + FileNameSize, Description, DescriptionSize);
454   Temp[DescriptionSize - 1] = 0;
455   TotalSize += DescriptionSize;
456 
457   REPORT_STATUS_CODE_EX (
458     (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
459     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE),
460     0,
461     NULL,
462     NULL,
463     AssertData,
464     TotalSize
465     );
466 
467   //
468   // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
469   //
470   if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
471     CpuBreakpoint ();
472   } else if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
473     CpuDeadLoop ();
474   }
475 }
476 
477 
478 /**
479   Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.
480 
481   This function fills Length bytes of Buffer with the value specified by
482   PcdDebugClearMemoryValue, and returns Buffer.
483 
484   If Buffer is NULL, then ASSERT().
485   If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
486 
487   @param   Buffer  Pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
488   @param   Length  Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
489 
490   @return  Buffer  Pointer to the target buffer filled with PcdDebugClearMemoryValue.
491 
492 **/
493 VOID *
494 EFIAPI
DebugClearMemory(OUT VOID * Buffer,IN UINTN Length)495 DebugClearMemory (
496   OUT VOID  *Buffer,
497   IN UINTN  Length
498   )
499 {
500   ASSERT (Buffer != NULL);
501 
502   return SetMem (Buffer, Length, PcdGet8 (PcdDebugClearMemoryValue));
503 }
504 
505 
506 /**
507   Returns TRUE if ASSERT() macros are enabled.
508 
509   This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
510   PcdDebugProperyMask is set.  Otherwise FALSE is returned.
511 
512   @retval  TRUE    The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set.
513   @retval  FALSE   The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear.
514 
515 **/
516 BOOLEAN
517 EFIAPI
DebugAssertEnabled(VOID)518 DebugAssertEnabled (
519   VOID
520   )
521 {
522   return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
523 }
524 
525 
526 /**
527   Returns TRUE if DEBUG() macros are enabled.
528 
529   This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
530   PcdDebugProperyMask is set.  Otherwise FALSE is returned.
531 
532   @retval  TRUE    The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
533   @retval  FALSE   The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.
534 
535 **/
536 BOOLEAN
537 EFIAPI
DebugPrintEnabled(VOID)538 DebugPrintEnabled (
539   VOID
540   )
541 {
542   return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
543 }
544 
545 
546 /**
547   Returns TRUE if DEBUG_CODE() macros are enabled.
548 
549   This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
550   PcdDebugProperyMask is set.  Otherwise FALSE is returned.
551 
552   @retval  TRUE    The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set.
553   @retval  FALSE   The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear.
554 
555 **/
556 BOOLEAN
557 EFIAPI
DebugCodeEnabled(VOID)558 DebugCodeEnabled (
559   VOID
560   )
561 {
562   return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);
563 }
564 
565 
566 /**
567   Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.
568 
569   This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
570   PcdDebugProperyMask is set.  Otherwise FALSE is returned.
571 
572   @retval  TRUE    The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set.
573   @retval  FALSE   The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear.
574 
575 **/
576 BOOLEAN
577 EFIAPI
DebugClearMemoryEnabled(VOID)578 DebugClearMemoryEnabled (
579   VOID
580   )
581 {
582   return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
583 }
584 
585 /**
586   Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel.
587 
588   This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel.
589 
590   @retval  TRUE    Current ErrorLevel is supported.
591   @retval  FALSE   Current ErrorLevel is not supported.
592 
593 **/
594 BOOLEAN
595 EFIAPI
DebugPrintLevelEnabled(IN CONST UINTN ErrorLevel)596 DebugPrintLevelEnabled (
597   IN  CONST UINTN        ErrorLevel
598   )
599 {
600   return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0);
601 }
602