UEFI DebugLib 介绍

1.我们调试中常用Debug 打印信息,这些会输出到BIOS串口日志中

cpp 复制代码
EFI_STATUS

EFIAPI

HelloWorld2(

  IN EFI_HANDLE        ImageHandle,

  IN EFI_SYSTEM_TABLE  *SystemTable

  )

{

    EFI_STATUS      Status;

    Status=EFI_SUCCESS;

    gST->ConOut->OutputString(gST->ConOut,L"ConOut:Hellow World \n\r");

    Print(L"Print:Hellow World\n");

    DEBUG ((DEBUG_ERROR, "Debug:Hellow World\n"));

    return Status;

}

UEFI shell下运行效果:我们发现这几种输出都打印到了Shell界面而不是串口中

通常在shell 界面显示打印信息会使用到Print() 和 gST->ConOut->OutputString,而Debug 是打印在串口日志中

Debug 对于调试至关重要,那么我们需要深入了解DebugLib 和Debug()实现

cpp 复制代码
 

/**

  Macro that calls DebugPrint().

  If MDEPKG_NDEBUG is not defined and the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED

  bit of PcdDebugProperyMask is set, then this macro passes Expression to

  DebugPrint().

  @param  Expression  Expression containing an error level, a format string,

                      and a variable argument list based on the format string.



**/

#if !defined (MDEPKG_NDEBUG)

#define DEBUG(Expression)        \

    do {                           \

      if (DebugPrintEnabled ()) {  \

        _DEBUG (Expression);       \

      }                            \

    } while (FALSE)

#else

#define DEBUG(Expression)

#endif

 

有多个Lib 对DebugPrintEnabled 做了定义,因此可以使用不同的Lib 让Debug()产生不同的效果,这点也适用于其他函数

对于不同的架构实现方式可能不同,但是可以用同样的模块代码,通过替换Lib去替换实现函数

EDK常用的Debuglib

DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf

DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf

DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

其中MDEPKG_NDEBUG和DebugPrintEnabled()时调试信息开关和等级的控制方法

包括PcdDebugPropertyMask DEBUG_PROPERTY_DEBUG_PRINT_ENABLED

BOOLEAN

EFIAPI

DebugPrintEnabled (

VOID

)

{

return (BOOLEAN)((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);

}

PcdDebugPropertyMask 定义

The mask is used to control DebugLib behavior.<BR><BR>

BIT0 - Enable Debug Assert.<BR>

BIT1 - Enable Debug Print.<BR>

BIT2 - Enable Debug Code.<BR>

BIT3 - Enable Clear Memory.<BR>

BIT4 - Enable BreakPoint as ASSERT.<BR>

BIT5 - Enable DeadLoop as ASSERT.<BR>

BIT6 - Enable Debug Assert as BreakPoint only.<BR>

@Prompt Debug Property.

@Expression 0x80000002 | (gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask & 0xC0) == 0

gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0|UINT8|0x00000005

//

// Declare bits for PcdDebugPropertyMask

//

#define DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED 0x01

#define DEBUG_PROPERTY_DEBUG_PRINT_ENABLED 0x02

#define DEBUG_PROPERTY_DEBUG_CODE_ENABLED 0x04

#define DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED 0x08

#define DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED 0x10

#define DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED 0x20

#define DEBUG_PROPERTY_ASSERT_ONLY_BREAKPOINT 0x40

第二个相关的Pcd : PcdFixedDebugPrintErrorLevel 打印信息等级常用的就是EFI_D_ERROR EFI_D_WARN EFI_D_INFO 等

This flag is used to control build time optimization based on debug print level.

Its default value is 0xFFFFFFFF to expose all debug print level.

BIT0 - Initialization message.<BR>

BIT1 - Warning message.<BR>

BIT2 - Load Event message.<BR>

BIT3 - File System message.<BR>

BIT4 - Allocate or Free Pool message.<BR>

BIT5 - Allocate or Free Page message.<BR>

BIT6 - Information message.<BR>

BIT7 - Dispatcher message.<BR>

BIT8 - Variable message.<BR>

BIT10 - Boot Manager message.<BR>

BIT12 - BlockIo Driver message.<BR>

BIT14 - Network Driver message.<BR>

BIT16 - UNDI Driver message.<BR>

BIT17 - LoadFile message.<BR>

BIT19 - Event message.<BR>

BIT20 - Global Coherency Database changes message.<BR>

BIT21 - Memory range cachability changes message.<BR>

BIT22 - Detailed debug message.<BR>

BIT31 - Error message.<BR>

@Prompt Fixed Debug Message Print Level.

gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel|0xFFFFFFFF|UINT32|0x30001016

//

// Declare bits for PcdDebugPrintErrorLevel and the ErrorLevel parameter of DebugPrint()

//

#define DEBUG_INIT 0x00000001 // Initialization

#define DEBUG_WARN 0x00000002 // Warnings

#define DEBUG_LOAD 0x00000004 // Load events

#define DEBUG_FS 0x00000008 // EFI File system

#define DEBUG_POOL 0x00000010 // Alloc & Free (pool)

#define DEBUG_PAGE 0x00000020 // Alloc & Free (page)

#define DEBUG_INFO 0x00000040 // Informational debug messages

#define DEBUG_DISPATCH 0x00000080 // PEI/DXE/SMM Dispatchers

#define DEBUG_VARIABLE 0x00000100 // Variable

#define DEBUG_BM 0x00000400 // Boot Manager

#define DEBUG_BLKIO 0x00001000 // BlkIo Driver

#define DEBUG_NET 0x00004000 // Network Io Driver

#define DEBUG_UNDI 0x00010000 // UNDI Driver

#define DEBUG_LOADFILE 0x00020000 // LoadFile

#define DEBUG_EVENT 0x00080000 // Event messages

#define DEBUG_GCD 0x00100000 // Global Coherency Database changes

#define DEBUG_CACHE 0x00200000 // Memory range cachability changes

#define DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may

// significantly impact boot performance

#define DEBUG_MANAGEABILITY 0x00800000 // Detailed debug and payload message of manageability

// related modules, such Redfish, IPMI, MCTP and etc.

#define DEBUG_ERROR 0x80000000 // Error

MdeModulePkg/Application/HelloWorld/HelloWorld.inf {

<PcdsFixedAtBuild>

gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel | 0xffffffff

gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xff

<LibraryClasses>

#DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf

#DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf

}

gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0 就不会打印Debug 信息

gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xff 进行打印

cpp 复制代码
 _DEBUG (Expression);  

 



#define _DEBUG(Expression)  _DEBUG_PRINT Expression



#define _DEBUG_PRINT(PrintLevel, ...)              \

    do {                                             \

      if (DebugPrintLevelEnabled (PrintLevel)) {     \

        DebugPrint (PrintLevel, ##__VA_ARGS__);      \

      }                                              \

    } while (FALSE)



BOOLEAN

EFIAPI

DebugPrintLevelEnabled (

  IN  CONST UINTN  ErrorLevel

  )

{

  return (BOOLEAN)((ErrorLevel & PcdGet32 (PcdFixedDebugPrintErrorLevel)) != 0);

}



**/

VOID

EFIAPI

DebugPrint (

  IN  UINTN        ErrorLevel,

  IN  CONST CHAR8  *Format,

  ...

  )

{

  VA_LIST  Marker;

  VA_START (Marker, Format);

  DebugVPrint (ErrorLevel, Format, Marker);

  VA_END (Marker);

}



VOID

EFIAPI

DebugVPrint (

  IN  UINTN        ErrorLevel,

  IN  CONST CHAR8  *Format,

  IN  VA_LIST      VaListMarker

  )

{

  DebugPrintMarker (ErrorLevel, Format, VaListMarker, NULL);

}

1.BaseDebugLibSerialPort Debuglib 使用的是SerialPortWrite 打印信息

DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf

MdePkg\Library\BaseDebugLibSerialPort\DebugLib.c

VOID

DebugPrintMarker (

  IN  UINTN        ErrorLevel,

  IN  CONST CHAR8  *Format,

  IN  VA_LIST      VaListMarker,

  IN  BASE_LIST    BaseListMarker

  )

{

  CHAR8  Buffer[MAX_DEBUG_MESSAGE_LENGTH];

  //

  // If Format is NULL, then ASSERT().

  //

  ASSERT (Format != NULL);

  //

  // Check driver debug mask value and global mask

  //

  if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {

    return;

  }

  if (AsciiStrStr (Format, "\n") != NULL) {

    UINTN           ModuleNameLength;

    ModuleNameLength = AsciiStrLen (gEfiCallerBaseName) + 2;

    *Buffer = '[';

    AsciiStrnCpyS (

    Buffer + 1,

    ModuleNameLength -1,

    gEfiCallerBaseName,

    ModuleNameLength - 2

    );

    *(Buffer + ModuleNameLength - 1) = ']';

    *(Buffer + ModuleNameLength)     = 0;

    //

    // Send the print string to a Serial Port

    //

    SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));

  }

  //

  // Convert the DEBUG() message to an ASCII String

  //

  if (BaseListMarker == NULL) {

    AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker);

  } else {

    AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker);

  }

  //

  // Send the print string to a Serial Port

  //

  SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));

}

  2.  PeiDxeDebugLibReportStatusCode是更通用的Debug 实现了从PEI DXE 等都有实现

 DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf

 MdeModulePkg\Library\PeiDxeDebugLibReportStatusCode\DebugLib.c

**/

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

    );

}



**/

#define REPORT_STATUS_CODE_EX(Type, Value, Instance, CallerId, ExtendedDataGuid, ExtendedData, ExtendedDataSize)  \

  (ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE)             ?  \

  ReportStatusCodeEx(Type,Value,Instance,CallerId,ExtendedDataGuid,ExtendedData,ExtendedDataSize)        :  \

  (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)                   ?  \

  ReportStatusCodeEx(Type,Value,Instance,CallerId,ExtendedDataGuid,ExtendedData,ExtendedDataSize)        :  \

  (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)                   ?  \

  ReportStatusCodeEx(Type,Value,Instance,CallerId,ExtendedDataGuid,ExtendedData,ExtendedDataSize)        :  \

  EFI_UNSUPPORTED

#endif

最后调用的是ReportStatusCodeEx,该函数在PEI,DXE Runtime 和SMM Driver中都有实现

ReportStatusCodeEx

PEI实现举例:最终调用的是PeiService 的ppi

cpp 复制代码
**/

EFI_STATUS

EFIAPI

ReportStatusCodeEx (

  IN EFI_STATUS_CODE_TYPE   Type,

  IN EFI_STATUS_CODE_VALUE  Value,

  IN UINT32                 Instance,

  IN CONST EFI_GUID         *CallerId          OPTIONAL,

  IN CONST EFI_GUID         *ExtendedDataGuid  OPTIONAL,

  IN CONST VOID             *ExtendedData      OPTIONAL,

  IN UINTN                  ExtendedDataSize

  )

{

  EFI_STATUS_CODE_DATA  *StatusCodeData;

  UINT64                Buffer[(MAX_EXTENDED_DATA_SIZE / sizeof (UINT64)) + 1];

  //

  // If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().

  //

  ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));

  //

  // If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().

  //

  ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));

  if (ExtendedDataSize > (MAX_EXTENDED_DATA_SIZE - sizeof (EFI_STATUS_CODE_DATA))) {

    //

    // The local variable Buffer not large enough to hold the extended data associated

    // with the status code being reported.

    //

    DEBUG ((DEBUG_ERROR, "Status code extended data is too large to be reported!\n"));

    return EFI_OUT_OF_RESOURCES;

  }

  StatusCodeData             = (EFI_STATUS_CODE_DATA  *)Buffer;

  StatusCodeData->HeaderSize = (UINT16)sizeof (EFI_STATUS_CODE_DATA);

  StatusCodeData->Size       = (UINT16)ExtendedDataSize;

  if (ExtendedDataGuid == NULL) {

    ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;

  }

  CopyGuid (&StatusCodeData->Type, ExtendedDataGuid);

  if (ExtendedData != NULL) {

    CopyMem (StatusCodeData + 1, ExtendedData, ExtendedDataSize);

  }

  if (CallerId == NULL) {

    CallerId = &gEfiCallerIdGuid;

  }

  return InternalReportStatusCode (Type, Value, Instance, CallerId, StatusCodeData);

}



///

/// Pei service instance

///

EFI_PEI_SERVICES  gPs = {

  {

    PEI_SERVICES_SIGNATURE,

    PEI_SERVICES_REVISION,

    sizeof (EFI_PEI_SERVICES),

    0,

    0

  },

  PeiInstallPpi,

  PeiReInstallPpi,

  PeiLocatePpi,

  PeiNotifyPpi,

  PeiGetBootMode,

  PeiSetBootMode,

  PeiGetHobList,

  PeiCreateHob,

  PeiFfsFindNextVolume,

  PeiFfsFindNextFile,

  PeiFfsFindSectionData,

  PeiInstallPeiMemory,

  PeiAllocatePages,

  PeiAllocatePool,

  (EFI_PEI_COPY_MEM)CopyMem,

  (EFI_PEI_SET_MEM)SetMem,

  PeiReportStatusCode,

  PeiResetSystem,

  &gPeiDefaultCpuIoPpi,

  &gPeiDefaultPciCfg2Ppi,

  PeiFfsFindFileByName,

  PeiFfsGetFileInfo,

  PeiFfsGetVolumeInfo,

  PeiRegisterForShadow,

  PeiFfsFindSectionData3,

  PeiFfsGetFileInfo2,

  PeiResetSystem2,

  PeiFreePages,

};

UEFI中 PeiService 中包含的函数

//

// Status Code

//

EFI_PEI_REPORT_STATUS_CODE ReportStatusCode;

PeiServices->PeiReportStatusCode

cpp 复制代码
 //

  // Locate StatusCode Ppi.

  //

  Status = PeiServicesLocatePpi (

             &gEfiPeiStatusCodePpiGuid,

             0,

             NULL,

             (VOID **)&StatusCodePpi

             );

 

EFI_STATUS

InternalReportStatusCode (

  IN EFI_STATUS_CODE_TYPE   Type,

  IN EFI_STATUS_CODE_VALUE  Value,

  IN UINT32                 Instance,

  IN CONST EFI_GUID         *CallerId OPTIONAL,

  IN EFI_STATUS_CODE_DATA   *Data     OPTIONAL

  )

{

  CONST EFI_PEI_SERVICES  **PeiServices;

  EFI_STATUS              Status;

  if ((ReportProgressCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE)) ||

      (ReportErrorCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)) ||

      (ReportDebugCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)))

  {

    GUID_WITH_MODULENAME    GuidWithName;

    EFI_GUID                *CallerGuid;

    CallerGuid = (EFI_GUID *)CallerId;

    if (CallerGuid != NULL) {

      CopyGuid (&GuidWithName.Guid, CallerId);

      GuidWithName.Signature  = REPORT_STATUS_GUID_MODULE_SIGNATURE;

      GuidWithName.ModuleName = gEfiCallerBaseName;

      CallerGuid = &GuidWithName.Guid;

    }

    PeiServices = GetPeiServicesTablePointer ();

    Status      = (*PeiServices)->ReportStatusCode (

                                    PeiServices,

                                    Type,

                                    Value,

                                    Instance,

                                    (EFI_GUID *)CallerGuid,

                                    Data

                                    );

    if (Status == EFI_NOT_AVAILABLE_YET) {

      Status = OemHookStatusCodeInitialize ();

      if (!EFI_ERROR (Status)) {

        return OemHookStatusCodeReport (Type, Value, Instance, (EFI_GUID *)CallerGuid, Data);

      }

    }

    return Status;

  }

  return EFI_UNSUPPORTED;

}

 

3.UefiDebugLibConOut.inf 这个Lib就是开始我们提到的将debug信息打印到Shell 使用的Lib

#DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

MdePkg\Library\UefiDebugLibConOut\DebugLib.c

同样关注不同Lib中的 DebugPrintMarker 实现 了解各DebugLib的区别

#define MAX_DEBUG_MESSAGE_LENGTH 0x100 定义了最大的Buffer size

cpp 复制代码
VOID

DebugPrintMarker (

  IN  UINTN        ErrorLevel,

  IN  CONST CHAR8  *Format,

  IN  VA_LIST      VaListMarker,

  IN  BASE_LIST    BaseListMarker

  )

{

  CHAR16  Buffer[MAX_DEBUG_MESSAGE_LENGTH];

  if (!mPostEBS) {

    //

    // If Format is NULL, then ASSERT().

    //

    ASSERT (Format != NULL);

    //

    // Check driver debug mask value and global mask

    //

    if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {

      return;

    }

    //

    // Convert the DEBUG() message to a Unicode String

    //

    if (BaseListMarker == NULL) {

      UnicodeVSPrintAsciiFormat (Buffer, sizeof (Buffer), Format, VaListMarker);

    } else {

      UnicodeBSPrintAsciiFormat (Buffer, sizeof (Buffer), Format, BaseListMarker);

    }

    //

    // Send the print string to the Console Output device

    //

    if ((mDebugST != NULL) && (mDebugST->ConOut != NULL)) {

      mDebugST->ConOut->OutputString (mDebugST->ConOut, Buffer);

    }

  }

}

可以看到最后调用的就是 mDebugST->ConOut->OutputString (mDebugST->ConOut, Buffer);

最后EFI Shell下常用的Print 最后调用的都是gRT->ConOut->OutputString ()

*

cpp 复制代码
*/

UINTN

EFIAPI

Print (

  IN CONST CHAR16  *Format,

  ...

  )

{

  VA_LIST  Marker;

  UINTN    Return;

  VA_START (Marker, Format);

  Return = InternalPrint (Format, gST->ConOut, Marker);

  VA_END (Marker);

  return Return;

}



UINTN

InternalPrint (

  IN  CONST CHAR16                     *Format,

  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *Console,

  IN  VA_LIST                          Marker

  )

{

  EFI_STATUS  Status;

  UINTN       Return;

  CHAR16      *Buffer;

  UINTN       BufferSize;

  ASSERT (Format != NULL);

  ASSERT (((UINTN)Format & BIT0) == 0);

  ASSERT (Console != NULL);

  BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);

  Buffer = (CHAR16 *)AllocatePool (BufferSize);

  ASSERT (Buffer != NULL);

  Return = UnicodeVSPrint (Buffer, BufferSize, Format, Marker);

  if ((Console != NULL) && (Return > 0)) {

    //

    // To be extra safe make sure Console has been initialized

    //

    Status = Console->OutputString (Console, Buffer);

    if (EFI_ERROR (Status)) {

      Return = 0;

    }

  }

  FreePool (Buffer);

  return Return;

}
  1. 除了常用的Debug() 我们还可以使用其他调试手段

(1)ASSERT()

(2)CpuBreakpoint ();

(3)CpuDeadLoop ();

(4)CpuPause ();

ASSERT是一种在程序中用于检查特定条件是否为真的方法。当条件为假时,断言会触发错误处理机制,通常会导致程序中

止或输出错误信息。

cpp 复制代码
HelloWorld2(

  IN EFI_HANDLE        ImageHandle,

  IN EFI_SYSTEM_TABLE  *SystemTable

  )

{

    EFI_STATUS      Status;

    Status=EFI_SUCCESS;

    UINT8 index=0;

    ASSERT(index == 1);

    gST->ConOut->OutputString(gST->ConOut,L"ConOut:Hellow World \n\r");

    Print(L"Print:Hellow World\n");

    DEBUG ((DEBUG_ERROR, "Debug:Hellow World\n"));

    return Status;

     

}

当运行到Assert 就会出现Assert 信息 会打印所在的函数 行数 和 报错条件不满足原因

cpp 复制代码
**/

#if !defined (MDEPKG_NDEBUG)

#define ASSERT(Expression)        \

    do {                            \

      if (DebugAssertEnabled ()) {  \

        if (!(Expression)) {        \

          _ASSERT (Expression);     \

          ANALYZER_UNREACHABLE ();  \

        }                           \

      }                             \

    } while (FALSE)

#else

#define ASSERT(Expression)

#endif

执行 CpuDeadLoop (); 后会出现Hang机现象 原因是出现循环

现在Shell应该在CpuDeadLoop()处循环等待。

cpp 复制代码
**/

VOID

EFIAPI

CpuDeadLoop (

  VOID

  )

{

  volatile UINTN  Index;

  for (Index = 0; Index == 0;) {

    CpuPause ();

  }

}

CpuPause (); 其实是等待 Nop 命令

bash 复制代码
CpuPause

    nop

    nop

    nop

    nop

    nop

    ret

CpuBreakpoint () 是设置断点 后续可以进行单步操作

cpp 复制代码
VOID

EFIAPI

CpuBreakpoint (

  VOID

  )

{

  __asm__ __volatile__ ("int $3");

}

 

  __asm{
          int 3;
  }

x86 系列处理器从其第一代产品英特尔 8086 开始就提供了一条专门用来支持调试的指令,即 INT 3。简单地说,这条指令

的目的就是使 CPU 中断(break)到调试器,以供调试者对执行现场进行各种分析。

当我们调试程序时,可以在可能有问题的地方插入一条 INT 3 指令,使 CPU 执行到这一点时停下来。这便是软件调试中经

常用到的断点(breakpoint)功能,因此 INT 3 指令又被称为断点指令。

相关推荐
九河云1 小时前
AWS账号注册费用详解:新用户是否需要付费?
服务器·云计算·aws
Lary_Rock1 小时前
RK3576 LINUX RKNN SDK 测试
linux·运维·服务器
幺零九零零2 小时前
【计算机网络】TCP协议面试常考(一)
服务器·tcp/ip·计算机网络
云飞云共享云桌面3 小时前
8位机械工程师如何共享一台图形工作站算力?
linux·服务器·网络
幺零九零零6 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
free7 小时前
netstat中sendq/recvq用于排查发送端发送数据的问题
服务器
力姆泰克8 小时前
看电动缸是如何提高农机的自动化水平
大数据·运维·服务器·数据库·人工智能·自动化·1024程序员节
力姆泰克8 小时前
力姆泰克电动缸助力农业机械装备,提高农机的自动化水平
大数据·服务器·数据库·人工智能·1024程序员节
程思扬8 小时前
为什么Uptime+Kuma本地部署与远程使用是网站监控新选择?
linux·服务器·网络·经验分享·后端·网络协议·1024程序员节
sun0077008 小时前
拷贝 cp -rdp 和 cp -a
linux·运维·服务器