阅读《UEFI原理与编程》,第八章,开发UEFI服务。其中提到了 Protocol的私有数据。
之前我们介绍过 EFI_LOADED_IMAGE_PROTOCOL,在【参考1】的程序中,就有涉及到LOADED_IMAGE_PRIVATE_DATA,简单的说,定义的 PROTOCOL是这个结构体的一部分,就能够找到整个LOADED_IMAGE_PRIVATE_DATA的结构体,从而获得一些额外的信息。
总结一下,这样的私有数据是这样定义的:
#define PROTOCOLNAME_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p','r','t','9')
typedef struct {
UINTN Signature;
UINTN Var1;
PROTOCOLNAME _PROTOCOL PROTOCOLNAME;
} PROTOCOLNAME_PRIVATE_DATA;
#define PROTOCOLNAME _PRIVATE_DATA_FROM_THIS(a) \
CR(a, PROTOCOLNAME_PRIVATE_DATA, PROTOCOLNAME, PROTOCOLNAME _PRIVATE_DATA_SIGNATURE)
在初始化的时候,要创建一个实际的PROTOCOLNAME_PRIVATE_DATA,然后初始化需要的变量,最后像其他的Protocol安装一样,将PROTOCOLNAME_PRIVATE_DATA. PROTOCOLNAME 安装到合适的Handle上即可。
编写代码测试一下,基于之前我们写的 PrintDriver 代码,先修改 Print9.h。加入了下面的定义:
#define PRINT9_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p','r','t','9')
typedef struct {
UINTN Signature;
UINTN Var1;
/// loaded PROTOCOLNAME
EFI_PRINT9_PROTOCOL PRINT9;
} EFI_PRINT9_PRIVATE_DATA;
#define EFI_PRINT9_PRIVATE_DATA_FROM_THIS(a) \
CR(a, EFI_PRINT9_PRIVATE_DATA, PRINT9, PRINT9_PRIVATE_DATA_SIGNATURE)
之后修改print.c。 这个 driver实现的功能很简单,每次调用UnicodeSPrint 函数的时候,会自动显示 EFI_PRINT9_PRIVATE_DATA 中的 Var1,并且增加1.
#include <PiDxe.h>
#include <Library/UefiLib.h>
#include "Print9.h"
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/MemoryAllocationLib.h>
EFI_PRINT9_PRIVATE_DATA *Image;
EFI_HANDLE mPrintThunkHandle = NULL;
extern EFI_SYSTEM_TABLE *gST;
//Copied from \MdeModulePkg\Library\DxePrintLibPrint2Protocol\PrintLib.c
UINTN
EFIAPI
MyUnicodeSPrint (
OUT CHAR16 *StartOfBuffer,
IN UINTN BufferSize,
IN CONST CHAR16 *FormatString,
...
)
{
VA_LIST Marker;
UINTN NumberOfPrinted=1;
CHAR16 *Buffer=L"12345678";
VA_START (Marker, FormatString);
//NumberOfPrinted = UnicodeVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
VA_END (Marker);
UnicodeSPrint(Buffer,8,L"%d",Image->Var1);
gST->ConOut->OutputString(gST->ConOut,Buffer);
Image->Var1++;
return NumberOfPrinted;
}
/**
The user Entry Point for Print module.
This is the entry point for Print DXE Driver. It installs the Print2 Protocol.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval Others Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
PrintEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status=EFI_SUCCESS;
//
// Allocate a new image structure
//
Image = AllocateZeroPool (sizeof(EFI_PRINT9_PRIVATE_DATA));
if (Image == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
Image->Signature = PRINT9_PRIVATE_DATA_SIGNATURE;
Image->PRINT9.UnicodeBSPrint=UnicodeBSPrint;
Image->PRINT9.UnicodeSPrint=MyUnicodeSPrint;
Image->PRINT9.UnicodeBSPrintAsciiFormat=UnicodeBSPrintAsciiFormat;
Image->PRINT9.UnicodeSPrintAsciiFormat=UnicodeSPrintAsciiFormat;
Image->PRINT9.UnicodeValueToString=UnicodeValueToString;
Image->PRINT9.AsciiBSPrint=AsciiBSPrint;
Image->PRINT9.AsciiSPrint=AsciiSPrint;
Image->PRINT9.AsciiBSPrintUnicodeFormat=AsciiBSPrintUnicodeFormat;
Image->PRINT9.AsciiSPrintUnicodeFormat=AsciiSPrintUnicodeFormat;
Image->PRINT9.AsciiValueToString=AsciiValueToString;
Status = gBS->InstallMultipleProtocolInterfaces (
&mPrintThunkHandle,
&gEfiPrint9ProtocolGuid,
&Image->PRINT9,
NULL
);
ASSERT_EFI_ERROR (Status);
Done:
return Status;
}
测试这个 Protocol 使用的还是之前的 pdt.efi,运行结果如下:
完整的代码下载
参考:
1. Step to UEFI (48) —– 被加载程序的ENTRYPOINT





















