Windows驱动开发(二)WDM/WDF的IOControl
上一章大概介绍了WDM/WDF的驱动模型,
链接:https://blog.csdn.net/o0xwh_93150o/article/details/104213348
这一章我们主要来看一下驱动程序中的IO请求是如何处理的。
其实驱动程序的主要功能也就是负责处理IO请求,其中大部分IO请求是在派遣函数中处理的。用户模式下的所有对驱动程序的IO请求,全部由操作系统转化为一个叫做IRP(IO request package)的数据结构,不同的IRP会被“派遣”到不同的派遣函数(dispatch function)中。IRP的处理机制类似windows应用程序中的“消息处理”机制,驱动程序接收到不同类型的IRP后,会进入不同的派遣函数。
首先,IRP拥有两个基本的属性,一个是MajorFunction,另一个则是MinorFunction,分别记录IRP的主类型和子类型。操作系统根据MajorFunction将IRP派遣到不同的派遣函数中,然后再判断这个IRP属于哪种MinorFunction。如下所示:
//创建设备,CreateFile时触发
DriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDispatchCreate;
//关闭设备,CloseHandle时触发
DriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDispatchClose;
//对设备进行WriteFile时触发
DriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDispatchWrite;
//对设备进行ReadFile时触发
DriverObject->MajorFunction[IRP_MJ_READ] = HelloDispatchRead;
当然,IRP的类型远不止这四种,对于其他没有设置的IRP类型,系统会默认将这些IRP类型与IoInvalidDeviceRequest函数关联。大部分的IRP都源于文件IO处理Win32 API,例如CreateFile与ReadFile。假如我们对这个类型的IRP不需要特别处理的话,只需要在派遣函数中直接返回success就可以了。如下:
NTSTATUS status = STATUS_SUCCESS;
//设置irp的完成状态
pIrp->IoStatus.Status = status;
//设置irp操作的实际字节数
pIrp->IoStatus.Infomation = 0;
//结束irp请求时需调用IoCompleteRequest
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
在驱动程序设置完这些IRP之后,是不是就可以使用用户应用程序向该驱动发送IO请求了呢?其实并不是如此,我们都知道,在用户态假如要操作这个设备,CreateFile时必要的一个参数,就是设备句柄,但是在用户态,其实是看不到内核态设备的句柄的,例如该设备的句柄为“\\Devices\\HelloDevice0”,这个句柄仅能被内核模式下的其他驱动所看见,所以我们需要创建一个符号链接,让用户态的程序可以得到这个句柄,类似“\\DosDevices\\HelloDevice0_LINK”这样。如下实例:
#define MYWDF_KDEVICE L“\\Devices\\HelloDevice0”
#define MYWDF_LINKNAME L“\\DosDevices\\HelloDevice0_LINK”
// 创建设备
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&object_attribs, DEVICE_CONTEXT_CTRL);
//为设备首先分配内存
device_init = WdfControlDeviceInitAllocate(WdfDeviceGetDriver(Device), &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);
RtlInitUnicodeString(&ustring, MYWDF_KDEVICE);
//将设备名字存入device_init中
status = WdfDeviceInitAssignName(device_init, &ustring);
if (!NT_SUCCESS(status)) {
//
}
//创建一个controldevice,用于创建符号链接
status = WdfDeviceCreate(&device_init, &object_attribs, &control_device);
if (!NT_SUCCESS(status)) {
//
}
RtlInitUnicodeString(&ustring, MYWDF_LINKNAME);
//创建符号链接
status = WdfDeviceCreateSymbolicLink(control_device, &ustring);
if (!NT_SUCCESS(status)) {
//
}
这样,你的设备就可以被用户态的程序所使用了,接下来,再在用户态使用CreateFIle打开这个符号链接就可以了。驱动程序中我们已经设置好了Write和Read的派遣函数,只要使用WriteFile和ReadFile,就可以触发这两个IRP回调函数了,这个就不再举例子了。
当然,有时候应用程序并不需要真的向这个设备进行读和写操作,它可能仅仅需要“告知”驱动程序,我想要做什么,驱动程序可以在自己的会话空间里就足够处理,这时,微软为我们准备了另一个Win32 API:DeviceIoControl。这个API会在内部使操作系统创建一个IRP_DEVICE_CONTROL类型的IRP,你只需要在驱动中设置这个类型IRP的回调函数就可以了。
DeviceIoControl的函数原型如下:
BOOL WINAPI DeviceIoControl(
_In_ HANDLE hDevice,
_In_ DWORD dwIoControlCode,
_In_opt_ LPVOID lpInBuffer,
_In_ DWORD nInBufferSize,
_Out_opt_ LPVOID lpOutBuffer,
_In_ DWORD nOutBufferSize,
_Out_opt_ LPDWORD lpBytesReturned,
_Inout_opt_ LPOVERLAPPED lpOverlapped);
其中第二个参数dwIoControlCode,就是IO控制码,即IOCTL值,用来告诉驱动程序,我需要进行哪种类型的交互,当然,前提是这个IOCTL值是驱动程序预先设置好已知的,我们可以用CTL_CODE这个宏来定义一组IOCTL值。CTL_CODE的定义为(DeviceType,Function,Method,Access),DeviceType为设备对象的类型,这个类型应该与创建设备(IoCreateDevice)时的类型匹配,如FILE_DEVICE_XX这样的宏;Function为驱动程序定义的IOCTL宏,0x0000-0x7FFFF为微软保留,0x800-0xFFF为程序员自定义;Method为操作模式,应使用如下四种之一,METHOD_BUFFERED(使用缓冲区操作),METHOD_IN_DIRECT(使用直写操作),METHOD_OUT_DIRECT(使用直写操作),METHOD_NEITHER(使用其他方式操作);Access为访问权限,如果没有特殊要求,一般使用FILE_ANY_ACCESS。如下是一个实例:
#define IOCTL_HELLO CTL_CODE(\
FILE_DEVICE_UNKNOWN, \
0x999, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
这里说一下关于METHOD_BUFFERED,使用缓冲内存模式的IOCTL,要避免在驱动中直接访问用户模式下的内存地址。在这种模式下,DeviceIoControl的大致流程是这样的,定义CTL_CODE宏->得到当前堆栈(IoGetCurrentIrpStackLocation)->得到输入缓冲区大小(DeviceIoControl.InputBufferLength)->得到输出缓冲区大小(DeviceIoControl.OutputBufferLength)->得到IOCTL码(DeviceIoControl.IoControlCode)->switch处理该IOCTL->设置IRP状态->结束IRP请求(IoCompleteRequest)。
关于驱动程序的IO请求就说到这里,下一章的话,我们就直接进入实战篇吧~拿一个WDF的总线驱动来分析一下。
Windows驱动开发(二)WDM/WDF的IOControl相关推荐
- Windows驱动开发VXD/WDM/WDF/DDK/WDK的联系和区别
背景介绍 首先,先从基础的东西说起,做任何程序的开发,你都需要一个配套的开发套件,专业术语叫做SDK(Software Development Kit,软件开发套件).比如:开发JAVA程序,我们可能 ...
- Windows驱动开发入门 --WDM inf文件模板
本文主要介绍安装WDM驱动的inf文件如何编写. 由于inf文件的规则比较复杂,写法也比较多样,故本文只介绍通过Visual Studio开发WDM驱动时的inf模板文件的通用写法. 模板文件如下: ...
- Windows驱动开发二:Windbg源码调试
在windbg中源码调试,编译好测试的驱动文件到指定路径打开 windbg-> Open source file 打开 在原代码文件同级目录中有编译打符号文件,Settings->Defa ...
- 客户端开发 Windows驱动开发(1)SDK WDK DDK WDM的关系
尽管Windows平台的SDK.DDK与WDK都包含了WinDBG工具包,但是用户获取WinDBG工具包的最主要方式还是从微软网站自由下载,因为这样获得的版本最新. 最近因为工作需要,尝试去了解WIN ...
- windows驱动开发-WDF编程
文章目录 前言 WDF编程前的准备工作 WDF编程 创建驱动对象 创建设备对象 设备对象的回调函数 链表操作 驱动的测试代码 其他 前言 注:本文的完整代码见仓库 18-WDF-reflect 代码参 ...
- Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础
Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...
- Windows驱动开发WDM (1) - 基本结构
陆陆续续做过一些驱动的开发,但是一直以来都没有系统的学习过.这次重新阅读<windows驱动开发技术详解>(张帆,史彩成等编著),写博客记录一下,用以加深自己对驱动的理解. 驱动对象(DR ...
- 《Windows驱动开发技术详解》学习笔记
Abstract 如果推荐 Windows 驱动开发的入门书,我强烈推荐<Windows驱动开发技术详解>.但是由于成书的时间较早,该书中提到的很多工具和环境都已不可用或找不到,而本文 ...
- 15、Windows驱动开发技术详解笔记(11) 基本概念
9.Windows驱动程序的入口函数规定为_DriverEntry@8,所以用C++编写时要用extern. 驱动程序中,不能使用编译器运行时函数,甚至C语言中的malloc,C++的new函数都不能 ...
- Windows驱动开发书籍简介
分享到 一键分享 QQ空间 新浪微博 百度搜藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 首页 我的主页 相册 广 ...
最新文章
- 【rsyslogd】rsyslog 中 timereported 与 timegenerated 区别
- javaWeb项目 IDEA中导入eclipes项目的方法。maven多模块项目(父子模块)与普通的web项目导入
- HTML第八章ppt,第八章 web基础教程之HTML篇v1.0.ppt
- 【华为云技术分享】弹性负载均衡服务助力企业应对高并发流量冲击
- 马云:首批助力欧洲防疫的物资今天到达比利时
- Linux下2号进程的kthreadd--Linux进程的管理与调度(七)
- 中柏平板触摸驱动_华北工控 | 工业平板电脑在医院自助设备中的广泛应用
- 51cto shell mysql备份数据库_shell脚本备份MYSQL数据库
- 【CSS】CSS样式的优先级
- python编程软件开发_Python编程-绑定方法、软件开发
- (一)基于Multisim的超外差接收系统:本地振荡器的设计
- iOS app中不能跳转到商店更新
- Linux命令之 jstack
- Redis各版本描述
- 一、项目概述和项目基本结构
- 10个无版权限制的免费图片素材资源网站
- anaconda 上实现Tensorflow MASK R-CNN Demo Windows (CPU版)
- 力扣leetCode459之重复的子字符串(双倍字符串解法)Java
- SQL Server 批量插入数据方案 SqlBulkCopy 的简单封装,让批量插入更方便
- Ubuntu软件快捷方式