最近看到 Github 上的Intel Hao Wu 提供了一个读取“EFI Partition Infomation Protocol”的工具,在 https://github.com/hwu25/edk2/tree/partition_info_test/MdeModulePkg/Application/DumpPartInfo 可以看到(https://github.com/hwu25/edk2 branch:partition_info_test)。于是进行了一番研究。
首先对于 Partition Information Protocol 可以在 UEFI Spec 2.7 中的 13.18 章节看到,通过它可以获得当前系统中的分区信息:


DumpPartInfo代码不复杂,放到 \MdeModulePkg\Application中,然后修改MdeModulePkg.dsc 即可正常编译。但是在实体机上运行的时候没有任何输出。转过头查看 DumpPartInfo.c代码发现其中使用 DEBUG() 宏作为输出。对于DEBUG这个宏,在之前的文章【参考1】中有过研究。这个宏在 \MdePkg\Include\Library\DebugLib.h 中有定义,所有的调用都是相同的头文件,但是在链接的时候会使用不同的文件作为实现。
为了确定具体实现的文件,查看Build 过程中生成的Makefile 在\Build\MdeModule\DEBUG_VS2015x86\X64\MdeModulePkg\Application\DumpPartInfo\DumpPartInfo\Makefile 可以看到,链接过程中使用了 UefiDebugLibStdErr ,因此我们需要查看 \MdePkg\Library\UefiDebugLibStdErr\DebugLib.c 才能看到具体的实现:
1.DebugPrintEnabled()函数,代码如下:
/**
Returns TRUE if DEBUG() macros are enabled.
This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
PcdDebugProperyMask is set. Otherwise FALSE is returned.
@retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
@retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.
**/
BOOLEAN
EFIAPI
DebugPrintEnabled (
VOID
)
{
return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
}
这里提示我们需要在 MdeModulePkg.dsc 打开下面的开关:
第一部分:
[Defines]
PLATFORM_NAME = MdeModule
PLATFORM_GUID = 587CE499-6CBE-43cd-94E2-186218569478
PLATFORM_VERSION = 0.98
DSC_SPECIFICATION = 0x00010005
OUTPUT_DIRECTORY = Build/MdeModule
SUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC|ARM|AARCH64
BUILD_TARGETS = DEBUG|RELEASE|NOOPT
SKUID_IDENTIFIER = DEFAULT
#LABZ_Debug_Start
#
# Debug output control
#
DEFINE DEBUG_ENABLE_OUTPUT = TRUE # Set to TRUE to enable debug output
DEFINE DEBUG_PRINT_ERROR_LEVEL = 0x80000040 # Flags to control amount of debug output
DEFINE DEBUG_PROPERTY_MASK = 2
#LABZ_Debug_End
[LibraryClasses]
第二部分:
2.实现上面的代码后,在 NT32Pkg 虚拟机中我们可以看到 DEBUG()能够实现在屏幕上的输出了,但实体机上仍然无输出。继续研究,输出的具体代码在UefiDebugLibStdErr\DebugLib.c 中下面这个函数:
VOID
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
CHAR16 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 a Unicode String
//
VA_START (Marker, Format);
UnicodeVSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, Marker);
VA_END (Marker);
//
// Send the print string to the Standard Error device
//
if ((gST != NULL) && (gST->StdErr != NULL)) {
gST->StdErr->OutputString (gST->StdErr, Buffer);
}
}
追踪显示 gST-> StdErr 并不是 NULL,但有可能是定义为串口。对于我们来说最简单的办法是将 StdErr 赋值为 StdOut 。修改DumpPartInfo.c代码如下:
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE *Handles;
UINTN HandleCount;
UINTN HandleIndex;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
CHAR16 *DPText;
EFI_PARTITION_INFO_PROTOCOL *PartInfo;
gST->StdErr=gST->ConOut;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiPartitionInfoProtocolGuid,
NULL,
&HandleCount,
&Handles
);
之后,实体机中工作正常了:

完整代码和 X64 EFI 文件下载:
参考:
1. http://www.lab-z.com/stu170dbg/ Application 中使用 DEBUG 宏