21
1月
2016

2、Windows的设备驱动框架

当上层模块要驱动(调用)下层模块,或者说要把对于设备的操作交给下一层模块去办的时候,或者I/O管理要调用一个模块(包括"老式"模块)时,就准备好一个称为"I/O请求包(I/O Request Packet)"即IRP的数据结构,并调用一个工具性的内核函数IoCallDriver()或IofCallDriver(),此时程序就根据IRP中的"操作码"转入了目标模块所提供的某个函数。其实IoCallDriver()是宏定义,就定义为IofCallDriver(),后者函数名中的'f'是"fast"的意思,

其调用界面如下:

FASTCALL IofCallDriver(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); 

快速调用函数是通过寄存器传递参数的。

可是上层模块或I/O管理机制怎么获取目标模块的设备对象指针呢?对于I/O管理,这是通过对象管理取得的,对象管理在打开一个设备对象时搜索对象目录,并建立起本进程与设备对象的连接.实际上一个上层模块完全可以有选择地驱动多个下层模块,就是说可以是一对多的关系,但是在典型的情况下确实只有一个。不过,反过来,如果建立了形式的堆叠,那么一个下层对象只能有一个上层对象,就是指针AttachedDevice所指向的设备对象。

堆叠中的上层模块可以为下层模块另行准备一个IRP,但是一般只是把来自上层的IRP略加修改就往下传。

现在我们可以考察有关的数据结构了。每个设备驱动模块(.sys模块)都有一个DRIVER_OBJECT数据结构:


 

typedef struct _DRIVER_OBJECT { 
CSHORT Type; //应该是IO_TYPE_DRIVER 
CSHORT Size; 
// The following links all of the devices created by a single driver 
// together on a list, and the Flags word provides an extensible flag 
// location for driver objects. 
PDEVICE_OBJECT DeviceObject; //指向第一个设备对象 
ULONG Flags; 
// The following section describes where the driver is loaded. The count 
// field is used to count the number of times the driver has had its 
// registered reinitialization routine invoked. 
PVOID DriverStart; 
ULONG DriverSize; 
PVOID DriverSection; 
PDRIVER_EXTENSION DriverExtension; //指向扩充部 
// The driver name field is used by the error log thread 
// determine the name of the driver that an I/O request is/was bound. 
UNICODE_STRING DriverName; 
// The following section is for registry support. Thise is a pointer 
// to the path to the hardware information in the registry 
PUNICODE_STRING HardwareDatabase; 
// The following section contains the optional pointer to an array of 
// alternate entry points to a driver for "fast I/O" support. Fast I/O 
// is performed by invoking the driver routine directly with separate 
// parameters, rather than using the standard IRP call mechanism. Note 
// that these functions may only be used for synchronous I/O, and when 
// the file is cached. 
PFAST_IO_DISPATCH FastIoDispatch; 
// The following section describes the entry points to this particular 
// driver. Note that the major function dispatch table must be the last 
// field in the object so that it remains extensible. 
PDRIVER_INITIALIZE DriverInit; 
PDRIVER_STARTIO DriverStartIo; 
PDRIVER_UNLOAD DriverUnload; 
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; 
} DRIVER_OBJECT; 

这里的MajorFunction[]是个函数指针数组,用来提供一组驱动函数。这个数组的大小为28,可见针对设备I/O的操作还是不少的。

 

1.#define IRP_MJ_CREATE 0x00 
2.#define IRP_MJ_CREATE_NAMED_PIPE 0x01 
3.#define IRP_MJ_CLOSE 0x02 
4.#define IRP_MJ_READ 0x03 
5.#define IRP_MJ_WRITE 0x04 
6.#define IRP_MJ_QUERY_INFORMATION 0x05 
7.#define IRP_MJ_SET_INFORMATION 0x06 
8.#define IRP_MJ_QUERY_EA 0x07 
9.#define IRP_MJ_SET_EA 0x08 
10.#define IRP_MJ_FLUSH_BUFFERS 0x09 
11.#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a 
12.#define IRP_MJ_SET_VOLUME_INFORMATION 0x0b 
13.#define IRP_MJ_DIRECTORY_CONTROL 0x0c 
14.#define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d 
15.#define IRP_MJ_DEVICE_CONTROL 0x0e 
16.#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f 
17.#define IRP_MJ_SHUTDOWN 0x10 
18.#define IRP_MJ_LOCK_CONTROL 0x11 
19.#define IRP_MJ_CLEANUP 0x12 
20.#define IRP_MJ_CREATE_MAILSLOT 0x13 
21.#define IRP_MJ_QUERY_SECURITY 0x14 
22.#define IRP_MJ_SET_SECURITY 0x15 
23.#define IRP_MJ_POWER 0x16 
24.#define IRP_MJ_SYSTEM_CONTROL 0x17 
25.#define IRP_MJ_DEVICE_CHANGE 0x18 
26.#define IRP_MJ_QUERY_QUOTA 0x19 
27.#define IRP_MJ_SET_QUOTA 0x1a 
28.#define IRP_MJ_PNP 0x1b 
29.#define IRP_MJ_PNP_POWER IRP_MJ_PNP // Obsolete... 
30.#define IRP_MJ_MAXIMUM_FUNCTION 0x1b 

当然,并非每一个驱动对象都要提供那么多的函数,实际上许多指针都是NULL。 除此之外,FastIoDispatch是个指针,可以指向一个FAST_IO_DISPATCH数据结构,里面是另一组函数指针,例如FastIoRead、FastIoWrite等。顾名思义,这是一组提供快速(简单)操作的函数。 除数据结构外,每个模块都有个总的初始化入口DriverEntry(),相当于每个DLL都有个DllMain()。 当然,很难想象这么一个数据结构就可以代表所有的驱动模块,覆盖所有模块的特性,这显然只是所有模块的属性中公共的、最基本的那一部分。而反映不同模块特性的那一部分,则需要存放在附属的数据结构中,首先就是DRIVER_EXTENSION:

 

1.typedef struct _DRIVER_EXTENSION { 
2. // Back pointer to Driver Object 
3. struct _DRIVER_OBJECT *DriverObject; 
4. // The AddDevice entry point is called by the Plug & Play manager to inform 
5. // the driver when a new device instance arrives that this driver must control. 
6. PDRIVER_ADD_DEVICE AddDevice; //每个模块都有自己的AddDevice函数 
7. 
8.// The count field is used to count the number of times the driver has 
9. // had its registered reinitialization routine invoked. 
10. ULONG Count; 
11. // The service name field is used by the pnp manager to determine 
12. // where the driver related info is stored in the registry. 
13. UNICODE_STRING ServiceKeyName; 
14. // Note: any new shared fields get added here. 
15.} DRIVER_EXTENSION; 

Categories: 驱动开发

Overall Rating (0)

0 out of 5 stars

Leave your comments

Post comment as a guest

0 Character restriction
Your text should be more than 3 characters
  • No comments found