HelloWorld 驱动详解

来源:互联网 发布:淘宝领券特卖网 编辑:程序博客网 时间:2024/05/22 01:47
driver.c:/*++Module Name:    driver.cAbstract:    This file contains the driver entry points and callbacks.Environment:    Kernel-mode Driver Framework--*/#include "driver.h"#include "driver.tmh"#ifdef ALLOC_PRAGMA#pragma alloc_text (INIT, DriverEntry)#pragma alloc_text (PAGE, HelloWordEvtDeviceAdd)#pragma alloc_text (PAGE, HelloWordEvtDriverContextCleanup)#endifNTSTATUSDriverEntry(    _In_ PDRIVER_OBJECT  DriverObject,    _In_ PUNICODE_STRING RegistryPath    )/*++Routine Description:    DriverEntry initializes the driver and is the first routine called by the    system after the driver is loaded. DriverEntry specifies the other entry    points in the function driver, such as EvtDevice and DriverUnload.Parameters Description:    DriverObject - represents the instance of the function driver that is loaded    into memory. DriverEntry must initialize members of DriverObject before it    returns to the caller. DriverObject is allocated by the system before the    driver is loaded, and it is released by the system after the system unloads    the function driver from memory.    RegistryPath - represents the driver specific path in the Registry.    The function driver can use the path to store driver related data between    reboots. The path does not store hardware instance specific data.Return Value:    STATUS_SUCCESS if successful,    STATUS_UNSUCCESSFUL otherwise.--*/{//modify by hyde    PDEVICE_OBJECT deviceObject;    PDEVICE_EXTENSION deviceExtension;    UNICODE_STRING symbolicLink;    UNICODE_STRING deviceName;    ULONG i;//modify by hyde//WDF_DRIVER_CONFIG config;    NTSTATUS status;    // WDF_OBJECT_ATTRIBUTES attributes;KdPrint(("Enter HelloDRIVER DriverEntry!\n"));UNREFERENCED_PARAMETER(RegistryPath); RtlInitUnicodeString(&deviceName, L"\\Device\\HelloDRIVER");//deal process by hydefor (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)    {        DriverObject->MajorFunction[i] = DefaultDispatch;     }DriverObject->DriverUnload = DriverUnload;    DriverObject->MajorFunction[IRP_MJ_CREATE] = DefaultDispatch;     DriverObject->MajorFunction[IRP_MJ_CLOSE] = DefaultDispatch;     DriverObject->MajorFunction[IRP_MJ_READ] = DefaultDispatch;     DriverObject->MajorFunction[IRP_MJ_WRITE] = DefaultDispatch; status=IoCreateDevice(DriverObject,                             sizeof(DEVICE_EXTENSION),                             &deviceName,                             FILE_DEVICE_UNKNOWN,                             0,                             TRUE,                             &deviceObject);if(!NT_SUCCESS(status))    {        return status;    }    deviceObject->Flags = DO_BUFFERED_IO;    deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;    deviceExtension->DeviceObject = deviceObject;    deviceExtension->DeviceName = deviceName;    RtlInitUnicodeString(&symbolicLink, L"\\??\\HelloDRIVER");    deviceExtension->SymbolicLink = symbolicLink;//create symbol link status = IoCreateSymbolicLink(&symbolicLink, &deviceName);if(!NT_SUCCESS(status))    {        IoDeleteDevice(deviceObject);        return status;    }//create symbol link    KdPrint(("End of HelloDRIVER DriverEntry!\n"));     return status;/*//delete by hyde    //    // Initialize WPP Tracing    //    WPP_INIT_TRACING( DriverObject, RegistryPath );    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");    //    // Register a cleanup callback so that we can call WPP_CLEANUP when    // the framework driver object is deleted during driver unload.    //    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);    attributes.EvtCleanupCallback = HelloWordEvtDriverContextCleanup;    WDF_DRIVER_CONFIG_INIT(&config,                           HelloWordEvtDeviceAdd                           );    status = WdfDriverCreate(DriverObject,                             RegistryPath,                             &attributes,                             &config,                             WDF_NO_HANDLE                             );    if (!NT_SUCCESS(status)) {        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);        WPP_CLEANUP(DriverObject);        return status;    }    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");    return status;}NTSTATUSHelloWordEvtDeviceAdd(    _In_    WDFDRIVER       Driver,    _Inout_ PWDFDEVICE_INIT DeviceInit    )/*++Routine Description:    EvtDeviceAdd is called by the framework in response to AddDevice    call from the PnP manager. We create and initialize a device object to    represent a new instance of the device.Arguments:    Driver - Handle to a framework driver object created in DriverEntry    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.Return Value:    NTSTATUS*//*//delete by hyde{    NTSTATUS status;    UNREFERENCED_PARAMETER(Driver);    PAGED_CODE();    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");    status = HelloWordCreateDevice(DeviceInit);    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");    return status;}VOIDHelloWordEvtDriverContextCleanup(    _In_ WDFOBJECT DriverObject    )/*++Routine Description:    Free all the resources allocated in DriverEntry.Arguments:    DriverObject - handle to a WDF Driver object.Return Value:    VOID.--*//*//delete by hyde{    UNREFERENCED_PARAMETER(DriverObject);    PAGED_CODE ();    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");    //    // Stop WPP Tracing    //    WPP_CLEANUP( WdfDriverWdmGetDriverObject(DriverObject) );}*/}/////////////////////////////////////////////////////////////////////////function declare unload device hydeVOIDDriverUnload (    __in PDRIVER_OBJECT DriverObject    ){PDEVICE_OBJECT deviceObject;UNICODE_STRING linkName;    KdPrint(("Enter HelloDRIVER DriverUnload!\n"));        deviceObject = DriverObject->DeviceObject;        while(NULL != deviceObject)    {        PDEVICE_EXTENSION deviceExtesion = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;              //delete the symbolLink to the device         linkName = deviceExtesion->SymbolicLink;        IoDeleteSymbolicLink(&linkName);        deviceObject = deviceObject->NextDevice;        IoDeleteDevice(deviceExtesion->DeviceObject);    }        KdPrint(("End of HelloDRIVER DriverUnload!\n"));}//function declare unload device hyde//function declare dispatch hydeNTSTATUSDefaultDispatch (    __in PDEVICE_OBJECT DeviceObject,    __in PIRP Irp    ){    NTSTATUS status;    KdPrint(("Enter HelloDRIVER DefaultDispatch!\n"));        UNREFERENCED_PARAMETER(DeviceObject);    status = STATUS_SUCCESS;       //finish the Irp request    Irp->IoStatus.Status = status;    Irp->IoStatus.Information = 0;    IoCompleteRequest(Irp, IO_NO_INCREMENT);        KdPrint(("End of HelloDRIVER DefaultDispatch!\n"));    return status;}///////////////////////////////////////////////////////////////////////


Hello_world 驱动详解

typedef struct _DEVICE_EXTENSION

{

PDEVICE_OBJECT DeviceObject;

UNICODE_STRING DeviceName;

UNICODE_STRING SymbolicLink;

}DEVICE_EXTENSION,*PDEVICE_EXTENSION;

上面的结构,主要是为了用以描述驱动程序的设备 扩展,它保存了我们自定义所需要的一些信息,有助于更加方便的编程,我觉得这有点像Linux 里面的driver data 活着private data成员一样,放一些我们自己所需要的一些成员

要养成将所有函数的申明放在一个头文件中,这样方便观看

在驱动开发的过程中,需要为每一个函数指定其实分页内存还是非分页内存。INIT标识是指定此函数在驱动加载的时候使用,代表这是初始化相关的函数,驱动加载以后可以从内存卸载。就比如:#pragma alloc_text (INIT, DriverEntry),还有就是指定函数是分页内存还是非分页内存,就比如下面:

#pragma alloc_text (PAGE, HelloWordEvtDeviceAdd)

#pragma alloc_text (PAGE, HelloWordEvtDriverContextCleanup)

上面的函数指定是分页内存,PAGE就代表此函数在驱动运行中可以被交换到磁盘上,如果不指定,那么编译器就默认为是非分页内存。一般情况下,我们不需要考虑这些问题,但是有些特殊情况下,代码是不允许交换到磁盘中的,否则将导致操作系统蓝屏,活着自动重启

还有一点就是函数的申明必须在这些指定内存分配的预处理之前,否则编译无法通过,因为如果函数还没有申明或则定义的话,那么我们是不能直接使用的,就像C语言里面是一样的

在windows 驱动中,我们经常会用到UNREFERENCED这个宏,这个宏的意思是告诉这个编译器这个参数,我们没有被引用过,那么为什么需要这样呢??大家在编译C语言的时候,一定看到过,当一个变量你从来没有使用过的话,那么编译器就会发出一个warnninng 的警告,我们使用这个宏的目的就是为了避免不必要的警告,驱动需要很稳定,哪怕一个警告,也要尽量的去除,否则说不准就会导致系统崩溃

在windows driver中需要为DriverObject->MajorFunction 进行赋值,这是driver 的回调函数或者称为派遣函数,但是driver 的卸载的派遣函数是单独出来的,不在MajorFunction 里面,上面的MajorFunction 里面最大的派遣函数数是IRP_MJ_MAXIMUM_FUNCTION,这里需要说明下提供给操作系统的一个操作函数也是这个MajorFunction 里面进行定义的,就像Linux下面的file_operation 一样的,操作函数集合如下,下面只是列举出一些常用的:

 DriverObject->MajorFunction[IRP_MJ_CREATE] = DefaultDispatch; 

    DriverObject->MajorFunction[IRP_MJ_CLOSE] = DefaultDispatch; 

    DriverObject->MajorFunction[IRP_MJ_READ] = DefaultDispatch; 

    DriverObject->MajorFunction[IRP_MJ_WRITE] = DefaultDispatch; 

赋值完成后,接下来就会进行device 的创建:

status=IoCreateDevice(DriverObject,

                             sizeof(DEVICE_EXTENSION),

                             &deviceName,

                             FILE_DEVICE_UNKNOWN,

                             0,

                             TRUE,

                             &deviceObject);

上面从字面的意思,也可以看出来时在创建设备

下面看下创建device 的函数的每个参数的意思是什么??

我查询了WDK 查询如下:

IoCreateDevice:The IoCreateDevice routine creates a device object for use by a driver 

Parameters:

DriverObject:

Pointer to the driver object for the caller. Each driver receives a pointer to its driver object in a parameter to its DriverEntry routine. WDM function and filter drivers also receive a driver object pointer in their AddDevice routines.

上面的注释,我们发现,我们创建driver 的入口点有的是在DriverEntry 或者是在AddDevice 里面 

DeviceExtensionSize:

Specifies the driver-determined number of bytes to be allocated for the device extension of the device object. The internal structure of the device extension is driver-defined. 

 DeviceName:

Optionally points to a buffer containing a null-terminated Unicode string that names the device object. The string must be a full path name. WDM filter and function drivers do not name their device objects. For more information, see Named Device Objects

Note If a device name is not supplied (that is, DeviceName is NULL), the device object created by IoCreateDevice will not (and cannot) have a discretionary access control list (DACL) associated with it. For additional information, see Security Descriptors

这里需要注意下就是这个devicename 带有路径去命名的;就例如如下:

RtlInitUnicodeString(&deviceName, L"\\Device\\HelloDRIVER");

DeviceType:

Specifies one of the system-defined FILE_DEVICE_XXX constants that indicate the type of device (such as FILE_DEVICE_DISK, FILE_DEVICE_KEYBOARD, etc.) or a vendor-defined value for a new type of device. For more information, see Specifying Device Types

DeviceCharacteristics:

Specifies one or more system-defined constants, ORed together, that provide additional information about the driver's device. For a list of possible device characteristics, see DEVICE_OBJECT. For more information about how to specify device characteristics, see Specifying Device Characteristics. Most drivers specify FILE_DEVICE_SECURE_OPEN for this parameter. 

Exclusive :

Specifies if the device object represents an exclusive device. Most drivers set this value to FALSE. For more information about exclusive access, see Specifying Exclusive Access to Device Objects这里世代表是否这个设备室独有的,一般都是FALSE

DeviceObject :

Pointer to a variable that receives a pointer to the newly created DEVICE_OBJECT structure. The DEVICE_OBJECT structure is allocated from nonpaged pool. 

下面看下PDEVICE_OBJECT deviceObject;这个设备描述结构体里面都有哪些成员:

typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT_DEVICE_OBJECT {

    CSHORT Type;

    USHORT Size;

    LONG ReferenceCount;

    struct _DRIVER_OBJECT *DriverObject;

    struct _DEVICE_OBJECT *NextDevice;

    struct _DEVICE_OBJECT *AttachedDevice;

    struct _IRP *CurrentIrp;

    PIO_TIMER Timer;

    ULONG Flags;                                // See above:  DO_...

    ULONG Characteristics;                      // See ntioapi:  FILE_...

    __volatile PVPB Vpb;

    PVOID DeviceExtension;

    DEVICE_TYPE DeviceType;

    CCHAR StackSize;

    union {

        LIST_ENTRY ListEntry;

        WAIT_CONTEXT_BLOCK Wcb;

    } Queue;

    ULONG AlignmentRequirement;

    KDEVICE_QUEUE DeviceQueue;

    KDPC Dpc;

    //

    //  The following field is for exclusive use by the filesystem to keep

    //  track of the number of Fsp threads currently using the device

    //

    ULONG ActiveThreadCount;

    PSECURITY_DESCRIPTOR SecurityDescriptor;

    KEVENT DeviceLock;

    USHORT SectorSize;

    USHORT Spare1;

    struct _DEVOBJ_EXTENSION  *DeviceObjectExtension;

    PVOID  Reserved;

DEVICE_OBJECT;

typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT

讲解下上面这个结构体里面一些成员:

Flags:设置设备的两种不同的缓冲区处理方式,有BUFFERED_IODO_DIRECT_IO着两种方式

DeviceExtension:是设备扩展数据,这个类型是Pvoid 型的,是一个空的类型,任何类型都可以赋值给空的类型是吧,我们上面定义的扩展类型也可以赋值给它

看下我们自己定义的扩展类型是什么结构的:

typedef struct _DEVICE_EXTENSION

{

PDEVICE_OBJECT DeviceObject;

UNICODE_STRING DeviceName;

UNICODE_STRING SymbolicLink;

}DEVICE_EXTENSION,*PDEVICE_EXTENSION;

里面就两个成员:

设备object、设备名字、设备链接符号名称

我们会在下面会这个描述符进行初始化,然后进行创建这个设备的链接描述符的,我感觉这个链接描述符应该就是我们在xp 下经常看到的快捷方式

 RtlInitUnicodeString(&symbolicLink, L"\\??\\HelloDRIVER");

 deviceExtension->SymbolicLink = symbolicLink;

//create symbol link

status = IoCreateSymbolicLink(&symbolicLink, &deviceName);

上面会进行链接描述符的初始化的动作,初始化的时候,命名规则也是带有路径的,下面看下创建链接描述符的函数的函数的实现方法:

IoCreateSymbolicLink

The IoCreateSymbolicLink routine sets up a symbolic link between a device object name and a user-visible name for the device. 

Parameters:

SymbolicLinkName 

Pointer to a buffered Unicode string that is the user-visible name. 

DeviceName 

Pointer to a buffered Unicode string that is the name of the driver-created device object. 

原创粉丝点击