1.UEFI中的Protocol引入了面向?qū)ο蟮乃枷耄?/b>
--用struct來模擬class
--用函數(shù)指針(Protocol的成員變量)模擬成員函數(shù),此種函數(shù)的第一個(gè)參數(shù)必須指向Protocol的指針,用來模擬this。
(通常,計(jì)算機(jī)中有很多的塊設(shè)備,每個(gè)塊設(shè)備都有一個(gè)EFI_BLOCK_IO_PROTOCOL的實(shí)例,This指針就是指向這個(gè)實(shí)例,用于告訴成員函數(shù)我們正在操作哪個(gè)設(shè)備。This指針是Protocol成員函數(shù)的一個(gè)重要特征。)
2.Protocol在UEFI內(nèi)核中的表示:
使用Protocol之前,我們需要知道Protocol位于什么地方。首先,我們要來認(rèn)識(shí)一下EFI_HANDLE
typedef VOID * EFI_HANDLE;
EFI_HANDLE是指向某種對(duì)象的指針,UEFI用它來指向某個(gè)對(duì)象。UEFI掃描總線后,會(huì)為總線上的每個(gè)設(shè)備創(chuàng)立一個(gè)Controller對(duì)象,用于控制設(shè)備,所有該設(shè)備的驅(qū)動(dòng)以protocol的形式安裝到這個(gè)Controller中,這個(gè)Controller就是一個(gè)EFI_HANDLE對(duì)象。當(dāng)我們將一個(gè).efi文件加載到內(nèi)存中時(shí),UEFI也會(huì)為該文件創(chuàng)建一個(gè)image對(duì)象。在UEFI內(nèi)部,EFI_HANDLE被理解為IHANDLE,IHANDLE的數(shù)據(jù)結(jié)構(gòu)代碼如下所示:
typedef struct{
UINTN Signature;//表明Handle的類別
LIST_ENTRY AllHandles;//所有Handle組成的鏈表
LIST_ENTRY Protocols;//此Handle的Protocols鏈表
UINTN LocateRequest;
UINT64 Key;
}IHANDLE;
每個(gè)IHANDLE都有一個(gè)protocols鏈表(雙向鏈表),存放屬于自己的protocol。所有的IHANDLE通過AllHandles連接起來。
3.如何使用protocol
Boot Services提供了對(duì)Protocol進(jìn)行操作的services,如OpenProtocol()、HandleProtocol()、LocateProtocol()三種服務(wù)用于找出指定的protocol:OpenProtocol()用于打開指定句柄上的Protocol;HandleProtocol()是OpenProtocol()的簡(jiǎn)化版;LocateProtocol()用于找出指定protocol在系統(tǒng)中的第一個(gè)實(shí)例。使用完P(guān)rotocol后還要通過CloseProtocol()關(guān)閉打開的protocol,否則可能造成內(nèi)存泄露,由于HandleProtocol和OpenProtocol沒有指定AgentHandle,所以無法關(guān)閉,如果一定要關(guān)閉,需要調(diào)用OpenProtocolInformation()獲得AgentHandle和ControllerHandle,然后關(guān)閉它。
除了打開和關(guān)閉protocol,有時(shí)候還有能找出支持某個(gè)Protocol的所有設(shè)備。例如要找出支持BlockIos的所有設(shè)備(即找出所有塊設(shè)備),這時(shí)候就要使用LocateHandleBuffer()服務(wù);如果想知道某個(gè)Protocol被哪些設(shè)備打開了,那么可以使用OpenProtocolInformation()服務(wù);ProtocolPerHandle()用于獲得指定設(shè)備所支持的所有Protocol。