21
1月
2016

3、Windows的设备驱动框架

每当装载一个设备驱动模块的时候,内核的I/O管理先是调用其DriverEntry(),再调用其AddDevice函数(如果有的话),这就完成了模块的初始化与安装。

DRIVER_OBJECT数据结构及其扩充部分主要提供设备驱动模块的各种操作(函数),而设备的状态则反映在"设备对象"DEVICE_OBJECT中,而且各层设备驱动的堆叠也是通过DEVICE_OBJECT实现的:

1.typedef struct _DEVICE_OBJECT { 
2. CSHORT Type; //应该是IO_TYPE_DEVICE 
3. USHORT Size; 
4. LONG ReferenceCount; 
5. struct _DRIVER_OBJECT *DriverObject; //指向本模块的驱动对象 
6.struct _DEVICE_OBJECT *NextDevice; //指向同一模块同一层中的下一个设备对象 
7.struct _DEVICE_OBJECT *AttachedDevice; //指向上一层的设备对象 
8.struct _IRP *CurrentIrp; 
9. PIO_TIMER Timer; 
10. ULONG Flags; 
11. ULONG Characteristics; 
12. PVPB Vpb; 
13. PVOID DeviceExtension; 
14. DEVICE_TYPE DeviceType; 
15. CCHAR StackSize; //堆叠的深度 
16.union { 
17. LIST_ENTRY ListEntry; 
18. WAIT_CONTEXT_BLOCK Wcb; 
19. } Queue; 
20. ULONG AlignmentRequirement; 
21. KDEVICE_QUEUE DeviceQueue; 
22. KDPC Dpc; 
23. // The following field is for exclusive use by the filesystem to keep 
24. // track of the number of Fsp threads currently using the device 
25. ULONG ActiveThreadCount; 
26. PSECURITY_DESCRIPTOR SecurityDescriptor; 
27. KEVENT DeviceLock; 
28. USHORT SectorSize; 
29. USHORT Spare1; 
30. struct _DEVOBJ_EXTENSION *DeviceObjectExtension; 
31. PVOID Reserved; 
32.} DEVICE_OBJECT; 

首先是StackSize,这与"堆栈"无关,而是指"堆叠"的大小,是从本设备对象开始往下直到最底层的设备对象为止这部分堆叠的深度。换言之,这个数值说明了本设备的驱动程序(在形式上)一共分几层。在这个堆叠中,有些层次是系统初始化或动态装入模块时就"装配"好了的,属于一个设备驱动模块堆叠的骨干,有些却可能是后来才动态装入的"过滤"模块。 指针DriverObject指向该设备对象所属的驱动对象。如前所述,驱动对象与设备对象是一对多的关系,每个驱动对象都有个设备对象队列,这里的指针NextDevice就是用来构成这种横向队列的。而另一个指针AttachedDevice,则用来构成纵向的队列即设备对象堆叠,这个指针总是指向其头顶的设备对象。 还有个重要的指针DeviceQueue,指向一个队列头,这是用于IRP的队列。Windows的设备驱动框架是面向异步操作的,对于某一层特定的设备对象而言,如果前面的操作尚未完成而后面的操作请求又来了,就可以将后来的操作请求即IRP先放在这个队列里,等前面的操作完成以后再来处理。 设备对象也可以有扩充数据结构,指针DeviceObjectExtension如果非空,就用来指向其扩充数据结构:

 

1.typedef struct _DEVOBJ_EXTENSION { 
2.CSHORT Type; 
3.USHORT Size; 
4.// Public part of the DeviceObjectExtension structure 
5.PDEVICE_OBJECT DeviceObject; // owning device object 
6.} DEVOBJ_EXTENSION; 

DEVOBJ_EXTENSION是统一定义的数据结构,从表面上看里面的附加信息极其有限,实际上只是Type和Size两个16位的字段。这个数据结构后来又被进一步扩充,现在实际使用的是EXTENDED_DEVOBJ_EXTENSION结构:

 1.typedef struct _EXTENDED_DEVOBJ_EXTENSION 
2.{ 
3.CSHORT Type; 
4.USHORT Size; 
5.PDEVICE_OBJECT DeviceObject; 
6.ULONG PowerFlags; 
7.struct DEVICE_OBJECT_POWER_EXTENSION *Dope; 
8.ULONG ExtensionFlags; 
9.struct _DEVICE_NODE *DeviceNode; 
10.PDEVICE_OBJECT AttachedTo; //用于堆叠的向下指针 
11.LONG StartIoCount; 
12.LONG StartIoKey; 
13.ULONG StartIoFlags; 
14.struct _VPB *Vpb; //文件卷参数块 
15.} EXTENDED_DEVOBJ_EXTENSION, *PEXTENDED_DEVOBJ_EXTENSION; 

显然,其开头的三个字段与DEVOBJ_EXTENSION结构中的相同,但是后面多了一些字段,其中就有用于堆叠的向下指针AttachedTo。还有一个很重要的字段是Vpb,用来指向一个"文件卷参数块"即VPB。 但是,不管是DEVOBJ_EXTENSION还是EXTENDED_DEVOBJ_EXTENSION,都只是附加信息的头部(实际上是尾部),真正的附加信息在伴随在其前面的扩充部数据结构中,而这里的Type和Size,其实也是指具体扩充部结构的类型和大小。 实际的扩充部结构则因具体的设备而异,由具体设备驱动模块的开发者自行定义,并不存在一种统一定义的数据结构,对其命名也没有规定,但是一般都以DEVICE_ EXTENSION为名,或具有XYZ_DEVICE_EXTENSION的形式。所以每个设备驱动模块的代码中都自行定义其自己的DEVICE_EXTENSION数据结构或类似的数据结构。 由于这些数据结构一般都只是局部于具体驱动模块而并无全局的意义,所以无须考虑命名冲突的问题。 建立起设备对象的堆叠之后,对于设备的操作是通过IRP即I/O请求包进行的。IRP的数据结构为:

 

 1.typedef struct _IRP { 
2.CSHORT Type; //应该是IO_TYPE_IRP 
3.USHORT Size; 
4.struct _MDL *MdlAddress; //指向MDL列表 
5.ULONG Flags; 
6.union { 
7.struct _IRP *MasterIrp; 
8.LONG IrpCount; 
9.PVOID SystemBuffer; //指向用户空间缓冲区映射在系统空间的地址(如果采用MDL) 
10.} AssociatedIrp; 
11.LIST_ENTRY ThreadListEntry; //用来将IRP挂入某个线程的IrpList队列 
12.IO_STATUS_BLOCK IoStatus; //用来返回操作的完成状况 
13.KPROCESSOR_MODE RequestorMode; 
14.BOOLEAN PendingReturned; 
15.CHAR StackCount; 
16.CHAR CurrentLocation; 
17.BOOLEAN Cancel; 
18.KIRQL CancelIrql; 
19.CCHAR ApcEnvironment; 
20.UCHAR AllocationFlags; 
21.PIO_STATUS_BLOCK UserIosb; 
22.PKEVENT UserEvent; 
23.union { 
24.struct { 
25.PIO_APC_ROUTINE UserApcRoutine; //指向用户空间APC函数 
26.PVOID UserApcContext; 
27.} AsynchronousParameters; 
28.LARGE_INTEGER AllocationSize; 
29.} Overlay; 
30.PDRIVER_CANCEL CancelRoutine; //指向撤销IRP时需要执行的函数 
31.PVOID UserBuffer; //指向用户空间缓冲区 
32.union { 
33.struct { 
34._ANONYMOUS_UNION union { 
35.KDEVICE_QUEUE_ENTRY DeviceQueueEntry; 
36.//用来将IRP挂入某个设备对象的DeviceQueue队列 
37._ANONYMOUS_STRUCT struct { 
38.PVOID DriverContext[4]; 
39.} DUMMYSTRUCTNAME; 
40.} DUMMYUNIONNAME; 
41.PETHREAD Thread; //指向发出IRP的线程 
42.PCHAR AuxiliaryBuffer; 
43._ANONYMOUS_STRUCT struct { 
44.LIST_ENTRY ListEntry; 
45._ANONYMOUS_UNION union { 
46.struct _IO_STACK_LOCATION *CurrentStackLocation; 
47.ULONG PacketType; 
48.} DUMMYUNIONNAME; 
49.} DUMMYSTRUCTNAME; 
50.struct _FILE_OBJECT *OriginalFileObject; 
51.//设备对象堆叠所关联的(打开)文件对象 
52.} Overlay; 
53.KAPC Apc; 
54.PVOID CompletionKey; 
55.} Tail; 
56.} IRP; 

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