文章作者: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. js判断是否为手机访问

    JavaScript判断浏览器类型一般有两种办法,一种是根据各种浏览器独有的属性来分辨,另一种是通过分析浏览器的userAgent属性来判断的.在许多情况下,值判断出浏览器类型之后,还需判断浏览器版本 ...

  2. liunx step by step(3)

    由于我的ubuntu是装载在virtualbox的虚拟机中,怎么实现其中的数据的共享,显得非常的必要:额,具体这么办. 1.安装增强功能.挂载光盘. 打开其相应的终端:fantlam@fantlam- ...

  3. apache 伪静态 .htaccess

    虽然网上有很多教程,但是我在这里进行简单对我用到的总结一下. 加载Rewrite模块: 在conf目录下httpd.conf中找到 LoadModule rewrite_module modules/ ...

  4. 超全Linux备份工具集合,满足你的所有需要!

    经常备份计算机上的数据是个好的做法,它可以手动完成,也可以设置成自动执行.许多备份工具拥有不同的功能特性,让用户可以配置备份类型.备份时间.备份对象.将备份活动记入日志及执行更多操作. 1.Rsync ...

  5. 如何将xml转为python中的字典

    如何将xml转为python中的字典 import cElementTree as ElementTree class XmlListConfig(list): def __init__(self, ...

  6. [Javascript] Wrap an API with a Proxy

    Proxies allow you to use functions that haven't yet been defined on an object. This means that you c ...

  7. [Node.js]26. Level 5 : Route rendering

    Instead of just writing out the quote to the response, instead render the quote.ejs template, passin ...

  8. jacoco统计自动化测试代码覆盖率

    一.下载jacoco, ant工具 jacoco: http://www.eclemma.org/jacoco/: ant: http://ant.apache.org 并添加到环境变量: 二.不停j ...

  9. 在Java程序中做字符串拼接时一定要记得的MessageFormat.format

    Java里从来少不了字符串拼接的活,Java程序员也肯定用到过StringBuffer,StringBuilder,以及被编译器优化掉的+=.但这些都和下文要谈的无关. 比如有这样的字符串: 张三将去 ...

  10. java数组转json

    public String toJsonObject(String[] list) { String json="["; for (int i=0;i<list.length ...