一、Handle和Protocol的API描述
如下:
Name | Description |
---|---|
InstallProtocolInterface | Removes a protocol interface from a device handle. |
UninstallProtocolInterface | Removes a protocol interface from a device handle. |
ReinstallProtocolInterface | Reinstalls a protocol interface on a device handle. |
RegisterProtocolNotify | Registers an event that is to be signaled whenever an interface is installed for a specified protocol. |
LocateHandle | Returns an array of handles that support a specified protocol. |
HandleProtocol | Queries a handle to determine if it supports a specified protocol. |
LocateDevicePath | Locates all devices on a device path that support a specified protocol and returns the handle to the device that is closest to the path. |
OpenProtocol | Adds elements to the list of agents consuming a protocol interface. |
CloseProtocol | t Removes elements from the list of agents consuming a protocol interface. |
OpenProtocolInformation | Retrieve the list of agents that are currently consuming a protocol interface. |
ConnectController | Uses a set of precedence rules to find the best set of drivers to manage a controller. |
DisconnectController | Informs a set of drivers to stop managing a controller. |
ProtocolsPerHandle | Retrieves the list of protocols installed on a handle. The return buffer is automatically allocated. |
LocateHandleBuffer | Retrieves the list of handles from the handle database that meet the search criteria. The return buffer is automatically allocated. |
LocateProtocol | Finds the first handle in the handle database the supports the requested protocol. |
InstallMultipleProtocolInterfaces | Installs one or more protocol interfaces onto a handle. |
UninstallMultipleProtocolInterfaces | Uninstalls one or more protocol interfaces from a handle. |
具体用法参考:《UEFI specification》
UEFI源码DxeMain.c
二、简单练习
我们用:
InstallProtocolInterface
UninstallProtocolInterface
ReinstallProtocolInterface
RegisterProtocolNotify
LocateHandle
HandleProtocol
进行简单编程练习。
1.Install
h文件
PATH:
EmulatorPkg/Include/Protocol/MyFirstWriteProtocol.h
code:
/** @file
My first dxe protocol.h
**/
#ifndef _MY_FIRST_LIB
#define _MY_FIRST_LIB
#define EFI_MY__FIRST_DXE_PROTOCOL_GUID \
{ \
0xab18f26c, 0xaa6f, 0x4919, { 0xa1, 0x98, 0x7d, 0xc7, 0xe0, 0xbe, 0x4b, 0x27 } \
}
extern EFI_GUID gEfiMyFirstDxeProtocolGuid;
/**
This funtion return num1+num2
@param[in] firstnum first number
@param[in] secendnum second number
@return reaslut
**/
typedef
UINTN
(EFIAPI *EFI_MY_PROTOCOL_ADD) (
IN UINTN firstnum,
IN UINTN secendnum
);
/**
This funtion return num1-num2
@param[in] firstnum first number
@param[in] secendnum second number
@return reaslut
**/
typedef
UINTN
(EFIAPI *EFI_MY_PROTOCOL_SUB) (
IN UINTN firstnum,
IN UINTN secendnum
);
struct _EFI_MY_FIRST_DXE_PROTOCOL{
UINTN num;
EFI_MY_PROTOCOL_ADD AddFun;
EFI_MY_PROTOCOL_SUB SubFun;
};
typedef struct _EFI_MY_FIRST_DXE_PROTOCOL EFI_MY_FIRST_DXE_PROTOCOL;
//
// add
//
UINTN
EFIAPI
add_function (
IN UINTN num1,
IN UINTN num2
);
//
// sub
//
UINTN
EFIAPI
sub_function (
IN UINTN num1,
IN UINTN num2
);
#endif
c文件
PATH:
EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyInstallInerface/MyInstallInerface.c
code:
/** @file
a driver for dxe to test handle and protocol
**/
#include <Library/UefiDriverEntryPoint.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/MyFirstWriteProtocol.h>
/**
This funtion return num1+num2
@param[in] firstnum first number
@param[in] secendnum second number
@return reaslut
**/
UINTN
EFIAPI
add_function (
IN UINTN num1,
IN UINTN num2
)
{
return num1+num2;
}
/**
This funtion return num1-num2
@param[in] firstnum first number
@param[in] secendnum second number
@return reaslut
**/
UINTN
EFIAPI
sub_function (
IN UINTN num1,
IN UINTN num2
)
{
return num1-num2;
}
/**
This funtion printf messg form RegisterProtocolNotify
@return reaslut
**/
VOID
EFIAPI
MyInstallRegisterProtocolNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
UINTN Temp;
for(Temp = 0; Temp <= 5; Temp++) {
DEBUG ((DEBUG_INFO, "\n"));
}
DEBUG ((DEBUG_INFO, "Install is OK! Form RegisterProtocolNotify!\n"));
//gBS->CloseEvent (Event);
}
/**
The user Entry Point for Driver
@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 other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
MyInstallInerfaceEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT Event;
EFI_HANDLE AddHandle=NULL;
EFI_MY_FIRST_DXE_PROTOCOL *TestProtocol=NULL;
VOID *Registration=NULL;
UINTN Temp;
TestProtocol = (EFI_MY_FIRST_DXE_PROTOCOL *) AllocateZeroPool (sizeof(EFI_MY_FIRST_DXE_PROTOCOL));
TestProtocol->num = 1;
TestProtocol->AddFun = add_function;
TestProtocol->SubFun = sub_function;
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
(EFI_EVENT_NOTIFY)MyInstallRegisterProtocolNotify,
NULL,
&Event
);
ASSERT_EFI_ERROR (Status);
Status = gBS->RegisterProtocolNotify (
&gEfiMyFirstDxeProtocolGuid,
Event,
&Registration
);
ASSERT_EFI_ERROR (Status);
Status = gBS->SignalEvent (Event);
for(Temp = 0; Temp <= 5; Temp++) {
DEBUG ((DEBUG_INFO, "\n"));
}
DEBUG ((DEBUG_INFO, "InstallProtocolInterface is begin!\n"));
Status = gBS->InstallProtocolInterface (
&AddHandle,
&gEfiMyFirstDxeProtocolGuid,
EFI_NATIVE_INTERFACE,
(void *)TestProtocol
);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "InstallProtocolInterface is end!\n"));
return Status;
}
inf文件
PATH:
EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyInstallInerface/MyInstallInerface.inf
code:
## @file
#
#
#
#
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = InstallInerface
FILE_GUID = 6987922E-ED34-4412-AE97-22A5E4ED3116
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = MyInstallInerfaceEntry
[Sources]
MyInstallInerface.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
EmulatorPkg/EmulatorPkg.dec
[LibraryClasses]
UefiDriverEntryPoint
DebugLib
UefiBootServicesTableLib
UefiLib
BaseLib
BaseMemoryLib
MemoryAllocationLib
[Protocols]
gEfiMyFirstDxeProtocolGuid
[Depex]
TRUE
dec文件
PATH:
edk2/EmulatorPkg/EmulatorPkg.dec
code:
[Protocols]
gEfiMyFirstDxeProtocolGuid = { 0xab18f26c, 0xaa6f, 0x4919, { 0xa1, 0x98, 0x7d, 0xc7, 0xe0, 0xbe, 0x4b, 0x27 } }
dsc文件
PATH:
edk2/EmulatorPkg/EmulatorPkg.dsc
code:
# DXE Phase modules
##
#
EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyInstallInerface/MyInstallInerface.inf
结果
在模拟器里面load InstallInerface,如下:
2.Locate
c文件
PATH:
EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyUnInstallInerface/MyUnInstallInerface.c
code:
/** @file
locate
**/
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Protocol/MyFirstWriteProtocol.h>
/**
This funtion return num1+num2
@param[in] firstnum first number
@param[in] secendnum second number
@return reaslut
**/
UINTN
EFIAPI
add_function (
IN UINTN num1,
IN UINTN num2
)
{
return num1+num2;
}
/**
This funtion return num1-num2
@param[in] firstnum first number
@param[in] secendnum second number
@return reaslut
**/
UINTN
EFIAPI
sub_function (
IN UINTN num1,
IN UINTN num2
)
{
return num1-num2;
}
/**
The user Entry Point for App
@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 other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
MyUnInstallInerfaceEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINTN HandleBufSize;
EFI_HANDLE *HandleBuf = NULL;
EFI_MY_FIRST_DXE_PROTOCOL *TestProtocol = NULL;
EFI_MY_FIRST_DXE_PROTOCOL *NewTestProtocol = NULL;
HandleBufSize = sizeof(EFI_HANDLE);
HandleBuf = (EFI_HANDLE *) AllocateZeroPool (HandleBufSize);
NewTestProtocol = (EFI_MY_FIRST_DXE_PROTOCOL *) AllocateZeroPool (sizeof(EFI_MY_FIRST_DXE_PROTOCOL));
NewTestProtocol->num = 5;
NewTestProtocol->AddFun = add_function;
NewTestProtocol->SubFun = sub_function;
Status = gBS->LocateHandle (
ByProtocol,
&gEfiMyFirstDxeProtocolGuid,
NULL,
&HandleBufSize,
HandleBuf
);
ASSERT_EFI_ERROR (Status);
Status = gBS->HandleProtocol (
*HandleBuf,
&gEfiMyFirstDxeProtocolGuid,
(VOID **)&TestProtocol
);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "InstallProtocolInterface num is %d \n", TestProtocol->num));
DEBUG ((DEBUG_INFO, "InstallProtocolInterface add 1+2=%d \n", TestProtocol->AddFun(1,2)));
DEBUG ((DEBUG_INFO, "ReinstallProtocolInterface is begin!\n"));
Status = gBS->ReinstallProtocolInterface (
*HandleBuf,
&gEfiMyFirstDxeProtocolGuid,
TestProtocol,
NewTestProtocol
);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "ReinstallProtocolInterface num is %d \n", NewTestProtocol->num));
DEBUG ((DEBUG_INFO, "ReinstallProtocolInterface add 3+3 = %d \n", TestProtocol->AddFun(3,3)));
DEBUG ((DEBUG_INFO, "UninstallProtocolInterface is begin!\n"));
Status = gBS->UninstallProtocolInterface(
*HandleBuf,
&gEfiMyFirstDxeProtocolGuid,
(VOID *)NewTestProtocol
);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "UninstallProtocolInterface is ok!\n"));
Status = gBS->LocateProtocol (
&gEfiMyFirstDxeProtocolGuid,
NULL,
(VOID **)&NewTestProtocol
);
DEBUG((DEBUG_INFO,"LocateProtocol %r\n",Status));
return EFI_SUCCESS;
}
inf文件
PATH:
EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyUnInstallInerface/MyUnInstallInerface.inf
code:
## @file
#
#
#
#
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UnInstallInerface
FILE_GUID = 6981136E-ED34-4412-AE97-22A522ED7115
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = MyUnInstallInerfaceEntry
[Sources]
MyUnInstallInerface.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
EmulatorPkg/EmulatorPkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
DebugLib
UefiBootServicesTableLib
UefiLib
BaseLib
BaseMemoryLib
MemoryAllocationLib
[Protocols]
gEfiMyFirstDxeProtocolGuid
[Depex]
gEfiMyFirstDxeProtocolGuid
dsc文件
PATH:
edk2/EmulatorPkg/EmulatorPkg.dsc
code:
#
# DXE Phase modules
##
EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyUnInstallInerface/MyUnInstallInerface.inf
结果
去执行locate这个APPLICATION,如下:
3.结果分析
主要说明以下:
1.把RegisterProtocolNotify()放在InstallProtocolInterface()之前,并在InstallProtocolInterface()之前执行SignalEvent,MyInstallRegisterProtocolNotify会执行两次,如果不执行SignalEvent则MyInstallRegisterProtocolNotify会执行一次。
2.把RegisterProtocolNotify()放在InstallProtocolInterface()之后,不执行SignalEvent,MyInstallRegisterProtocolNotify不会被执行,如果在RegisterProtocolNotify()之后执行,则MyInstallRegisterProtocolNotify会执行一次。
其实上面就可以分析出来为什么在RegisterProtocolNotify之后要去执行SignalEvent,就是为了保证在InstallProtocolInterface时MyInstallRegisterProtocolNotify至少被执行一次,不然RegisterProtocolNotify就没有执行,作用也就消失。
至于为什么这么设计,有兴趣可以去看下源码。
三、简单理解
-
EFI_BOOT_SERVICES.InstallProtocolInterface()给对应的handle安装一个特定的 handle,如果传进去的handle为NULL,则会创建一个新的handle。
InstallMultipleProtocolInterfaces()可以一次性安装多个protocol -
EFI_BOOT_SERVICES.ReinstallProtocolInterface()用一个新的protocol去替换原来的protocol,但是根据上面情况来看,如果在第一次Install之后,没有close event 的话,RegisterProtocolNotify将会被再执行一次。
-
EFI_BOOT_SERVICES.RegisterProtocolNotify()创建一个Event,当对应的protocol被安装的时候,就会single,调用callback,第三个参数OUT VOID **Registration,在调用callback的时候会返回一个SearchKey,在locate时候能用的上。
-
UninstallProtocolInterface()卸载对应handle上特定的protocol
UninstallMultipleProtocolInterfaces()可以一次性卸载多个protocol -
EFI_BOOT_SERVICES.LocateHandle()
typedef
EFI_STATUS
(EFIAPI *EFI_LOCATE_HANDLE) (
IN EFI_LOCATE_SEARCH_TYPE SearchType ,
IN EFI_GUID *Protocol OPTIONAL,
IN VOID *SearchKey OPTIONAL,
IN OUT UINTN *BufferSize ,
OUT EFI_HANDLE *Buffer
);
第1个参数可选则search type,一共有三种:AllHandles,ByRegisterNotify,ByProtocol
使用AllHandles会得到一个包含所有handle的数组头,ByProtocol
可以根据特定的protocol得到所有安装这个protocol的handle
的数组头,ByRegisterNotify找到所有安装执行对应SearchKey的callback 的handle数组头。
EFI_BOOT_SERVICES.LocateHandleBuffer()类似,会返回数组头和数值大小
- EFI_BOOT_SERVICES.OpenProtocol()打开对应handle下的protocol,
typedef
EFI_STATUS
(EFIAPI *EFI_OPEN_PROTOCOL) (
IN EFI_HANDLE Handle ,
IN EFI_GUID * Protocol ,
OUT VOID ** Interface OPTIONAL,
IN EFI_HANDLE AgentHandle ,
IN EFI_HANDLE ControllerHandle ,
IN UINT32 Attributes
);
可以理解为谁去打开谁安装的protocol IN EFI_HANDLE AgentHandle,对应contorller下的child IN EFI_HANDLE ControllerHandle,对应contorller 当AgentHandle 传Handle 的时候理解为自己打开自己的特定protocol,类似与EFI_BOOT_SERVICES.HandleProtocol()
IN UINT32 Attributes
如果这个driver 允许打开的, protocol 和其他的driver 共用,这时候,就用EFI_OPEN_PROTOCOL_BY_DRIVER 作为Attribute, 反之,如果这个driver 不允许其他的driver 共享打开的protocol, 就用OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
7.EFI_BOOT_SERVICES.OpenProtocolInformation()
获得所有打开指定Handle特定Protocol的一个数组信息和数组大小