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_IO和DO_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.