DeviceIoControl解读

DeviceIoControl解读设备驱动程序可以被当作内核模式函数包来看待,I/O控制代码就是用来指定访问其中的哪个函数的。DeviceIoControl函数的dwIoControlCode参数就是这个代码,它指出了我们需要进行的操作,以及如何进行操作。 控制代码是32位数字型常量,可以CTL_CODE宏来定义,它们定义在winioctl.inc和ntddk.inc文件中。 控制代码中各数据位字段的含义如下: ◎

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
设备驱动程序可以被当作内核模式函数包来看待,I/O控制代码就是用来指定访问其中的哪个函数的。DeviceIoControl函数的dwIoControlCode参数就是这个代码,它指出了我们需要进行的操作,以及如何进行操作。 


控制代码是32位数字型常量,可以CTL_CODE宏来定义,它们定义在winioctl.inc和ntddk.inc文件中。 




控制代码中各数据位字段的含义如下: 


◎ DeviceType–设备类型(16bit)指出了设备的类型,微软保留了0-7FFFh的取值,剩下的8000h-0FFFFh供开发商定义新的内 核模式驱动程序。我们可以在\include\w2k\ntddk.inc文件中找到一组FILE_DEVICE_XXX符号常量,这些值都是微软保留的 值,我们可以使用其中的FILE_DEVICE_UNKNOWN。当然你也可以定义另外一个FILE_DEVICE_XXX值 


◎ Access–存取代码(2bit)指明应用程序存取设备的方式,由于这个字段只有2位,所以只有4种可能性: 


· FILE_ANY_ACCESS (0)–最大的存取权限,就是什么操作都可以 


· FILE_READ_ACCESS (1)–读权限,设备将数据传递到指定的缓冲区 


· FILE_WRITE_ACCESS (2)–写权限,可以从内存中向设备传递数据 


· FILE_READ_ACCESS or FILE_WRITE_ACCESS (3)–读写权限,设备和内存缓冲区之间可以互相传递数据 


◎ Function–功能代码(12bit)用来描述要进行的操作,我们可以用800h-0FFFh来定义自己的I/O控制代码,0-7FFh之间的值是被微软保留的,用来定义公用的I/O控制代码 


◎ Method–缓冲模式(2bit)表示I/O管理器如何对输入和输出的数据进行缓冲,这个字段的长度是2位,所以有4种可能性: 


· METHOD_BUFFERED (0)–对I/O进行缓冲 


· METHOD_IN_DIRECT (1)–对输入不进行缓冲 


· METHOD_OUT_DIRECT (2)–对输出不进行缓冲 


· METHOD_NEITHER (3)–都不缓冲 




缓冲模式的管理我们会在后面进行更详细的讨论,当前最重要的是,虽然进行缓冲会带来一些额外的内存开销,但却是最安全的,因为系统已经做好了相关的全部工 作。在传输的数据小于一页(4Kb)的时候,驱动程序通常使用缓冲方式的I/O,因为对大量小块内存进行内存锁定带来的开销也是很大的。在 VirtToPhys驱动程序中,我们使用带缓冲的方式。 


读者可以手工去定义I/O控制代码,但是使用CTL_CODE宏会方便得多,它提供了创建IOCTL值的算法,具体如下: 




CTL_CODE MACRO DeviceType:= <0> , Function:= <0> , Method:= <0> , Access:= <0> 


EXITM %(((DeviceType) SHL 16) OR ((Access) SHL 14) OR ((Function) SHL 2) OR (Method)) 


ENDM 




CTL_CODE宏在winioctl.inc文件和ntddk.inc文件中都有定义。




在应用程序里定义的CTL_CODE和驱动中IRP_MJ_DEVICE_CONTROL的函数里控制码对应即可。在驱动程序里取出码值进行对比操作,如:


   dwIoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;


    switch (dwIoControlCode)


    {



     // 我们约定,缓冲区共两个DWORD,第一个DWORD为端口,第二个DWORD为数据


     // 一般做法是专门定义一个结构,此处简单化处理了


     case IOCTL_MYPORT_READ_BYTE:   // 从端口读字节


      pvIOBuffer[1] = _inp(pvIOBuffer[0]);


      Irp->IoStatus.Information = 8;   // 输出长度为8


      break;


     case IOCTL_MYPORT_WRITE_BYTE:   // 写字节到端口


      _outp(pvIOBuffer[0], pvIOBuffer[1]);


      break;


     default:   // 不支持的IOCTL


      Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;


    }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/196547.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号