一、 编写源代码
  1. 编写UEFI Application 代码C:\edkii\OvmfPkg\MyHelloWorldAppProtocol\MyHelloWorldAppProtocol.c,

    ...
    static EFI_MYHELLOWORLD_PROTOCOL * gMyHelloWorldProtocol = NULL;
    
    EFI_STATUS
    EFIAPI
    MyHelloWorldAppProtocolEntry(
      IN EFI_HANDLE        ImageHandle,
      IN EFI_SYSTEM_TABLE  *SystemTable
    )
    { 
      EFI_STATUS  Status = EFI_SUCCESS;
      DEBUG ((EFI_D_ERROR , "[MyHelloWorldProtocol] MyHelloWorldAppProtocolEntry Start..\n"));
      Print (L"[MyHelloWorldProtocol]  MyHelloWorldAppProtocolEntry Start..\n");
      
      Status = gBS->LocateProtocol(&gMyHelloWorldPEIGUID,NULL,(VOID **)&gMyHelloWorldProtocol);
      if (EFI_ERROR(Status)){
         Print(L"[MyHelloWorldProtocol] Locate Protocol gMyHelloWorldProtocol %r \n",Status);
         return Status;
      }
      gMyHelloWorldProtocol->PrintMsg(gMyHelloWorldProtocol,L"Hello World App.....\n");
      DEBUG ((EFI_D_ERROR, "[MyHelloWorldProtocol] MyHelloWorldAppProtocolEntry End..\n"));
      Print (L"[MyHelloWorldProtocol] MyHelloWorldAppProtocolEntry  End ... \n");
     
      return Status;
    }
    
  2. 编写UEFI DXE Driver代码C:\edkii\OvmfPkg\MyHelloWorldDXEProtocol\MyHelloWorldDXEProtocol.c,

    ...
    static EFI_MYHELLOWORLD_PROTOCOL  gMyHelloWorldProtocol ;
    
    EFI_STATUS
    EFIAPI
    MyHelloWorldDXEProtocolEntry(
      IN EFI_HANDLE        ImageHandle,
      IN EFI_SYSTEM_TABLE  *SystemTable
    )
    { 
      EFI_STATUS                              Status = EFI_SUCCESS;
      DEBUG ((EFI_D_ERROR , "[MyHelloWorldProtocol]  MyHelloWorldDXEProtocolEntry Start..\n"));
    
      gMyHelloWorldProtocol.PrintMsg = PrintHelloWorldMsg;
      gMyHelloWorldProtocol.Revision = 1;
      
      Status = gBS->InstallProtocolInterface(&ImageHandle,
                                             &gMyHelloWorldPEIGUID,
                                             EFI_NATIVE_INTERFACE,
                                             &gMyHelloWorldProtocol
                                             );
      if (!EFI_ERROR(Status)){
        DEBUG ((EFI_D_ERROR ,"[MyHelloWorldProtocol] MyHelloWorldDXEProtocolEntry Installed Protocol Successfully..\n"));
      }else{
        DEBUG ((EFI_D_ERROR ,"[MyHelloWorldProtocol] MyHelloWorldDXEProtocolEntry Installed Protocol Failly..\n"));
      }
      
      DEBUG ((EFI_D_ERROR , "[MyHelloWorldProtocol]  MyHelloWorldDXEProtocolEntry End..\n"));
      return Status;
    }
    
二、 编译生成EFI文件

运行edksetup.bat编译整个OvmfPkg Package

三、 运行 DXE Driver MyHelloWorldDXEProtocol与UEFI APP MyHelloWorldAppProtocol
  1. 拷贝 C:\edkii\Build\OvmfX64\DEBUG_VS2013x86\FV\OVMF.fdC:\qemu;拷贝C:\edkii\Build\OvmfX64\DEBUG_VS2013x86\X64\OvmfPkg\MyHelloWorldAppProtocol\MyHelloWorldAppProtocol\OUTPUT\MyHelloWorldAppProtocol.efi 到 虚拟盘HDD_BOOT.img
  2. 执行setup-qemu-x64.bat | findstr MyHelloWorldProtocol , 然后在UEFI SHELL 中执行 MyHelloWorldAppProtocol.efi,结果如下,
    在这里插入图片描述在这里插入图片描述
四、 小结

借助Protocol 机制,应用程序可以很容易的访问驱动程序(DXE Driver)的资源。本文中,驱动模块MyHelloWorldDXEProtocol 在程序入口注册Protocol服务gMyHelloWorldProtocol,该服务的标识为gMyHelloWorldPEIGUID;而后应用程序MyHelloWorldAppProtocol在其入口函数中借助GUID即可获取驱动中注册的服务,之后就可以调用服务中的函数了。其中,创建Protocol有多个接口,可以一创建单个或者多个Protocol。获取Protocol同样有多个接口,如 LocateProtocol,HandleProtocol,OpenProtocol具体差异可以参照spec。
在Dxe/gRT/BDS阶段,protocol扮演着非常重要的角色,比如PCIe,Oprom,SMM, MultiProcessor, Variable, driver model, Smbios, ACPI 等子系统或者服务, 具体来说如果你在UEFI环境下想操作某一个设备SATA/NVME/CXL/VGA /Serial port, 你甚至不需要直接关心这些domain的library实现,只需要通过spec给出的guid去拿到对应的Protocol instance,然后调用相应的函数就可以了。从另一方面说,protocol机制保护了厂商的利益,比如AMD,Intel,IBV, OEM在release code时候将一些核心驱动以xxx.efi 形式release,用户拿到后只需要Locate对应的Protocol就可以完成对设备的访问。
总之Protocol的意义大概如下,

  1. 实现代码的隔离,移除了对调用库的依赖
  2. 保护厂商的利益,比如Intel release的 BIOS code中,ASPPED VGA驱动,VMD驱动, SATA控制器驱动,PFR驱动,网卡驱动 都是以Oprom的形式分发
  3. 实现驱动事件的联动,
    1) 比如说如果你想让驱动B在驱动A之后执行,可以在B的驱动中加入dependency如下,
    [depex]
    gDriverAProtocol # 该gDriverAProtocol在驱动A 安装
    2)比如说如果你想让驱动B中的某一个函数被驱动A某一个Protocol触发
    gBS->RegisterProtocolNotify(&gDriverAProtocol, …callback) //驱动B
    gBS->InstallProtocolInterface(&gDriverAProtocol, xxx)//驱动A,一旦该Protocol被安装,B中callback将会被调用
    Protocol在edk2中大量使用,如果希望快速的找出当前code的 Protocol使用情况,在VSCODE可以使用以下的regex来检索,

//以 gEfiSmmSwDispatch2ProtocolGuid regex检索为例,使用以下匹配可以很快从trunk中搜出所有的相关的Protocol操作

.*?\((?=(\n|[^\)]*?)gEfiSmmSwDispatch2ProtocolGuid)             //查询所有的gEfiSmmSwDispatch2ProtocolGuid操作
Install.*?\((?=(\n|[^\)]*?)gEfiSmmSwDispatch2ProtocolGuid)      //查询所有的gEfiSmmSwDispatch2ProtocolGuid Install操作
Locate.*?\((?=(\n|[^\)]*?)gEfiSmmSwDispatch2ProtocolGuid)       //查询所有的gEfiSmmSwDispatch2ProtocolGuid Locate操作
Register.*?\((?=(\n|[^\)]*?)gEfiSmmSwDispatch2ProtocolGuid)     //查询所有的gEfiSmmSwDispatch2ProtocolGuid Register操作

在这里插入图片描述

在这里插入图片描述

注意: Protocol是gBS管理的,说以一旦系统boot到bootloader(grub/lilo) 当ExitBootService Event被触发,所有的gBS 服务将会被丢弃(DXE protocol将不能使用),如果还想使用BIOS提供的service, 就只能使用gRT 或者 gSmm了.

[DXEProtocol DEMO源码]

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐