最近看到 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 宏