Windows驱动开发WDM (3)- 设备内存读写方式
2012-11-22 14:35
701 查看
驱动所创建的设备一般有3种方式:缓冲区方式,直接方式和其他方式(对应DO_BUFFERED_IO, DO_DIRECT_IO和0)。
比如:
DO_BUFFERED_IO指定当前设备以缓冲区方式工作。
通常用户模式和内核模式交互的时候,用户模式会传一个buffer进来,注意:这个buffer是用户模式的虚拟地址。尽管驱动程序可以访问用户模式的虚拟地址,但是这里有个问题,就是当进程切换的时候,同一个用户模式的虚拟地址对应不同的物理地址,这样当驱动去读取这个地址的时候就会出错,这是灾难性的错误。所以,内核模式的驱动一般都不会直接使用用户模式的虚拟地址(特殊需要也可以使用,但是需要很高的技术要求,而且需要很小心)。
缓冲区方式(DO_BUFFERED_IO)
I/O管理器先创建一个与用户模式数据缓冲区大小相等的系统缓冲区。驱动程序将使用这个系统缓冲区工作。I/O管理器负责在系统缓冲区和用户模式缓冲区之间复制数据。
系统缓冲区的地址用 Irp->AssociatedIrp.SystemBuffer记录,缓冲区的长度记录在IO_STACK_LOCATION里面,比如WriteFile的系统缓冲区的长度记录在IO_STACK_LOCATION的Parameters.Write.Length里面。
以缓冲区方式工作的设备,无论是读还是写,都会发生用户模式地址和内核模式地址的数据复制。这个过程是由操作系统负责,内核模式地址的空间的分配和回收都由操作系统负责,驱动程序无需关心。
缓冲区方式比较简单地解决了用户模式地址传入驱动的问题,同时一个很明显的缺点是:用户模式地址和内核模式地址的数据复制会影响性能。
适用:少量内存操作。
直接方式(DO_DIRECT_IO)
I/O管理器锁定了包含用户模式缓冲区的物理内存页,并创建一个称为MDL(内存描述符表)的辅助数据结构来描述锁定页。驱动程序将使用MDL工作。
Irp->MdlAddress指向MDL。通过DDK的三个宏:MmGetMdlByteCount, MmGetMdlVirtualAddress, MmGetMdlByteOffset可以得到锁定缓冲区长度,锁定缓冲区起始地址(也就是用户模式程序的buffer的起始虚拟地址)和偏移量。
MDL的长度(通过MmGetMdlByteCount得到)应该和IO_STACK_LOCATION里面的Parameters.Read.Length(假设是ReadFile)相等,不然就出错了。
调用MmGetSystemAddressForMdlSafe可以将用户模式虚拟地址映射成内核模式的地址,这样驱动程序就可以使用这个内核模式的虚拟地址了。这也就是说直接方式下用户模式地址和内核模式地址指向同一块物理内存。无论进程怎么切换,内核模式地址都不变,这样就可以找到正确的物理内存。
跟缓冲区方式相比,直接方式操作稍微复杂一些,但是省去了用户模式地址和内核模式地址的数据复制,提高了性能。
其他方式(0)
I/O管理器仅简单地把用户模式的虚拟地址传递给驱动程序。使用用户模式地址的驱动程序应十分小心。
一般很少使用,仅限高手。
总体来讲,优先考虑缓冲区方式,如果内存比较大,考虑直接方式,其他方式在特殊情况下使用(尽量少用,因为比较难控制)。
比如:
fdo->Flags |= DO_BUFFERED_IO
DO_BUFFERED_IO指定当前设备以缓冲区方式工作。
通常用户模式和内核模式交互的时候,用户模式会传一个buffer进来,注意:这个buffer是用户模式的虚拟地址。尽管驱动程序可以访问用户模式的虚拟地址,但是这里有个问题,就是当进程切换的时候,同一个用户模式的虚拟地址对应不同的物理地址,这样当驱动去读取这个地址的时候就会出错,这是灾难性的错误。所以,内核模式的驱动一般都不会直接使用用户模式的虚拟地址(特殊需要也可以使用,但是需要很高的技术要求,而且需要很小心)。
缓冲区方式(DO_BUFFERED_IO)
I/O管理器先创建一个与用户模式数据缓冲区大小相等的系统缓冲区。驱动程序将使用这个系统缓冲区工作。I/O管理器负责在系统缓冲区和用户模式缓冲区之间复制数据。
系统缓冲区的地址用 Irp->AssociatedIrp.SystemBuffer记录,缓冲区的长度记录在IO_STACK_LOCATION里面,比如WriteFile的系统缓冲区的长度记录在IO_STACK_LOCATION的Parameters.Write.Length里面。
以缓冲区方式工作的设备,无论是读还是写,都会发生用户模式地址和内核模式地址的数据复制。这个过程是由操作系统负责,内核模式地址的空间的分配和回收都由操作系统负责,驱动程序无需关心。
缓冲区方式比较简单地解决了用户模式地址传入驱动的问题,同时一个很明显的缺点是:用户模式地址和内核模式地址的数据复制会影响性能。
适用:少量内存操作。
直接方式(DO_DIRECT_IO)
I/O管理器锁定了包含用户模式缓冲区的物理内存页,并创建一个称为MDL(内存描述符表)的辅助数据结构来描述锁定页。驱动程序将使用MDL工作。
Irp->MdlAddress指向MDL。通过DDK的三个宏:MmGetMdlByteCount, MmGetMdlVirtualAddress, MmGetMdlByteOffset可以得到锁定缓冲区长度,锁定缓冲区起始地址(也就是用户模式程序的buffer的起始虚拟地址)和偏移量。
MDL的长度(通过MmGetMdlByteCount得到)应该和IO_STACK_LOCATION里面的Parameters.Read.Length(假设是ReadFile)相等,不然就出错了。
调用MmGetSystemAddressForMdlSafe可以将用户模式虚拟地址映射成内核模式的地址,这样驱动程序就可以使用这个内核模式的虚拟地址了。这也就是说直接方式下用户模式地址和内核模式地址指向同一块物理内存。无论进程怎么切换,内核模式地址都不变,这样就可以找到正确的物理内存。
跟缓冲区方式相比,直接方式操作稍微复杂一些,但是省去了用户模式地址和内核模式地址的数据复制,提高了性能。
其他方式(0)
I/O管理器仅简单地把用户模式的虚拟地址传递给驱动程序。使用用户模式地址的驱动程序应十分小心。
一般很少使用,仅限高手。
总体来讲,优先考虑缓冲区方式,如果内存比较大,考虑直接方式,其他方式在特殊情况下使用(尽量少用,因为比较难控制)。
相关文章推荐
- 24、Windows派遣函数(2)-Windows驱动开发详解笔记,直接读写方式
- Windows驱动开发WDM (4)- 缓冲区方式例子
- 驱动开发之 设备读写方式:直接方式
- Windows 驱动开发基础(七)WDM设备的基本结构
- Windows驱动开发WDM (14)- 分层驱动(设备栈,I/O栈)
- Windows驱动开发WDM (5)- DeviceIoControl(直接方式交互"输出buffer")
- Windows驱动开发WDM (11)- 多个设备对象(同一个驱动)
- 驱动开发之 设备读写方式:缓冲区方式
- Windows驱动开发WDM (5)- DeviceIoControl(直接方式交互"输出buffer")
- 驱动开发之 设备读写方式:缓冲区方式
- 驱动开发之 设备读写方式:Neither方式
- Linux 字符设备驱动开发--内存读写操作
- 《连载 | 物联网框架ServerSuperIO教程》-4.如开发一套设备驱动,同时支持串口和网络通讯。附:将来支持Windows 10 IOT
- Windows驱动开发WDM (8)- 内核同步对象
- Windows 7驱动开发系列(五)--WDM驱动设计原则
- Windows驱动开发WDM (10)- StartIo取消例程
- 【驱动开发】Windows系统下枚举设备的几个函数
- windows 驱动开发 DDK与WDK WDM的区别
- 谈WDM与WDF (windows驱动开发)
- 《物联网框架ServerSuperIO教程》-4.如开发一套设备驱动,同时支持串口和网络通讯。附:将来支持Windows 10 IOT