UEFI 基础教程 (六) - PROTOCOL 简单使用
一、 编写源代码编写UEFI Application 代码C:\edkii\OvmfPkg\MyHelloWorldAppProtocol\MyHelloWorldAppProtocol.c,...static EFI_MYHELLOWORLD_PROTOCOL * gMyHelloWorldProtocol = NULL;EFI_STATUSEFIAPIMyHelloWorld...
一、 编写源代码
-
编写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; } -
编写
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
- 拷贝
C:\edkii\Build\OvmfX64\DEBUG_VS2013x86\FV\OVMF.fd到C:\qemu;拷贝C:\edkii\Build\OvmfX64\DEBUG_VS2013x86\X64\OvmfPkg\MyHelloWorldAppProtocol\MyHelloWorldAppProtocol\OUTPUT\MyHelloWorldAppProtocol.efi到 虚拟盘HDD_BOOT.img - 执行
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的意义大概如下,
- 实现代码的隔离,移除了对调用库的依赖
- 保护厂商的利益,比如Intel release的 BIOS code中,ASPPED VGA驱动,VMD驱动, SATA控制器驱动,PFR驱动,网卡驱动 都是以Oprom的形式分发
- 实现驱动事件的联动,
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了.
更多推荐



所有评论(0)