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