典型IO处理
=========
多数的IO操作并不涉及到IO系统的所有组件. 一个典型的IO请求起始于一个应用程序执行一个IO相关的函数(比如说, 从一个设备中读取数据), 这个函数由IO管理器, 加上一个或多个设备驱动程序, 还有HAL来处理.
正如刚才所说, 在Windows中, 线程在虚拟文件上执行IO操作. 操作系统将所有的IO请求抽象为在一个虚拟文件上的操作, 隐藏了IO操作可能不是针对一个文件结构的设备的事实. 这些抽象合成了一个应用程序对设备的接口. 一个虚拟文件会与任何的IO源设备或IO目的设备向关联, 这些设备被当做文件一样的对待(比如文件, 目录, 管道, 和邮件槽) 所有读取的字节或者写入的字节都被简单的认为是指向这些虚拟文件的字节流. 用户态应用程序(不关事Windows 或者POSIX)调用API来完成对操作系统内部的IO系统函数的调用, 完成从文件读取, 写入文件和其他的操作. IO管理器动态的将这些请求引导至合适的设备驱动程序. 下图说明了一个典型IO请求的过程.
设备驱动
为了与IO管理器和其他的IO系统组件整合, 设备驱动程序必须让自身的管理设备的角色与它针对某种设备管理的实现相一致.
设备驱动的类型
========
Windows支持一系列的驱动程序类型和编程环境. 甚至在一个设备驱动类型中, 编程环境都可能不一样, 这取决于驱动程序想要操纵的设备的类型. 范围最大的驱动类型分类就是看它是一个用户态的驱动程序呢, 还是一个内核态的驱动程序. Windows支持的用户态的驱动程序有:
- Virtual Device Drivers(VDDs) 虚拟设备驱动是用来仿真16的MS-DOS应用程序的. 虚拟设备驱动欺骗MS-DOS应用程序, 让他们认为他们正在使用IO端口, 然后将这些假的使用转换为Windows的原生态的功能, 有原生态的功能将请求发送给实实在在的设备驱动. 因为Windows是一种处于完全保护模式下的操作系统, 用户态的MS-DOS应用程序不能直接的访问硬件, 要访问硬件就必须通过内核态的驱动程序.
- Windows子系统打印驱动- 转换设备无关的图形请求为针对打印相关的命令. 一般, 这些命令被发送到内核态的端口驱动, 比如说并口驱动(Parport.sys) 或者是串行总线打印端口驱动(universal serial bus)(Usbprint.sys)
这里, 我们的精力会集中在内核态的设备驱动上. 内核态的驱动程序有很多种, 大致可以分成以下几类:
- 文件系统驱动(File system drivers) - 接受对文件的请求, 通过完成自己内部的显示的对海量存储器的访问或者网络驱动程序的访问, 来满足它接受的请求.
- 即插即用驱动(Plug and Play) - 与硬件协同工作并与Windows电源管理器和PnP管理器集成. 他们包括为海量存储设备的驱动, 视频适配器, 输入设备和网络适配器.
- 非即插即用驱动程序(non-plug and play drivers) - 也叫做内核扩展, 通过为用户态提供访问内核态的驱动和服务延伸了系统的功能. 他们不与Pnp管理器以及电源管理器集成. 举个他们的例子吧, 比如说网络API和协议驱动. Regmon的驱动也是一个例子.
WDM驱动
=========
WDM驱动是附着在Windows Driver Model(WDM)上的设备驱动. WDM包括对Windows的电源管理的支持, 对即插即用的支持, 对WMI的支持, 还支持大多数的附着在WDM上的驱动程序. WDM在Windows, Windows98还有Windows Me上实现的, 所以WDM驱动程序与这些版本的操作系统在原始程序上是兼容的, 并且在某些情况下, 在二进制上也是兼容的. 有以下三种类型的WDM驱动:
- 总线驱动- 管理一个逻辑上或者物理上的总线. 举例几个总线吧, PCMCIA, PCI, USB, IEEE1394, 和ISA. 一个总线驱动检测和通知PnP管理器, 告诉它有设备附着在它控制的总线上了, 同时还管理总线的电源设置.
- 功能驱动- 管理某一种特殊类型的设备. 总线驱动通过PnP管理器对功能驱动展现设备. 功能驱动是对操作系统输出设备可操作的接口的一种驱动. 总的来说, 它是对设备操作知道的最多的驱动程序.
- 过滤驱动- 它是在底层的功能驱动之上或之下的逻辑层次, 扩大或者修改一个设备或者另一个驱动的行为. 举例说明, 一个键盘捕捉功能可以通过在键盘功能驱动之上的键盘过滤驱动来实现.
在WDM中, 没有一个驱动程序负责控制一个特定设备的方方面面. 总线驱动负责检测总线成员关系的变化(设备添加, 设备移除), 帮助PnP管理器来遍历所有的总线上的设备, 访问总线相关的注册表配置, 在某些情况下, 还控制总线供给设备的电环. 功能驱动基本上是唯一访问设备硬件的驱动程序.
注意: 在Windows2000, XP, 2003中, HAL拥有与在Windows NT中不同的角色. 在Windows2000之前, 希望添加本来不支持的硬件总线支持的第三方的硬件厂商不得不实现自己的HAL. Windows2k, windowsxp和Windows 2003允许第三方来实现总线驱动来为不支持的硬件总线提供支持.
分层的驱动
========
对一个个体硬件的支持可以通常拆分为几个驱动, 每个驱动提供让设备正常工作的功能支持的一部分. 出了WDM总线驱动, 功能驱动和过滤驱动, 赢家支持可以在以下的几个组件中拆分开来.
- 类驱动(class drivers)- 实现了某一类设备的IO处理, 诸如磁盘, 磁带, 或者CD-ROM. 这些硬件接口都已经被标准化了, 所以一个驱动可以为一大批不同种类的生产商提供支持.
- 端口驱动(port drivers)- 实现了针对来自某一类IO端口的IO请求的处理, 比方说SCSI, 并且被以内核态函数库的形式实现, 而不是实际的设备驱动.
- 小型端口驱动程序(miniport drivers)- 映射普通IO请求为一种针对一类IO端口的适配器的请求, 比如说SCSI 适配器. 小型端口驱动程序是导入有端口驱动提供的功能的实际的设备驱动程序.
一个例子会帮助演示一下设备驱动如何工作的. 一个文件系统驱动程序接受了一个要向在某个文件中的某个特定地点写入数据的请求. 它将这个请求转化为一个向硬盘中某个特定的"逻辑上"的文件写入一组字节的请求. 然后, 它就传递(通过IO管理器)这个请求到一个简单的磁盘驱动程序. 这个磁盘驱动程序, 依次地, 将请求转换到一个磁盘的物理位置(cylinder/track/sector )(磁柱/磁道/扇区), 然后操控磁头来写入数据. 这个分层的过程见下图:
上图说明了在两层驱动程序之间的劳务分配. IO管理器收到了一个从某个文件的某个位置开始写入数据的请求. IO管理器传递请求给文件系统驱动程序, 文件系统驱动程序将从与文件相关的操作转换成为在磁盘的某个起始位置开始的写入, 还有送过来的一些字节. 文件系统调用IO管理器来传递这个请求给磁盘驱动程序, 磁盘驱动程序在讲请求转化为磁盘物理位置的写入操作, 将那些字节写入磁盘中.
因为所有的驱动程序, 文件系统驱动和设备驱动都一样, 都存在于相同的操作系统架构之中, 另一个驱动可以被很容易的插入到架构层次中来, 而不需要修改现有的IO系统的驱动. 比如说, 好几个磁盘可以被看作是一个很大的单个磁盘, 所需要做的就是添加一个新驱动而已. 这样的在windows中存在的驱动提供磁盘容错支持. (然而在所有版本的windows中, 是由服务器版本的包括fault-tlerant disk support). 这种逻辑上的, 体积管理器驱动存在于文件系统驱动和磁盘驱动之间, 下图可以详细说明.