UEFI开发与调试---ImageHandle和ControllerHandle

1.ImageHandle

每个uefi module都是一个image,而每个image对应都有一个ImageHandle,其实ImageHandle的类型就是EFI_HANDLE

typedef VOID                      *EFI_HANDLE;

因此实际上每个ImageHandle是一个void*指针,那么也就是说任何结构体都可以传给他,其实通过代码可知在uefi中,传入ImageHandle中的数据结构只会是IHANDLE:

///
/// 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;

由此可知,每个ImageHandle其实就对应一个IHANDLE结构,这个结构就是用于描述此image的,我们可以在ImageHandle上安装一系列的接口(就是Protocol),比如在DXE和UEFI驱动中,这一系列接口通过Protocols这个成员连接在一起,它还有AllHandles链表,也就是说系统中所有的IHANDLE也都是连接在一起的,这就会在整个UEFI运行过程中组成一个EFI_HANDLE数据库。

因此在某个模块中实现的接口(Protocol),可以通过一系列的函数,先找到ImageHandle,再通过它找到对应的Protocol,然后在其它的地方调用这些Protocol。UEFI中所有的IHANDLE是通过AllHandles连接在一起的,所有的protocol是通过PROTOCOL_ENTRY结构连接在一起的。

关于ImageHandle和Procotol之间的关系可以参考下图:

摘自UEFI原理与编程_戴正华

2.ControllerHandle

看了一些书,也在网上搜索了一些Controller的概念,总结了一下我的理解。其实ControllerHandle和上文中介绍的ImageHandle本质上并没有区别,两者都是EFI_HANDLE对象,也就是IHANDLE数据结构。Controller控制器更多的含义应该是逻辑意义上的,它代表着当前IHANDLE对象的父对象,这样对我来说可能更好理解一些,子对象的实现是依赖于父对象之上的,这就更像是linux kernel中,bus总线和device设备之间的关系。

比如说我们系统中要实现一个AC97音频驱动,那么可能会有两个UEFI Driver,一个是PCI驱动,一个是AC97音频驱动提供音频操作的函数,那么我们可以认为PCI驱动是AC97音频驱动的Controller控制器,而AC97音频驱动的实现依赖PCI驱动。

Controller在UEFI中的体现就是函数和参数的命名,比如我们常用到的操作:

gBS->ConnectController()
gBS->DisconnectController()

gBS->ConnectController()这个函数就是用来把我们的驱动按照到父对象上,也就是Controller上,而gBS->DisconnectController()是把我们驱动从对应的Controller上断开。实际进一步跟下去,他们的实现是这样的:

 EFI_STATUS
 EFIAPI
 CoreConnectController (
   IN  EFI_HANDLE                ControllerHandle,
   IN  EFI_HANDLE                *DriverImageHandle    OPTIONAL,
   IN  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath  OPTIONAL,
   IN  BOOLEAN                   Recursive
   )
EFI_STATUS
EFIAPI
CoreDisconnectController (
  IN  EFI_HANDLE  ControllerHandle,
  IN  EFI_HANDLE  DriverImageHandle  OPTIONAL,
  IN  EFI_HANDLE  ChildHandle        OPTIONAL
  )

举例说明这个函数如何使用,我们可以这样使用:

扫描二维码关注公众号,回复: 2520367 查看本文章
EFI_STATUS
EFIAPI
BdsLibConnectAllEfi (
  VOID
  )
{
  EFI_STATUS  Status;
  UINTN       HandleCount;
  EFI_HANDLE  *HandleBuffer;
  UINTN       Index;

  Status = gBS->LocateHandleBuffer (
                  AllHandles,
                  NULL,
                  NULL,
                  &HandleCount,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  for (Index = 0; Index < HandleCount; Index++) {
    Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
  }

  if (HandleBuffer != NULL) {
    FreePool (HandleBuffer);
  }

  return EFI_SUCCESS;
}

猜你喜欢

转载自blog.csdn.net/rikeyone/article/details/81391551