DXE编程 - Handle和Protocol的简单运用

一、Handle和Protocol的API描述

如下:

NameDescription
InstallProtocolInterfaceRemoves a protocol interface from a device handle.
UninstallProtocolInterfaceRemoves a protocol interface from a device handle.
ReinstallProtocolInterfaceReinstalls a protocol interface on a device handle.
RegisterProtocolNotifyRegisters an event that is to be signaled whenever an interface is installed for a specified protocol.
LocateHandleReturns an array of handles that support a specified protocol.
HandleProtocolQueries a handle to determine if it supports a specified protocol.
LocateDevicePathLocates all devices on a device path that support a specified protocol and returns the handle to the device that is closest to the path.
OpenProtocolAdds elements to the list of agents consuming a protocol interface.
CloseProtocolt Removes elements from the list of agents consuming a protocol interface.
OpenProtocolInformationRetrieve the list of agents that are currently consuming a protocol interface.
ConnectControllerUses a set of precedence rules to find the best set of drivers to manage a controller.
DisconnectControllerInforms a set of drivers to stop managing a controller.
ProtocolsPerHandleRetrieves the list of protocols installed on a handle. The return buffer is automatically allocated.
LocateHandleBufferRetrieves the list of handles from the handle database that meet the search criteria. The return buffer is automatically allocated.
LocateProtocolFinds the first handle in the handle database the supports the requested protocol.
InstallMultipleProtocolInterfacesInstalls one or more protocol interfaces onto a handle.
UninstallMultipleProtocolInterfacesUninstalls one or more protocol interfaces from a handle.

具体用法参考:《UEFI specification》
        UEFI源码DxeMain.c

二、简单练习

我们用:

InstallProtocolInterface
UninstallProtocolInterface
ReinstallProtocolInterface
RegisterProtocolNotify
LocateHandle
HandleProtocol

进行简单编程练习。

1.Install

h文件

PATH:

EmulatorPkg/Include/Protocol/MyFirstWriteProtocol.h

code:

/** @file
  My first dxe protocol.h

**/
#ifndef _MY_FIRST_LIB
#define _MY_FIRST_LIB

#define EFI_MY__FIRST_DXE_PROTOCOL_GUID \
  { \
   0xab18f26c, 0xaa6f, 0x4919, { 0xa1, 0x98, 0x7d, 0xc7, 0xe0, 0xbe, 0x4b, 0x27 } \
  }

extern EFI_GUID gEfiMyFirstDxeProtocolGuid;

/**
  This funtion return num1+num2

  @param[in]  firstnum      first number
  @param[in]  secendnum     second number

  @return reaslut
**/

typedef
UINTN
(EFIAPI *EFI_MY_PROTOCOL_ADD) (
	IN UINTN                firstnum,
	IN UINTN                secendnum                  
	);


/**
  This funtion return num1-num2

  @param[in]  firstnum      first number
  @param[in]  secendnum     second number

  @return reaslut
**/
typedef
UINTN
(EFIAPI *EFI_MY_PROTOCOL_SUB) (
	IN UINTN                firstnum,
	IN UINTN                secendnum                  
	);

struct _EFI_MY_FIRST_DXE_PROTOCOL{
  UINTN                         num;
  EFI_MY_PROTOCOL_ADD           AddFun;  
  EFI_MY_PROTOCOL_SUB           SubFun;  
};

typedef struct _EFI_MY_FIRST_DXE_PROTOCOL  EFI_MY_FIRST_DXE_PROTOCOL;


//
// add
//
UINTN
EFIAPI
add_function (
  IN UINTN           num1,
  IN UINTN           num2
  );

//
// sub
//
UINTN
EFIAPI
sub_function (
  IN UINTN           num1,
  IN UINTN           num2
  );
  
#endif

c文件

PATH:

EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyInstallInerface/MyInstallInerface.c

code:

/** @file
  a driver for dxe to test handle and protocol

**/

#include <Library/UefiDriverEntryPoint.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h> 
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>


#include <Protocol/MyFirstWriteProtocol.h>

/**
  This funtion return num1+num2

  @param[in]  firstnum      first number
  @param[in]  secendnum     second number

  @return reaslut
**/
UINTN
EFIAPI
add_function (
  IN UINTN           num1,
  IN UINTN           num2
  )
{
  return num1+num2;
}



/**
  This funtion return num1-num2

  @param[in]  firstnum      first number
  @param[in]  secendnum     second number

  @return reaslut
**/
UINTN
EFIAPI
sub_function (
  IN UINTN           num1,
  IN UINTN           num2
  )
{
  return num1-num2;
}


/**
  This funtion printf messg form RegisterProtocolNotify

  @return reaslut
**/
VOID
EFIAPI
MyInstallRegisterProtocolNotify (
  IN  EFI_EVENT                Event,
  IN  VOID                     *Context
  )
{
  UINTN                        Temp;
  for(Temp = 0; Temp <= 5; Temp++) {
    DEBUG ((DEBUG_INFO, "\n"));
  }
  DEBUG ((DEBUG_INFO, "Install is OK! Form RegisterProtocolNotify!\n"));
  //gBS->CloseEvent (Event);
}


/**
  The user Entry Point for Driver
  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
  @param[in] SystemTable    A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.
  @retval other             Some error occurs when executing this entry point.

**/
EFI_STATUS
EFIAPI
MyInstallInerfaceEntry (
  IN EFI_HANDLE               ImageHandle,
  IN EFI_SYSTEM_TABLE         *SystemTable
  )
{
  EFI_STATUS                  Status;
  EFI_EVENT                   Event;
  EFI_HANDLE                  AddHandle=NULL;
  EFI_MY_FIRST_DXE_PROTOCOL   *TestProtocol=NULL;
  VOID                        *Registration=NULL;
  UINTN                       Temp;

  TestProtocol                = (EFI_MY_FIRST_DXE_PROTOCOL *) AllocateZeroPool (sizeof(EFI_MY_FIRST_DXE_PROTOCOL));
  TestProtocol->num           = 1;
  TestProtocol->AddFun        = add_function;
  TestProtocol->SubFun        = sub_function;


  Status = gBS->CreateEvent (
                  EVT_NOTIFY_SIGNAL,
                  TPL_CALLBACK,
                  (EFI_EVENT_NOTIFY)MyInstallRegisterProtocolNotify,
                  NULL,
                  &Event
                  );
  ASSERT_EFI_ERROR (Status);

  Status = gBS->RegisterProtocolNotify ( 
                 &gEfiMyFirstDxeProtocolGuid,
                 Event,
                 &Registration
                 );
  ASSERT_EFI_ERROR (Status);
  Status = gBS->SignalEvent (Event);

  for(Temp = 0; Temp <= 5; Temp++) {
    DEBUG ((DEBUG_INFO, "\n"));
  }
  DEBUG ((DEBUG_INFO, "InstallProtocolInterface is begin!\n"));
  Status = gBS->InstallProtocolInterface (
                  &AddHandle,
                  &gEfiMyFirstDxeProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  (void *)TestProtocol
                  );
  ASSERT_EFI_ERROR (Status);
  DEBUG ((DEBUG_INFO, "InstallProtocolInterface is end!\n"));

  return Status;
}

inf文件

PATH:

EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyInstallInerface/MyInstallInerface.inf

code:

## @file
#  
#
#
#
#
#
##

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = InstallInerface
  FILE_GUID                      = 6987922E-ED34-4412-AE97-22A5E4ED3116
  MODULE_TYPE                    = DXE_DRIVER
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = MyInstallInerfaceEntry



[Sources]
  MyInstallInerface.c

[Packages]
  MdePkg/MdePkg.dec
  MdeModulePkg/MdeModulePkg.dec
  EmulatorPkg/EmulatorPkg.dec

[LibraryClasses]
  UefiDriverEntryPoint
  DebugLib
  UefiBootServicesTableLib
  UefiLib
  BaseLib
  BaseMemoryLib
  MemoryAllocationLib

[Protocols]
  gEfiMyFirstDxeProtocolGuid

[Depex]
 TRUE

dec文件

PATH:

edk2/EmulatorPkg/EmulatorPkg.dec

code:

[Protocols]
  gEfiMyFirstDxeProtocolGuid     = { 0xab18f26c, 0xaa6f, 0x4919, { 0xa1, 0x98, 0x7d, 0xc7, 0xe0, 0xbe, 0x4b, 0x27 } }

dsc文件

PATH:

edk2/EmulatorPkg/EmulatorPkg.dsc

code:

  #  DXE Phase modules
  ##
  #
  EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyInstallInerface/MyInstallInerface.inf

结果

在模拟器里面load InstallInerface,如下:
在这里插入图片描述

2.Locate

c文件

PATH:

EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyUnInstallInerface/MyUnInstallInerface.c

code:

/** @file
  locate

**/
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h> 
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiApplicationEntryPoint.h>

#include <Protocol/MyFirstWriteProtocol.h>

/**
  This funtion return num1+num2

  @param[in]  firstnum      first number
  @param[in]  secendnum     second number

  @return reaslut
**/
UINTN
EFIAPI
add_function (
  IN UINTN           num1,
  IN UINTN           num2
  )
{
  return num1+num2;
}

/**
  This funtion return num1-num2

  @param[in]  firstnum      first number
  @param[in]  secendnum     second number

  @return reaslut
**/
UINTN
EFIAPI
sub_function (
  IN UINTN           num1,
  IN UINTN           num2
  )
{
  return num1-num2;
}

/**
  The user Entry Point for App

  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
  @param[in] SystemTable    A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.
  @retval other             Some error occurs when executing this entry point.

**/
EFI_STATUS
EFIAPI
MyUnInstallInerfaceEntry (
  IN EFI_HANDLE                  ImageHandle,
  IN EFI_SYSTEM_TABLE            *SystemTable
  )
{
  EFI_STATUS                     Status;
  UINTN                          HandleBufSize;
  EFI_HANDLE                     *HandleBuf = NULL;
  EFI_MY_FIRST_DXE_PROTOCOL      *TestProtocol = NULL;
  EFI_MY_FIRST_DXE_PROTOCOL      *NewTestProtocol = NULL;


  HandleBufSize                  = sizeof(EFI_HANDLE);
  HandleBuf                      = (EFI_HANDLE *) AllocateZeroPool (HandleBufSize);
  NewTestProtocol                = (EFI_MY_FIRST_DXE_PROTOCOL *) AllocateZeroPool (sizeof(EFI_MY_FIRST_DXE_PROTOCOL));
  NewTestProtocol->num           = 5;
  NewTestProtocol->AddFun        = add_function;
  NewTestProtocol->SubFun        = sub_function;

  Status = gBS->LocateHandle (
                  ByProtocol,
                  &gEfiMyFirstDxeProtocolGuid,
                  NULL,
                  &HandleBufSize,
                  HandleBuf
                  );
  ASSERT_EFI_ERROR (Status);

  Status = gBS->HandleProtocol (
                  *HandleBuf,
                  &gEfiMyFirstDxeProtocolGuid,
                  (VOID **)&TestProtocol
                  );
  ASSERT_EFI_ERROR (Status);
  DEBUG ((DEBUG_INFO, "InstallProtocolInterface num is %d \n", TestProtocol->num));
  DEBUG ((DEBUG_INFO, "InstallProtocolInterface add 1+2=%d \n", TestProtocol->AddFun(1,2)));

  DEBUG ((DEBUG_INFO, "ReinstallProtocolInterface is begin!\n"));
  Status = gBS->ReinstallProtocolInterface (
                 *HandleBuf,
                 &gEfiMyFirstDxeProtocolGuid,
                 TestProtocol,
                 NewTestProtocol
                 );
  ASSERT_EFI_ERROR (Status);
  DEBUG ((DEBUG_INFO, "ReinstallProtocolInterface num is %d \n", NewTestProtocol->num));
  DEBUG ((DEBUG_INFO, "ReinstallProtocolInterface add 3+3 = %d \n", TestProtocol->AddFun(3,3)));

  DEBUG ((DEBUG_INFO, "UninstallProtocolInterface is begin!\n"));
  Status = gBS->UninstallProtocolInterface(
                  *HandleBuf,
                  &gEfiMyFirstDxeProtocolGuid,
                  (VOID *)NewTestProtocol
                  );
  ASSERT_EFI_ERROR (Status);
  DEBUG ((DEBUG_INFO, "UninstallProtocolInterface is ok!\n"));
  
  Status = gBS->LocateProtocol (
                  &gEfiMyFirstDxeProtocolGuid,
                  NULL,
                  (VOID **)&NewTestProtocol
                  );
  DEBUG((DEBUG_INFO,"LocateProtocol %r\n",Status));

  return EFI_SUCCESS;
}

inf文件

PATH:

EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyUnInstallInerface/MyUnInstallInerface.inf

code:

## @file
#  
#
#
#
#
#
##

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = UnInstallInerface
  FILE_GUID                      = 6981136E-ED34-4412-AE97-22A522ED7115
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = MyUnInstallInerfaceEntry

[Sources]
  MyUnInstallInerface.c

[Packages]
  MdePkg/MdePkg.dec
  MdeModulePkg/MdeModulePkg.dec
  EmulatorPkg/EmulatorPkg.dec

[LibraryClasses]
  UefiApplicationEntryPoint
  DebugLib
  UefiBootServicesTableLib
  UefiLib
  BaseLib
  BaseMemoryLib
  MemoryAllocationLib

[Protocols]
  gEfiMyFirstDxeProtocolGuid

[Depex]
  gEfiMyFirstDxeProtocolGuid

dsc文件

PATH:

edk2/EmulatorPkg/EmulatorPkg.dsc

code:

  #
  #  DXE Phase modules
  ##
  EmulatorPkg/TestByMy/DxeTest/HandleProtocolTest/MyUnInstallInerface/MyUnInstallInerface.inf

结果

去执行locate这个APPLICATION,如下:
在这里插入图片描述

3.结果分析

主要说明以下:
1.把RegisterProtocolNotify()放在InstallProtocolInterface()之前,并在InstallProtocolInterface()之前执行SignalEvent,MyInstallRegisterProtocolNotify会执行两次,如果不执行SignalEvent则MyInstallRegisterProtocolNotify会执行一次。
2.把RegisterProtocolNotify()放在InstallProtocolInterface()之后,不执行SignalEvent,MyInstallRegisterProtocolNotify不会被执行,如果在RegisterProtocolNotify()之后执行,则MyInstallRegisterProtocolNotify会执行一次。
其实上面就可以分析出来为什么在RegisterProtocolNotify之后要去执行SignalEvent,就是为了保证在InstallProtocolInterface时MyInstallRegisterProtocolNotify至少被执行一次,不然RegisterProtocolNotify就没有执行,作用也就消失。
至于为什么这么设计,有兴趣可以去看下源码。

三、简单理解

  1. EFI_BOOT_SERVICES.InstallProtocolInterface()给对应的handle安装一个特定的 handle,如果传进去的handle为NULL,则会创建一个新的handle。
    InstallMultipleProtocolInterfaces()可以一次性安装多个protocol

  2. EFI_BOOT_SERVICES.ReinstallProtocolInterface()用一个新的protocol去替换原来的protocol,但是根据上面情况来看,如果在第一次Install之后,没有close event 的话,RegisterProtocolNotify将会被再执行一次。

  3. EFI_BOOT_SERVICES.RegisterProtocolNotify()创建一个Event,当对应的protocol被安装的时候,就会single,调用callback,第三个参数OUT VOID **Registration,在调用callback的时候会返回一个SearchKey,在locate时候能用的上。

  4. UninstallProtocolInterface()卸载对应handle上特定的protocol
    UninstallMultipleProtocolInterfaces()可以一次性卸载多个protocol

  5. EFI_BOOT_SERVICES.LocateHandle()

typedef
EFI_STATUS
(EFIAPI *EFI_LOCATE_HANDLE) (
  IN EFI_LOCATE_SEARCH_TYPE   SearchType ,
  IN EFI_GUID                     *Protocol OPTIONAL,
  IN VOID                         *SearchKey OPTIONAL,
  IN OUT UINTN                   *BufferSize ,
OUT EFI_HANDLE                *Buffer
);

第1个参数可选则search type,一共有三种:AllHandles,ByRegisterNotify,ByProtocol
使用AllHandles会得到一个包含所有handle的数组头,ByProtocol
可以根据特定的protocol得到所有安装这个protocol的handle
的数组头,ByRegisterNotify找到所有安装执行对应SearchKey的callback 的handle数组头。
EFI_BOOT_SERVICES.LocateHandleBuffer()类似,会返回数组头和数值大小

  1. EFI_BOOT_SERVICES.OpenProtocol()打开对应handle下的protocol,
typedef
 EFI_STATUS
 (EFIAPI *EFI_OPEN_PROTOCOL) (
IN EFI_HANDLE        Handle ,
IN EFI_GUID           * Protocol ,
OUT VOID             ** Interface OPTIONAL,
IN EFI_HANDLE        AgentHandle ,
IN EFI_HANDLE        ControllerHandle ,
IN UINT32             Attributes
);

可以理解为谁去打开谁安装的protocol IN EFI_HANDLE AgentHandle,对应contorller下的child IN EFI_HANDLE ControllerHandle,对应contorller 当AgentHandle 传Handle 的时候理解为自己打开自己的特定protocol,类似与EFI_BOOT_SERVICES.HandleProtocol()
IN UINT32 Attributes
如果这个driver 允许打开的, protocol 和其他的driver 共用,这时候,就用EFI_OPEN_PROTOCOL_BY_DRIVER 作为Attribute, 反之,如果这个driver 不允许其他的driver 共享打开的protocol, 就用OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE

7.EFI_BOOT_SERVICES.OpenProtocolInformation()
获得所有打开指定Handle特定Protocol的一个数组信息和数组大小

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值