zoukankan      html  css  js  c++  java
  • 23、Windows派遣函数(1)Windows驱动开发详解笔记,IRP

    驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的。用户模式下所有对驱动程序的I/O请求,全部由操作系统转化为一个叫做IRP的数据结构,不同的IRP数据会被“派遣”到不同的派遣函数(Dispatch Function)中。

    1IRP

    IRPI/O request packet)有两个属性,一个是MajorFunction,另外一个是MinorFunction。操作系统根据MajorFunctionIRP 派遣到不同的派遣函数中;在派遣函数中还可以继续判断IRP属于那种MinorFunction

    示例代码 P187

     

    代码
    1 #pragma INITCODE
    2  extern "C" NTSTATUS DriverEntry (
    3 IN PDRIVER_OBJECT pDriverObject,
    4 IN PUNICODE_STRING pRegistryPath )
    5 {
    6 NTSTATUS status;
    7 KdPrint(("Enter DriverEntry\n"));
    8
    9 //设置卸载函数
    10   pDriverObject->DriverUnload = HelloDDKUnload;
    11
    12 //设置派遣函数
    13   pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
    14 pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
    15 pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
    16 pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutin;
    17 pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
    18 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
    19 pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
    20 pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
    21 pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;
    22
    23 //创建驱动设备对象
    24 status = CreateDevice(pDriverObject);
    25
    26 KdPrint(("Leave DriverEntry\n"));
    27 return status;
    28 }
    29 /************************************************************************
    30 * 函数名称:HelloDDKDispatchRoutin
    31 * 功能描述:对读IRP进行处理
    32 * 参数列表:
    33 pDevObj:功能设备对象
    34 pIrp:从IO请求包
    35 * 返回 值:返回状态
    36 *************************************************************************/
    37 #pragma PAGEDCODE
    38 NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
    39 IN PIRP pIrp)
    40 {
    41 KdPrint(("Enter HelloDDKDispatchRoutin\n"));
    42
    43 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    44 //建立一个字符串数组与IRP类型对应起来
    45 static char* irpname[] =
    46 {
    47 "IRP_MJ_CREATE",
    48 "IRP_MJ_CREATE_NAMED_PIPE",
    49 "IRP_MJ_CLOSE",
    50 "IRP_MJ_READ",
    51 "IRP_MJ_WRITE",
    52 "IRP_MJ_QUERY_INFORMATION",
    53 "IRP_MJ_SET_INFORMATION",
    54 "IRP_MJ_QUERY_EA",
    55 "IRP_MJ_SET_EA",
    56 "IRP_MJ_FLUSH_BUFFERS",
    57 "IRP_MJ_QUERY_VOLUME_INFORMATION",
    58 "IRP_MJ_SET_VOLUME_INFORMATION",
    59 "IRP_MJ_DIRECTORY_CONTROL",
    60 "IRP_MJ_FILE_SYSTEM_CONTROL",
    61 "IRP_MJ_DEVICE_CONTROL",
    62 "IRP_MJ_INTERNAL_DEVICE_CONTROL",
    63 "IRP_MJ_SHUTDOWN",
    64 "IRP_MJ_LOCK_CONTROL",
    65 "IRP_MJ_CLEANUP",
    66 "IRP_MJ_CREATE_MAILSLOT",
    67 "IRP_MJ_QUERY_SECURITY",
    68 "IRP_MJ_SET_SECURITY",
    69 "IRP_MJ_POWER",
    70 "IRP_MJ_SYSTEM_CONTROL",
    71 "IRP_MJ_DEVICE_CHANGE",
    72 "IRP_MJ_QUERY_QUOTA",
    73 "IRP_MJ_SET_QUOTA",
    74 "IRP_MJ_PNP",
    75 };
    76
    77 UCHAR type = stack->MajorFunction;
    78 if (type >= arraysize(irpname))
    79 KdPrint((" - Unknown IRP, major type %X\n", type));
    80 else
    81 KdPrint(("\t%s\n", irpname[type]));
    82
    83
    84 //对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
    85 NTSTATUS status = STATUS_SUCCESS;
    86 // 完成IRP
    87 pIrp->IoStatus.Status = status;
    88 pIrp->IoStatus.Information = 0; // bytes xfered
    89 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    90
    91 KdPrint(("Leave HelloDDKDispatchRoutin\n"));
    92
    93 return status;
    94 }

      在DriverEntry的驱动对象pDriverObject中,有个函数指针数组MajorFunction,系统默认这些IRP类型与IoInvalidateDeviceRequest函数关联。

    IRP类型

    http://www.cnblogs.com/mydomain/archive/2010/10/19/1855980.html

    1)简单处理

    IRP状态设置成功,结束IRP请求,让派遣函数返回。

    如上示例

    #if (DRV_BOARD_TYPE == DRV_SCU)

    if (strTrunk.tm[i] >= GESW_LOCAL_NET_MODID) /* 端口在奇槽位板 */

    {

    ucPortIdx += GESW_LOCAL_NET_PORT;

    ucPort |= GESW_BOARD_IDX;

    }

    #endif

    设备名只能被内核模式下看到,用户模式下用符号链接,IoCreateSymbolicLink来创建。

    示例代码 P191

     

    代码
    1 #include <windows.h>
    2 #include <stdio.h>
    3
    4 int main()
    5 {
    6 HANDLE hDevice =
    7 CreateFile("\\\\.\\HelloDDK",
    8 GENERIC_READ | GENERIC_WRITE,
    9 0, // share mode none
    10 NULL, // no security
    11 OPEN_EXISTING,
    12 FILE_ATTRIBUTE_NORMAL,
    13 NULL ); // no template
    14
    15 if (hDevice == INVALID_HANDLE_VALUE)
    16 {
    17 printf("Failed to obtain file handle to device: "
    18 "%s with Win32 error code: %d\n",
    19 "MyWDMDevice", GetLastError() );
    20 return 1;
    21 }
    22
    23 CloseHandle(hDevice);
    24 return 0;
    25 }

      驱动对象会创建一个个的设备对象,并将这些设备对象“叠”成一个垂直结构,类似栈,称为“设备栈”。

    IRP 会被操作系统发送到设备栈的顶层,如果顶层没有处理,则OSIRP转发到设备栈的下一层设备处理,以此类推。为了记录IRP在每层所做的操作,IRP会有一个I/O Stack Locations数组,每个I/O Stack Locations元素记录着对应设备所做的操作;可以通过IoGetCurrentIrpStackLocation 来获得本层设备对应的I/O Stack Locations

    I/O Stack Locations可以参见MSDN中图示。IRPTrace来跟踪IRP的调用情况。

    2、缓冲区方式读写操作

    驱动程序所创建的设备的一般有三种读写方式:缓冲区方式,直接方式,其他方式;对应DO_BUFFERED_IODO_DIRECT_IOand 0

    DO_BUFFERED_IO的意思是OS将应用程序提供缓冲区的数据复制到内核模式下的地址中来避免由于内核模式下进程切合切换而引起的读写错误问题。一般通过ReadFile,WriteFile来读写。优点是简单的解决了将用户地址地址传入驱动的问题,缺点是需要数据在两个模式下复制,影响效率。

    在派遣函数中,通过IO_STACK_LOCATION中的ULONG ulReadLength = stack->Parameters.Read.Length;来知道ReadFile请求多少字节。再设置 pIrp->IoStatus.Information = ulReadLength;来记录设备实际操作了多少字节。

    示例代码 P198

    代码
    1 /************************************************************************
    2 * 函数名称:DriverEntry
    3 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
    4 * 参数列表:
    5 pDriverObject:从I/O管理器中传进来的驱动对象
    6 pRegistryPath:驱动程序在注册表的中的路径
    7 * 返回 值:返回初始化驱动状态
    8 *************************************************************************/
    9 #pragma INITCODE
    10 extern "C" NTSTATUS DriverEntry (
    11 IN PDRIVER_OBJECT pDriverObject,
    12 IN PUNICODE_STRING pRegistryPath )
    13 {
    14 NTSTATUS status;
    15 KdPrint(("Enter DriverEntry\n"));
    16
    17 //设置卸载函数
    18 pDriverObject->DriverUnload = HelloDDKUnload;
    19
    20 //设置派遣函数
    21 pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
    22 pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
    23 pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
    24 pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKRead;
    25 pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
    26 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
    27 pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
    28 pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
    29 pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;
    30
    31 //创建驱动设备对象
    32 status = CreateDevice(pDriverObject);
    33
    34 KdPrint(("Leave DriverEntry\n"));
    35 return status;
    36 }
    37
    38 /************************************************************************
    39 * 函数名称:CreateDevice
    40 * 功能描述:初始化设备对象
    41 * 参数列表:
    42 pDriverObject:从I/O管理器中传进来的驱动对象
    43 * 返回 值:返回初始化状态
    44 *************************************************************************/
    45 #pragma INITCODE
    46 NTSTATUS CreateDevice (
    47 IN PDRIVER_OBJECT pDriverObject)
    48 {
    49 NTSTATUS status;
    50 PDEVICE_OBJECT pDevObj;
    51 PDEVICE_EXTENSION pDevExt;
    52
    53 //创建设备名称
    54 UNICODE_STRING devName;
    55 RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
    56
    57 //创建设备
    58 status = IoCreateDevice( pDriverObject,
    59 sizeof(DEVICE_EXTENSION),
    60 &(UNICODE_STRING)devName,
    61 FILE_DEVICE_UNKNOWN,
    62 0, TRUE,
    63 &pDevObj );
    64 if (!NT_SUCCESS(status))
    65 return status;
    66
    67 pDevObj->Flags |= DO_BUFFERED_IO;
    68 pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
    69 pDevExt->pDevice = pDevObj;
    70 pDevExt->ustrDeviceName = devName;
    71 //创建符号链接
    72 UNICODE_STRING symLinkName;
    73 RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
    74 pDevExt->ustrSymLinkName = symLinkName;
    75 status = IoCreateSymbolicLink( &symLinkName,&devName );
    76 if (!NT_SUCCESS(status))
    77 {
    78 IoDeleteDevice( pDevObj );
    79 return status;
    80 }
    81 return STATUS_SUCCESS;
    82 }
    83 /************************************************************************
    84 * 函数名称:HelloDDKUnload
    85 * 功能描述:负责驱动程序的卸载操作
    86 * 参数列表:
    87 pDriverObject:驱动对象
    88 * 返回 值:返回状态
    89 *************************************************************************/
    90 #pragma PAGEDCODE
    91 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
    92 {
    93 PDEVICE_OBJECT pNextObj;
    94 KdPrint(("Enter DriverUnload\n"));
    95 pNextObj = pDriverObject->DeviceObject;
    96 while (pNextObj != NULL)
    97 {
    98 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
    99 pNextObj->DeviceExtension;
    100
    101 //删除符号链接
    102 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
    103 IoDeleteSymbolicLink(&pLinkName);
    104 pNextObj = pNextObj->NextDevice;
    105 IoDeleteDevice( pDevExt->pDevice );
    106 }
    107 }
    108 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
    109 IN PIRP pIrp)
    110 {
    111 KdPrint(("Enter HelloDDKRead\n"));
    112
    113 //对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
    114 NTSTATUS status = STATUS_SUCCESS;
    115
    116 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    117 ULONG ulReadLength = stack->Parameters.Read.Length;
    118
    119 // 完成IRP
    120 //设置IRP完成状态
    121 pIrp->IoStatus.Status = status;
    122
    123 //设置IRP操作了多少字节
    124 pIrp->IoStatus.Information = ulReadLength; // bytes xfered
    125
    126 memset(pIrp->AssociatedIrp.SystemBuffer,0xAA,ulReadLength);
    127
    128 //处理IRP
    129 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    130
    131 KdPrint(("Leave HelloDDKRead\n"));
    132
    133 return status;
    134 }
    参考

    1Windows 驱动开发技术详解

    2http://msdn.microsoft.com/en-us/library/ff565757%28VS.85%29.aspx

    3Windows驱动学习笔记,灰狐

  • 相关阅读:
    搭建自己的 github.io 博客
    转:华为副总裁一封信:透露年薪千万的工作感悟,太震撼了!
    SNF开发平台WinForm之五-高级查询使用说明-SNF快速开发平台3.3-Spring.Net.Framework
    SNF开发平台WinForm之四-开发-主细表管理页面-SNF快速开发平台3.3-Spring.Net.Framework
    SNF开发平台WinForm之三-开发-单表选择控件创建-SNF快速开发平台3.3-Spring.Net.Framework
    SNF开发平台WinForm之二-开发-单表表单管理页面-SNF快速开发平台3.3-Spring.Net.Framework
    SNF开发平台WinForm之一-开发-单表表格编辑管理页面-SNF快速开发平台3.3-Spring.Net.Framework
    C#基础总结之八面向对象知识点总结-继承与多态-接口
    C#基础总结之七面向对象知识点总结1
    C#基础总结之六 DataTable (临时表/数据源) 和Datatable 名片练习
  • 原文地址:https://www.cnblogs.com/mydomain/p/1864845.html
Copyright © 2011-2022 走看看