文章目录
- `记录驱动开发前的知识储备工作`
- 一、驱动开发环境搭建
- 二、驱动开发框架(重点:WDF框架)
- 1、前世今生
- (1)Vista简介
- (2)发展历史
- 2、基于框架的驱动程序的 WDM
- (1)驱动程序类型
- (2)驱动程序堆栈
- (3)设备堆栈
- (4)I/O请求数据包
- 3、 WDF的优势
- 三、完整的驱动签名流程(Win10)
- 四、Windows的GUID
- 五、总结
记录驱动开发前的知识储备工作
一、驱动开发环境搭建
参考我这篇:WIN10 驱动开发环境从0搭建
二、驱动开发框架(重点:WDF框架)
1、前世今生
(1)Vista简介
Windows Vista
是微软公司2006年11月30日正式发布的操作系统,2017年
4月11日,微软正式终止对Windows Vista的一切支持。
(2)发展历史
最早使用——>VXD (已经废弃)
Vista支持——>WDM
Vista及其以后——>WDF
: 意为Windows Driver Foundation,此模型比WDM更先进、合理,将WDF中关于电源、PnP等一些复杂的细节由微软实现,所以在此模型上开发驱动会比以前要简单。
2、基于框架的驱动程序的 WDM
(1)驱动程序类型
- 总线驱动程序:
总线驱动程序检测插入到父级总线中的子设备,并报告这些子设备的特征,从而支持 I/O 总线; - 功能驱动程序:功能驱动程序控制设备和总线的I/O 操作;
- 筛选器驱动程序:筛选器驱动程序接收、审查并可能修改在用户应用程序和驱动程序之间或在各驱动程序之间传输的数据。
(2)驱动程序堆栈
在 Windows 操作系统中,WDM 驱动程序按名为驱动程序堆栈 的垂直调用序列分层。在 I/O 请求已通过操作系统的 I/O 管理器之后,堆栈中位于最顶层的驱动
程序通常会从
用户应用程序
接收这些请求。较低层的驱动程序通常与计算机硬件通信。
简单的驱动程序堆栈包括位于堆栈底部的总线驱动程序,该驱动程序用于处理总线特定的 I/O 操作,并枚举与总线相连的子设备。总线驱动程序上方通常有一个或多个设备特定的功能驱动程序。这些功能驱动程序处理与总线相连的设备的 I/O 操作。筛选器驱动程序可位于功能驱动程序上方,也可以位于总线驱动程序和功能驱动程序之间。正在运行的系统具有多个驱动程序堆栈,可支持不同类型的设备。
(3)设备堆栈
每个驱动程序堆栈都支持一个或多个设备堆栈。设备堆栈是一组根据 WDM 定义的 DEVICE_OBJECT 结构创建的设备对象。
每个设备堆栈都表示一台设备。每个驱动程序为其每台设备创建一个设备对象,并将每个设备对象附加到设备堆栈。当插入和拔出设备以及每当重新引导系统时,将创建和删除设备堆栈。
总线驱动程序在检测到已插入或拔出子设备时会通知即插即用 (PnP) 管理器。作为响应,PnP 管理器要求总线驱动程序为连接到父设备(即总线)的每台子设备创建一个物理设备对象 (PDO)。PDO 随即成为设备堆栈的底部。
接下来,PnP 管理器加载功能驱动程序和筛选器驱动程序以便支持每台设备(如果尚未加载这些驱动程序),然后 PnP 管理器会调用这些驱动程序,使每个驱动程序都可以创建一个设备对象并将该设备对象添加到设备堆栈的顶层。功能驱动程序创建函数设备对象 (FDO),筛选器驱动程序创建筛选器设备对象(筛选器 DO)。
I/O 管理器将 I/O 请求发送到设备的驱动程序时,它会将该请求传递到创建设备堆栈中的顶层设备对象的驱动程序。
(4)I/O请求数据包
I/O 管理器通过创建 I/O 请求数据包 (IRP),将应用程序的 I/O 请求发送到驱动程序。IRP 可包含执行 I/O 操作(如读/写操作)的请求或执行 I/O 控制 (IOCTL) 操作(如返回状态)的请求。此外,PnP 管理器还会创建表示驱动程序必须执行的 PnP和电源管理操作的 IRP,并将这些 IRP 发送到驱动程序。
I/O 管理器通常在用户应用程序请求读取或写入操作时创建读取或写入 IRP。I/O 管理器将 IRP 传递到位于驱动程序堆栈顶层的驱动程序,该驱动程序或者为该请求提供服务,或者将该请求传递到下一层驱动程序。某些请求会传输到堆栈底部,而某些请求则完全由较高层的驱动程序处理。
每当驱动程序接收 IRP 时,该程序还会接收一个指向某个设备对象的指针,该设备对象表示必须处理该操作的设备。因此,驱动程序堆栈中的驱动程序使用设备对象确定应将特定请求传输到插入的哪个设备。
基于框架的驱动程序通常不会直接访问 IRP。内核模式驱动程序框架将表示读取、写入和设备 I/O 控制操作的 WDM IRP 转换为驱动程序在 I/O 队列中接收的框架请求对象。框架在内部处理 PnP 和电源管理 IRP,并使用事件回调函数向驱动程序发送 PnP 和电源事件通知。
3、 WDF的优势
以WDM为基础进行建模和封装,降低开发难度,改动如下:
- WDF面向对象;
- 内核模式和用户模式的驱动程序,都采用WDF的基类,内核模式派生的对象是“KMDF”框架,用户模式派生的对象是“UMDF”;
- WDF将即插即用和电源管理封装在对象内,成了缺省(默认)行为;
- WDM驱动程序中,一方面要处理硬件,另一方面要处理驱动程序与操作系统内核的交互。现在WDF则将驱动程序与操作系统内核之间进行了分离,
驱动程序与操作系统交互工作
交给框架内封装
的方法(函数)完成; - 两种模式的驱动程序(KMDF、UMDF)都使用同一环境进行构建,这一环境称为WDK:(Windows Driver Kit)集成驱动程序开发系统;
- 效率不变。
三、完整的驱动签名流程(Win10)
-
证书选择:
(1)购买一个EV代码签名的证书;
(2)网上随便下载一个; -
数字签名工具下载:下载地址
-
导入证书
-
设置规则:签哪个证书
-
添加规则
四、Windows的GUID
全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128位的数字标识符,用于唯一标识一个任意计算机。GUID 的总数达到了2128(3.4×1038)个,所以随机生成两个相同GUID的可能性非常小,但并不为0。所以,用于生成GUID的算法通常都加入了非随机的参数(如时间
),以保证这种重复的情况不会发生。
- 程序:
#include <objbase.h>
#include <stdio.h>
//--生成GUID
const char* newGUID()
{
static char buf[64] = {0};
GUID guid;
if (S_OK == ::CoCreateGuid(&guid))
{
_snprintf(buf, sizeof(buf)
, "{%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}"
, guid.Data1
, guid.Data2
, guid.Data3
, guid.Data4[0], guid.Data4[1]
, guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5]
, guid.Data4[6], guid.Data4[7]
);
}
return (const char*)buf;
}
int main(int argc, char* argv[])
{
//--COM
CoInitialize(NULL);
printf(newGUID());
printf("\n");
//--COM
CoUninitialize();
return 0;
}
五、总结
- WinDGB是唯一内核驱动调试器,但不必须;
- WDF比WDM好;
- 编译出来的sys文件是PE(可移植可执行)文件格式;
- 驱动开发需要为每个函数指定分页内存/非分页内存,分页内存
仅低中断
级别的例程可以访问的,而非分页内存则是各个中断级别
的例程都可以使用的; - 关注warnning;
- 关注回调函数;
- 进行必要的失败处理;
- INF文件中的信息来确定哪个为函数驱动程序、哪个为筛选器驱动程序。安装后,PnP管理器通过注册表确定设备的驱动程序。