How to use protocol in UEFI
Preface
Start-up service provides a wealth of services for developers to operate protocol, we can use protocol can also develop protocol. This article mainly describes how to use protocol.
The use of protocol is generally divided into the following three steps:
1. Identify the Protocol object by initiating the service;
2. Use of the services provided by this Protocol;
3. Close the Open protocol
You can use the Openprotocolinformation service to view all the devices that open a protocol.
There are four types of start-up services, namely: Openprotocol, Handleprotocol, Locateprotocol and Localhandlebuffer. They are described separately below. First, Openprotocol service
Openprotocol is used to query whether the specified protocol is supported in the specified handle, and if so, the protocol is turned on, otherwise an error code is returned.
Openprotocol function prototypes in BS (Start-up service):
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
);
return value:
return value |
Description |
Efi_success |
The interface information for the specified protocol was returned. |
efi_unsupported |
The device does not support the specified protocol. |
Efi_invalid_parameter |
Handle is NULL. |
Efi_invalid_parameter |
Protocol is NULL. |
Efi_invalid_parameter |
Interface is NULL. |
Handle: Query Handle provides Protocol *protocol: Protocol to open (pointer to secondary Protocol GUID) **interface: Returns an open Protocol object Agenthandle: Open the image controllerhandle for this protocol: Open the Controller for this Protocol
Attributes: How to open this Protocol
Handle is the provider of the Protocol, if the Protocol is in the protocols list of handle, the pointer to the Protocol object is written to *interface, and efi_success is returned, otherwise efi_ Unsupported.
If Openprotocol is called in the driver, then Controllerhandle is the controller that owns the driver, which is the controller that requests the Protocol; Agenthandle is the Efi_driver_binding_ The handle of the Protocol object. Efi_driver_binding_protocol is a protocol that will be used by UEFI driver Development, which is responsible for driver installation and uninstallation.
If the application is called Openprotocol, then Agenthandle is the handle of the utility, which is the first parameter of Uefimain, which can be ignored at this time.
List of attribute values:
Note: Screenshots are from Uefi Spec 2_6. Refer to Uefi Spec for this section.
Openhandle Sample Program Snippet:
Open Blockio Efi_handle imagehandle;
Efi_driver_binding_protocol *this;
In Efi_hadnle controllerhandle; extern efi_guid Blockioprotocolguid;
Efi_block_io_protocol *blockio;
Efi_status STATUS; Using Openprotocol in your application, the general Controllerhandle will be set to null Status = Gbs->openprotocol (Controllerhandle, Handle &gefiblockioprotocolguid,//protocol &blockio,//INTERFAC
E Imagehandle,//agenthandle NULL,//controllerhandle Efi_open_protocol_by_handle_protocol//attribute)//used in the drive, Openprotocol, Controllerhandle is the HANDLE Status of the Controller = gBS- >openprotocol (Controllerhandle,//handle &gefiblockioprotocolguid,//proto
Col &blockio,//interface This->driverbindinghandle,//agenthandle Controllerhandle,//controllerhandle Efi_open_protocoL_get_protocol//attribute)
Gefiblockioprotocolguid is a global variable, and the variable is defined in AUTOGEN.C. AUTOGEN.C is generated by the build tool based on the. inf and. Dec files, Gefiblockioprotocolguid is a variable of type Efi_guid and its efi_guid value is defined in. Dec. If you want to use Gefiblockioprotocolguid in an application or driver, you must declare it in [protocols] in the. inf file so that it is included in the AUTOGEN.C when it is preprocessed. Second, Handleprotocol service
The Openprotocol function is powerful, but the use is more complex, need to provide handle and protocol GUID, also provide Agenthandle, controllerhandle and attributes. But most of the time developers just want to get protocol objects through the Protocol GUID, and don't care about the details of how to open them. To make it easier for developers to use protocol, the start-up service provides handleprotocol to simplify opening protocol.
function prototypes for Handleprotocol services:
typedef
Efi_status
(Efiapi *efi_handle_protocol) (in
Efi_handle HANDLE, in
efi_guid *protocol,
Out VOID **interface
);
return value |
Description |
Efi_success |
The interface information for the specified protocol was returned. |
efi_unsupported |
The device does not support the specified protocol. |
Efi_invalid_parameter |
Handle is NULL. |
Efi_invalid_parameter |
Protocol is NULL. |
Efi_invalid_parameter |
Interface is NULL. |
Handleprotocol is a simplified version of Openprotocol, which eliminates the need to pass in Agenthandle, Controllerhandle, and attribute when calling Handleprotocol. Its interior is actually still called the Openprotocol.
Handleprotocol's internal implementation:
Efi_status
Handleprotocol (
in Efi_handle HANDLE, in
efi_guid *protocol, out
VOID **interface
)
{
return Openprotocol (
Handle,
Protocol,
Interface,
eficoreimagehandle,
NULL,
efi_open_protocol_by_handle_protocol
);
}
Handleprotocol Use Example:
Status = Gbs->handleprotocol (
controllerhandle, //handle
&gefiblockioprotocolguid, // Protocol
&blockio, //interface
)
Third, Locateprotocol service
Openprotocol and Handleprotocol are used to open a protocol on a specified device, and to use these two functions, the first thing to do is to get a handle to the device. Sometimes the developer does not care about which device the protocol is on, especially when the system has only one instance of the protocol. The start service provides a locateprotocol (... ) service, which can find the first instance of the specified protocol from the UEFI kernel.
Locateprotocol Service function Prototype:
typedef
Efi_status
(Efiapi *efi_locate_protocol) (in
efi_guid *protocol, in
VOID *registration, OPTIONAL out
VOID **interface
);
return value |
Description |
Efi_success |
A protocol Instance matching protocol is found and returned in Interface. |
Efi_invalid_parameter |
Interface is NULL. |
Efi_not_found |
No protocol instances were found that match protocol and registration. |
There may be more than one instance of a protocol in the UEFI kernel, for example, one Efi_disk_io_protocol instance per hard disk and each partition. Locateprotocol sequentially searches the handle linked list, returning the first instance of the protocol found.
The following example is used to find the first Simple_file_system_protocol instance in the system.
efi_simple_file_syste_protocol* simplefs;
Gbs->locateprotocol (
gefisimplefilesystemprotocolguid,
NULL,
&simplefs
);
Iv. Locateprotocolbuffer Services
The first three are methods of finding protocol from the device. Sometimes developers need to find all the devices that support a protocol, such as finding all the devices that have Blockio installed in the system. Locatehandle and Locateprotocolbuffer provide this service.
Locateprotocolbuffer function Prototypes:
typedef
Efi_status
(Efiapi *efi_locate_handle_buffer) (
in Efi_locate_search_type searchtype,//Lookup mode In
efi_guid *protocol OPTIONAL, //specified Protocol
in VOID *searchkey OPTIONAL, type of//protocol_notify
in Out Uintn *nohandles, //Returns the number of HANDLE found out
efi_handle **buffer //allocates HANDLE array and returns
);
return value |
Description |
efi_success |
The array of handles was returned. |
efi_not_found |
No handles match the search. |
efi_buffer_too_small |
The buffersize is TOO SMALL for the result. BufferSize have been updated with the size needed to complete the request. |
efi_invalid_parameter |
SearchType is not a member of Efi_locate_search_type |
efi_invalid_parameter |
searchtype is byregisternotify and Searchkey is NULL. |
efi_invalid_parameter |
searchtype is Byprotocol and Protocol is NULL. |
efi_invalid_parameter |
One or more matches be found and buffersize is NULL. |
efi_invalid_parameter |
buffersize is large enough for the result and Buffer is NULL. |
There are three kinds of searchtype: Allhandles used to find out all the handle;byregisternotify in the system for finding all matching searchkey from registerprotocolnotify handle The Byprotocol is used to find handle that support the specified protocol from the system handle database.
Type definitions for SearchType:
typedef enum{
Allhandles,
byregisternotify,
byprotocol
} efi_locate_search_type;
Locatehandle Service function Prototype:
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
);
return value |
Description |
efi_success |
The array of handles was returned. |
efi_not_found |
No handles match the search. |
efi_buffer_too_small |
The buffersize is TOO SMALL for the result. BufferSize have been updated with the size needed to complete the request. |
efi_invalid_parameter |
SearchType is not a member of Efi_locate_search_type |
efi_invalid_parameter |
searchtype is byregisternotify and Searchkey is NULL. |
efi_invalid_parameter |
searchtype is Byprotocol and Protocol is NULL. |
efi_invalid_parameter |
One or more matches be found and buffersize is NULL. |
efi_invalid_parameter |
buffersize is large enough for the result and Buffer is NULL. |
The biggest difference between the Locatehandle service and the Locatehandlebuffer service is that the caller is responsible for managing the memory occupied by the buffer array. v. Other protocol services
In addition to protocol and finding devices based on protocol these commonly used services, start the service about using protocol services there are Protocolsperhandle and openprotocolinformation. 1. Protocolsperhandle
The protocolsperhandle is used to obtain all the protocol supported by the specified device. These protocol GUIDs are returned by Protocolbuffer to the caller, and UEFI is responsible for allocating memory to Protocolbuffer, which is responsible for freeing the memory.
Protocolsperhandle function Prototypes:
typedef
Efi_status
(Efiapi *efi_protocols_per_handle) (
in Efi_handle HANDLE, out
efi_guid * * * Protocolbuffer, out
uintn *protocolbuffercount
);
return value |
Description |
Efi_success |
The list of protocol interface GUIDs installed on Handle is returned in Protocolbuffer. The number of protocol interface GUIDs is returned in Protocolbuffercount. |
Efi_invalid_parameter |
Handle is NULL. |
Efi_invalid_parameter |
Protocolbuffer is NULL. |
Efi_invalid_parameter |
Protocolbuffercount is NULL. |
Efi_out_of_resources |
There isn't enough pool memory to store the results |
2. Openprotocolinformation
The openprotocolinformation is used to obtain open information for the specified protocol on the specified device.
Openprotocolinformation function Prototypes:
typedef
Efi_status
(Efiapi *efi_open_protocol_information) (
in Efi_handle HANDLE, in
efi_guid * Protocol, out
efi_open_protocol_information_entry **entrybuffer, out
uintn *entrycount
);
return value |
Description |
Efi_success |
The Open protocol information is returned in Entrybuffer,and the number of entries is returned entrycount. |
Efi_not_found |
Handle does not a support for the protocol specified by protocol. |
Efi_out_of_resources |
There is not enough resources available to allocate entrybuffer. |
Efi_open_protocol_information_entry data Structure
typedef struct {
efi_handle agenthandle;
Efi_handle Controllerhandle;
UINT32 Attributes;
UINT32 opencount;
} Efi_open_protocol_information_entry;
Handle is the handle to this device, and the open information is stored in the Protocol_interdace openlist list. The same protocol on the device may be turned on and off many times. Protocol updates the Openlist list each time it is successfully opened and closed. After successful opening, a efi_open_protocol_information_entry is added to the device handle, if an item already exists in the Openlist list with the current (Agenthandle,controllerhandle, Attributes) is exactly the same, the item Opencount plus one. Closing protocol will reduce the opencount of the openlist counterpart by one, and opencount delete the corresponding item when it is zero. Vi. Closeprotocol Services
Protocol you need to close the open protocol with Closeprotocol after you have finished using it.
Closeprotocol function Prototypes:
typedef
Efi_status
(Efiapi *efi_close_protocol) (in
Efi_handle HANDLE, in
efi_guid *protocol,
in Efi_handle Agenthandle,
In Efi_handle controllerhandle
);
return value |
description |
efi_success |
the protocol instance was closed. |
efi_invalid_parameter |
Handle is NULL. |
efi_invalid_parameter |
agenthandle is NULL. |
efi_invalid_parameter |
controllerhandle is isn't null and Controllerhandle is null. |
efi_invalid_parameter |
Protocol is NULL. |
efi_not_found |
Handle does not support the protocol specified by protocol. |
efi_not_found |
The protocol interface specified by Handle and protocol are not currently Open by Agenthandle and Controllerhandle. |
The protocol opened through Handleprotocol and Locateprotocol cannot be closed because no agenthandle is specified. If you must close it, call Openprotocolinformation () to get agenthandle and Controllerhandle, and then close it. Vii. Summary
This part, do not live to explain the use of protocol method. Protocol provides a way to communicate between UEFI applications and UEFI drivers. With protocol, users can use the services provided by the driver, as well as other services provided by the system. Be familiar with the data structure of the protocol you use. reference "UEFI principles and Programming" Uefi Spec 2_6 EDK2 GitHub