博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
驱动开发之 设备读写方式:缓冲区方式
阅读量:6720 次
发布时间:2019-06-25

本文共 2288 字,大约阅读时间需要 7 分钟。

1.

设备对象一共同拥有三种读写方式:缓冲区方式读写(Buffered方式);直接方式读写(Direct方式)。Neither方式。这三种方式的Flags分别相应DO_BUFFERED_IO,DO_DIRECT_IO,0

在buffered方式中。I/O管理器先创建一个与用户模式数据缓冲区大小相等的系统缓冲区。而你的驱动程序将使用这个系统缓冲区工作。I/O管理器负责在系统缓冲区和用户模式缓冲区之间复制数据。

 

在direct方式中,I/O管理器锁定了包括用户模式缓冲区的物理内存页。并创建一个称为MDL(内存描写叙述符表)的辅助数据结构来描写叙述锁定页。因此你的驱动程序将使用MDL工作。 
在neither方式中。I/O管理器仅简单地把用户模式的虚拟地址传递给你。

而使用用户模式地址的驱动程序应十分小心。

2.

以下介绍缓冲区方式读写。其长处是比較简单的攻克了将用户地址传入驱动的问题,缺点是须要用户模式和内核模式之间数据复制。可想而知。执行效率会受到影响。

适合少量内存操作时使用的一种方法。

创建好设备IoCreateDevice后。须要设置DO_BUFFERED_IO,  pDevObj->Flags |= DO_BUFFERED_IO.

如今以readfile为例,首先应用程序中须要提供一段缓冲区并把缓冲区大小作为參数传入,比如

UCHAR OutputBuffer[10];

DWORD RetLen = 0;
readfile(hDevice,OutputBuffer,sizeof(OutputBuffer),&RetLen,NULL);

OutputBuffer是提供的输出缓冲区。是用户模式的内存地址,操作系统将此缓冲区的数据拷贝到内核模式下的地址中,sizeof(OutputBuffer)是缓冲区的大小,而RetLen是真正的输出的字节数。

那么内核模式怎么得到此内核模式地址呢?怎么得到writefile或readfile的字节数呢?答案在以下。

此内核模式下的地址能够通过此readfile创建的IRP的AssociatedIrp.SystemBuffer得到。

假如请求的IRP为PIRP pIrp(通常是派遣函数的參数),那么UCHAR* OutputBuffer= (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;

而readfile请求的字节数为IO_STACK_LOCATION中的Parameters.Read.Length,writefilew为IO_STACK_LOCATION中的Parameters.Write.Length

//得到当前堆栈

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
//得到readfile缓冲区大小
ULONG cbread = stack->Parameters..Read.Length;
//得到writefile缓冲区大小
ULONG cbwrite = stack->Parameters.Write.Length;

得到了内核模式下的缓冲区地址了就能够对此缓冲区操作了。比方:

UCHAR* OutputBuffer= (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;

ULONG cbread = stack->Parameters..Read.Length;

memcpy(OutputBuffer,0xBB,cbread);

这样用户模式下的缓冲区内得到的数据是0xBB。

另外还要设置实际操作的字节数,pIrp->IoStatus.Information = cbread;(实际操作的字节数不一定要设置为缓冲区的大小。但也不应该大于缓冲区的大小)

那么用户模式下readfile的RetLen被设置为cbread。

以下是IRP_MJ_READ的派遣函数:

NTSTATUS DispatchRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) {	KdPrint(("Enter DispatchRead\n"));	//对一般IRP的简单操作。后面会介绍对IRP更复杂的操作	NTSTATUS status = STATUS_SUCCESS;	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);	ULONG ulReadLength = stack->Parameters.Read.Length;		// 完毕IRP	//设置IRP完毕状态	pIrp->IoStatus.Status = status;	//设置IRP操作了多少字节	pIrp->IoStatus.Information = ulReadLength;		memset(pIrp->AssociatedIrp.SystemBuffer,0xAA,ulReadLength);	//处理IRP	IoCompleteRequest( pIrp, IO_NO_INCREMENT );	KdPrint(("Leave DispatchRead\n"));	return status;}
设备读写方式:直接读取方式:

Neither方式:

转载于:https://www.cnblogs.com/gavanwanggw/p/6908009.html

你可能感兴趣的文章
三、一个简单的BDB JE例子
查看>>
在Windows Server2008R2安装Oracle Database 11g Release 2
查看>>
借助mysql和DNS view实现智能DNS(centos6.3 x64环境)
查看>>
维纳-辛钦 (Wiener–Khinchin) 定理
查看>>
修改mysql的数据库密码
查看>>
Nginx安装图文
查看>>
解决DataNode启动不起来原因
查看>>
tomcat处理jsp页面的流程
查看>>
fedora的一些使用记录(二)
查看>>
为什么电子人的世界阴盛阳衰?
查看>>
解析InputStream流工具
查看>>
我的友情链接
查看>>
varchar2转clob
查看>>
ansible--循环
查看>>
Jenkins安装部署篇
查看>>
(原创)BFS广度优先算法,看完这篇就够了
查看>>
如何让Ubuntu服务器远离鬼影漏洞(GHOST)影响
查看>>
java反射之动态代理学习笔记
查看>>
ElasticSearch 安装 elasticsearch-analysis-ik分词器
查看>>
清空RMON统计的数据
查看>>