123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- /** @file
- Debug Library based on report status code library.
- Note that if the debug message length is larger than the maximum allowable
- record length, then the debug message will be ignored directly.
- Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <PiPei.h>
- #include <Guid/StatusCodeDataTypeId.h>
- #include <Guid/StatusCodeDataTypeDebug.h>
- #include <Library/DebugLib.h>
- #include <Library/BaseLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/ReportStatusCodeLib.h>
- #include <Library/PcdLib.h>
- #include <Library/DebugPrintErrorLevelLib.h>
- //
- // VA_LIST can not initialize to NULL for all compiler, so we use this to
- // indicate a null VA_LIST
- //
- VA_LIST mVaListNull;
- /**
- 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().
- If the length of the message string specificed by Format is larger than the maximum allowable
- record length, then directly return and not print it.
- @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 base on Null-terminated format string and a
- VA_LIST argument list or a BASE_LIST argument 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.
- Only one list type is used.
- If BaseListMarker == NULL, then use VaListMarker.
- Otherwise use BaseListMarker and the VaListMarker should be initilized as
- mVaListNull.
- 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.
- @param BaseListMarker BASE_LIST marker for the variable argument list.
- **/
- VOID
- DebugPrintMarker (
- IN UINTN ErrorLevel,
- IN CONST CHAR8 *Format,
- IN VA_LIST VaListMarker,
- IN BASE_LIST BaseListMarker
- )
- {
- UINT64 Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1];
- EFI_DEBUG_INFO *DebugInfo;
- UINTN TotalSize;
- BASE_LIST BaseListMarkerPointer;
- CHAR8 *FormatString;
- BOOLEAN Long;
- //
- // If Format is NULL, then ASSERT().
- //
- ASSERT (Format != NULL);
- //
- // Check driver Debug Level value and global debug level
- //
- if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
- return;
- }
- //
- // Compute the total size of the record.
- // Note that the passing-in format string and variable parameters will be constructed to
- // the following layout:
- //
- // Buffer->|------------------------|
- // | Padding | 4 bytes
- // DebugInfo->|------------------------|
- // | EFI_DEBUG_INFO | sizeof(EFI_DEBUG_INFO)
- // BaseListMarkerPointer->|------------------------|
- // | ... |
- // | variable arguments | 12 * sizeof (UINT64)
- // | ... |
- // |------------------------|
- // | Format String |
- // |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer)
- //
- TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format);
- //
- // If the TotalSize is larger than the maximum record size, then truncate it.
- //
- if (TotalSize > sizeof (Buffer)) {
- TotalSize = sizeof (Buffer);
- }
- //
- // Fill in EFI_DEBUG_INFO
- //
- // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarkerPointer is
- // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarkerPointer will cause
- // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO))
- // just makes address of BaseListMarkerPointer, which follows DebugInfo, 64-bit aligned.
- //
- DebugInfo = (EFI_DEBUG_INFO *)(Buffer) + 1;
- DebugInfo->ErrorLevel = (UINT32)ErrorLevel;
- BaseListMarkerPointer = (BASE_LIST)(DebugInfo + 1);
- FormatString = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12);
- //
- // Copy the Format string into the record. It will be truncated if it's too long.
- //
- AsciiStrnCpyS (
- FormatString,
- sizeof (Buffer) - (4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64)),
- Format,
- sizeof (Buffer) - (4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64)) - 1
- );
- //
- // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
- // of format in DEBUG string, which is followed by the DEBUG format string.
- // Here we will process the variable arguments and pack them in this area.
- //
- //
- // Use the actual format string.
- //
- Format = FormatString;
- 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.
- //
- if (BaseListMarker == NULL) {
- BASE_ARG (BaseListMarkerPointer, UINTN) = VA_ARG (VaListMarker, UINTN);
- } else {
- BASE_ARG (BaseListMarkerPointer, UINTN) = BASE_ARG (BaseListMarker, 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) {
- if (BaseListMarker == NULL) {
- BASE_ARG (BaseListMarkerPointer, INT64) = VA_ARG (VaListMarker, INT64);
- } else {
- BASE_ARG (BaseListMarkerPointer, INT64) = BASE_ARG (BaseListMarker, INT64);
- }
- } else {
- if (BaseListMarker == NULL) {
- BASE_ARG (BaseListMarkerPointer, int) = VA_ARG (VaListMarker, int);
- } else {
- BASE_ARG (BaseListMarkerPointer, int) = BASE_ARG (BaseListMarker, int);
- }
- }
- } else if ((*Format == 's') || (*Format == 'S') || (*Format == 'a') || (*Format == 'g') || (*Format == 't')) {
- if (BaseListMarker == NULL) {
- BASE_ARG (BaseListMarkerPointer, VOID *) = VA_ARG (VaListMarker, VOID *);
- } else {
- BASE_ARG (BaseListMarkerPointer, VOID *) = BASE_ARG (BaseListMarker, VOID *);
- }
- } else if (*Format == 'c') {
- if (BaseListMarker == NULL) {
- BASE_ARG (BaseListMarkerPointer, UINTN) = VA_ARG (VaListMarker, UINTN);
- } else {
- BASE_ARG (BaseListMarkerPointer, UINTN) = BASE_ARG (BaseListMarker, UINTN);
- }
- } else if (*Format == 'r') {
- if (BaseListMarker == NULL) {
- BASE_ARG (BaseListMarkerPointer, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);
- } else {
- BASE_ARG (BaseListMarkerPointer, RETURN_STATUS) = BASE_ARG (BaseListMarker, RETURN_STATUS);
- }
- }
- //
- // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then ASSERT()
- // This indicates that the DEBUG() macro is passing in more argument than can be handled by
- // the EFI_DEBUG_INFO record
- //
- ASSERT ((CHAR8 *)BaseListMarkerPointer <= FormatString);
- //
- // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return
- //
- if ((CHAR8 *)BaseListMarkerPointer > FormatString) {
- return;
- }
- }
- //
- // Send the DebugInfo record
- //
- REPORT_STATUS_CODE_EX (
- EFI_DEBUG_CODE,
- (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED),
- 0,
- NULL,
- &gEfiStatusCodeDataTypeDebugGuid,
- DebugInfo,
- TotalSize
- );
- }
- /**
- 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
- )
- {
- DebugPrintMarker (ErrorLevel, Format, VaListMarker, NULL);
- }
- /**
- 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
- )
- {
- DebugPrintMarker (ErrorLevel, Format, mVaListNull, 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 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 Pointer to the description of the assert condition.
- **/
- VOID
- EFIAPI
- DebugAssert (
- IN CONST CHAR8 *FileName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *Description
- )
- {
- UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)];
- EFI_DEBUG_ASSERT_DATA *AssertData;
- UINTN HeaderSize;
- UINTN TotalSize;
- CHAR8 *Temp;
- UINTN ModuleNameSize;
- UINTN FileNameSize;
- UINTN DescriptionSize;
- //
- // Get string size
- //
- HeaderSize = sizeof (EFI_DEBUG_ASSERT_DATA);
- //
- // Compute string size of module name enclosed by []
- //
- ModuleNameSize = 2 + AsciiStrSize (gEfiCallerBaseName);
- FileNameSize = AsciiStrSize (FileName);
- DescriptionSize = AsciiStrSize (Description);
- //
- // Make sure it will all fit in the passed in buffer.
- //
- if (HeaderSize + ModuleNameSize + FileNameSize + DescriptionSize > sizeof (Buffer)) {
- //
- // remove module name if it's too long to be filled into buffer
- //
- ModuleNameSize = 0;
- if (HeaderSize + FileNameSize + DescriptionSize > sizeof (Buffer)) {
- //
- // FileName + Description is too long to be filled into buffer.
- //
- if (HeaderSize + FileNameSize < sizeof (Buffer)) {
- //
- // Description has enough buffer to be truncated.
- //
- DescriptionSize = sizeof (Buffer) - HeaderSize - FileNameSize;
- } else {
- //
- // FileName is too long to be filled into buffer.
- // FileName will be truncated. Reserved one byte for Description NULL terminator.
- //
- DescriptionSize = 1;
- FileNameSize = sizeof (Buffer) - HeaderSize - DescriptionSize;
- }
- }
- }
- //
- // Fill in EFI_DEBUG_ASSERT_DATA
- //
- AssertData = (EFI_DEBUG_ASSERT_DATA *)Buffer;
- AssertData->LineNumber = (UINT32)LineNumber;
- TotalSize = sizeof (EFI_DEBUG_ASSERT_DATA);
- Temp = (CHAR8 *)(AssertData + 1);
- //
- // Copy Ascii [ModuleName].
- //
- if (ModuleNameSize != 0) {
- CopyMem (Temp, "[", 1);
- CopyMem (Temp + 1, gEfiCallerBaseName, ModuleNameSize - 3);
- CopyMem (Temp + ModuleNameSize - 2, "] ", 2);
- }
- //
- // Copy Ascii FileName including NULL terminator.
- //
- Temp = CopyMem (Temp + ModuleNameSize, FileName, FileNameSize);
- Temp[FileNameSize - 1] = 0;
- TotalSize += (ModuleNameSize + FileNameSize);
- //
- // Copy Ascii Description include NULL terminator.
- //
- Temp = CopyMem (Temp + FileNameSize, Description, DescriptionSize);
- Temp[DescriptionSize - 1] = 0;
- TotalSize += DescriptionSize;
- REPORT_STATUS_CODE_EX (
- (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
- (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE),
- 0,
- NULL,
- NULL,
- AssertData,
- TotalSize
- );
- //
- // 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 ();
- }
- }
- /**
- 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 Pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
- @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
- @return Buffer 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);
- }
|