HelloWorld 驅動詳解

driver.c:
/*++

Module Name:

    driver.c

Abstract:

    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)
#endif



NTSTATUS
DriverEntry(
    _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 hyde
	for (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;
}

NTSTATUS
HelloWordEvtDeviceAdd(
    _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;
}

VOID
HelloWordEvtDriverContextCleanup(
    _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 hyde

VOID
DriverUnload (
    __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 hyde

NTSTATUS
DefaultDispatch (
    __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. 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章