1 UEFI驱动的分类
从功能上划分,UEFI驱动可以分为以下类别:
- 符合UEFI驱动模型的驱动,包括总线驱动、设备驱动和混合驱动,一般用来驱动对应的硬件设备
- 服务性驱动,这类驱动不管理任何设备,一般用来产生Protocol
- 初始化驱动,不产生任何句柄,也不增加任何Protocol到系统数据库,主要用来进行一些初始化操作,操作完就会从系统内存中卸载
- 根桥型驱动,用来初始化平台上的根桥控制器,并产生一个设备地址Protocol,以及访问总线设备的Protocol,一般通过总线驱动访问设备。
在UEFI模块中驱动有两种类型:DXE_DRIVER 和 UEFI DRIVER,
2 UEFI驱动模型
驱动程序包含有硬件设备的信息,有了这些信息计算机就可以和设备进行通信,一个完整的驱动框架至少要完成以下任务:
- 找到支持的硬件设备
- 安装驱动到此硬件设备
- 从硬件设备卸载驱动
UEFI驱动模型的核心是通过EFI Driver Binding Protocol管理驱动程序,一个完整的驱动程序包含两个核心部分:EFI Driver Binding Protocol以及驱动服务本身。作为一个用户友好的驱动程序,通常它还要包括一个EFI Component Name Protocol。
2.1 UEFI Driver Binding Protocol的构成
首先来看UEFI驱动模型是如何管理驱动的。在UEFI驱动的入口函数函数中,安装EFI Driver Binding Protocol(EDBP)到某个Handle(大部分是自身,即ImageHandle),这个EBDP实例会常驻内存,用于驱动的安装和卸载。使用EBDP使得我们可以多次操作(查找设备、安装卸载)驱动。其代码原型为:
typedef struct _EFI_DRIVER_BINDING_PROTOCOL EFI_DRIVER_BINDING_PROTOCOL;
//该协议提供了确定驱动程序是否支持给定控制器所需的服务。
//如果支持控制器,那么它还提供启动和停止控制器的例程。
struct _EFI_DRIVER_BINDING_PROTOCOL {
EFI_DRIVER_BINDING_SUPPORTED Supported;
EFI_DRIVER_BINDING_START Start;
EFI_DRIVER_BINDING_STOP Stop;
UINT32 Version; //驱动的版本号,在所有支持同一个控制器的EDBP中,版本号高的具有较高的优先级,有限被安装到设备上。
EFI_HANDLE ImageHandle; //生成EDBP的映像文件句柄
EFI_HANDLE DriverBindingHandle; //安装了EDBP的Handle
};
(1)Supported函数
Supported函数用于检查一个设备控制器是否支持该驱动。其函数原型为:
typedef
EFI_STATUS
(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED)(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle, //要检测的控制器的句柄,这个句柄必需支持向驱动提供I/O抽象的protocol接口
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL //指向设备路径的剩余部分
);
(2)Start函数
Start函数用来将驱动安装到设备上并启动硬件设备,在函数中最重要的事情是调用InstallProtocolInterface()或者InstallMutipleProtocolInterface()在ControllerHandle上安装驱动protocol,其函数原型为:
typedef
EFI_STATUS
(EFIAPI *EFI_DRIVER_BINDING_START)(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle, //驱动被安装到这个Handle上
IN EFI_DEVICE_PATH_PROTOCOL