UEFI DebugLib 介绍

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

EFI_STATUSEFIAPIHelloWorld2(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()实现

 /**Macro that calls DebugPrint().If MDEPKG_NDEBUG is not defined and the DEBUG_PROPERTY_DEBUG_PRINT_ENABLEDbit of PcdDebugProperyMask is set, then this macro passes Expression toDebugPrint().@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_NDEBUGDebugPrintEnabled()时调试信息开关和等级的控制方法

包括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  进行打印

 _DEBUG (Expression);  #define _DEBUG(Expression)  _DEBUG_PRINT Expression#define _DEBUG_PRINT(PrintLevel, ...)              \do {                                             \if (DebugPrintLevelEnabled (PrintLevel)) {     \DebugPrint (PrintLevel, ##__VA_ARGS__);      \}                                              \} while (FALSE)BOOLEANEFIAPIDebugPrintLevelEnabled (IN  CONST UINTN  ErrorLevel){return (BOOLEAN)((ErrorLevel & PcdGet32 (PcdFixedDebugPrintErrorLevel)) != 0);}**/VOIDEFIAPIDebugPrint (IN  UINTN        ErrorLevel,IN  CONST CHAR8  *Format,...){VA_LIST  Marker;VA_START (Marker, Format);DebugVPrint (ErrorLevel, Format, Marker);VA_END (Marker);}VOIDEFIAPIDebugVPrint (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.infMdePkg\Library\BaseDebugLibSerialPort\DebugLib.cVOIDDebugPrintMarker (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.infMdeModulePkg\Library\PeiDxeDebugLibReportStatusCode\DebugLib.c**/VOIDDebugPrintMarker (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

**/EFI_STATUSEFIAPIReportStatusCodeEx (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

 //// Locate StatusCode Ppi.//Status = PeiServicesLocatePpi (&gEfiPeiStatusCodePpiGuid,0,NULL,(VOID **)&StatusCodePpi);EFI_STATUSInternalReportStatusCode (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

VOIDDebugPrintMarker (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 ()


*

*/UINTNEFIAPIPrint (IN CONST CHAR16  *Format,...){VA_LIST  Marker;UINTN    Return;VA_START (Marker, Format);Return = InternalPrint (Format, gST->ConOut, Marker);VA_END (Marker);return Return;}UINTNInternalPrint (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() 我们还可以使用其他调试手段

 1ASSERT()

 2CpuBreakpoint ();

  3CpuDeadLoop ();

   4CpuPause ();

 

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

止或输出错误信息。

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 信息 会打印所在的函数 行数 和 报错条件不满足原因

**/#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()处循环等待。

**/VOIDEFIAPICpuDeadLoop (VOID){volatile UINTN  Index;for (Index = 0; Index == 0;) {CpuPause ();}}

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

CpuPausenopnopnopnopnopret

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

VOIDEFIAPICpuBreakpoint (VOID){__asm__ __volatile__ ("int $3");}__asm{int 3;}

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

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

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

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/387909.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HomeServer平台选择,介绍常用功能

​​ 平台选择 HomeServer 的性能要求不高&#xff0c;以下是我的硬件参数&#xff0c;可供参考&#xff1a; ‍ 硬件&#xff1a; 平台&#xff1a;旧笔记本CPU&#xff1a;i5 4210u内存 8G硬盘&#xff1a;128G 固态做系统盘&#xff0c;1T1T 机械盘组 RAID1 做存储。硬…

【数据结构与算法】详解计数排序:小范围整数排序的最佳选择

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 二、计数排序的基本原理 三、实现步骤 1. 确定数据范围 2. 初始化计数数组…

Serverless Knative冷启动与自动扩缩容研究:从原理到实践

最近一个研究生网页的提问&#xff0c;然后就有了这篇博客&#xff01; 大佬你好&#xff0c;我看到您的关于Serverless的文章于是十分冒昧的向您提问。我现在是一名在研究通过Serverless容器调度解决冷启动问题的本科生&#xff0c;导师放养&#xff0c;就让看论文但是后面的代…

ubuntu20.04.6 安装Skywalking 10.0.1

1.前置准备 1.1. **jdk17&#xff08;Skywalking10 jdk22不兼容&#xff0c;用17版本即可&#xff09;**安装&#xff1a; https://blog.csdn.net/CsethCRM/article/details/140768670 1.2. elasticsearch安装&#xff1a; https://blog.csdn.net/CsethCRM/article/details…

Python入门宝藏《看漫画学Python》,495页漫画带你弄清python知识点!简单易懂 | 附PDF全彩版

华为出品的《看漫画学Python》全彩PDF教程是一本适合Python初学者的学习资料&#xff0c;通过漫画的形式将复杂的Python技术问题简单化&#xff0c;使学习过程更加生动有趣。以下是对该教程的内容简介、本书概要及本书目录的详细解析&#xff1a; 内容简介 《看漫画学Python》…

手机三要素接口怎么对接呢?(一)

一、什么是手机三要素&#xff1f; 手机三要素又叫运营商三要素&#xff0c;运营商实名认证&#xff0c;运营商实名核验&#xff0c;手机三要素实名验证&#xff0c;手机三要素实名核验&#xff0c;每个人的称呼都不同&#xff0c;但是入参和出参是一样的。 输入姓名、身份证…

MATLAB基础:函数与函数控制语句

今天我们继续学习Matlab中函数相关知识。 API的查询和调用 help 命令是最基本的查询方法&#xff0c;可查询所有目录、指定目录、命令、函数。 我们直接点击帮助菜单即可查询所需的API函数。 lookfor 关键字用于搜索相关的命令和函数。 如&#xff0c;我们输入lookfor inpu…

矩估计与最大似然估计的通俗理解

点估计与区间估计 矩估计与最大似然估计都属于点估计&#xff0c;也就是估计出来的结果是一个具体的值。对比区间估计&#xff0c;通过样本得出的估计值是一个范围区间。例如估计馒头店每天卖出的馒头个数&#xff0c;点估计就是最终直接估计每天卖出10个&#xff0c;而区间估…

【机器学习基础】机器学习的数学基础

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

鸿蒙(HarmonyOS)DatePicker+TimePicker时间选择控件

一、操作环境 操作系统: Windows 11 专业版、IDE:DevEco Studio 3.1.1 Release、SDK:HarmonyOS 3.1.0&#xff08;API 9&#xff09; 二、效果图 可实现两种选择方式&#xff0c;可带时分选择&#xff0c;也可不带&#xff0c;使用更加方便。 三、代码 SelectedDateDialog…

2024下半年,前端的技术风口来了

“ 你近期有体验过哪些大模型产品呢&#xff1f; 你有使用大模型API做过一些实际开发吗&#xff1f; 在你日常开发中&#xff0c;可以与大模型相关应用结合来完成工作吗&#xff1f; ” **最近&#xff0c;一直在和同事聊&#xff0c;关于前端可以用大模型干点啥&#xff…

实战:安装ElasticSearch 和常用操作命令

概叙 科普文&#xff1a;深入理解ElasticSearch体系结构-CSDN博客 Elasticsearch各版本比较 ElasticSearch 单点安装 1 创建普通用户 #1 创建普通用户名&#xff0c;密码 [roothlink1 lyz]# useradd lyz [roothlink1 lyz]# passwd lyz#2 然后 关闭xshell 重新登录 ip 地址…

Nat Med·UNI:开启计算病理学新篇章的自监督基础模型|顶刊精析·24-07-31

小罗碎碎念 本期推文主题 这一期推文是病理AI基础模型UNI的详细介绍&#xff0c;原文如下。下期推文会介绍如何使用这个模型&#xff0c;为了你能看懂下期的推文&#xff0c;强烈建议你好好看看今天这期推文。 看完这篇推文以后&#xff0c;你大概就能清楚这个模型对自己的数据…

卷积神经网络(六)---实现 cifar10 分类

cifar10 数据集有60000张图片&#xff0c;每张图片的大小都是 32x32 的三通道的彩色图&#xff0c;一共是10种类别、每种类别有6000张图片&#xff0c;如图4.27所示。 图 4.27 cifar数据集 使用前面讲过的残差结构来处理 cifar10 数据集&#xff0c;可以实现比较高的准确率。 …

麦田物语第十五天

系列文章目录 麦田物语第十五天 文章目录 系列文章目录一、构建游戏的时间系统二、时间系统 UI 制作总结 一、构建游戏的时间系统 在该游戏中我们要构建年月日天时分秒等时间的概念&#xff0c;从而实现季节的更替&#xff0c;昼夜的更替等&#xff08;不同的季节可以播种不同…

【MATLAB源码】机器视觉与图像识别技术实战示例文档---鱼苗面积预测计数

系列文章目录 第一篇文章&#xff1a;【MATLAB源码】机器视觉与图像识别技术—视觉系统的构成(视频与图像格式转换代码及软件下载) 第二篇文章&#xff1a;【MATLAB源码】机器视觉与图像识别技术(2)—图像分割基础 第三篇文章&#xff1a;【MATLAB源码】机器视觉与图像识别技术…

提交高通量测序处理数据到 GEO --- 操作流程

❝ 写在前面 由于最近在提交课题数据到 NCBI 数据库&#xff0c;整理了相关笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. 提交高通量测序数据到 GEO --- 说明书 2. 提交高通量测序原…

jQuery前端网页制作

1、Jquery的概述 1.1JavaScript库 JavaScript 高级程序设计(特别是对浏览器差异的复杂处理),通常很困难也很耗时。 为了应对这些调整,许多的 JavaScript (helper) 库应运而生。 这些 JavaScript 库常被称为 JavaScript 框架。 市面上一些广受欢迎的 JavaScript 框架:…

基于Docker搭建ELK

目录 1.系统操作 2.搭建es 3.kibana(新起终端跟es一起启动) 4.logstash&#xff08;新起终端和es一起启动&#xff09; 5.修改logstash配置文件 6. 创建索引 7. exit #退出容器 8. 在logstash节点插入数据&#xff0c;测试是否能拿取到&#xff08;下面如果本身有数据…

基于多种机器学习的豆瓣电影评分预测与多维度可视化【可加系统】

有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 在本研究中&#xff0c;我们采用Python编程语言&#xff0c;利用爬虫技术实时获取豆瓣电影最新数据。通过分析豆瓣网站的结构&#xff0c;我们设计了一套有效的策略来爬取电影相关的JSON格式数据。…