1 介绍
同样在UEFI Spec的第七章Boot Service中有两个关于Protocol创建的函数,分别是InstallProtocolInterface()和InstallMultipleProtocolInterfaces()。顾名思义,前者是只安装一个ProtocolInterface,后者可以安装一个或多个ProtocolInterface,此外,InstallMultipleProtocolInterfaces()比InstallProtocolInterface()执行更多的错误检查,因此规范建议使用InstallMultipleProtocolInterfaces()。但本文以InstallProtocolInterface()为例。

1.1 InstallProtocolInterface()
函数原型为:

typedef
 EFI_STATUS
 (EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE) (
 IN OUT EFI_HANDLE *Handle,
 IN EFI_GUID *Protocol,
 IN EFI_INTERFACE_TYPE InterfaceType,
 IN VOID *Interface
 );

参数:
Handle: 一个指向要安装接口的EFI_HANDLE的指针。如果Handle在输入时为NULL,则创建一个新的句柄并在输出时返回。如果Handle在输入时不为NULL,则协议被添加到句柄中,句柄未被修改就返回。类型EFI_HANDLE在“相关定义”中定义。如果*Handle不是一个有效句柄,则返回EFI_INVALID_PARAMETER。
Protocol: GUID,用来标识这个Protocol。调用方负责传递一个有效的GUID。
InterfaceType: 指示是否以native form提供Interface。该值指示请求的原始执行环境。它是一个枚举类型。这里不太明白“native form”是什么含义。
Interface: 一个指向协议接口的指针。接口必须符合协议定义的结构。如果一个结构与协议没有关联,则可以使用NULL。

1.2 InstallMultipleProtocolInterfaces()
函数原型为:

typedef
 EFI_STATUS
 EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) (
 IN OUT EFI_HANDLE *Handle,
 …
 );

参数:
Handle: 指向要在上面安装新协议接口的句柄的指针,或者如果要分配新句柄,则指向NULL。
… : 一个变量参数列表,包含对协议guid和协议接口。

2 Protocol创建
Protocol的创建需要准备几个部分:
1)Protocol GUID;
2)构建Protocol的成员函数以及结构体;
3)实例化一个Protocol结构体类型的实例。
注意事项:Protocol的成员函数,其函数类型必须是EFIAPI修饰的,并且第一个函数参数必须为This指针。

2.1 步骤
首先创建一个Module,新建CreateProtocol.inf和CreateProtocol.c。
在EmulatorPkg.dsc文件的[Components]下添加EmulatorPkg/Application/CreateProtocol
/CreateProtocol.inf。文件内容可见后文附录。
然后编译成CreateProtocol.efi文件,在shell环境下加载。结果如图:

我们可以使用LocateProtocol()函数来验证可不可以加载我们创建的Protocol,这个内容在上文Protocol的使用中已经介绍过了。只要把这个函数里的参数IN EFI_GUID *Protocol换成我们定义的Protocol的GUID就可以了。
这时候编译会出现问题,因为还需要把我们定义的GUID也就是gEfiCreateProtocolGUID添加到/vUDK2017/MdePkg/MdePkg.dec文件的[Protocols]下。
编译完成后首先在shell下运行使用Protocol的程序,这时候程序不会Locate到我们定义的Protocol,因为我们还没有将它load进内存;然后我们使用load命令将CreateProtocol.efi加载到内存,再Locate,这时候程序可以成功找到我们定义的Protocol。结果如下图:

附录

CreateProtocol.c文件
 #include<Uefi.h>
 #include<Library/UefiDriverEntryPoint.h>
 #include<Library/UefiBootServicesTableLib.h>
 #include<Library/UefiLib.h>typedef EFI_STATUS(EFIAPI* EFI_INPUT_MSG)();
//protocol结构体
 struct _EFI_CREATE_PROTOCOL{
 UINT64 Revsion; //版本
 EFI_INPUT_MSG InputMsg; //成员函数
 };typedef struct _EFI_CREATE_PROTOCOL EFI_CREATE_PROTOCOL;
 //定义GUID
 #define EFI_CREATE_PROTOCOL_GUID 
 {0xa32ccd8b, 0x021b, 0x4a7f, {0x9d, 0xc0, 0xe5, 0x16, 0x35, 0x63, 0x8f, 0xb7}}EFI_GUID gEfiCreateProtocolGUID = EFI_CREATE_PROTOCOL_GUID;
//Protocol中成员函数的实现
 EFI_STATUS EFIAPI InputMsg(IN EFI_CREATE_PROTOCOL This)
 {
 gST->ConOut->OutputString(gST->ConOut,L"Create Protocol\n");
 return EFI_SUCCESS;
 }
 //Protocol的实例
 EFI_CREATE_PROTOCOL gMyProtocol;
 //初始化Protocol实例函数
 EFI_STATUS MyCreateProtocolInit()
 {
 EFI_CREATE_PROTOCOL myProtocol = &gMyProtocol;
 myProtocol->Revsion = 0x101;
 myProtocol->InputMsg = InputMsg;
 return EFI_SUCCESS;
 }//Driver的入口函数
 EFI_STATUS
 EFIAPI
 CreateProtocolEntry(
 IN EFI_HANDLE ImageHandle,
 IN EFI_SYSTEM_TABLE *SystemTable
 )
 {
 EFI_STATUS Status;
 MyCreateProtocolInit();
 //Install一个Protocol
 Status = gBS->InstallProtocolInterface(
 &ImageHandle,
 &gEfiCreateProtocolGUID,
 EFI_NATIVE_INTERFACE,
 &gMyProtocol
 );
 if(!EFI_ERROR(Status))
 {
 gST->ConOut->OutputString(gST->ConOut,L"Success\n");
 return Status;
 }else{
 gST->ConOut->OutputString(gST->ConOut,L"Failed\n");
 }
 return Status;
 }

CreateProtocol.inf文件

[Defines]
 INF_VERSION = 0x00010005
 BASE_NAME = CreateProtocol
 FILE_GUID = 2d7ee62a-8f25-4a0c-bcc7-a0c8edc31643
 MODULE_TYPE = UEFI_DRIVER
 VERSION_STRING = 1.0
 ENTRY_POINT = CreateProtocolEntry[Sources]
 CreateProtocol.c[Packages]
 MdePkg/MdePkg.dec[LibraryClasses]
 UefiDriverEntryPoint
 UefiLib