导图社区 适用于所有驱动程序开发人员的概念
适用于所有驱动程序开发人员的概念,根据微软官方文档做出的总结,需要自取,包含用户模式和内核模式、虚拟地址空间、设备节点和设别堆栈等。
编辑于2021-07-21 10:02:39国家卫健委《成人肥胖食养指南》华南地区食谱: 4个季节(春、夏、秋、冬),每个季节3个能量级(1200kcal、1400kcal、1600kcal),共计12个食谱。
国家卫健委《成人肥胖食养指南》西南地区食谱: 4个季节(春、夏、秋、冬),每个季节3个能量级(1200kcal、1400kcal、1600kcal),共计12个食谱。
国家卫健委《成人肥胖食养指南》华中地区食谱: 4个季节(春、夏、秋、冬),每个季节3个能量级(1200kcal、1400kcal、1600kcal),共计12个食谱。
社区模板帮助中心,点此进入>>
国家卫健委《成人肥胖食养指南》华南地区食谱: 4个季节(春、夏、秋、冬),每个季节3个能量级(1200kcal、1400kcal、1600kcal),共计12个食谱。
国家卫健委《成人肥胖食养指南》西南地区食谱: 4个季节(春、夏、秋、冬),每个季节3个能量级(1200kcal、1400kcal、1600kcal),共计12个食谱。
国家卫健委《成人肥胖食养指南》华中地区食谱: 4个季节(春、夏、秋、冬),每个季节3个能量级(1200kcal、1400kcal、1600kcal),共计12个食谱。
适用于所有驱动程序开发人员的概念
用户模式和内核模式
处理器(processor)的两种模式
根据运行的代码的类型,在两个模式之间切换
应用程序在用户模式下运行
核心操作系统组件在内核模式下运行
驱动程序多以内核模式运行,但某些也会以用户模式运行
用户模式
为应用程序创建进程
专用的“虚拟地址空间”
虚拟地址空间受限
数据只能访问和修改有限数据
专用的“句柄表”
每个应用程序都隔离运行
故障仅局限于某个应用程序
防止应用程序更改、损坏关键的操作系统数据
内核模式
共用单个虚拟地址空间
不会与其他驱动程序和操作系统本身隔离
数据能访问和修改所有数据
操作系统或其他驱动程序的数据可能会受到安全威胁
内核模式驱动程序发生故障,整个操作系统就会发生故障
用户模式组件与内核模式组件之间的通信
虚拟地址空间
处理器读取或写入内存时,会使用到虚拟地址空间
地址空间
地址:数据读取的基本单位,16进制序号
实体所占用的内存大小
计算机领域中,“实体”这个抽象的名词 表示任何可以发送或接收信息的硬件或软件进程。 在许多情况下,“实体”就是一个特定的软件模块。
每个用户模式进程都有其各自的专用虚拟地址空间
对于 32 位进程,虚拟地址空间通常为 2 GB
范围从 0x00000000 至 0x7FFFFFFF
对于 64 位 Windows 上的 64 位进程,虚拟地址空间为 128 TB
范围从 0x000'00000000 至 0x7FFF'FFFFFFFF
一系列虚拟地址有时称为一系列“虚拟内存”
地址之间的联系
逻辑地址
机器语言指令中用来指定一个操作数或一条指令的地址
分段单元
MMU硬件电路单元
线性地址
虚拟地址
通常为32位无符号的整型数
分页单元
MMU硬件电路单元
物理地址
虚拟地址访问内存的优势
程序可以使用一系列连续的虚拟地址来访问物理内存中不连续的大内存缓冲区
程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区
物理内存的供应量变小时,内存管理器会将物理内存页保存到磁盘文件
物理内存被分页, 就像一本书里面的好多页纸, 每张纸上记录了不同的信息。 通常每个物理内存页的大小为 4 KB
数据或代码页会根据需要在物理内存与磁盘之间移动
不同进程使用的虚拟地址彼此隔离
一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存
两个 64 位进程的虚拟地址空间:Notepad.exe 和 MyApp.exe
每个进程都有其各自的虚拟地址空间
范围从 0x000'0000000 至 0x7FF'FFFFFFFF
每个阴影块都表示虚拟内存或物理内存的一个页(大小为 4 KB)
Notepad 进程使用从 0x7F7'93950000 开始的虚拟地址的三个连续页面 但虚拟地址的这三个连续页面会映射到物理内存中的非连续页面
两个进程都使用从 0x7F7'93950000 开始的虚拟内存页面 但这些虚拟页面映射到物理内存的不同页面
用户空间和系统空间
每个用户模式进程都有其各自的专用虚拟地址空间
称为“用户空间”
内核模式下运行的所有代码都共享单个虚拟地址空间
称为“系统空间”
在 32 位 Windows 中,可用的虚拟地址空间共计为 2^32 字节(4 GB)
通常,较低的 2 GB 用于用户空间
较高的 2 GB 用于系统空间
可以选择指定(在启动时)超过 2 GB 可用于用户空间
其结果是系统空间可用的虚拟地址更少
用户空间3GB,系统空间1GB
64位系统中
虚拟地址空间的理论大小为 2^64 字节(16艾字节)
艾字节:EB 1EB = 1024PB 1PB = 1024TB 1TB = 1024GB
实际上仅使用 16 艾字节范围的一小部分
用户模式下运行的代码可以访问用户空间,但不能访问系统空间
防止用户模式代码读取或更改受保护的操作系统数据结构
内核模式下运行的代码既可以访问用户空间,也可以访问系统空间
内核模式下运行的代码可以访问系统空间和当前用户模式进程的虚拟地址空间
内核模式下运行的驱动程序,在直接从用户空间地址中读写地址时需非常小心
如下方案说明了原因:
用户模式程序发起从设备读取数据的请求
程序提供缓冲区的起始地址以接收数据
内核模式下运行的设备驱动程序例程启动读取操作,并将控制权返回给其调用程序
稍后,设备中断了当前正在运行的任何线程以显示读取操作完成
中断由此任意线程(属于任意进程)上运行的内核模式驱动程序例程进行处理
此时,驱动程序不得将数据写入用户模式程序在步骤 1 中提供的起始地址
起始地址位于发起请求的进程的虚拟地址空间中,该进程很可能与当前进程不同
起始地址位于用户空间,当前进程位于系统空间
分页缓冲池和非分页缓冲池
系统空间中,用于动态分配内存的两个区域:分页缓冲池和非分页缓冲池
分页缓冲池中分配的内存可以根据需要调出到磁盘文件
非分页缓冲池中分配的内存永远无法调出到磁盘文件
在用户空间中
所有物理内存页面都可以根据需要调出到磁盘文件
在系统空间中
某些物理页面可以调出,而其他物理页面则不能
设备节点和设备堆栈
简介
在PnP设备树中,用来表示设备的节点称为设备节点
PNP: Plug and Play 即插即用
设备树的根节点称为“根设备节点”
设备堆栈
向设备发送 I/O 请求时,一些驱动程序会帮助处理该请求
这些驱动程序中的每一个都与一个设备对象相关联
这些设备对象在堆栈中进行排列
设备对象的顺序与它们的关联驱动程序一起被称为设备堆栈
设备节点和即插即用设备树
即插即用设备树,通常简称为设备树
一种Windows用以整理设备的树形结构
设备树中的节点表示复合设备上的某个设备或单个函数
某些节点表示与物理设备无关联的软件组件
设备树中的节点称为“设备节点”
设备树的根节点称为“根设备节点”
设备树说明了 PnP 环境中固有的父/子关系
设备树中的一些节点表示包含与之连接的子设备的总线
总线非线
PCI Bus
将节点视为表示设备还是总线取决于自己的观点
可以将显示适配器(Display Adapter) 视为在准备将帧显示在屏幕上时扮演重要角色的设备, 也可以将其视为可以检测和枚举所连接监视器的总线。
Display Adapter
设备对象和设备堆栈
设备对象是 DEVICE_OBJECT 结构的实例
每个设备节点中,都有设备对象的有序列表
其中每一个设备对象都与一个驱动程序相关联
设备对象的有序列表与它们的关联驱动程序一起被称为设备节点的设备堆栈
(设备对象,驱动程序)pairs的有序列表
有时将设备堆栈视为设备对象的有序列表
有时将设备堆栈视为驱动程序的有序列表
根据上下文去确定
设备堆栈是如何构建的?
PnP管理器请求每个总线的driver去枚举连接到总线的子设备
driver为总线上的每个设备创建PDO来响应请求
PnP管理器将设备节点与每个新创建的PDO关联
并查询注册表以确定哪些驱动程序要成为该节点的一部分
设备堆栈必须有且只有一个Function Driver
设备堆栈的主要驱动程序
负责读、写以及设备控制请求
由函数驱动程序创建的设备对象称为“函数设备对象” (FDO)
设备堆栈可以选择具有一个或多个Filter Driver
在程序处理读写以及设备控制时,扮演辅助角色
由筛选器驱动程序创建的设备对象称为“筛选器设备对象” (Filter DO)
可以通过注册表确定设备的Function和filter驱动程序
以PCI总线为例
PnP管理器请求PCI总线驱动枚举所有连接到PCI总线的设备
Pci.sys为每个连接到PCI总线的每个设备创建设备对象,以响应请求
这些设备对象被称为PDO
PDO:physical device object 物理设备对象
创建PDO后的图形
创建FDO和Filter DO后的图形
在设备堆栈中
位于函数驱动程序之上的筛选器驱动程序称为“上筛选器驱动程序”
位于函数驱动程序之下的筛选器驱动程序称为“下筛选器驱动程序”
PDO 始终为设备堆栈中的底部设备对象
程序通过INF文件确定Function和Filter驱动程序
INF为信息文件
通常由Microsoft或IDV提供
总线驱动程序
上图中驱动程序Pci.sys扮演两个角色
Pci.sys 与 PCI 总线设备节点中的 FDO 关联
Pci.sys 为 PCI 总线的“函数驱动程序”
Pci.sys 与 PCI 总线节点的每个子节点中的 PDO 关联
Pci.sys为子节点的“总线驱动程序”
与当前节点FOD关联的驱动称为“Function Driver”
与1中节点的子节点PDO关联的驱动程序称为“Bus Driver”
同一个驱动程序
用户模式设备堆栈
在某些情形下,设备不仅具有内核模式设备堆栈,同时还有用户模式设备堆栈
用户模式驱动程序通常基于用户模式驱动程序框架 (UMDF)
是 Windows 驱动程序框架 (WDF) 提供的驱动程序模型之一
驱动程序为用户模式 DLL
设备对象为实现 IWDFDevice 接口的 COM 对象
UMDF 设备堆栈中的设备对象称为“WDF 设备对象” (WDF DO)
图显示了设备节点、内核模式设备堆栈以及 USB-FX-2 设备的用户模式设备堆栈
用户模式和内核模式堆栈中的驱动程序参与在 USB-FX-2 设备上定向的 I/O 请求
I/O请求数据包
IRP I/O Request Package
发送到设备驱动程序的大部分请求都打包在其中
系统组件或驱动程序,通过调用IoCallDriver函数,将IRP发送到驱动程序
IoCallDriver有两个参数
指向 DEVICE_OBJECT 的指针
DEVICE_OBJECT 具有指向关联 DRIVER_OBJECT 的指针
指向 IRP 的指针
当组件调用 IoCallDriver 时,我们说
组件将 IRP 发送到设备对象
组件将 IRP 发送到与设备对象关联的驱动程序
有时,使用短语“传递 IRP” 或“转发 IRP”
而非“发送 IRP”
IRP 由在堆栈中排列的多个驱动程序进行处理
堆栈中的每个驱动程序都与一个设备对象相关联
如果 IRP 由设备堆栈进行处理
则通常先将 IRP 发送至设备堆栈中的顶部设备对象
下图IRP会先被发送到设备堆栈顶部的Filter DO
沿着设备堆栈向下传递 IRP
由设备对象对应的驱动程序处理请求
某些 IRP 会沿着设备堆栈一路向下传递至物理设备对象 (PDO)
其他 IRP 从未到达 PDO
这些 IRP 由 PDO 上面的驱动程序之一完成
某种意义上,IRP 结构是自包含结构
它包含驱动程序处理 I/O 请求所需的所有信息
驱动程序堆栈
参与 I/O 请求的驱动程序整体序列称为请求的“驱动程序堆栈”
无论涉及了多少个设备堆栈
引用特定技术的分层驱动程序组
由多个设备堆栈处理的 I/O 请求
有时处理 IRP 的过程中会涉及到多个设备堆栈
下图说明了处理单个 IRP 的过程中涉及到四个设备堆栈的情形
IRP 由 Disk.sys 创建
Disk.sys 是“My USB Storage Device”节点的设备堆栈中的函数驱动程序
Disk.sys 将 IRP 沿着设备堆栈向下传递到 Usbstor.sys
IRP 传递到 Usbstor.sys
Usbstor.sys 为“My USB Storage Device”节点的 PDO 驱动程序
Usbstor.sys 为“USB Mass Storage Device”节点的 FDO 驱动程序
IRP 传递到 Usbhub.sys
Usbhub.sys 为“USB Mass Storage Device”节点的 PDO 驱动程序
Usbhub.sys为“USB Root Hub”节点的 FDO 驱动程序
IRP 传递到(Usbuhci.sys、Usbport.sys)对
(Usbuhci.sys、Usbport.sys)对为“USB Root Hub”节点的 PDO 驱动程序
(Usbuhci.sys、Usbport.sys)对为“USB Host Controller”节点的 FDO 驱动程序
I/O 请求的驱动程序堆栈
通过关注驱动程序而非设备节点及其单个设备堆栈来获取该序列的其他视图
参与 I/O 请求的驱动程序的序列称为 I/O 请求的驱动程序堆栈
按照驱动程序参与请求的次序从上到下画驱动程序
注意
I/O 请求的驱动程序堆栈与设备节点的设备堆栈完全不同
I/O 请求的驱动程序堆栈不必要留在设备树的某一分支中
技术驱动程序堆栈
为每个驱动程序提供友好名称,并对上图做一些细小更改
出现与WDK文档中的类似框图
将每个部分都视为属于特定技术或属于操作系统的特定组件或一部分
第一部分属于卷管理器
第二部分属于操作系统的存储组件
第三个部分属于操作系统的核心USB
技术驱动程序堆栈
显示特定技术或操作系统的特定组件或一部分的所有驱动程序的框图
微型驱动程序和驱动程序对
微型驱动程序
微型端口驱动程序
可用作半个驱动程序对
驱动程序对的一半(前半部分),一般用以处理特定任务
如:(微型端口、端口)的驱动程序对
简化驱动程序开发
驱动程序对
驱动程序拆分为两个部分
(specific.sys、general.sys)对
一个驱动程序处理整个设备集合共同的常规任务
由Microsoft 提供
另一个驱动程序处理特定于单个设备的任务
由Microsoft或IHV提供
IHV:independent hardware vendor 独立的硬件供应商
处理设备特定任务的驱动程序有多个名称
微型端口驱动程序
微型类驱动程序
微型驱动程序
可用的驱动程序对
(屏幕微型端口驱动程序,屏幕端口驱动程序)
(音频微型端口驱动程序、音频端口驱动程序)
(存储微型端口驱动程序,存储端口驱动程序)
(电池微型类驱动程序,电池类驱动程序)
(HID 微型驱动程序,HID 类驱动程序)
(转换器微型类驱动程序、转换器端口驱动程序)
(NDIS 微型端口驱动程序、NDIS 库)
可用的一些(特定、通用)对
内核模式驱动程序必须有DriverEntry 的函数
填充 DRIVER_OBJECT 结构的某些成员
MajorFunction 成员为指向函数的大量指针
这些函数处理 I/O 请求数据包 (IRP)
驱动程序使用指向函数的指针填充 MajorFunction 数组的多个成员
根据 IRP 的主要函数代码对 IRP 进行分类
由常量标识
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_PNP
例:检查 parport 驱动程序的函数指针
0: kd> !drvobj parport 2
0: kd> !drvobj parport 2 Driver object (fffffa80048d9e70) is for: \Driver\Parport DriverEntry: fffff880065ea070 parport!GsDriverEntry DriverStartIo: 00000000 DriverUnload: fffff880065e131c parport!PptUnload AddDevice: fffff880065d2008 parport!P5AddDevice Dispatch routines: [00] IRP_MJ_CREATE fffff880065d49d0 parport!PptDispatchCreateOpen [01] IRP_MJ_CREATE_NAMED_PIPE fffff80001b6ecd4 nt!IopInvalidDeviceRequest [02] IRP_MJ_CLOSE fffff880065d4a78 parport!PptDispatchClose [03] IRP_MJ_READ fffff880065d4bac parport!PptDispatchRead [04] IRP_MJ_WRITE fffff880065d4bac parport!PptDispatchRead [05] IRP_MJ_QUERY_INFORMATION fffff880065d4c40 parport!PptDispatchQueryInformation [06] IRP_MJ_SET_INFORMATION fffff880065d4ce4 parport!PptDispatchSetInformation [07] IRP_MJ_QUERY_EA fffff80001b6ecd4 nt!IopInvalidDeviceRequest [08] IRP_MJ_SET_EA fffff80001b6ecd4 nt!IopInvalidDeviceRequest [09] IRP_MJ_FLUSH_BUFFERS fffff80001b6ecd4 nt!IopInvalidDeviceRequest [0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff80001b6ecd4 nt!IopInvalidDeviceRequest [0b] IRP_MJ_SET_VOLUME_INFORMATION fffff80001b6ecd4 nt!IopInvalidDeviceRequest [0c] IRP_MJ_DIRECTORY_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest [0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest [0e] IRP_MJ_DEVICE_CONTROL fffff880065d4be8 parport!PptDispatchDeviceControl [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff880065d4c24 parport!PptDispatchInternalDeviceControl [10] IRP_MJ_SHUTDOWN fffff80001b6ecd4 nt!IopInvalidDeviceRequest [11] IRP_MJ_LOCK_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest [12] IRP_MJ_CLEANUP fffff880065d4af4 parport!PptDispatchCleanup [13] IRP_MJ_CREATE_MAILSLOT fffff80001b6ecd4 nt!IopInvalidDeviceRequest [14] IRP_MJ_QUERY_SECURITY fffff80001b6ecd4 nt!IopInvalidDeviceRequest [15] IRP_MJ_SET_SECURITY fffff80001b6ecd4 nt!IopInvalidDeviceRequest [16] IRP_MJ_POWER fffff880065d491c parport!PptDispatchPower [17] IRP_MJ_SYSTEM_CONTROL fffff880065d4d4c parport!PptDispatchSystemControl [18] IRP_MJ_DEVICE_CHANGE fffff80001b6ecd4 nt!IopInvalidDeviceRequest [19] IRP_MJ_QUERY_QUOTA fffff80001b6ecd4 nt!IopInvalidDeviceRequest [1a] IRP_MJ_SET_QUOTA fffff80001b6ecd4 nt!IopInvalidDeviceRequest [1b] IRP_MJ_PNP fffff880065d4840 parport!PptDispatchPnp
parport为并行端口判优器
输出中(注释)可以看到以下内容
parport.sys 实现 GsDriverEntry
驱动程序的入口点
在生成驱动程序时自动生成
执行一些初始化,然后调用 DriverEntry
DriverEntry由驱动程序开发人员实现
parport 驱动程序为指向调度函数的指针提供了一些主要函数代码
parport 驱动程序位于其 DriverEntry 函数中
IRP_MJ_CREATE
IRP_MJ_CLOSE
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_QUERY_INFORMATION
IRP_MJ_SET_INFORMATION
IRP_MJ_DEVICE_CONTROL
IRP_MJ_INTERNAL_DEVICE_CONTROL
IRP_MJ_CLEANUP
IRP_MJ_POWER
IRP_MJ_SYSTEM_CONTROL
IRP_MJ_PNP
其余元素包含指向默认调度函数 nt!IopInvalidDeviceRequest 的指针
parport 驱动程序提供了用于 Unload 和 AddDevice 的函数指针, 但未提供用于 StartIo 的函数指针
AddDevice 函数很独特
其函数指针未存储在 DRIVER_OBJECT 结构中
而是存储在 DRIVER_OBJECT 结构扩展的 AddDevice 成员中
图说明了 parport 驱动程序在其 DriverEntry 函数中提供的函数指针
parport 提供的函数指针被阴影遮蔽
specific.sys 的 DriverEntry 函数无需进行上述操作
只需将 DRIVER_OBJECT 结构传递至 general.sys 实现的初始化函数即可
注释说明了在(ProsewareRobot.sys、GeneralRobot.sys)对中如何调用初始化函数
PVOID g_ProsewareRobottCallbacks[3] = {DeviceControlCallback, PnpCallback, PowerCallback}; // DriverEntry function in ProsewareRobot.sys NTSTATUS DriverEntry (DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath) { // Call the initialization function implemented by GeneralRobot.sys. return GeneralRobotInit(DriverObject, RegistryPath, g_ProsewareRobottCallbacks); }
当 I/O 管理器将 IRP 发送至驱动程序对时
IRP 首先转至由 GeneralRobot.sys 实现的调度函数
如果 GeneralRobot.sys 可以自行处理 IRP
则无需涉及到特定驱动程序 ProsewareRobot.sys
如果 GeneralRobot.sys 可以处理部分但不是全部的 IRP 处理
则它会从由 ProsewareRobot.sys 实现的回调函数之一获取帮助
GeneralRobot.sys 接收指向 GeneralRobotInit 调用中 ProsewareRobot 回调的指针
在 DriverEntry 返回的某个点,会构造用于 Proseware Robot 设备节点的设备堆栈
顶部为与筛选器驱动程序 AfterThought.sys 关联的筛选器 DO
Filter Do:筛选器设备对象
中间为与驱动程序对(ProsewareRobot.sys、GeneralRobot.sys)关联的FDO
FDO:功能设备对象
用作设备堆栈的函数驱动程序
底部设备对象为与 Pci.sys 关联的PDO
PDO:物理设备对象
驱动程序对仅占用设备堆栈中的一层并且仅与一个设备对象关联:FDO
驱动程序对示例
1: kd> !drvobj netwlv64 2
1: kd> !drvobj netwlv64 2 Driver object (fffffa8002e5f420) is for: \Driver\netwlv64 DriverEntry: fffff8800482f064 netwlv64!GsDriverEntry DriverStartIo: 00000000 DriverUnload: fffff8800195c5f4 ndis!ndisMUnloadEx AddDevice: fffff88001940d30 ndis!ndisPnPAddDevice Dispatch routines: [00] IRP_MJ_CREATE fffff880018b5530 ndis!ndisCreateIrpHandler [01] IRP_MJ_CREATE_NAMED_PIPE fffff88001936f00 ndis!ndisDummyIrpHandler [02] IRP_MJ_CLOSE fffff880018b5870 ndis!ndisCloseIrpHandler [03] IRP_MJ_READ fffff88001936f00 ndis!ndisDummyIrpHandler [04] IRP_MJ_WRITE fffff88001936f00 ndis!ndisDummyIrpHandler [05] IRP_MJ_QUERY_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler [06] IRP_MJ_SET_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler [07] IRP_MJ_QUERY_EA fffff88001936f00 ndis!ndisDummyIrpHandler [08] IRP_MJ_SET_EA fffff88001936f00 ndis!ndisDummyIrpHandler [09] IRP_MJ_FLUSH_BUFFERS fffff88001936f00 ndis!ndisDummyIrpHandler [0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler [0b] IRP_MJ_SET_VOLUME_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler [0c] IRP_MJ_DIRECTORY_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler [0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler [0e] IRP_MJ_DEVICE_CONTROL fffff8800193696c ndis!ndisDeviceControlIrpHandler [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff880018f9114 ndis!ndisDeviceInternalIrpDispatch [10] IRP_MJ_SHUTDOWN fffff88001936f00 ndis!ndisDummyIrpHandler [11] IRP_MJ_LOCK_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler [12] IRP_MJ_CLEANUP fffff88001936f00 ndis!ndisDummyIrpHandler [13] IRP_MJ_CREATE_MAILSLOT fffff88001936f00 ndis!ndisDummyIrpHandler [14] IRP_MJ_QUERY_SECURITY fffff88001936f00 ndis!ndisDummyIrpHandler [15] IRP_MJ_SET_SECURITY fffff88001936f00 ndis!ndisDummyIrpHandler [16] IRP_MJ_POWER fffff880018c35e8 ndis!ndisPowerDispatch [17] IRP_MJ_SYSTEM_CONTROL fffff880019392c8 ndis!ndisWMIDispatch [18] IRP_MJ_DEVICE_CHANGE fffff88001936f00 ndis!ndisDummyIrpHandler [19] IRP_MJ_QUERY_QUOTA fffff88001936f00 ndis!ndisDummyIrpHandler [1a] IRP_MJ_SET_QUOTA fffff88001936f00 ndis!ndisDummyIrpHandler [1b] IRP_MJ_PNP fffff8800193e518 ndis!ndisPnPDispatch
netwlv64.sys 实现 GsDriverEntry,驱动程序的入口点
GsDriverEntry(在生成驱动程序时自动生成)执行一些初始化
然后调用 DriverEntry(由驱动程序开发人员编写)
ndis.sys 实现 AddDevice、Unload 以及多个调度函数
两个模块共同形成(NDIS 微型端口、NDIS 库)对
Netwlv64.sys 为 NDIS 微型端口驱动程序,ndis.sys 为 NDIS 库
作为通用驱动程序对模型的 KMDF
驱动程序分为两部分:一部分进行通用处理,另一部分进行特定设备特有的处理
通用部分(由 Microsoft 编写)称为框架
特定部分(由 Microsoft 或独立的硬件供应商编写)称为 KMDF 驱动程序
IRP先框架,后KMDF
在(KMDF 驱动程序,框架)对中
框架处理各种内核模式驱动程序共同的任务
I/O 请求排队
线程同步
大部分即插即用任务以及大部分电源管理任务
KMDF 驱动程序处理需要与特定设备交互的任务
KMDF 驱动程序通过注册事件处理程序来参与处理请求
其中,事件处理程序在框架需要时被调用
KMDF 扩展和三重驱动程序
使用基于类的 KMDF 扩展的驱动程序有以下三个部分
我们将其称为“三重驱动程序”
框架
处理大部分驱动程序共同的任务
基于类的框架扩展
处理特定于特殊类的设备的任务
即处理某一系列子任务的问题
KMDF 驱动程序
处理特定于特殊设备的任务
框架处理大部分驱动程序共同的常规任务
SpbCx.sys 处理特定于 SPB 总线类的任务
所有SPB总线的共同任务
SpbCx.sys 实现的事件处理程序的一些示例
EvtIoRead
KMDF 驱动程序处理特定于 I2C 总线的任务
此驱动程序被称为 MyI2CBusDriver.sys
由 MyI2CBusDriver.sys 实现的事件处理程序的一些示例
EvtSpbControllerLock
EvtSpbIoRead
EvtSpbIoSequence
驱动程序的上沿和下沿
当驱动程序实现一组
高层驱动程序可以调用的函数
称为“驱动程序的上沿”
或者“驱动程序的上沿接口”
低层驱动程序可以调用的函数
称为“驱动程序的下沿”
或者“驱动程序的下沿接口”
绘制相同设备节点和设备堆栈图的另一种方法
在微型端口驱动程序的上面绘制端口驱动程序, 并非意味着该端口驱动程序位于设备堆栈中微型驱动程序的上面
Windows驱动程序工具包中的头文件
头文件包含版本信息
不论驱动程序在哪个版本的 Windows 上运行
都可以使用一组相同的头文件
Windows 操作系统版本的预定义常量值
#if (NTDDI_VERSION >= NTDDI_WIN7) _Must_inspect_result_ NTKERNELAPI NTSTATUS KeSetTargetProcessorDpcEx ( _Inout_ PKDPC Dpc, _In_ PPROCESSOR_NUMBER ProcNumber ); #endif 在该示例中,你可以看到仅在 Windows 7 和更高版本的 Windows 中才提供 KeSetTargetProcessorDpcEx 函数。
NTDDI_WIN10
Windows 10
NTDDI_WINBLUE
Windows 8.1
NTDDI_WIN8
Windows 8
NTDDI_WIN7
Windows 7
NTDDI_WS08SP4
Windows Server 2008 SP4
NTDDI_WS08SP3
Windows Server 2008 SP3
NTDDI_WS08SP2
Windows Server 2008 SP2
NTDDI_WS08
Windows 2008 Server
WDK 支持多种版本的 Windows, 还支持多种版本的KMDF 和UMDF
WDK 头文件中的版本信息与 Windows 版本有关,但与 KMDF 或 UMDF 版本无关
用于不同版本的 KMDF 和 UMDF 的头文件放置在不同的目录中
为不同版本的Windows编写驱动程序
创建驱动程序项目时,请指定最低目标操作系统
为低版本的 Windows 开发驱动程序,且希望在更高版本的 Windows运行
不得使用任何未记录的函数
也不得以文档中介绍的方式之外的任何其他方式使用记录的函数
应在每次发布新版本的 Windows 时在其上对驱动程序进行测试
编写仅使用共同功能的多版本驱动程序
编写使用版本相关功能的多版本驱动程序
确定 Windows 版本
有条件地调用与 Windows 版本相关的函数
适用于所有驱动程序开发人员的概念
用户模式和内核模式
处理器的两种模式
用户模式
应用程序运行的模式
有专用的虚拟地址空间
数据只能访问和修改有限数据
故障只影响当前应用
内核模式
驱动等系统程序运行的模式
共用一个虚拟地址空间
数据能访问和修改所有数据
存在安全问题
修改内核模式中的数据
可能系统崩溃、安全威胁
某些驱动也在用户模式下运行
虚拟地址空间
地址空间
程序实体所占用的内存大小
连续的地址空间
其物理地址不一定连续
用户模式下,不同程序有各自的虚拟地址空间
内核模式下,共用一个虚拟地址空间
设备节点和设备堆栈
I/O请求数据包
IRP I/O Request Package
驱动程序堆栈
微型驱动程序和驱动程序对
Windows驱动程序工具包中的头文件
为不同版本的Windows编写驱动程序
驱动相关的缩写
WDM
Windows Driver Model
dGPU
Discrete GPUs
独立显卡