2010年9月29日 星期三

淺談EFI Protocol

EFI的Protocol類似於物件導向中的Interface,它訂定好一個標準,而實作是經由別的程式來完成,而使用也是透過這個標準來使用。
一個Protocol基本上是由數個變數與函式指標所組成的結構,也會跟隨著一個唯一識別的GUID(Globally Unique Identifier),這部分與PEI階段的PEIM中的PPI滿像的,各個不同程式間可利用方法將所需的功能找出來使用。
安裝一個Protocol時會與自己對應的GUID配在一起,放置於Handle Database中,Handle Database是一個Linked List,每個Handle被串在一起,而Handle底下又與屬於它的所有GUID | Protocol相連。

EFI DRIVER BINDING PROTOCOL原型:
typedef struct _EFI_DRIVER_BINDING_PROTOCOL {
 EFI_DRIVER_BINDING_PROTOCOL_SUPPORTED Supported;
 EFI_DRIVER_BINDING_PROTOCOL_START Start;
 EFI_DRIVER_BINDING_PROTOCOL_STOP Stop;
 UINT32 Version;
 EFI_HANDLE ImageHandle;
 EFI_HANDLE DriverBindingHandle;
} EFI_DRIVER_BINDING_PROTOCOL;

其GUID:
#define EFI_DRIVER_BINDING_PROTOCOL_GUID \
{0x18A031AB,0xB443,0x4D1A,0xA5,0xC0,0x0C,0x09,0x26,0x1E,0x9F,0x71}

extern EFI_GUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID;
基本上是使用gEfiDriverBindingProtocolGuid這個變數來與EFI DRIVER BINDING PROTOCOL做關聯。

與Protocol常用的相關服務如下:
InstallMultipleProtocolInterfaces (
 IN OUT EFI_HANDLE *Handle,
 ...
 );

安裝數個Protocol與搭配的GUID至指定的Handle底下。

UninstallMultipleProtocolInterfaces (
 IN EFI_HANDLE Handle,
 ...
 );

移除數個Handle底下的Protocol與所搭配的GUID。

LocateHandleBuffer (
 IN EFI_LOCATE_SEARCH_TYPE SearchType,
 IN EFI_GUID *Protocol OPTIONAL,
 IN VOID *SearchKey OPTIONAL,
 IN OUT UINTN *NoHandles,
 OUT EFI_HANDLE **Buffer
 );

可將全部或以特定的條件將Handle取出。

ProtocolsPerHandle (
 IN EFI_HANDLE Handle,
 OUT EFI_GUID ***ProtocolBuffer,
 OUT UINTN *ProtocolBufferCount
 );

取得指定的Handle底下所有的Protocol GUID陣列,並傳出數量。

OpenProtocolInformation (
 IN EFI_HANDLE Handle,
 IN EFI_GUID *Protocol,
 OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
 OUT UINTN *EntryCount
 );

取得Handle底下指定的GUID的Information Entry陣列,並回傳數量。

LocateProtocol (
 IN EFI_GUID *Protocol,
 IN VOID *Registration OPTIONAL,
 OUT VOID **Interface
 );

以指定的GUID取出第一個Protocol。

HandleProtocol (
 IN EFI_HANDLE Handle,
 IN EFI_GUID *Protocol,
 OUT VOID **Interface
 );

取出Handle中指定的Protocol,以GUID為識別。

OpenProtocol (
 IN EFI_HANDLE Handle,
 IN EFI_GUID *Protocol,
 OUT VOID **Interface OPTIONAL,
 IN EFI_HANDLE AgentHandle,
 IN EFI_HANDLE ControllerHandle,
 IN UINT32 Attributes
 );

類似HandleProtocol(),但提供了更安全的做法,綁訂指定的Handle,避免使用中的Protocol被Uninstall。
此為最後一個參數的定義:
#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002
#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004
#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008
#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010
#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020
依需要使用,有些定義可不用CloseProtocol()。

CloseProtocol (
 IN EFI_HANDLE Handle,
 IN EFI_GUID *Protocol,
 IN EFI_HANDLE AgentHandle,
 IN EFI_HANDLE ControllerHandle
 );

為以OpenProtocol()開啟的Protocol解除占用。