UEFI 실전-DEBUG
17837 단어 UEFI 개발 기반
약술
UEFI 개발에서 가장 중요한 부분은 직렬 디버깅 정보 인쇄를 추가하는 것입니다. 이것은 DEBUG 매크로를 통해 완성됩니다.
UEFI 코드에서는 다음과 같은 매우 많은 DEBUG 코드를 볼 수 있습니다. DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole
"));
주의해야 할 사항은 다음과 같습니다.
1. 괄호는 이중이고 아래는 첫 번째 파라미터, 두 번째 파라미터로 각각 EFI 라고 부른다.D_xx와 문자열이지만 실제로는 약간의 문제가 있습니다.
2. 두 번째 매개 변수는 문자열입니다. 이 문자열 안에는 포맷 로고도 사용할 수 있습니다. 다음은 DEBUG에서 자주 사용하는 로고입니다.
DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole
"));
3. 첫 번째 매개변수는 플롯 레벨을 나타내고 다음 매개변수는 플롯 레벨을 나타냅니다.
//
// 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 // SNP 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_ERROR 0x80000000 // Error
//
// Aliases of debug message mask bits
//
#define EFI_D_INIT DEBUG_INIT
#define EFI_D_WARN DEBUG_WARN
#define EFI_D_LOAD DEBUG_LOAD
#define EFI_D_FS DEBUG_FS
#define EFI_D_POOL DEBUG_POOL
#define EFI_D_PAGE DEBUG_PAGE
#define EFI_D_INFO DEBUG_INFO
#define EFI_D_DISPATCH DEBUG_DISPATCH
#define EFI_D_VARIABLE DEBUG_VARIABLE
#define EFI_D_BM DEBUG_BM
#define EFI_D_BLKIO DEBUG_BLKIO
#define EFI_D_NET DEBUG_NET
#define EFI_D_UNDI DEBUG_UNDI
#define EFI_D_LOADFILE DEBUG_LOADFILE
#define EFI_D_EVENT DEBUG_EVENT
#define EFI_D_VERBOSE DEBUG_VERBOSE
#define EFI_D_ERROR DEBUG_ERROR
위의 매크로 정의에 대해서도 다음과 같이 설명할 수 있습니다.
1) 먼저 여기에 두 층을 정의했는데 이것은 EDK와 EDKII의 호환 관계이기 때문에 일반적으로EFI로 시작하는 버전이 비교적 좋다.
2) 특이한 것이 하나 있는데 EFID_ERROR, 이것은 가장 높은 1로 표시된 오류입니다.
글로벌 PCD 변수의 구성에 따라 인쇄되는 레벨이 결정됩니다. 이 레벨은 다음에 설명합니다.
4. DEBUG에서 인쇄 문자의 길이는 제한되어 있으며 최대 200자까지 가능합니다.
큰 실현
1. DEBUG 매크로의 위치는 MdePkg\Include\Library\DebugLib입니다.h 파일:/**
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
여기 MDEPKG 주의해야 돼요.NDEBUG 매크로, 이 매크로를 켜면 모든 DEBUG 정보가 인쇄되지 않을 것입니다. #else 분기가 갔기 때문입니다.
MDEPKGNDEBUG 이 매크로는 일반적으로 dsc 파일에 정의됩니다. 여기는OvmfPkgX64입니다.dsc의 예:[BuildOptions]
GCC:*_UNIXGCC_*_CC_FLAGS = -DMDEPKG_NDEBUG
GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
Release 버전에서는 디버깅 인쇄를 결정하기 위해 일반적으로 정의되는 것을 볼 수 있습니다. 이것도 이해할 수 있습니다.
2. MDEPKG를 제외하고는NDEBUG 이 매크로는 Debug PrintEnabled ()
이 함수는 DebugLib에 정의되어 있으며, 서로 다른 Pkg은 서로 다른 실현이 있을 수 있으며,OvmfPkgX64로 정의될 수 있습니다.dsc의 예:!ifdef $(DEBUG_ON_SERIAL_PORT)
DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
!else
DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
!endif
Base Debug LibSerial Port를 살펴보겠습니다.inf의 구현:BOOLEAN
EFIAPI
DebugPrintEnabled (
VOID
)
{
return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
}
PcdDebugPropertyMask라는 PCD 변수의 값을 판단하는 것을 볼 수 있으며, 이것은OvmfPkgX64에 정의되어 있습니다.dsc:!ifdef $(SOURCE_DEBUG_ENABLE)
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17
!else
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
!endif
또 다른 매크로 DEBUGPROPERTY_DEBUG_PRINT_ENABLED는 다음과 같이 정의됩니다.//
// 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
그래서 OvmfPkgX64에 대해 확인할 수 있습니다.dsc, 함수 DebugPrintEnabled()가 TRUE를 반환합니다.
3. 그 다음에 주목해야 할 것은DEBUG 매크로:/**
Internal worker macro that calls DebugPrint().
This macro calls DebugPrint() passing in the debug error level, a format
string, and a variable argument list.
__VA_ARGS__ is not supported by EBC compiler, Microsoft Visual Studio .NET 2003
and Microsoft Windows Server 2003 Driver Development Kit (Microsoft WINDDK) version 3790.1830.
@param Expression Expression containing an error level, a format string,
and a variable argument list based on the format string.
**/
#if !defined(MDE_CPU_EBC) && (!defined (_MSC_VER) || _MSC_VER > 1400)
#define _DEBUG_PRINT(PrintLevel, ...) \
do { \
if (DebugPrintLevelEnabled (PrintLevel)) { \
DebugPrint (PrintLevel, ##__VA_ARGS__); \
} \
} while (FALSE)
#define _DEBUG(Expression) _DEBUG_PRINT Expression
#else
#define _DEBUG(Expression) DebugPrint Expression
#endif
여기에는 또 몇 가지 판단 조건이 관련되어 있다.
우선 컴파일러의 지원 상황입니다. 이것은 주석에 설명되어 있습니다.
또 하나는 DebugPrintLevelEnabled () 함수입니다. 이 함수에는 PrintLevel이라는 매개 변수가 있습니다. 이것은 DEBUG 함수의 첫 번째 매개 변수입니다.
이 함수도 DebugLib 라이브러리에 정의되어 있으며, 우리도BaseDebugLibSerialPort를 사용합니다.inf의 구현:/**
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);
}
여기에는 MdePkg에 정의된 PCD 변수도 포함됩니다.dec 파일: ## 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.
# BIT1 - Warning message.
# BIT2 - Load Event message.
# BIT3 - File System message.
# BIT4 - Allocate or Free Pool message.
# BIT5 - Allocate or Free Page message.
# BIT6 - Information message.
# BIT7 - Dispatcher message.
# BIT8 - Variable message.
# BIT10 - Boot Manager message.
# BIT12 - BlockIo Driver message.
# BIT14 - Network Driver message.
# BIT16 - UNDI Driver message.
# BIT17 - LoadFile message.
# BIT19 - Event message.
# BIT20 - Global Coherency Database changes message.
# BIT21 - Memory range cachability changes message.
# BIT22 - Detailed debug message.
# BIT31 - Error message.
# @Prompt Fixed Debug Message Print Level.
gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel|0xFFFFFFFF|UINT32|0x30001016
그것의 값은 전체 FF이기 때문에 이 함수는 반드시 TRUE로 되돌아옵니다. DEBUG 매크로의 첫 번째 인자가 여기에 쓸모가 없기 때문입니다.
4.1. 그 다음에 진정한 함수인 Debug Print () 가 언급되었는데, Debug Lib에 정의되었는지,Base Debug LibSerial Port에 정의되었는지.inf의 예:VOID
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
VA_LIST Marker;
//
// 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 an ASCII String
//
VA_START (Marker, Format);
AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
VA_END (Marker);
//
// Send the print string to a Serial Port
//
SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
}
함수도 비교적 간단하다. 몇 가지 설명이 있다.
1) 버퍼는 크기가 있는 그룹으로 DEBUG가 출력할 수 있는 정보는 크기 제한이 있음을 나타낸다.
2)GetDebugPrintErrorLevel() 함수는 PCD 변수를 가져오고 DEBUG의 첫 번째 인자와 비교하여 출력이 필요한지 확인합니다.
여기에 사용된 PCD 변수는 PCdDebugPrintErrorLevel이며 값은 dsc 파일에 정의되어 있습니다. # DEBUG_INIT 0x00000001 // Initialization
# DEBUG_WARN 0x00000002 // Warnings
# DEBUG_LOAD 0x00000004 // Load events
# DEBUG_FS 0x00000008 // EFI File system
# DEBUG_POOL 0x00000010 // Alloc & Free (pool)
# DEBUG_PAGE 0x00000020 // Alloc & Free (page)
# DEBUG_INFO 0x00000040 // Informational debug messages
# DEBUG_DISPATCH 0x00000080 // PEI/DXE/SMM Dispatchers
# DEBUG_VARIABLE 0x00000100 // Variable
# DEBUG_BM 0x00000400 // Boot Manager
# DEBUG_BLKIO 0x00001000 // BlkIo Driver
# DEBUG_NET 0x00004000 // SNP Driver
# DEBUG_UNDI 0x00010000 // UNDI Driver
# DEBUG_LOADFILE 0x00020000 // LoadFile
# DEBUG_EVENT 0x00080000 // Event messages
# DEBUG_GCD 0x00100000 // Global Coherency Database changes
# DEBUG_CACHE 0x00200000 // Memory range cachability changes
# DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may
# // significantly impact boot performance
# DEBUG_ERROR 0x80000000 // Error
# jw_debug, change 0x8000004F to 0x80000040
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000040
5.1. 그 다음은 SerialPortWrite () 함수로 특정한 매체에 출력된 것이다.
4.2. BaseDebugLibSerialPort 말고는ff라는 실현 방식 외에 (OVMF는 이런 방식을 사용했다) 더욱 보편적인 실현이 있다. 그것이 바로 PeiDxe Debug Lib Report Status Code이다.inf의 실현 방식은 다음과 같다. //
// Send the DebugInfo record
//
REPORT_STATUS_CODE_EX (
EFI_DEBUG_CODE,
(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED),
0,
NULL,
&gEfiStatusCodeDataTypeDebugGuid,
DebugInfo,
TotalSize
);
여기에 또 하나의 매크로 리포트를 사용했습니다STATUS_CODE_EX의 구현은 다음과 같습니다.#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
xxxEnabled () 와 type 매개 변수에 따라 함수 ReportStatusCodeEx () 실행 여부를 결정합니다.
여기서 Enabled는 dsc 파일의 PCD 변수에 따라 지정됩니다. ReportDebugCodeEnabled()의 경우/**
Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
@retval TRUE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
PcdReportStatusCodeProperyMask is set.
@retval FALSE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
PcdReportStatusCodeProperyMask is clear.
**/
BOOLEAN
EFIAPI
ReportDebugCodeEnabled (
VOID
)
{
return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
}
PCD 변수는 PcdReportStatusCodePropertyMask를 가리키며 그 값은//
// Declare bits for PcdReportStatusCodePropertyMask
//
#define REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED 0x00000001
#define REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED 0x00000002
#define REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED 0x00000004
여기 있는 3개의 값이 딱 REPORTSTATUS_CODE_EX宏 안에 있는 것들은 일일이 대응한다.
REPORT 정보STATUS_CODE_EX의 첫 번째 매개변수 type 에는///
/// Definition of code types. All other values masked by
/// EFI_STATUS_CODE_TYPE_MASK are reserved for use by
/// this specification.
///
///@{
#define EFI_PROGRESS_CODE 0x00000001
#define EFI_ERROR_CODE 0x00000002
#define EFI_DEBUG_CODE 0x00000003
///@}
Dell DEBUG 매크로에 EFI 사용DEBUG_CODE 유형입니다.
사실 REPORTSTATUS_CODE_EX 매크로는 단독으로 꺼내서 사용할 수 있으며, 예를 들어 BdsEntry와 같은 다른 type 유형을 사용할 수 있다.c 에는 다음과 같은 내용이 있습니다. REPORT_STATUS_CODE_EX (
EFI_ERROR_CODE,
PcdGet32 (PcdErrorCodeSetVariable),
0,
NULL,
&gEdkiiStatusCodeDataTypeVariableGuid,
SetVariableStatus,
sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
);
5.2. 그 다음은 함수 ReportStatus CodeEx () 와 관련이 있습니다.
그것의 실현은 매우 많은데 PEI 단계, DXE 단계, SMM 모듈, RUNTIME 모듈 등은 모두 서로 다른 실현을 가지고 있다.
다음은 DXE 단계를 예로 들면 Mde Module Pkg/Library/Dxe Report Status CodeLib/Dxe Report Status CodeLib에 있습니다.inf.
그것의 실현은 결코 복잡하지 않지만, 그 중에서 우선순위의 변화가 있다는 것을 주의해야 한다. 이것은 실제 응용에서 일부 문제를 초래할 수 있다.
ReportStatus CodeEx () 함수는 인터넷 ReportStatus Code () 함수를 호출했고, 후자는 gEfiStatus CodeRuntime Protocol Guid에 대응하는 Protocol을 통해 출력했다.
6. gEfiStatus CodeRuntime Protocol Guid의 경우 Intel Framework Module Pkg/Universal/Status Code/Runtime Dxe/Status CodeRuntime Dxe.ff에 설치된 (Coreboot에 대해 말하자면) 이 Protocol은 하나의 함수만 포함합니다: ReportDispatcher. 인터넷 ReportStatusCode () 함수에서 이 함수를 호출했습니다.
7. ReportDispatcher() 함수에서 주목해야 할 주요 코드는 다음과 같습니다. if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
SerialStatusCodeReportWorker (
CodeType,
Value,
Instance,
CallerId,
Data
);
}
if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
RtMemoryStatusCodeReportWorker (
CodeType,
Value,
Instance
);
}
if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
DataHubStatusCodeReportWorker (
CodeType,
Value,
Instance,
CallerId,
Data
);
}
if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
//
// Call OEM hook status code library API to report status code to OEM device
//
OemHookStatusCodeReport (
CodeType,
Value,
Instance,
CallerId,
Data
);
}
서로 다른 PCD 변수에 따라 서로 다른 인쇄 출력을 선택할 수 있고 심지어 사용자 정의 방식도 선택할 수 있다.
Serial Status CodeReportWorker () 의 경우, 마지막까지 Serial PortWrite () 를 호출했는데, 이것은 OVMF의 실현과 대응한다.
OVMF 버전과 달리 여기에는 더 많은 확장이 가능합니다.
지금까지 DEBUG의 성취였습니다.
또한 DEBUG와 동일한 수준의 디버그 코드인 ASSERT를 추가하면 다음과 같은 코드가 적용됩니다.VOID
EFIAPI
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
ASSERT를 사용할 때는 ASSERT 이후 코드가 CPU Dead Loop에 들어갈 수 있을 때 코드가 계속 실행되지 않도록 주의해야 한다.
일반적으로 발행판의 UEFI에서는 이런 상황을 발생시키지 않는다. 이 사용은 DSC(또는 DEC)의 PCD를 설정해야 한다. PCdDebugPropertyMask는 서로 다른 값을 설정할 수 있다. 각 BIT는 다음과 같은 의미를 가진다.//
// 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
DEBUG를 설정하면PROPERTY_ASSERT_DEADLOOP_ENABLED가 Dead Loop으로 이동합니다. //
// 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 ();
}
ASSERT 사용에 대해서는 언급하지 않았습니다. 예를 들면 다음과 같습니다.ASSERT (FileHandle != NULL);
특히 여기()의 조건은 우리가 원하는 것이기 때문에 ASSERT(FALSE)야말로 진정한 잘못된 상황이다.
사실 ASSERT도 있어요. ASSERT.EFI_ERROR (Status);
즉, Status가 잘못된 반환 값이면 ASSERT입니다.
/**
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
[BuildOptions]
GCC:*_UNIXGCC_*_CC_FLAGS = -DMDEPKG_NDEBUG
GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
!ifdef $(DEBUG_ON_SERIAL_PORT)
DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
!else
DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
!endif
BOOLEAN
EFIAPI
DebugPrintEnabled (
VOID
)
{
return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
}
!ifdef $(SOURCE_DEBUG_ENABLE)
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17
!else
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
!endif
//
// 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
/**
Internal worker macro that calls DebugPrint().
This macro calls DebugPrint() passing in the debug error level, a format
string, and a variable argument list.
__VA_ARGS__ is not supported by EBC compiler, Microsoft Visual Studio .NET 2003
and Microsoft Windows Server 2003 Driver Development Kit (Microsoft WINDDK) version 3790.1830.
@param Expression Expression containing an error level, a format string,
and a variable argument list based on the format string.
**/
#if !defined(MDE_CPU_EBC) && (!defined (_MSC_VER) || _MSC_VER > 1400)
#define _DEBUG_PRINT(PrintLevel, ...) \
do { \
if (DebugPrintLevelEnabled (PrintLevel)) { \
DebugPrint (PrintLevel, ##__VA_ARGS__); \
} \
} while (FALSE)
#define _DEBUG(Expression) _DEBUG_PRINT Expression
#else
#define _DEBUG(Expression) DebugPrint Expression
#endif
/**
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);
}
## 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.
# BIT1 - Warning message.
# BIT2 - Load Event message.
# BIT3 - File System message.
# BIT4 - Allocate or Free Pool message.
# BIT5 - Allocate or Free Page message.
# BIT6 - Information message.
# BIT7 - Dispatcher message.
# BIT8 - Variable message.
# BIT10 - Boot Manager message.
# BIT12 - BlockIo Driver message.
# BIT14 - Network Driver message.
# BIT16 - UNDI Driver message.
# BIT17 - LoadFile message.
# BIT19 - Event message.
# BIT20 - Global Coherency Database changes message.
# BIT21 - Memory range cachability changes message.
# BIT22 - Detailed debug message.
# BIT31 - Error message.
# @Prompt Fixed Debug Message Print Level.
gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel|0xFFFFFFFF|UINT32|0x30001016
VOID
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
VA_LIST Marker;
//
// 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 an ASCII String
//
VA_START (Marker, Format);
AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
VA_END (Marker);
//
// Send the print string to a Serial Port
//
SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
}
# DEBUG_INIT 0x00000001 // Initialization
# DEBUG_WARN 0x00000002 // Warnings
# DEBUG_LOAD 0x00000004 // Load events
# DEBUG_FS 0x00000008 // EFI File system
# DEBUG_POOL 0x00000010 // Alloc & Free (pool)
# DEBUG_PAGE 0x00000020 // Alloc & Free (page)
# DEBUG_INFO 0x00000040 // Informational debug messages
# DEBUG_DISPATCH 0x00000080 // PEI/DXE/SMM Dispatchers
# DEBUG_VARIABLE 0x00000100 // Variable
# DEBUG_BM 0x00000400 // Boot Manager
# DEBUG_BLKIO 0x00001000 // BlkIo Driver
# DEBUG_NET 0x00004000 // SNP Driver
# DEBUG_UNDI 0x00010000 // UNDI Driver
# DEBUG_LOADFILE 0x00020000 // LoadFile
# DEBUG_EVENT 0x00080000 // Event messages
# DEBUG_GCD 0x00100000 // Global Coherency Database changes
# DEBUG_CACHE 0x00200000 // Memory range cachability changes
# DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may
# // significantly impact boot performance
# DEBUG_ERROR 0x80000000 // Error
# jw_debug, change 0x8000004F to 0x80000040
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000040
//
// 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
/**
Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
@retval TRUE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
PcdReportStatusCodeProperyMask is set.
@retval FALSE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
PcdReportStatusCodeProperyMask is clear.
**/
BOOLEAN
EFIAPI
ReportDebugCodeEnabled (
VOID
)
{
return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
}
//
// Declare bits for PcdReportStatusCodePropertyMask
//
#define REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED 0x00000001
#define REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED 0x00000002
#define REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED 0x00000004
///
/// Definition of code types. All other values masked by
/// EFI_STATUS_CODE_TYPE_MASK are reserved for use by
/// this specification.
///
///@{
#define EFI_PROGRESS_CODE 0x00000001
#define EFI_ERROR_CODE 0x00000002
#define EFI_DEBUG_CODE 0x00000003
///@}
REPORT_STATUS_CODE_EX (
EFI_ERROR_CODE,
PcdGet32 (PcdErrorCodeSetVariable),
0,
NULL,
&gEdkiiStatusCodeDataTypeVariableGuid,
SetVariableStatus,
sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
);
if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
SerialStatusCodeReportWorker (
CodeType,
Value,
Instance,
CallerId,
Data
);
}
if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
RtMemoryStatusCodeReportWorker (
CodeType,
Value,
Instance
);
}
if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
DataHubStatusCodeReportWorker (
CodeType,
Value,
Instance,
CallerId,
Data
);
}
if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
//
// Call OEM hook status code library API to report status code to OEM device
//
OemHookStatusCodeReport (
CodeType,
Value,
Instance,
CallerId,
Data
);
}
VOID
EFIAPI
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
//
// 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
//
// 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 ();
}
ASSERT (FileHandle != NULL);