dxe communication 之protocol

来源:互联网 发布:网络购物诈骗定义 编辑:程序博客网 时间:2024/05/18 12:37
dxe driver 之间可以通过三种方式来沟通
第一种方式是用protocal
protocol 使用前需要先install,install protocol 主要有下面三个API
 InstallProtocolInterface()
 ReInstallProtocolInterface()
 InstallMultipleProtocolInterfaces()

要使用protocol 需要用下面两个API
LocateProtocol()
OpenProtocol()


EFI_HANDLE mNewHandle = NULL;

EFI_SAMPLE_PROTOCOL mSampleProtocol = {
SampleProtocolApi
};

EFI_STATUS
EFIAPI
SampleProtocolApi(
VOID
)
{
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
SampleDriverInitialize (
IN EFI_HANDLE
ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;

Status = gBS->InstallMultipleProtocolInterfaces (
&mNewHandle,
&gEfiSampleProtocolGuid,
&mSampleProtocol,
NULL
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}

一般我们会在inf文件中指定moudle的入口函数,例如 ENTRY_POINT                    = InstallAcpiS3Save
本例中的ENTRY_POINT就是SampleDriverInitialize
在这个SampleDriverInitialize函数中就会调用InstallMultipleProtocolInterfaces 来install protocal,每个
protocal 都有一个gEfiSampleProtocolGuid。

因此我们在使用这个protocal的时候就会根据gEfiSampleProtocolGuid 来找到mSampleProtocol,这样就可以用mSampleProtocol 中注册的函数或者变量
EFI_STATUS
SampleFunction (
VOID
)
{
EFI_STATUS
Status;
EFI_SAMPLE_PROTOCOL *SampleProtocol;

Status = gBS->LocateProtocol (
&gEfiSampleProtocolGuid,
NULL,
(VOID **) &SampleProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = SampleProtocol->SampleProtocolApi();
return Status;
}

例如在SampleFunction 中首先让LocateProtocol通过gEfiSampleProtocolGuid 就找到SampleProtocol,也就是上面install的mSampleProtocol。这样就可以使用mSampleProtocol的SampleProtocolApi() 函数。

而InstallProtocolInterface 和 LocateProtocol 都是在mdemodulepkg/core/dxe/dxemian 中赋值的
EFI_BOOT_SERVICES mBootServices = {
  {
  (EFI_INSTALL_PROTOCOL_INTERFACE)              CoreInstallProtocolInterface,             // InstallProtocolInterface
  (EFI_REINSTALL_PROTOCOL_INTERFACE)            CoreReinstallProtocolInterface,           // ReinstallProtocolInterface
}
我们先看看InstallProtocolInterface
EFI_STATUS
EFIAPI
CoreInstallProtocolInterface (
  IN OUT EFI_HANDLE     *UserHandle,
  IN EFI_GUID           *Protocol,
  IN EFI_INTERFACE_TYPE InterfaceType,
  IN VOID               *Interface
  )
{
  return CoreInstallProtocolInterfaceNotify (
            UserHandle,
            Protocol,
            InterfaceType,
            Interface,
            TRUE
            );
#不做任何出来添加notify 为true后调用CoreInstallProtocolInterfaceNotify
}

在CoreInstallProtocolInterfaceNotify 中下面这段code是基本的检测。
  if (UserHandle == NULL || Protocol == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (InterfaceType != EFI_NATIVE_INTERFACE) {
    return EFI_INVALID_PARAMETER;
  }
可以通过这行log将要install的protocal打印出来方便debug
  DEBUG((DEBUG_INFO, "InstallProtocolInterface: %g %p\n", Protocol, Interface));

  if (*UserHandle != NULL) {
    Status = CoreHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
    if (!EFI_ERROR (Status)) {
      return EFI_INVALID_PARAMETER;
    }
  }
如果UserHandle 不是null,就要检查这个protocal是否已经注册过,也就说protocal不能重复注册,也不会覆盖注册
调用CoreFindProtocolEntry 来找PROTOCOL_ENTRY。其核心代码如下:
  for (Link = mProtocolDatabase.ForwardLink;
       Link != &mProtocolDatabase;
       Link = Link->ForwardLink) {

    Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
    if (CompareGuid (&Item->ProtocolID, Protocol)) {

      //
      // This is the protocol entry
      //

      ProtEntry = Item;
      break;
    }
  }
主要是通过比较guid是否相等,由于我们是新注册的因此肯定找不到,因此就新建一个PROTOCOL_ENTRY,然后将其插入到mProtocolDatabase
  if ((ProtEntry == NULL) && Create) {
    ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));

    if (ProtEntry != NULL) {
      //
      // Initialize new protocol entry structure
      //
      ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
      CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
      InitializeListHead (&ProtEntry->Protocols);
      InitializeListHead (&ProtEntry->Notify);

      //
      // Add it to protocol database
      //
      InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
    }
  }
继续回到CoreInstallProtocolInterfaceNotify 中
找到ProtEntry后,就要申请一个  PROTOCOL_INTERFACE  *Prot;
  Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));
  if (Prot == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

最终要的就是Prot 对象
如果UserHandle 里面的内容是零的话,也就是UserHandle 没有指向任何handle
  Handle = (IHANDLE *)*UserHandle;
  if (Handle == NULL) {
    Handle = AllocateZeroPool (sizeof(IHANDLE));
    if (Handle == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Done;
    }

    //
    // Initialize new handler structure
    //
    Handle->Signature = EFI_HANDLE_SIGNATURE;
    InitializeListHead (&Handle->Protocols);

    //
    // Initialize the Key to show that the handle has been created/modified
    //
    gHandleDatabaseKey++;
    Handle->Key = gHandleDatabaseKey;

    //
    // Add this handle to the list global list of all handles
    // in the system
    //
    InsertTailList (&gHandleList, &Handle->AllHandles);
  }

因此这里申请IHANDLE 对象,初始化之后就将其插入到gHandleList 中,也就是说uefi中所有的handle都是在gHandleList 这个list中,这是一个全局变量.
  Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
  Prot->Handle = Handle;
  Prot->Protocol = ProtEntry;
  Prot->Interface = Interface;

  //
  // Initalize OpenProtocol Data base
  //
  InitializeListHead (&Prot->OpenList);
  Prot->OpenListCount = 0;

  //
  // Add this protocol interface to the head of the supported
  // protocol list for this handle
  //
  InsertHeadList (&Handle->Protocols, &Prot->Link);

  //
  // Add this protocol interface to the tail of the
  // protocol entry
  //
  InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
这段code就是将ProtEntry 插入到Prot 中,由于ProtEntry 已经在mProtocolDatabase中了,因此根据mProtocolDatabase 就可以找到Prot。
再来看看CoreLocateProtocol 是怎么根据guid找到protocal的
CoreLocateProtocol (
  IN  EFI_GUID  *Protocol,
  IN  VOID      *Registration OPTIONAL,
  OUT VOID      **Interface
  )
{
  EFI_STATUS              Status;
  LOCATE_POSITION         Position;
  PROTOCOL_NOTIFY         *ProtNotify;
  IHANDLE                 *Handle;

  if (Interface == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Protocol == NULL) {
    return EFI_NOT_FOUND;
  }

  *Interface = NULL;
  Status = EFI_SUCCESS;

  //
  // Set initial position
  //
  Position.Protocol  = Protocol;
  Position.SearchKey = Registration;
  Position.Position  = &gHandleList;

  //
  // Lock the protocol database
  //
  Status = CoreAcquireLockOrFail (&gProtocolDatabaseLock);
  if (EFI_ERROR (Status)) {
    return EFI_NOT_FOUND;
  }

  mEfiLocateHandleRequest += 1;

  if (Registration == NULL) {
    //
    // Look up the protocol entry and set the head pointer
    //
    Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
    if (Position.ProtEntry == NULL) {
      Status = EFI_NOT_FOUND;
      goto Done;
    }
    Position.Position = &Position.ProtEntry->Protocols;

    Handle = CoreGetNextLocateByProtocol (&Position, Interface);
  } else {
    Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
  }

  if (Handle == NULL) {
    Status = EFI_NOT_FOUND;
  } else if (Registration != NULL) {
    //
    // If this is a search by register notify and a handle was
    // returned, update the register notification position
    //
    ProtNotify = Registration;
    ProtNotify->Position = ProtNotify->Position->ForwardLink;
  }

Done:
  CoreReleaseProtocolLock ();
  return Status;
}
在本例中Registration 为null,因此在CoreLocateProtocol 中是走if的case
首先通过CoreFindProtocolEntry找到ProtEntry,然后根据ProtEntry 找到interface和handle,最后将interface返回,基本上是InstallProtocolInterface的反过程.


0 0
原创粉丝点击