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都会触发。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值