操作IRP所有驱动开发人员都要知道的知识(Draft)

上传人:艾力 文档编号:35485192 上传时间:2018-03-16 格式:PDF 页数:20 大小:90KB
返回 下载 相关 举报
操作IRP所有驱动开发人员都要知道的知识(Draft)_第1页
第1页 / 共20页
操作IRP所有驱动开发人员都要知道的知识(Draft)_第2页
第2页 / 共20页
操作IRP所有驱动开发人员都要知道的知识(Draft)_第3页
第3页 / 共20页
操作IRP所有驱动开发人员都要知道的知识(Draft)_第4页
第4页 / 共20页
操作IRP所有驱动开发人员都要知道的知识(Draft)_第5页
第5页 / 共20页
点击查看更多>>
资源描述

《操作IRP所有驱动开发人员都要知道的知识(Draft)》由会员分享,可在线阅读,更多相关《操作IRP所有驱动开发人员都要知道的知识(Draft)(20页珍藏版)》请在金锄头文库上搜索。

1、操作 IRP: 所有驱动开发人员都要知道的知识 (Draft) 翻译:Puffel 2007-8-3 概要概要 在微软的 Windows 操作系统家族中, 都通过发送 I/O 请求包(IRP, I/o Request Packets)来进行 和驱动程序的通讯。 用来封装 IRP 的数据结构不仅仅用来描述一个 I/O 操作的请求本身的内容, 还要用来维护这一请求在一系列驱动程序中传递的过程中的相关状态信息。 实现这一数据结构其实是为了两重目的,也就是说 IRP 可以被定义理解为: l 一个放置 I/O 请求的容器 或者 l 一个与线程无关的调用栈 从以上这两个角度来考虑 IRP,将有助于驱动开发

2、人员理解作为驱动,程序应该如何去正确 响应发来的 I/O 请求。 本文中关于例程(routines)和问题的讨论,请参考最新的微软 Windows 驱动开发包(WDK, Microsoft Windows Driver Kit)。 第一重定义:第一重定义:IRP是一个放置是一个放置I/O请求的容器请求的容器 操作系统以 IRP 的形式进行绝大多数发给驱动程序的 I/O 操作请求。 因为下列特点, 使得 IRP 非常适合于这一目的: l IRP 设计来可以被异步操作 l IRP 可以被在完成前取消 l IRP 设计来适合于需要多驱动协同完成的输入输出操作 IRP 数据结构封装了一个被请求的驱动所

3、需要的,用来回复这一请求的全部信息。而请求则可能来自于用户模式或者内核模式。其实不论请求来自那里,对于被请求的驱动程序,所 需要的信息是一样的。 所有的 IRP 都包含有下“表一”中的两个部分: l 一个用来描述主要 I/O 请求的头部 l 一组用来描述下级请求(有时就被称作子请求,sub-requests)的参数 Generated by Foxit PDF Creator Foxit Software http:/ For evaluation only.IRP HeaderParameters for sub-request. . .Parameters for sub-requestP

4、arameters for sub-request表一: IRP 的结构 其中,头部的数据尺寸是固定,且对所有 IRP 都相同的。而下级请求数组的尺寸则依 赖于会有多少个驱动要来操作这一请求。 IRP头部的内容:头部的内容: 一个 IRP 通常会被某个由一些驱动程序组成的栈来执行。每个 IRP 的头部信息,都各自包 含着每个要操作这个 IRP 的驱动程序会要使用的数据。 当一个给定的驱动正在处理一个 IRP 时,这个驱动就被定义为此 IRP 的当前拥有者(the current owner)。 每一个 IRP 的头部,都包含有以下的指针(Pointer): l 指向针对这一 IRP 的用以读取

5、输入以及写回输出的缓冲区 l 指向当前拥有这一 IRP 的驱动程序的内存区域 l 指向一个由当前拥有这一 IRP 的驱动提供的例程。这一例程将由系统在 IRP 被取 消时后调用。 l 指向当前的子请求的参数 另外, 除了这些指针, IRP 头部还包含有其它数据, 用来描述请求的状态和其它内在信息(微 软未开放的信息)。 IRP参数组:参数组: 在 IRP 头部之后是子请求数组。一个 IRP 可以有不只一个子请求,这是由于 IRP 通常会是 被由多个一些驱动程序组成的栈来操作。每一个 IRP 都被分配了一个固定数量的,这样的 子请求, 通常是对应于设备栈中的每一个驱动程序有一个。 这个编号恰好与

6、相应栈最顶端设 备的 StackSize 相匹配一致,虽然在栈中间的驱动其实可以被分配的小一点。还有,如果 一个驱动程序需要把请求发送到一个不同的设备栈处理,这个驱动程序就必须重新分配创 建一个新的 IRP。 每一个子请求都表示一个对应的 I/O 栈的位置(一个类型为 IO_STACK_LOCATION 的结构), 并且特定的 IRP 通常典型的为每一个其被发送到的目的设备栈上的每个驱动仅维持包含 一个这样的栈位置信息。 在 IRP 头部的一个域中还包含有标识当前正在被使用的 I/O 栈位置 信息。这个域的值被称作 IRP 栈指针(IRP stack pointer)或者当前栈位置(curre

7、nt stack Generated by Foxit PDF Creator Foxit Software http:/ For evaluation only.location)。 对于特定的 IO_STACK_LOCATION 结构,会包含有以下内容: l 对于特定 IRP 的主要以及次要的方法代码 l 针对这些代码的参数 l 一个指向相应驱动的设备对象(device object)的指针 l 一个指向 IoCompletion 例程的指针,如果驱动有过设定 l 一个指向和这一请求相关联的文件对象的指针 l 一些可变标志以及上下文关联区域 特定的 IO_STACK_LOCATION 结构

8、并不包含有指针标识指向输入和输出位置,这些(输 入、输出)指针本身就由 IRP 自身所包含。所有的子请求操作都使用同一缓冲区进行。 第二重定义:第二重定义:IRP作为一个线程无关的调用栈作为一个线程无关的调用栈 进行一个设备的 I/O 操作通常典型的需要调用这一设备相关的不止一个驱动。每一个和这 一设备相关的驱动都会创建一个设备对象(device object), 并且这些设备对象会垂直压入 (排 列进) 一个设备栈(device stack)中。 IRP 会在设备栈中从上到下的一个个被传递过去 (进去) 。 对于栈中的每一个驱动,IRP 都会用(包含)一个指针标识一个栈位置。由于驱动可以异步

9、 的处理请求,因此 IRP 就像是一个线程无关的调用栈一样,就像表二中所表示的: Parameter1 for AIoCompletion routine for initiatorParameter2 for AParameter1 for BParameter2 for BParameter1 for CParameter2 for CIoCompletion routine for AIoCompletion routine for BIRP HeaderThread StackParameter1 for A Parameter2 for A Return address to ini

10、tiator Parameter1 for B Parameter2 for B Return address to A Parameter1 for C Parameter2 for C Return address to B表二:IRP 作为线程无关的调用栈 在表二中, 左侧, 线程栈表示了驱动程序 A,B 和 C 的参数和返回值地址是如何在调用栈(call stack)中被组织的;而右侧,图表展示了这些参数和返回值地址是如何在一个 IRP 中对应到 I/O 栈位置以及 IoCompletion 例程上的。 IRP 操作所具有的异步特质对于操作系统和 Windows 驱动模型(WDM, W

11、indows Driver Model)是非常关键的。在一个同步的,单线程的 I/O 结构设计中,发送了请求的应用程序以 及传递请求的驱动程序都要在更低层的组件完成请求任务之前处于等待中。 这样的设计对于 运用系统资源是很没有效率的,会降低整个系统的性能。 Generated by Foxit PDF Creator Foxit Software http:/ For evaluation only.IRP 的结构提供了一种可被继承的异步方式的设计,使得应用程序能够将一个或多个 I/O 请 求排入队列,而不必等待。在 I/O 请求被处理的过程中,这个应用程序被解放出来可以进行 其他的计算, 或

12、者向队列里排入更多的 I/O 请求。 由于所有被用来处理请求的信息都被以 IRP 的形式封装起来了,所以请求线程的调用栈可以从 I/O 请求中分离出去。 将 IRP 传递到下一级的驱动程序 将 IRP 传递到下一级驱动程序(又被称作为转发 IRP)是指 IRP 等价于一个子例程调用。当驱 动转发一个 IRP,它(驱动程序)必须向 IRP 参数组增加下一个 I/O 栈位置,告知这一 IRP 栈的指针,然后调用下一驱动的分发例程(dispatch routine)。基本说来,就是驱动向下调用 IRP 栈(calling down the IRP stack)。 传递一个 IRP,驱动通常(典型的)

13、会采取以下几个步骤: 1. 建立下一个 I/O 栈位置的参数。驱动程序可以采取: l 调用 IoGetNextIrpStackLocation 例程来得到一个指针指向下一个 I/O 栈位置, 然后将请求参数组复制到那个得到的位置。 l 调用 IoCopyCurrentIrpStackLocationToNext 例程(如果驱动按第二步设置了 IoCompletion 例程) ,或者 IoSkioCurrentIrpStackLocation 例程(如果没有在第二 步设置 IoCompletion 例程)来传递当前位置所使用的同样的参数组。 注意注意:驱动程序不能够使用 RtlCopyMemor

14、y 例程来复制当前的参数组。这个 例程把指针复制到当前驱动的 IoCompletion 例 程,而且这样会导致 IoCompletion 例程被调用不止一次(重入?) 。 2. 如果需要的话,调用 IoSetCompletionRoutine 例程,为后期处理(post-porcessing)设 置一个 IoCompletion 例程。 如果驱动设置了 IpCompletion 例程, 那么他在上一步 (第 一步)中必须使用 IoCopyCurrentIrpStackLocationToNext。 3. 通过调用 IoCallDriver 例程将请求传递到下一个驱动。这个例程会自动通告 IRP

15、 栈 指针,并且调用下一个驱动的分发例程。 在驱动程序将 IRP 传递个下一个驱动之后,就不再拥有这个 IRP,并且不能试图再去访问这 个它。否则会导致系统崩溃。那个 IRP 会被其它的驱动或者线程释放或完成。如果驱动需 要访问一个已经在栈里传下去的 IRP,这个驱动必须实现(设置)IoCompletion 例程。当 I/O 管理器(I/O Manager)调用 IoCompletion 例程时, 这个驱动就能够在 IoCompletion 例程执行期 间重新获得对这一 IRP 的所有权。如此,IoCompletion 例程就能够访问 IRP 中的域。 若是驱动的分发例程也还须在 IRP 被后

16、面的驱动处理完成之后再处理它, 这个 IoCompletion 例程必须返回 STATUS_MORE_PROCESSING_REQUIRED,以将 IRP 的所有权返回给分发 例程。如此一来,I/O 管理器会停止 IRP 的处理,将最终完成 IRP 的任务留给分发例程。分 发例程能够在之后调用 ICompleteRequest 来完成这个 IRP, 或者还能将这个 IRP 标记为等候 进一步处理。 Generated by Foxit PDF Creator Foxit Software http:/ For evaluation only.完成(齐整)一个完成(齐整)一个IRP 当输入、输出操作(I/O)完成时,完成这个 I/O 操作的驱动会调用 IoCompleteReq

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号