Windows驱动的IOCTL

虽然目前,没有具体的项目,但是Direct3D学习还是会继续。其实很多东西,虽然看起来现在没多大用处,说不定将来有很大的用处。这个无法衡量,多学点,总是有好处的。后面,断断续续,会把另外的几个方向,WDDM 驱动,数据结构算法,也开始捡起来继续。现在需要的是,将知识变成体系。所以,需要大量的总结。

我们今天看一下Windows驱动中的IOCTL,IOCTL顾名思义,就是IO控制码。也就是输入输出控制码。Window驱动中大量充斥着这样的控制码。前面的文章,我们知道,所有在驱动中的流都是以IRP的形式进行的。而用来标识IRP的就是这些IOCTL码。回忆一下MSDN中的IRP的结构。

typedef struct _IRP {
    .
    .
    PMDL  MdlAddress;
    ULONG  Flags;
    union {
      struct _IRP  *MasterIrp;
       .
       .
       PVOID  SystemBuffer;
     } AssociatedIrp;
     .
     .
     IO_STATUS_BLOCK  IoStatus;
     KPROCESSOR_MODE  RequestorMode;
     BOOLEAN PendingReturned;
     .
     .
     BOOLEAN  Cancel;
     KIRQL  CancelIrql;
     .
     .
     PDRIVER_CANCEL  CancelRoutine;
     PVOID UserBuffer;
     union {
        struct {
         .
         .
         union {
            KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
            struct {
              PVOID  DriverContext[4];
             };
          };
         .
         .
         PETHREAD  Thread;
         .
         .
         LIST_ENTRY  ListEntry;
         .
         .
         } Overlay;
      .
      .
      } Tail;
  } IRP, *PIRP;

我们知道IRP的一些信息都是存储在IO的堆栈中的:

typedef struct _IO_STACK_LOCATION {
       UCHAR  MajorFunction;
       UCHAR  MinorFunction;
       UCHAR  Flags;
       UCHAR  Control;
        union {
              //
              // Parameters for IRP_MJ_CREATE 
              //
              struct {
                   PIO_SECURITY_CONTEXT SecurityContext;
                   ULONG Options;
                   USHORT POINTER_ALIGNMENT FileAttributes;
                   USHORT ShareAccess;
                   ULONG POINTER_ALIGNMENT EaLength;
               } Create;
              //
              // Parameters for IRP_MJ_READ 
              //
              struct {
                   ULONG Length;
                   ULONG POINTER_ALIGNMENT Key;
                   LARGE_INTEGER ByteOffset;
               } Read;
              //
              // Parameters for IRP_MJ_WRITE 
              //
              struct {
                   ULONG Length;
                   ULONG POINTER_ALIGNMENT Key;
                   LARGE_INTEGER ByteOffset;
               } Write;
              //
              // Parameters for IRP_MJ_QUERY_INFORMATION 
              //
              struct {
                   ULONG Length;
                   FILE_INFORMATION_CLASS POINTER_ALIGNMENT   
      FileInformationClass;
               } QueryFile;
              //
              // Parameters for IRP_MJ_SET_INFORMATION 
              //
              struct {
                   ULONG Length;
                   FILE_INFORMATION_CLASS POINTER_ALIGNMENT   
      FileInformationClass;
                   PFILE_OBJECT FileObject;
                   union {
                        struct {
                            BOOLEAN ReplaceIfExists;
                            BOOLEAN AdvanceOnly;
                        };
                        ULONG ClusterCount;
                        HANDLE DeleteHandle;
                         };
               } SetFile;
              //
              // Parameters for IRP_MJ_QUERY_VOLUME_INFORMATION 
              //
              struct {
                   ULONG Length;
                   FS_INFORMATION_CLASS POINTER_ALIGNMENT    
     FsInformationClass;
               } QueryVolume;
              //
              // Parameters for IRP_MJ_DEVICE_CONTROL and    
     IRP_MJ_INTERNAL_DEVICE_CONTROL 
              //
              struct {
                   ULONG OutputBufferLength;
                   ULONG POINTER_ALIGNMENT InputBufferLength;
                   ULONG POINTER_ALIGNMENT IoControlCode;
                   PVOID Type3InputBuffer;
               } DeviceIoControl;
              //
              // Nonsystem service parameters.
              //
              // Parameters for IRP_MN_MOUNT_VOLUME 
              //
              struct {
                   PVOID DoNotUse1;
                   PDEVICE_OBJECT DeviceObject;
               } MountVolume;
              //
              // Parameters for IRP_MN_VERIFY_VOLUME 
              //
              struct {
                   PVOID DoNotUse1;
                   PDEVICE_OBJECT DeviceObject;
               } VerifyVolume;
              //
              // Parameters for Scsi using IRP_MJ_INTERNAL_DEVICE_CONTROL 
              //
              struct {
                   struct _SCSI_REQUEST_BLOCK *Srb;
               } Scsi;
              //
              // Parameters for IRP_MN_QUERY_DEVICE_RELATIONS 
              //
              struct {
                   DEVICE_RELATION_TYPE Type;
               } QueryDeviceRelations;
              //
              // Parameters for IRP_MN_QUERY_INTERFACE 
              //
              struct {
                   CONST GUID *InterfaceType;
                  USHORT Size;
                   USHORT Version;
                   PINTERFACE Interface;
                   PVOID InterfaceSpecificData;
               } QueryInterface;
              //
              // Parameters for IRP_MN_QUERY_CAPABILITIES 
              //
              struct {
                   PDEVICE_CAPABILITIES Capabilities;
               } DeviceCapabilities;
              //
              // Parameters for IRP_MN_FILTER_RESOURCE_REQUIREMENTS 
              //
              struct {
                   PIO_RESOURCE_REQUIREMENTS_LIST     
    IoResourceRequirementList;
               } FilterResourceRequirements;
              //
              // Parameters for IRP_MN_READ_CONFIG and IRP_MN_WRITE_CONFIG 
              //
              struct {
                   ULONG WhichSpace;
                   PVOID Buffer;
                   ULONG Offset;
                   ULONG POINTER_ALIGNMENT Length;
               } ReadWriteConfig;
              //
              // Parameters for IRP_MN_SET_LOCK 
              //
              struct {
                   BOOLEAN Lock;
               } SetLock;
              //
              // Parameters for IRP_MN_QUERY_ID 
              //
              struct {
                   BUS_QUERY_ID_TYPE IdType;
               } QueryId;
              //
              // Parameters for IRP_MN_QUERY_DEVICE_TEXT 
              //
              struct {
                   DEVICE_TEXT_TYPE DeviceTextType;
                   LCID POINTER_ALIGNMENT LocaleId;
                } QueryDeviceText;
              //
              // Parameters for IRP_MN_DEVICE_USAGE_NOTIFICATION 
              //
              struct {
                   BOOLEAN InPath;
                    BOOLEAN Reserved[3];
                    DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT  
         Type;
               } UsageNotification;
              //
              // Parameters for IRP_MN_WAIT_WAKE 
              //
              struct {
                   SYSTEM_POWER_STATE PowerState;
              } WaitWake;
              //
              // Parameter for IRP_MN_POWER_SEQUENCE 
              //
              struct {
                   PPOWER_SEQUENCE PowerSequence;
               } PowerSequence;
              //
              // Parameters for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER 
              //
              struct {
                   ULONG SystemContext;
                   POWER_STATE_TYPE POINTER_ALIGNMENT Type;
                   POWER_STATE POINTER_ALIGNMENT State;
                   POWER_ACTION POINTER_ALIGNMENT ShutdownType;
               } Power;
              //
              // Parameters for IRP_MN_START_DEVICE 
              //
              struct {
                   PCM_RESOURCE_LIST AllocatedResources;
                   PCM_RESOURCE_LIST AllocatedResourcesTranslated;
                } StartDevice;
              //
              // Parameters for WMI Minor IRPs 
              //
              struct {
                   ULONG_PTR ProviderId;
                   PVOID DataPath;
                   ULONG BufferSize;
                   PVOID Buffer;
              } WMI;
              //
              // Others - driver-specific
              //
              struct {
                   PVOID Argument1;
                   PVOID Argument2;
                   PVOID Argument3;
                   PVOID Argument4;
               } Others;
         } Parameters;
     PDEVICE_OBJECT  DeviceObject;
     PFILE_OBJECT  FileObject;
     .
     .
  } IO_STACK_LOCATION, *PIO_STACK_LOCATION;

在IO堆栈中,我们看到了大量的IOCTL。这个是在WDM中的,在WDF对其进行了封装。我们在WDF中,一般使用如下的3个函数向其他模块发送这些IRP.我认为REQUEST是WDM中的IRP和IO_STATION_LOCATION的封装。

看一下异步函数:

WdfIoTargetFormatRequestForInternalIoctl,WdfIoTargetFormatRequestForInternalIoctlOthers,WdfIoTargetFormatRequestForIoctl,WdfIoTargetFormatRequestForRead,WdfIoTargetFormatRequestForWrite,这是是异步的,后面需要设置完成例程,和真正发送请求。

再看一下同步的:
WdfIoTargetSendInternalIoctlOthersSynchronouslyWdfIoTargetSendInternalIoctlSynchronouslyWdfIoTargetSendIoctlSynchronouslyWdfIoTargetSendReadSynchronouslyWdfIoTargetSendWriteSynchronously,同步需要等待,所以可以直接发。

先看一下异步的例子:

NTSTATUS
NICSendOidRequestToTargetAsync(
    IN WDFIOTARGET  IoTarget,
    IN WDFREQUEST  Request,
    IN PFILE_OBJECT  FileObject,
    IN ULONG  IoctlControlCode,
    IN OUT PVOID  InputBuffer,
    IN ULONG  InputBufferLength,
    IN OUT PVOID  OutputBuffer,
    IN ULONG  OutputBufferLength,
    OUT PULONG  BytesReadOrWritten
    )
{
    NTSTATUS  status;
    PREQUEST_CONTEXT  reqContext;
    WDF_REQUEST_REUSE_PARAMS  params;
    WDFMEMORY  inputMem, outputMem;
    
    WDF_REQUEST_REUSE_PARAMS_INIT(
                                  &params, 
                                  WDF_REQUEST_REUSE_NO_FLAGS, 
                                  STATUS_SUCCESS
                                  );
    status = WdfRequestReuse(Request, &params);
    if (!NT_SUCCESS(status)){
        return status;
    }
    reqContext = GetRequestContext(Request);
    inputMem = outputMem = NULL;
    
    if (InputBuffer != NULL) {
        status = WdfMemoryAssignBuffer(
                                       reqContext->InputMemory,
                                       InputBuffer, 
                                       InputBufferLength
                                       );
        if (!NT_SUCCESS(status)) {
             return status;
        }
        inputMem = reqContext->InputMemory;
    }
    if (OutputBuffer != NULL) {
        status = WdfMemoryAssignBuffer(
                                       reqContext->OutputMemory,
                                       OutputBuffer, 
                                       OutputBufferLength
                                       );
        if (!NT_SUCCESS(status)) {
            return status;
        }
        outputMem = reqContext->OutputMemory;
    }
    status = WdfIoTargetFormatRequestForIoctl(
                                              IoTarget,
                                              Request,
                                              IoctlControlCode,
                                              inputMem,
                                              NULL,
                                              outputMem,
                                              NULL
                                              );
    if (!NT_SUCCESS(status)) {
        return status;
    }
    WdfRequestSetCompletionRoutine(
                                   Request,
                                   NICSendOidRequestToTargetAsyncCompletionRoutine,
                                   BytesReadOrWritten
                                   );
    if (WdfRequestSend(
                       Request,
                       IoTarget,
                       WDF_NO_SEND_OPTIONS
                       ) == FALSE) {
        status = WdfRequestGetStatus(Request);
    }
    return status;
}

再看一下同步的:

WDF_MEMORY_DESCRIPTOR  outputDescriptor;
NTSTATUS  status;
HID_COLLECTION_INFORMATION  collectionInformation;
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
                                  &outputDescriptor,
                                  (PVOID) &collectionInformation,
                                  sizeof(HID_COLLECTION_INFORMATION)
                                  );
status = WdfIoTargetSendIoctlSynchronously(
                                           hidTarget,
                                           NULL,
                                           IOCTL_HID_GET_COLLECTION_INFORMATION,
                                           NULL,
                                           &outputDescriptor,
                                           NULL,
                                           NULL
                                           )

上面是发送,我们在驱动中如何进行处理这些IOCTL了,有些IOCTL,已经被WDF封装了,直接成为了驱动对象的一些域了,比如
IRP_MN_START_DEVICE,IRP_MN_FILTER_RESOURCE_REQUIREMENTS 等。有些我们自己定义的流给应用程序的接口,我们需要在请求对象中获取。调用函数

WdfRequestGetParameters(
       IN WDFREQUEST  Request,
      OUT PWDF_REQUEST_PARAMETERS  Parameters
     );

请求对象会在队列处理函数中,以参数的形式传给你,所以,你可以得到请求的参数,以确定IOCTL,而做不同的操作。
回忆一下请求参数:

typedef struct _WDF_REQUEST_PARAMETERS {
    USHORT Size;
    UCHAR MinorFunction;
    WDF_REQUEST_TYPE Type;
    union {
        //
        // Parameters for IRP_MJ_CREATE
        //
        struct {
            PIO_SECURITY_CONTEXT SecurityContext;
            ULONG Options;
            USHORT POINTER_ALIGNMENT FileAttributes;
            USHORT ShareAccess;
            ULONG POINTER_ALIGNMENT EaLength;
        } Create;
        //
        // Parameters for IRP_MJ_READ
        //
        struct {
            size_t Length;
            ULONG POINTER_ALIGNMENT Key;
            LONGLONG DeviceOffset;
        } Read;
        //
        // Parameters for IRP_MJ_WRITE 
        //
        struct {
            size_t Length;
            ULONG POINTER_ALIGNMENT Key;
            LONGLONG DeviceOffset;
        } Write;
        //
        // Parameters for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL 
        //
        struct {
            size_t OutputBufferLength;
            size_t POINTER_ALIGNMENT InputBufferLength;
            ULONG POINTER_ALIGNMENT IoControlCode;
            PVOID Type3InputBuffer;
        } DeviceIoControl;
        struct {
            PVOID Arg1;
            PVOID  Arg2;
            ULONG POINTER_ALIGNMENT IoControlCode;
            PVOID Arg4;
        } Others;
    } Parameters;
} WDF_REQUEST_PARAMETERS, *PWDF_REQUEST_PARAMETERS;

这里,我们就可以很方便的得到控制码进行操作了。

http://blog.csdn.net/z18_28_19/article/details/8892552
转载自其博客,因为排版较乱,所以重新编辑后发到自己博客记录。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值