[转载]windows过滤驱动程序设计入门(驱动程序基本结构,设备栈,IRP栈和工作原理)

本文转载自: http://blog.csdn.net/arvon2012/article/details/7789724

最近在学习windows驱动设计,认真看了些教材后总结了我认为驱动中都会涉及到,也最重要的概念,和大家分享。如果有说的不对的请大家留言指出。谢谢!

这里主要是写概念,代码涉及的不多也不详细,但是我会说出涉及到的API,详细的使用细节大家可以自己动手搜搜。掌握下面的概念之后,看驱动开发的教材里的代码,或者理解教材里说的内容应该就顺利很多!

过滤驱动程序概括:

对于windows驱动程序设计来说,理论上,我们要做的就是创建设备对象(包括完成这个设备对象内部的功能、参数等),然后将这个设备对象绑定到我们要过滤的设备上。一个设备对应一个驱动对象,而一个驱动对象可以生成许多设备对象,这些设备对象是实现功能、完成任务的东西(我们在程序中反复玩弄和折磨的就是他们)。

驱动的层次结构架构:

------------------------------------------------------------------------------------------------------------------------------------------------

上层应用(调用系统API,希望完成一些工作)

------------------------------------------------------------------------------------------------------------------------------------------------

IO控制器(解析上层请求,向下层发IRP包)

------------------------------------------------------------------------------------------------------------------------------------------------

N层过滤驱动(拦截IRP包,做预处理)

------------------------------------------------------------------------------------------------------------------------------------------------

。。。

------------------------------------------------------------------------------------------------------------------------------------------------

目标设备(被过滤设备或者原始设备或者真实设备或者物理设备。。。)(接收IRP包,并按包的指示工作)

------------------------------------------------------------------------------------------------------------------------------------------------

重要概念:
1.设备栈:DeviceStack

设备栈是什么?里面装的是什么东西?怎么工作的?

在编写过滤驱动的过程中,我们每生成一个设备对象(代表一个过滤驱动),就一定会把它绑定到我们要过滤的目标设备上。那么如果把多个过滤驱动的对象绑定到同一个设备上是怎么绑呢?系统怎么管理他们呢?答案就是设备栈。原始的被绑定设备和往他上面绑的过滤设备们组合在一起就成了一个设备组。这个设备组会被系统管理成一个栈的结构,形成的就是设备栈。后绑定的设备原本希望绑最下面的目标设备,而实际上绑在了最外面,就像礼品包装纸一样,一层层往外裹。所以当有请求发给目标设备的时候,请求会按栈中的次序从栈顶(最外层)开始依次被栈中的过滤对象依次处理。最后发给目标设备。

相关的函数:

当新的设备想要加入设备栈(绑定目标设备)的时候,就会调用绑定函数:IoAttachDeviceToDeviceStackSafe,它第三个参数返回被绑定后的对象指针(其实根据上面的说明能看出来,这个这真就是栈顶)。在这个API的使用当中,大家会发现,一般把第三个参数保存到这个过滤驱动的设备扩展的AttachedToDeviceObject字段,那么通过这个字段是不是可以把IRP依次传递下去?当然,因为它代表当前过滤驱动下一层的设备。

绑定设备的三部曲:

第一步:创建设备(准备往其他设备上绑的设备),用IoCreateDevice,第一个参数是设备对象,过滤驱动中填的就是过滤设备。

第二步:为创建的设备设置标志位:把A绑定到B上,就要让AB的标识位一致(这样系统看起来,就以为自己发送IRP到目标设备了),所以创建了A后,要设置一些重要的标识位。

第三步:绑定:调用绑定函数进行绑定,绑上目标设备栈的栈顶设备(这一步结束后,可以通过我们创建的设备对象flag设置设备已经启动)

2.服务请求包:IRP和IRP栈

IRP

包里面是什么?怎么产生?怎么工作的?

包里面存放了接收设备要完成请求的工作所需要的一切信息~~~很大很复杂的一个结构体。在WDK的wdm.h中可以找到他。大家在使用的时候会发现,一般都只涉及到一些常用字段。

当用户程序在用户层(Ring3)调用一些系统API,比如(ReadFile)的时候,这些函数的请求最终会被IO控制器接收,然后发出IRP,这个IRP会被向下发送,然后一次又一次的被各种设备处理然后发送给下一个设备。在这个过程中,IRP包又可以被中间的处理设备修改。

IRP栈:

那么IRP栈中的内容是什么?系统怎么使用的这个栈进行工作的?

大家看一些教材的时候一定会发现在自己创建的设备过滤到IRP包,然后想对IRP包进行操作的时候,总是会访问IRP栈。上一段中说了,一个IRP的生命中,有可能会敬礼许多段和接收到他的设备的爱情,在这个过程中,IRP中的一些字段难免会不断被改变。而一个IRP栈就像是日记本,记录了IRP的改变过程,所以栈顶的肯定是现在最新的IRP。这就是为什么。。。看下面的函数:

IoGetCurrentIrpStackLocation(irp),每当我们想获得IRP的时候,就这样调用。仔细看这个api中的单词Current,就能猜到这个函数的意思就是访问IRP栈顶、最新状态的IRP(这个最新状态的IRP是经过上层设备各种修改的IRP)。

3.下面说下IRP中存的数据

IRP携带数据是通过携带数据所在内存区域的指针来实现的。这样的指针有三个:

UserBuffer,MDLAddress,SystemBuffer。不同的设备会用不同的指针去存要携带的数据。下面是三个指针的原理:

a.SystemBuffer是把用户层空间中的缓冲中的数据复制到内核层空间中使用,这种方式效率很低。

b.UserBuffer是把应用层的缓冲地址直接传递进来,供内核层使用。优点是系统实现的很快,传个地址就行,缺点:内核进程切换,当前的进程被切出去了,访问会结束。为什么会这样?内核空间是共享的,所以内核进程都用公共的空间,内核进程一旦切换,前一个进程遗留的数据肯定就被干掉了~

c.MDL方式是弥补了上面这个缺点,也就是说这个内存描述符表通过添加一个表项,永久的把一段应用层空间和内核空间一段虚拟空间绑定在了一起。这样相当于内核使用访问自己空间的地址,其实是在不知不脚的访问用户空间中的内容。因为这个访问方式是用MDL实现和管理的,所以就算内核当前进程发生了切换啥的,只要MDL表在(这不废话吗?),就永远可以访问到用户空间的那一段内容。而不是简单的把用户空间的一个指针作为值暂时的存到内核空间的一个变量中。

4.IRP的传递

IRP在驱动设备的工作中起着全程指导的作用,他会在一系列的设备中被转发,自己也会不断改变,那么大家经常遇到这个情况:对于一个过滤驱动来说,他拦截了IRP后,仔细的看了看这个IRP后,发现不是自己感兴趣的,就打算原封不懂得扔给下一层设备处理。在一些教材的示例代码中完成这功能的就一对好基友:

如下:

IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceObject,Irp);

上面这对基友的工作机制可有讲究了:IoCallDriver单独工作时,效果是自动把irp栈中当前IRP包的下一个包发送到某个真实设备上。。。(因为这个函数认为之前的操作修改了IRP,并且把修改内容压入到IRP栈中新的栈顶地址上,所以让他来调用下一个设备工作,下一个设备收到的IRP也是目前设备处理后的新的IRP,从地址角度来说,就是当前IRP在IRP栈中的地址的下一个地址(新的栈顶)),而IoSkipCurrentIrpStackLocation写在IoCallDriver前面的效果是让IoCallDriver调用的下一层设备收到的IRP包就是本层设备受到的那个。这就完成了所谓的“跳过当前设备”的操作。【抱歉,杂家表达能力有限,是不是说的很晕?】

5.IRP请求的完成:

比较简单,调用一个函数:IoCompleteRequest 例程表示调用者的已经完成了对指定I/O请求的所有处理操作,并且向I/O管理器返回指定的IRP报文。

6.当然,过滤设备可以绑定也可以解绑Unload:

Unload设备没什么复杂代码,就是调用IoDeleteDeviceIRP。

时间: 2024-11-03 22:13:45

[转载]windows过滤驱动程序设计入门(驱动程序基本结构,设备栈,IRP栈和工作原理)的相关文章

[转载]文件过滤驱动 文件系统激活通知 IoRegisterFsRegistrationChange函数实现

IoRegisterFsRegistrationChange 注册一个文件系统变动回调函数,用来被通知文件系统的激活和注销,激活是指第一次加载文件系统,当一个文件系统已经加载后,当加载一个同种文件系统的卷时,该文件系统就和激活没关系.话说该函数调用后,激活的文件系统会重新激活一遍,在2k SP4之后的系统都会这样做. 现在考虑下,这种机制是怎么实现的,猜测是在注册的时候,注册完成后,系统将各种类型的文件系统,都调用该回调函数一遍,来一次所有文件系统激活的通知.而事实上,也应该如此,reactOs

文件过滤驱动开发入门笔记

转载(详细教程):http://blog.csdn.net/chenyujing1234/article/details/7565346 转载(文件驱动小例子SFilter):http://download.csdn.net/detail/wangqjpp/4826392 转载(楚狂人教程):http://blog.csdn.net/joshua_yu/article/details/589981 转载(Win7 VS2012 环境搭建教程):http://blog.sina.com.cn/s/

基于嵌入式Linux的千兆以太网卡驱动程序设计及测试

一. 引言 千兆以太网是一种具有高带宽和高响应的新网络技术,相关协议遵循IEEE 802.3规范标准.采用和10M以太网相似的帧格式.网络协议和布线系统,基于光纤和短距离同轴电缆的物理层介质,更适用于交换机.服务器等数据吞吐率大的设备.本文设计实现一种基于嵌入式Linux千兆以太网卡的驱动程序,并完成后续的测试工作和代码移植. 千兆以太网网卡工作在OSI网络架构的物理层和数据链路层,其中物理层由PHY芯片管理,数据链路层由千兆以太网控制器(GMAC)管理.硬件构架上,GMAC控制器由核心层.MT

File System Minifilter Drivers(文件系统微型过滤驱动)

问题: 公司之前有一套文件过滤驱动,但是在实施过程中经常出现问题,现在交由我维护.于是在边看代码的过程中,一边查看官方资料,进行整理. 这套文件过滤驱动的目的只要是根据应用层下发的策略来控制对某些特定文件的控制,例如根据后缀名来决定是否允许查看,是否允许查看指定目录啊之类的功能. 介绍: MSDN上对可安装的文件系统驱动介绍http://msdn.microsoft.com/en-us/library/windows/hardware/ff548143(v=vs.85).aspx:其中树形结构菜

第四季-专题18-FLASH驱动程序设计

专题18-FLASH驱动程序设计 第1课-块设备驱动系统架构 块设备快速体验 块设备是指只能以块为单位进行访问的设备,块大小一般是512个字节的整数倍.常见的块设备包括硬件,SD卡,光盘等. l  insmod simple-blk.ko l  ls /dev/simp_blkdev0 l  mkfs.ext3 /dev/simp_blk0 l  mkdir –p /mnt/blk l  mount /dev/simp_blk0 /mnt/blk l  cp /etc/init.d/* /mnt

键盘过滤驱动

在笔者接触驱动到如今以来一以后大半个月的时间,从中让我深深的体会到了万事开头难,以及学习持之以恒的重要性.笔者也是个驱动新人,開始接触驱动的时候看着张帆的<Windows驱动开发技术具体解释>讲的挺细,对新手来说是个不错的学习资料,可是更重要的还是自己要多动手练习,笔者在学习到同步操作的相关知识的时候,实在是看天书.最后还是放弃了学习本书.再找了本楚狂人的资料学习,感觉本书对新手来说还是比較吃力的,当中笔者就是这样,非常多知识点不是非常明确,仅仅能凭借自己的感觉去做,只是造成的后果就是无情的蓝

[转载]MongoDB开发学习 经典入门

如果你从来没有接触MongoDB或对MongoDB有一点了解,如果你是C#开发人员,那么你不妨花几分钟看看本文.本文将一步一步带您轻松入门. 阅读目录 一:简介 二:特点 三:下载安装和开启服务器 四:使用mongo.exe 执行数据库增删改查操作 五:更多命令 六:MongoDB语法与现有关系型数据库SQL语法比较 七:可视化的客户端管理工具MongoVUE 八:在C#中使用官方驱动操作MongoDB 九,在C#中使用samus驱动操作MongoDB 十:写个批处理,方便开启Mongodb服务

实验报告 实验4 外设驱动程序设计

北京电子科技学院(BESTI) 实     验    报     告 课程: 密码系统设计基础                                                               班级: 1352班.1353班 姓名:王玥.刘浩晨                                                                    学号:20135318.20135232 成绩:                      

实验四 外设驱动程序设计(小组)

小组成员:20135305姚歌 20135310陈巧然 一.实验目的与要求 掌握实时系统应用和驱动程序的编写 选择某个接口电路(串口.LED.LCD.USB) 平台可选择Windows或Linux 二.实验内容 在ARM开发平台下,选择某个进行接口电路驱动程序设计 三.实验步骤 1.阅读和理解源代码进入/arm2410cl/exp/drivers/01_demo,使用vi 编辑器或其他编辑器阅读理解源代码2.编译驱动模块及测试程序上面介绍了在 Makefile 中有两种编译方法,可以在本机上使用