UEFI DebugLib 介绍

news2024/11/12 16:43:19

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

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

 

/**

  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_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)



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

**/

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

 //

  // 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

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


*

*/

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() 我们还可以使用其他调试手段

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

**/

VOID

EFIAPI

CpuDeadLoop (

  VOID

  )

{

  volatile UINTN  Index;

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

    CpuPause ();

  }

}

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

CpuPause

    nop

    nop

    nop

    nop

    nop

    ret

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

VOID

EFIAPI

CpuBreakpoint (

  VOID

  )

{

  __asm__ __volatile__ ("int $3");

}

 

  __asm{
          int 3;
  }

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

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

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

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

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何保护您的 WordPress 不被黑?

明月可以说是见到过太多 WordPress 网站被黑的示例了&#xff0c;加上平时明月也会接一些 WordPress 疑难杂症的解决服务订单&#xff0c;所以这方面绝对是专业对口了。作为一个资深 WordPress 博客站长&#xff0c;谁都有被黑过的经历&#xff0c;都是一步步走过来的&#xff…

从零入门AI for Science(AI+化学)#Datawhale AI 夏令营

基于天池平台“第二届世界科学智能大赛 物质科学赛道&#xff1a;催化反应产率预测”使用平台 我的Notebook 魔搭社区 https://modelscope.cn/my/mynotebook/preset 赛事官网 上海科学智能研究院 http://competition.sais.com.cn/competitionDetail/532233/myScore Task1 …

七、SpringBoot日志

1. 得到日志对象 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; //打印日志…

【Vue实战教程】之Vue工程化项目详解

Vue工程化项目 随着多年的发展&#xff0c;前端越来越模块化、组件化、工程化&#xff0c;这是前端发展的大趋势。webpack是目前用于构建前端工程化项目的主流工具之一&#xff0c;也正变得越来越重要。本章节我们来详细讲解一下如何使用webpack搭建Vue工程化项目。 1 使用we…

Web渗透-WAF绕过技巧

一、WAF简介 Web应用防护系统&#xff08;也称为&#xff1a;网站应用级入侵防御系统。英文&#xff1a;Web Application Firewall&#xff0c;简称&#xff1a; WAF&#xff09;。利用国际上公认的一种说法&#xff1a;Web应用防火墙是通过执行一系列针对HTTP/HTTPS的安全策略…

叮!2024 龙蜥操作系统大会议题征集正式启动

定啦&#xff01;2024 龙蜥操作系统大会&#xff08;OpenAnolis Conference&#xff0c;以下简称“龙蜥大会”&#xff09;将于 2024 年 8 月 30 日在北京中关村国家自主创新示范区会议中心盛大召开。 2024 龙蜥大会由中关村科学城管委会、海淀区委网信办、中国开源软件推进联…

配置sublime的中的C++编译器(.sublime-build),实现C++20

GCC 4.8: 支持 C11 (部分) GCC 4.9: 支持 C11 和 C14 (部分) GCC 5: 完全支持 C14 GCC 6: 支持 C14 和 C17 (部分) GCC 7: 支持 C17 (大部分) GCC 8: 完全支持 C17&#xff0c;部分支持 C20 GCC 9: 支持更多的 C20 特性 GCC 10: 支持大部分 C20 特性 GCC 11: 更全面地支持 C20 …

uniapp开发精选短视频视频小程序实战笔记20240725,实现顶部轮播图和热门短剧

创建项目 创建项目,叫video_app。 在pages.json里面修改一下标题: 新建search搜索页面和me我的页面。 此时界面预览效果如下: 引入静态资源 主要是static里面的内容,全部复制过来。 配置底部导航栏 pages.json,放到顶层,和全部样式同级: "tabBar&quo…

Java的类加载机制

Java的类加载机制是指将类的字节码文件&#xff08;.class文件&#xff09;加载到JVM中并将其转换为Class对象的过程。这个过程由类加载器&#xff08;ClassLoader&#xff09;完成。Java的类加载机制具有动态性和灵活性&#xff0c;使得Java能够支持动态加载类、实现模块化开发…

4s店客户管理系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;门店管理&#xff0c;车展管理&#xff0c;汽车品牌管理&#xff0c;新闻头条管理&#xff0c;预约试驾管理&#xff0c;我的收藏管理&#xff0c;系统管理 微信端账号功能包括&a…

HTTP请求入参类型解读

HTTP请求入参类型解读 Content-Type 在HTTP请求中&#xff0c;Content-Type请求头用于指示资源的MIME类型&#xff0c;即请求体的媒体类型。它告诉服务器实际发送的数据类型是什么&#xff0c;以便服务器能够正确地解析和处理这些数据。Content-Type可以有多种值&#xff0c;…

13.2 MongoDB

13.2 MongoDB 1. 概述2. docker安装3. SpringBoot整合MongoDB3.1 依赖3.2 配置连接1. 基于`yml`配置2. 基于配置类配置3.3 启动项坑1坑23.4 新增业务1. 实体类映射2. 数据层3. 业务层4. 控制层5. 测试结果3.5 单条记录查询业务1. 数据层2. 业务层3. 控制层4. 断点测试3.6 分页查…

代码随想录算法训练营day6 | 242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1.两数之和

文章目录 哈希表键值 哈希函数哈希冲突拉链法线性探测法 常见的三种哈希结构集合映射C实现std::unordered_setstd::map 小结242.有效的字母异位词思路复习 349. 两个数组的交集使用数组实现哈希表的情况思路使用set实现哈希表的情况 202. 快乐数思路 1.两数之和思路 总结 今天是…

FoundationDB 基本使用

目录 一、FoundationDB介绍 二、安装单机版FoundationDB 2.1 下载安装程序 2.2 安装FoundationDB 2.3 修改配置信息 2.4 管理FoundationDB服务 三、fdbcli的常用命令 3.1连接数据库 3.2退出fdbcli 3.3查看版本 3.4 写模式 3.5写入键值 3.6读取键值 3.7删除键值 …

花几千上万学习Java,真没必要!(二十七)

1、Math类&#xff1a; package mathtest.com; public class MathDemo { public static void main(String[] args) { // 定义圆的半径 double radius 5.0; // 计算并打印圆的周长 double circumference 2 * Math.PI * radius; System.out.printf("圆的周长: %.2f…

Vue 状态管理 Vue CLI

Vue 状态管理 & Vue CLI 1、状态管理2、集中状态管理2.1 Vuex2.1.1 Vuex核心概念2.1.2 Vuex Store实例2.1.3 Vuex Getter2.1.4 Vuex Mutation2.1.4 Vuex Actions2.1.4 Vuex Module 2.2 Pinia2.2.1功能增强 3、Vuex 实现原理4、Pinia 实现原理5、CLI5.1 实现 1、状态管理 将…

【机器学习】激活函数:神经网络的灵魂

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 激活函数&#xff1a;神经网络的灵魂什么是激活函数?常见激活函数类型1. Sigmo…

Linux环境安装KubeSphere容器云平台并实现远程访问Web UI 界面

文章目录 前言1. 部署KubeSphere2. 本地测试访问3. Linux 安装Cpolar4. 配置KubeSphere公网访问地址5. 公网远程访问KubeSphere6. 固定KubeSphere公网地址 前言 本文主要介绍如何在Linux CentOS搭建KubeSphere并结合Cpolar内网穿透工具&#xff0c;实现远程访问&#xff0c;根…

UE4调试UE4Editor-Cmd.exe

在工作中&#xff0c;我们看到这样的构建命令&#xff1a; %EnginePath%\Binaries\Win64\UE4Editor-Cmd.exe %ClientPath%\%ProjectName%.uproject -runHotPatcher {其它参数} 我们应该如何调试UE4Editor-Cmd.exe呢&#xff1f;其实调试 UE4Editor.exe 就可以了&#xff08;参考…

Mac安装Hoomebrew与升级Python版本

参考 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装了Python 3.x版本&#xff0c;你可以使用以下命令来设置默认的Python版本&#xff1a; # 首先找到新安…