文章作者:grayfox
作者主页:http://nokyo.blogbus.com
原始出处:http://www.blogbus.com/nokyo-logs/34010655.html

这一节会对IRP进行稍微详细的讲解,这是在看了王艳平的《Windows网络与通信程序设计》之后理解的。
      在Windows中几乎所有的I/O都是通过包(packet)驱动的,每个单独的I/O由一个工作命令描述,此命令将会告诉驱动程序需要一些什么操作,并通过I/O子系统跟踪处理过程。这些工作命令就表现为一个个被称为IRP的数据结构。
      IRP是从未分页内存申请的大小可变的结构,它由两部分组成:
      1,包含一般簿记信息的头区域,即IRP头。
      2,若干个成为I/O堆栈位置的内存块,即I/O堆栈。

IRP头部是一个固定长度的结构,它包含了关于整个I/O请求的各种信息。其中的一部分信息可以通过驱动程序访问,另一部分仅供I/O管理器使用,下面列出了允许驱动程序访问的域:

I/O_STATUS_BLOCK    I/OStatus;          // 包含I/O请求的状态
PVOID    AssociatedIrp.SystemBuffer;    // 指向系统缓冲区空间(使用缓冲区I/O)
PMDL    MdlAddress;         // 指向用户缓冲区空间的内核描述表(使用直接I/O)
PVOID    UserBuffer;         // I/O缓冲区的用户空间地址
BOOLEAN    Cancel;          // 指明此IRP已经被取消

I/OStatus的成员包含I/O操作的最终状态,当驱动程序将要完成IRP处理时,它将IRP的Status状态域设置为STATUS_XXX,同时应该将它的InformatI/On域设为0(如果有错误发生)或者一个功能代码指定的值(例如传输的字节数)。

紧跟在IRP头部之后的是I/O堆栈,这是一个I/O_STACK_LOCATI/ON结构的数组,这个数组中元素的个数是根据不同的实际情况而定的。
      I/O堆栈的主要目的是保存功能代码和I/O请求的参数,至于MajorFunctI/On域的作用就不用废话了,Parameters这个联合体需要根据不同情况作出不同的解释,它有Read、Write、DeviceI/OControl三种可能的解释,分别对应三个Win32 API函数,下面列出了I/O堆栈中一些常用的成员域:

UCHAR MajorFunctI/On;               // IRP_MJ_XXX功能代码
struct Read;                               // IRP_MJ_READ的参数
struct Write;                              // IRP_MJ_WRITE的参数
struct DeviceI/OControl;              // IRP_MJ_DEVICE_CONTROL的参数
PDEVICE_OBJECT DeviceObject;   // 该I/O请求的目标设备
PFILE_OBJECT FileObject;            // 该I/O请求的文件对象(如果有的话)

其中FileObject对应着用户模式下CreateFile函数创建的文件对象,FILE_OBJECT结构中的FsContext和FsContext2域是Per-Handle变量,即文件句柄唯一变量,驱动程序可在这里指定要为每个文件对象关联的数据。

Windows操作系统家族支持三种数据传输机制: 
      缓存 I/O(Buffered I/O)在内核模式上操作对用户数据的拷贝 
      直接 I/O(Direct I/O)通过内存描述元列表(MDL, Memory Descriptor List)以及内核模式的指针直接访问用户数据 
      其他方式 I/O(Method neither I/O,既非缓存,也非直接 I/O)通过用户模式的指针访问用户数据

对于标准的 I/O请求,例如IRP_MJ_READ和 IRP_MJ_WRITE,应该在驱动刚刚创建设备后,马上通过修改DeviceObject->Flags域的值来指定支持哪一种传输机制。

缓存 I/O 
 
      为了以缓存 I/O的方式接收读、写的请求,驱动会在初始化时在DeviceObject->Flags域上设置DO_BUFFERED_I/O标志。当驱动收到了一个缓存I/O 的请求,在特定的Irp->AssociatedIrp.SystemBuffer 域中会放有驱动应该操作的内核模式缓冲区的地址。 I/O 管理器,在进行读请求时将数据由内核模式缓冲区拷贝到用户模式缓冲区,或者在进行写请求时从用户模式缓冲区向内核模式缓冲区拷贝数据。 
 
直接 I/O 
 
      为了以直接 I/O的方式接收读、写请求,驱动会在初始化时在DeviceObject->Flags域上设置DO_DIRECT_I/O标志。当驱动接收到一个直接 I/O请求,特定的Irp->MdlAddress域中会放有一个用来描述请求缓冲区的MDL的地址。这个MDL列出了缓冲区的虚拟地址和尺寸,连同相应缓冲区中的物理页表(physical pages)。I/O 管理器会在将请求发送给驱动之前锁定这些物理页,并在(请求)完成的过程中解锁。驱动千万不能使用 MDL中列举的用户模式缓冲区地址,而必须通过调用 MmGetSystemAddressForMdlSafe宏来得到一个内核模式的地址。 
 
其他方式 I/O 
 
      为了接收非缓存非直接 I/O 的方式的请求,驱动初始化时在 DeviceObject->Flags域上既不设置 DO_BUFFERED_I/O 标志,也不设置 DO_DIRECT_I/O 标志。当驱动接收到这样的请求,相应的 Irp->UserBuffer 域会放有附属于这个请求的数据地址。因为这个缓冲区在用户地址空间上,驱动程序必须在用之前使相应的地址合法化。驱动程序在 try/except块里调用ProbeForRead或者 ProbeForWrite函数来合法化特定的指针。驱动还必须完全在 try/except块里处理所有对这一缓冲区的访问。 
另外,驱动还必须在应用(manipulating)数据之前将它拷贝到池(the pool)或堆栈里一个安全的内核模式地址。将数据拷贝到内核模式缓冲区确保了用户模式的调用者不会在驱动已经合法化数据之后再修改它。

【驱动笔记10】再谈IRP的更多相关文章

  1. 【驱动笔记9】初探IRP

    文章作者:grayfox作者主页:http://nokyo.blogbus.com原始出处:http://www.blogbus.com/nokyo-logs/34005738.html 此前我们可能 ...

  2. IBatis.Net学习笔记六--再谈查询

    在IBatis.Net学习笔记五--常用的查询方式 中我提到了一些IBatis.Net中的查询,特别是配置文件的写法. 后来通过大家的讨论,特别是Anders Cui 的提醒,又发现了其他的多表查询的 ...

  3. Samsung_tiny4412(驱动笔记10)----mdev,bus,device,driver,platform

    /*********************************************************************************** * * mdev,bus,de ...

  4. C++ Primer 学习笔记_32_STL实践与分析(6) --再谈string类型(下)

    STL实践与分析 --再谈string类型(下) 四.string类型的查找操作 string类型提供了6种查找函数,每种函数以不同形式的find命名.这些操作所有返回string::size_typ ...

  5. C++ Primer 学习笔记_44_STL实践与分析(18)--再谈迭代器【下】

    STL实践与分析 --再谈迭代器[下] 三.反向迭代器[续:习题] //P355 习题11.19 int main() { vector<int> iVec; for (vector< ...

  6. C++ Primer 学习笔记_43_STL实践与分析(17)--再谈迭代器【中】

    STL实践与分析 --再谈迭代器[中] 二.iostream迭代[续] 3.ostream_iterator对象和ostream_iterator对象的使用 能够使用ostream_iterator对 ...

  7. 【转】 Pro Android学习笔记(四三):Fragment(8):再谈Transaction和管理器

    目录(?)[-] Transaction的一些操作 再谈FragmentManager 调用其他fragment的方法 唤起activity 唤起fragment和相互通信 一些其它 Transact ...

  8. [转载]再谈百度:KPI、无人机,以及一个必须给父母看的案例

    [转载]再谈百度:KPI.无人机,以及一个必须给父母看的案例 发表于 2016-03-15   |   0 Comments   |   阅读次数 33 原文: 再谈百度:KPI.无人机,以及一个必须 ...

  9. 再谈angularJS数据绑定机制及背后原理—angularJS常见问题总结

    这篇是对angularJS的一些疑点回顾,是对目前angularJS开发的各种常见问题的整理汇总.如果对文中的题目全部了然于胸,觉得对整个angular框架应该掌握的七七八八了.希望志同道合的通知补充 ...

随机推荐

  1. iframe跨域与session失效问题

    何为跨域跨域session/cookie? 也就是第三方session/cookie.第一方session/cookie指的是访客当前访问的网站给访客的浏览器设置的seesion /cookie, 会 ...

  2. UML解惑:图说UML中的六大关系

    UML定义的关系主要有六种:依赖.类属.关联.实现.聚合和组合.这些类间关系的理解和使用是掌握和应用UML的关键,而也就是这几种关系,往往会让初学者迷惑.这里给出这六种主要UML关系的说明和类图描述, ...

  3. Linux c 屏蔽信号、切换信号

    信号导致的问题 不是任何信号我们都需要的,如果遇到我们不想处理的信号,我们怎么避免这个信号? 1.      信号屏蔽 intsigprocmask(int how,//操作方式 SIG_BLOCK屏 ...

  4. 项目加入 TFS报错

      新建一个项目,然后在解决方案上右击,选择Add solution to source control的时候,总是失败,output窗口中出现的错误信息如下: An error was raised ...

  5. [Node.js] Level 3 new. Steam

    File Read Stream Lets use the fs module to read a file and log its contents to the console. Use the  ...

  6. 从servlet中获取spring的WebApplicationContext

    需要做一个参数初始化类,当web应用被加载时从数据库里取出相关的参数设置 ,并把这些参数放置到application里,jsp页面可以从中取出. 1.在web.xml中配置: <servlet& ...

  7. 【OpenCV新手教程之十七】OpenCV重映射 &amp; SURF特征点检測合辑

    本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/30974513 作者:毛星云(浅墨)  ...

  8. Jquery 应用积累

    1.控制div显隐 $("#id").show()表示display:block, $("#id").hide()表示display:none; $(" ...

  9. JBOSS启动报错解决方案

    同一个jboss下不可以放不同的项目包,否则报错: 注意:如果后期使用,注意删除上图的本地文件,重新加载即可.

  10. LESS详解之变量(@)

    变量基本上是每个语言脚本上都会涉及的一个小小知识点,是学好语言脚本的必经之路.LESS中也可以设置变量,然后通过变量可以改变整个网站的设计风格.良好的掌握LESS中变量的用法,是LESS的基础. 变量 ...