UEFI中的Protocol

以下內容爲學習《UEFI原理與編程》(戴正華)第四章和第六章的摘要

UEFI是用C語言來實現的,但UEFI中Protocol是作爲一種對象來設計和使用。例如:

// 通過這個protocol可以控制塊設備

struct  _EFI_BLOCK_IO_PROTOCOL{

UINT64 Revision;

EFI_BLOCK_IO_MEDIA *Media;

EFI_BLOCK_RESET Reset;

EFI_BLOCK_READ ReadBlocks;

EFI_BLOCK_ERITE WriteBlocks;

EFI_BLOCK_FLUSH FlushBlocks;

};

extern EFI_GUID gEfiBlockIoProtocolGuid;


每個protocol必須有一個唯一的GUID, 例如:

///
/// Global ID for EFI_PEI_RECOVERY_BLOCK_IO_PPI
///
#define EFI_PEI_RECOVERY_BLOCK_IO_PPI_GUID \
  { \
    0x695d8aa1, 0x42ee, 0x4c46, { 0x80, 0x5c, 0x6e, 0xa6, 0xbc, 0xe7, 0x99, 0xe3 } \
  }


EFI_BLOCK_IO_PROTOCOL的ReadBlocks服務的函數原型

/*++
  Routine Description:
    Read BufferSize bytes from Lba into Buffer.

  Arguments:
    This       - Protocol instance pointer.
    MediaId    - Id of the media, changes every time the media is replaced.
    Lba        - The starting Logical Block Address to read from
    BufferSize - Size of Buffer, must be a multiple of device block size.
    Buffer     - Buffer containing read data

  Returns:
    EFI_SUCCESS           - The data was read correctly from the device.
    EFI_DEVICE_ERROR      - The device reported an error while performing the read.
    EFI_NO_MEDIA          - There is no media in the device.
    EFI_MEDIA_CHANGED     - The MediaId does not matched the current device.
    EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the device.
    EFI_INVALID_PARAMETER - The read request contains device addresses that are not  valid for the device.
--*/
typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_READ) (
  IN EFI_BLOCK_IO_PROTOCOL          * This,
  IN UINT32                         MediaId,
  IN EFI_LBA                        Lba,
  IN UINTN                          BufferSize,
  OUT VOID                          *Buffer
  )


使用Protocol之前,要先弄清楚Protocol在UEFI內核中是怎樣表示的。首先來認識EFI_HANDLE.

typedef  VOID  *EFI_HANDLE;

EFI_HANDLE 是指向某種對象的指針,UEFI用它來表示某個對象。UEFI掃描總線後,會爲每個設備建立一個Controller對象,用於控制設備,所有該設備的驅動以Protocol的形式安裝到這個Controller中,這個Controller就是一個EFI_HANDLE對象。當我們加載.efi文件到內存中時,UEFI也會爲該文件建立一個Image對象,這個對象也是EFI_HANGDLE對象。在UEFI內部,EFI_HANDLE被理解爲IHANDLE. 可查看Handle.h

///
/// IHANDLE - contains a list of protocol handles
///
typedef struct {
  UINTN               Signature;
  /// All handles list of IHANDLE
  LIST_ENTRY          AllHandles;
  /// List of PROTOCOL_INTERFACE's for this handle
  LIST_ENTRY          Protocols;      
  UINTN               LocateRequest;
  /// The Handle Database Key value when this handle was last created or modified
  UINT64              Key;
} IHANDLE;


所有IHANDLE通過AllHandles鏈接,而每個IHANDLE的Protocol通過Protocols鏈接。

IHANDLE的Protocols是一個雙向鏈表,鏈表中的每一個元素是PROTOCOL_INTERFACE, 通過PROTOCOL_INTERFACE的Protocol指針可以得到這個Protocol的GUID,通過Interface指針可以得到這個Protocol的實例。

///
/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
/// with a protocol interface structure
///
typedef struct {
  UINTN                       Signature;
  /// Link on IHANDLE.Protocols
  LIST_ENTRY                  Link;   
  /// Back pointer
  IHANDLE                     *Handle;  
  /// Link on PROTOCOL_ENTRY.Protocols
  LIST_ENTRY                  ByProtocol; 
  /// The protocol ID
  PROTOCOL_ENTRY              *Protocol;  
  /// The interface value
  VOID                        *Interface; 
  /// OPEN_PROTOCOL_DATA list
  LIST_ENTRY                  OpenList;       
  UINTN                       OpenListCount;

} PROTOCOL_INTERFACE;


///
/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
/// database.  Each handler that supports this protocol is listed, along
/// with a list of registered notifies.
///
typedef struct {
  UINTN               Signature;
  /// Link Entry inserted to mProtocolDatabase
  LIST_ENTRY          AllEntries;  
  /// ID of the protocol
  EFI_GUID            ProtocolID;  
  /// All protocol interfaces
  LIST_ENTRY          Protocols;     
  /// Registerd notification handlers
  LIST_ENTRY          Notify;                 
} PROTOCOL_ENTRY;


所有的Protocol均放在mProtocolDatabase指向的PROTOCOL_ENTRY鏈表中。PROTOCOL_ENTRY包含三個鏈表。

AllEntries是PROTOCOL_ENTRY鏈。

Protocols指向此Protocol的所有實例。   例如:系統中可能有很多塊設備,每個塊設備都有一個EFI_BLOCK_IO_PROTOCOL實例,所有的EFI_BLOCK_IO_PROTOCOL實例都會插入到PROTOCOL_ENTRY.Protocols鏈表中。

Notify指向PROTOCOL_NOTIFY鏈表,當PROTOCOL_ENTRY,ProtocolID對應的Protocol安裝時,Notify鏈表中所有Event都會觸發。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章