/** @file | |
PEI debug lib instance base on gEdkiiDebugPpiGuid to save PEIM size. | |
Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <PiPei.h> | |
#include <Ppi/Debug.h> | |
#include <Library/DebugLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/PeiServicesLib.h> | |
#include <Library/DebugPrintErrorLevelLib.h> | |
#include <Library/BaseLib.h> | |
/** | |
Prints a debug message to the debug output device if the specified | |
error level is enabled. | |
If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function | |
GetDebugPrintErrorLevel (), then print the message specified by Format and | |
the associated variable argument list to the debug output device. | |
If Format is NULL, then ASSERT(). | |
@param ErrorLevel The error level of the debug message. | |
@param Format Format string for the debug message to print. | |
@param ... Variable argument list whose contents are accessed | |
based on the format string specified by Format. | |
**/ | |
VOID | |
EFIAPI | |
DebugPrint ( | |
IN UINTN ErrorLevel, | |
IN CONST CHAR8 *Format, | |
... | |
) | |
{ | |
VA_LIST Marker; | |
VA_START (Marker, Format); | |
DebugVPrint (ErrorLevel, Format, Marker); | |
VA_END (Marker); | |
} | |
/** | |
Prints a debug message to the debug output device if the specified | |
error level is enabled. | |
This function use BASE_LIST which would provide a more compatible | |
service than VA_LIST. | |
If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function | |
GetDebugPrintErrorLevel (), then print the message specified by Format and | |
the associated variable argument list to the debug output device. | |
If Format is NULL, then ASSERT(). | |
@param ErrorLevel The error level of the debug message. | |
@param Format Format string for the debug message to print. | |
@param BaseListMarker BASE_LIST marker for the variable argument list. | |
**/ | |
VOID | |
EFIAPI | |
DebugBPrint ( | |
IN UINTN ErrorLevel, | |
IN CONST CHAR8 *Format, | |
IN BASE_LIST BaseListMarker | |
) | |
{ | |
EFI_STATUS Status; | |
EDKII_DEBUG_PPI *DebugPpi; | |
// | |
// If Format is NULL, then ASSERT(). | |
// | |
ASSERT (Format != NULL); | |
// | |
// Check driver Debug Level value and global debug level | |
// | |
if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) { | |
return; | |
} | |
Status = PeiServicesLocatePpi ( | |
&gEdkiiDebugPpiGuid, | |
0, | |
NULL, | |
(VOID **)&DebugPpi | |
); | |
if (EFI_ERROR (Status)) { | |
return; | |
} | |
DebugPpi->DebugBPrint ( | |
ErrorLevel, | |
Format, | |
BaseListMarker | |
); | |
} | |
/** | |
Worker function that convert a VA_LIST to a BASE_LIST based on a | |
Null-terminated format string. | |
@param Format Null-terminated format string. | |
@param VaListMarker VA_LIST style variable argument list consumed | |
by processing Format. | |
@param BaseListMarker BASE_LIST style variable argument list consumed | |
by processing Format. | |
@param Size The size, in bytes, of the BaseListMarker buffer. | |
@return TRUE The VA_LIST has been converted to BASE_LIST. | |
@return FALSE The VA_LIST has not been converted to BASE_LIST. | |
**/ | |
BOOLEAN | |
VaListToBaseList ( | |
IN CONST CHAR8 *Format, | |
IN VA_LIST VaListMarker, | |
OUT BASE_LIST BaseListMarker, | |
IN UINTN Size | |
) | |
{ | |
BASE_LIST BaseListStart; | |
BOOLEAN Long; | |
ASSERT (Format != NULL); | |
ASSERT (BaseListMarker != NULL); | |
BaseListStart = BaseListMarker; | |
for ( ; *Format != '\0'; Format++) { | |
// | |
// Only format with prefix % is processed. | |
// | |
if (*Format != '%') { | |
continue; | |
} | |
Long = FALSE; | |
// | |
// Parse Flags and Width | |
// | |
for (Format++; TRUE; Format++) { | |
if ((*Format == '.') || (*Format == '-') || (*Format == '+') || (*Format == ' ')) { | |
// | |
// These characters in format field are omitted. | |
// | |
continue; | |
} | |
if ((*Format >= '0') && (*Format <= '9')) { | |
// | |
// These characters in format field are omitted. | |
// | |
continue; | |
} | |
if ((*Format == 'L') || (*Format == 'l')) { | |
// | |
// 'L" or "l" in format field means the number being printed is a UINT64 | |
// | |
Long = TRUE; | |
continue; | |
} | |
if (*Format == '*') { | |
// | |
// '*' in format field means the precision of the field is specified by | |
// a UINTN argument in the argument list. | |
// | |
BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN); | |
continue; | |
} | |
if (*Format == '\0') { | |
// | |
// Make no output if Format string terminates unexpectedly when | |
// looking up for flag, width, precision and type. | |
// | |
Format--; | |
} | |
// | |
// When valid argument type detected or format string terminates unexpectedly, | |
// the inner loop is done. | |
// | |
break; | |
} | |
// | |
// Pack variable arguments into the storage area following EFI_DEBUG_INFO. | |
// | |
if ((*Format == 'p') && (sizeof (VOID *) > 4)) { | |
Long = TRUE; | |
} | |
if ((*Format == 'p') || (*Format == 'X') || (*Format == 'x') || (*Format == 'd') || (*Format == 'u')) { | |
if (Long) { | |
BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64); | |
} else { | |
BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int); | |
} | |
} else if ((*Format == 's') || (*Format == 'S') || (*Format == 'a') || (*Format == 'g') || (*Format == 't')) { | |
BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *); | |
} else if (*Format == 'c') { | |
BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN); | |
} else if (*Format == 'r') { | |
BASE_ARG (BaseListMarker, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS); | |
} | |
// | |
// If the converted BASE_LIST is larger than the size of BaseListMarker, then return FALSE | |
// | |
if (((UINTN)BaseListMarker - (UINTN)BaseListStart) > Size) { | |
return FALSE; | |
} | |
} | |
return TRUE; | |
} | |
/** | |
Prints a debug message to the debug output device if the specified | |
error level is enabled. | |
If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function | |
GetDebugPrintErrorLevel (), then print the message specified by Format and | |
the associated variable argument list to the debug output device. | |
If Format is NULL, then ASSERT(). | |
@param ErrorLevel The error level of the debug message. | |
@param Format Format string for the debug message to print. | |
@param VaListMarker VA_LIST marker for the variable argument list. | |
**/ | |
VOID | |
EFIAPI | |
DebugVPrint ( | |
IN UINTN ErrorLevel, | |
IN CONST CHAR8 *Format, | |
IN VA_LIST VaListMarker | |
) | |
{ | |
UINT64 BaseListMarker[256 / sizeof (UINT64)]; | |
BOOLEAN Converted; | |
// | |
// Convert the VaList to BaseList | |
// | |
Converted = VaListToBaseList ( | |
Format, | |
VaListMarker, | |
(BASE_LIST)BaseListMarker, | |
sizeof (BaseListMarker) - 8 | |
); | |
if (!Converted) { | |
return; | |
} | |
DebugBPrint (ErrorLevel, Format, (BASE_LIST)BaseListMarker); | |
} | |
/** | |
Prints an assert message containing a filename, line number, and description. | |
This may be followed by a breakpoint or a dead loop. | |
Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n" | |
to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of | |
PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if | |
DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then | |
CpuDeadLoop() is called. If neither of these bits are set, then this function | |
returns immediately after the message is printed to the debug output device. | |
DebugAssert() must actively prevent recursion. If DebugAssert() is called while | |
processing another DebugAssert(), then DebugAssert() must return immediately. | |
If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed. | |
If Description is NULL, then a <Description> string of "(NULL) Description" is printed. | |
@param FileName The pointer to the name of the source file that generated the assert condition. | |
@param LineNumber The line number in the source file that generated the assert condition | |
@param Description The pointer to the description of the assert condition. | |
**/ | |
VOID | |
EFIAPI | |
DebugAssert ( | |
IN CONST CHAR8 *FileName, | |
IN UINTN LineNumber, | |
IN CONST CHAR8 *Description | |
) | |
{ | |
EFI_STATUS Status; | |
EDKII_DEBUG_PPI *DebugPpi; | |
Status = PeiServicesLocatePpi ( | |
&gEdkiiDebugPpiGuid, | |
0, | |
NULL, | |
(VOID **)&DebugPpi | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// Generate a Breakpoint, DeadLoop, or NOP based on PCD settings | |
// | |
if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { | |
CpuBreakpoint (); | |
} else if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) { | |
CpuDeadLoop (); | |
} | |
} else { | |
DebugPpi->DebugAssert ( | |
FileName, | |
LineNumber, | |
Description | |
); | |
} | |
} | |
/** | |
Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer. | |
This function fills Length bytes of Buffer with the value specified by | |
PcdDebugClearMemoryValue, and returns Buffer. | |
If Buffer is NULL, then ASSERT(). | |
If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). | |
@param Buffer The pointer to the target buffer to be filled with PcdDebugClearMemoryValue. | |
@param Length The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. | |
@return Buffer The pointer to the target buffer filled with PcdDebugClearMemoryValue. | |
**/ | |
VOID * | |
EFIAPI | |
DebugClearMemory ( | |
OUT VOID *Buffer, | |
IN UINTN Length | |
) | |
{ | |
ASSERT (Buffer != NULL); | |
return SetMem (Buffer, Length, PcdGet8 (PcdDebugClearMemoryValue)); | |
} | |
/** | |
Returns TRUE if ASSERT() macros are enabled. | |
This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of | |
PcdDebugProperyMask is set. Otherwise, FALSE is returned. | |
@retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set. | |
@retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear. | |
**/ | |
BOOLEAN | |
EFIAPI | |
DebugAssertEnabled ( | |
VOID | |
) | |
{ | |
return (BOOLEAN)((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); | |
} | |
/** | |
Returns TRUE if DEBUG() macros are enabled. | |
This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of | |
PcdDebugProperyMask is set. Otherwise, FALSE is returned. | |
@retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set. | |
@retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear. | |
**/ | |
BOOLEAN | |
EFIAPI | |
DebugPrintEnabled ( | |
VOID | |
) | |
{ | |
return (BOOLEAN)((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); | |
} | |
/** | |
Returns TRUE if DEBUG_CODE() macros are enabled. | |
This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of | |
PcdDebugProperyMask is set. Otherwise, FALSE is returned. | |
@retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set. | |
@retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear. | |
**/ | |
BOOLEAN | |
EFIAPI | |
DebugCodeEnabled ( | |
VOID | |
) | |
{ | |
return (BOOLEAN)((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); | |
} | |
/** | |
Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled. | |
This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of | |
PcdDebugProperyMask is set. Otherwise, FALSE is returned. | |
@retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set. | |
@retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear. | |
**/ | |
BOOLEAN | |
EFIAPI | |
DebugClearMemoryEnabled ( | |
VOID | |
) | |
{ | |
return (BOOLEAN)((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); | |
} | |
/** | |
Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel. | |
This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel. | |
@retval TRUE Current ErrorLevel is supported. | |
@retval FALSE Current ErrorLevel is not supported. | |
**/ | |
BOOLEAN | |
EFIAPI | |
DebugPrintLevelEnabled ( | |
IN CONST UINTN ErrorLevel | |
) | |
{ | |
return (BOOLEAN)((ErrorLevel & PcdGet32 (PcdFixedDebugPrintErrorLevel)) != 0); | |
} |