zoukankan      html  css  js  c++  java
  • 驱动对象 设备对象 设备栈 乱杂谈

    驱动对象 设备对象 设备栈 乱杂谈
     
    作者: JIURL
     
                    主页: http://jiurl.yeah.net/
     
       
     


    --------------------------------------------------------------------------------
     

        用有限的几句话就舒舒服服的建立起对驱动对象和设备对象的概念是不可能的。刚开始是一片模糊,了解的多了,慢慢就清楚。下面的内容会使你对他们了解的清楚些。

    为了后面的叙述方便,首先列出驱动对象和设备对象的结构。

    驱动对象结构 DRIVER_OBJECT ,定义如下

    struct _DRIVER_OBJECT (sizeof=168)
    +00 int16 Type
    +02 int16 Size
    +04 struct _DEVICE_OBJECT *DeviceObject
    +08 uint32 Flags
    +0c void *DriverStart
    +10 uint32 DriverSize
    +14 void *DriverSection
    +18 struct _DRIVER_EXTENSION *DriverExtension
    +1c struct _UNICODE_STRING DriverName
    +1c uint16 Length
    +1e uint16 MaximumLength
    +20 uint16 *Buffer
    +24 struct _UNICODE_STRING *HardwareDatabase
    +28 struct _FAST_IO_DISPATCH *FastIoDispatch
    +2c function *DriverInit
    +30 function *DriverStartIo
    +34 function *DriverUnload
    +38 function *MajorFunction[28]

    DDK 中有对于一些域的说明

    [00] IRP_MJ_CREATE
    [01] IRP_MJ_CREATE_NAMED_PIPE
    [02] IRP_MJ_CLOSE
    [03] IRP_MJ_READ
    [04] IRP_MJ_WRITE
    [05] IRP_MJ_QUERY_INFORMATION
    [06] IRP_MJ_SET_INFORMATION
    [07] IRP_MJ_QUERY_EA
    [08] IRP_MJ_SET_EA
    [09] IRP_MJ_FLUSH_BUFFERS
    [0a] IRP_MJ_QUERY_VOLUME_INFORMATION
    [0b] IRP_MJ_SET_VOLUME_INFORMATION
    [0c] IRP_MJ_DIRECTORY_CONTROL
    [0d] IRP_MJ_FILE_SYSTEM_CONTROL
    [0e] IRP_MJ_DEVICE_CONTROL
    [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL
    [10] IRP_MJ_SHUTDOWN
    [11] IRP_MJ_LOCK_CONTROL
    [12] IRP_MJ_CLEANUP
    [13] IRP_MJ_CREATE_MAILSLOT
    [14] IRP_MJ_QUERY_SECURITY
    [15] IRP_MJ_SET_SECURITY
    [16] IRP_MJ_POWER
    [17] IRP_MJ_SYSTEM_CONTROL
    [18] IRP_MJ_DEVICE_CHANGE
    [19] IRP_MJ_QUERY_QUOTA
    [1a] IRP_MJ_SET_QUOTA
    [1b] IRP_MJ_PNP

    struct _DRIVER_EXTENSION (sizeof=24)
    +00 struct _DRIVER_OBJECT *DriverObject
    +04 function *AddDevice
    +08 uint32 Count
    +0c struct _UNICODE_STRING ServiceKeyName
    +0c uint16 Length
    +0e uint16 MaximumLength
    +10 uint16 *Buffer
    +14 struct _IO_CLIENT_EXTENSION *ClientDriverExtension


    设备对象结构 DEVICE_OBJECT ,定义如下

    struct _DEVICE_OBJECT (sizeof=184)
    +00 int16 Type
    +02 uint16 Size
    +04 int32 ReferenceCount
    +08 struct _DRIVER_OBJECT *DriverObject
    +0c struct _DEVICE_OBJECT *NextDevice
    +10 struct _DEVICE_OBJECT *AttachedDevice
    +14 struct _IRP *CurrentIrp
    +18 struct _IO_TIMER *Timer
    +1c uint32 Flags
    +20 uint32 Characteristics
    +24 struct _VPB *Vpb
    +28 void *DeviceExtension
    +2c uint32 DeviceType
    +30 char StackSize
    +34 union __unnamed62 Queue
    +34 struct _LIST_ENTRY ListEntry
    +34 struct _LIST_ENTRY *Flink
    +38 struct _LIST_ENTRY *Blink
    +34 struct _WAIT_CONTEXT_BLOCK Wcb
    +34 struct _KDEVICE_QUEUE_ENTRY WaitQueueEntry
    +34 struct _LIST_ENTRY DeviceListEntry
    +34 struct _LIST_ENTRY *Flink
    +38 struct _LIST_ENTRY *Blink
    +3c uint32 SortKey
    +40 byte Inserted
    +44 function *DeviceRoutine
    +48 void *DeviceContext
    +4c uint32 NumberOfMapRegisters
    +50 void *DeviceObject
    +54 void *CurrentIrp
    +58 struct _KDPC *BufferChainingDpc
    +5c uint32 AlignmentRequirement
    +60 struct _KDEVICE_QUEUE DeviceQueue
    +60 int16 Type
    +62 int16 Size
    +64 struct _LIST_ENTRY DeviceListHead
    +64 struct _LIST_ENTRY *Flink
    +68 struct _LIST_ENTRY *Blink
    +6c uint32 Lock
    +70 byte Busy
    +74 struct _KDPC Dpc
    +74 int16 Type
    +76 byte Number
    +77 byte Importance
    +78 struct _LIST_ENTRY DpcListEntry
    +78 struct _LIST_ENTRY *Flink
    +7c struct _LIST_ENTRY *Blink
    +80 function *DeferredRoutine
    +84 void *DeferredContext
    +88 void *SystemArgument1
    +8c void *SystemArgument2
    +90 uint32 *Lock
    +94 uint32 ActiveThreadCount
    +98 void *SecurityDescriptor
    +9c struct _KEVENT DeviceLock
    +9c struct _DISPATCHER_HEADER Header
    +9c byte Type
    +9d byte Absolute
    +9e byte Size
    +9f byte Inserted
    +a0 int32 SignalState
    +a4 struct _LIST_ENTRY WaitListHead
    +a4 struct _LIST_ENTRY *Flink
    +a8 struct _LIST_ENTRY *Blink
    +ac uint16 SectorSize
    +ae uint16 Spare1
    +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension
    +b4 void *Reserved

    DDK 中有对于一些域的说明

    struct _DEVOBJ_EXTENSION (sizeof=36)
    +00 int16 Type
    +02 uint16 Size
    +04 struct _DEVICE_OBJECT *DeviceObject
    +08 uint32 PowerFlags
    +0c *Dope
    +10 uint32 ExtensionFlags
    +14 void *DeviceNode
    +18 struct _DEVICE_OBJECT *AttachedTo
    +1c struct _LIST_ENTRY FileObjectList
    +1c struct _LIST_ENTRY *Flink
    +20 struct _LIST_ENTRY *Blink

    有一个载入内存的驱动程序文件,就会有一个驱动对象(DRIVER_OBJECT)。

    比如,驱动 i8042prt 是在系统初始化阶段,IO 管理器调用函数 nt!IopLoadDriver 载入的。nt!IopLoadDriver 读取注册表,获得驱动程序文件 i8042prt.SYS 的路径,将这个文件载入内存。之后会调用 nt!ObCreateObject 创建一个驱动对象,并初始化这个驱动对象。

    设备对象(DEVICE_OBJECT)由驱动创建。一个驱动可以创建多个设备对象(DEVICE_OBJECT)。通过驱动对象(DRIVER_OBJECT),可以找到由该驱动创建的所有设备对象(DEVICE_OBJECT)。一个驱动创建的所有设备对象(DEVICE_OBJECT)链成一条链,该驱动的驱动对象(DRIVER_OBJECT)可以找到这个链。一个设备对象(DEVICE_OBJECT)也可以找到创建它的驱动的驱动对象(DRIVER_OBJECT)。下面我们使用 WinDbg 实际观察驱动 i8042prt 的情况,i8042prt 是完成 ps/2 键盘驱动主要功能的驱动程序。

    在这里我们先做个说明,对于同时插有 ps/2 键盘和 ps/2 鼠标的计算机上, i8042prt 会创建两个设备对象,一个用于键盘,一个用于鼠标。

    首先我们从命名对象地址空间,找到 i8042prt 的 DRIVER_OBJECT 的地址

    kd> !object \driver\i8042prt
    Object: fe4f69f0 Type: (fe4ec3e0) Driver
    ObjectHeader: fe4f69d8
    HandleCount: 0 PointerCount: 5
    Directory Object: fe51bf30 Name: i8042prt

    下面我们看 i8042prt 的 DRIVER_OBJECT 中的内容

    kd> !strct driver_object fe4f69f0
    struct _DRIVER_OBJECT (sizeof=168)
    +00 int16 Type = 0004
    +02 int16 Size = 00a8
    +04 struct _DEVICE_OBJECT *DeviceObject = FE4D3BA0
    // 注意 DeviceObject 链上的第一个设备对象
    +08 uint32 Flags = 00000012
    +0c void *DriverStart = FE1BD000
    +10 uint32 DriverSize = 00021000
    +14 void *DriverSection = FE4F6CC8
    +18 struct _DRIVER_EXTENSION *DriverExtension = FE4F6A98
    +1c struct _UNICODE_STRING DriverName
    +1c uint16 Length = 0020
    +1e uint16 MaximumLength = 0020
    +20 uint16 *Buffer = E127FE88
    +24 struct _UNICODE_STRING *HardwareDatabase = 80541FC0
    +28 struct _FAST_IO_DISPATCH *FastIoDispatch = 00000000
    +2c function *DriverInit = FE1D8000
    +30 function *DriverStartIo = FE1BF444
    +34 function *DriverUnload = FE1CB920
    +38 function *MajorFunction[28] = FE1CB000
    80425354
    FE1CB14E
    80425354
    80425354
    80425354
    80425354
    80425354
    80425354
    FE1BE558
    80425354
    80425354
    80425354
    80425354
    FE1CB243
    FE1BE667
    80425354
    80425354
    80425354
    80425354
    80425354
    80425354
    FE1D2C63
    FE1D3633
    80425354
    80425354
    80425354
    FE1D1BFB


    我们看到了 DeviceObject 上的第一个设备对象的地址 FE4D3BA0 ,我们使用 WinDbg 的 !devobj 命令,来获得一些信息

    kd> !devobj FE4D3BA0
    Device object (fe4d3ba0) is for:
    \Driver\i8042prt DriverObject fe4f69f0
    Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
    DevExt fe4d3c58 DevObjExt fe4d3ed8
    ExtensionFlags (0xc0000000)
    Unknown flags 0xc0000000
    AttachedDevice (Upper) fe4d3a60 \Driver\vmmouse
    AttachedTo (Lower) fe4dd610 \Driver\ACPI
    Device queue is not busy.

    从获得的信息来看,这是用于鼠标的那个设备对象,下面我们看这个设备对象 DEVICE_OBJECT 中的具体内容

    kd> !strct device_object FE4D3BA0
    struct _DEVICE_OBJECT (sizeof=184)
    +00 int16 Type = 0003
    +02 uint16 Size = 0338
    +04 int32 ReferenceCount = 00000000
    +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0
    // 正是 \Driver\i8042prt 的驱动对象的地址
    +0c struct _DEVICE_OBJECT *NextDevice = FE4F5020
    // DeviceObject 链的下一个
    +10 struct _DEVICE_OBJECT *AttachedDevice = FE4D3A60
    +14 struct _IRP *CurrentIrp = 00000000
    ...

    我们看到了设备对象 +0c struct _DEVICE_OBJECT *NextDevice 处是 DeviceObject 链上的下一个设备对象的地址,值为 FE4F5020 ,我们使用 WinDbg 的 !devobj 命令,来获得一些信息

    kd> !devobj FE4F5020
    Device object (fe4f5020) is for:
    \Driver\i8042prt DriverObject fe4f69f0
    Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
    DevExt fe4f50d8 DevObjExt fe4f5358
    ExtensionFlags (0xc0000000)
    Unknown flags 0xc0000000
    AttachedDevice (Upper) fe4f5df0 \Driver\Kbdclass
    AttachedTo (Lower) fe4dd730 \Driver\ACPI
    Device queue is not busy.

    从获得的信息来看,这是用于键盘的那个设备对象,下面我们看这个设备对象 DEVICE_OBJECT 中的具体内容

    kd> !strct device_object FE4F5020
    struct _DEVICE_OBJECT (sizeof=184)
    +00 int16 Type = 0003
    +02 uint16 Size = 0338
    +04 int32 ReferenceCount = 00000000
    +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0
    // 正是 \Driver\i8042prt 的驱动对象的地址
    +0c struct _DEVICE_OBJECT *NextDevice = 00000000
    // 为空,表明链结束了。
    +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5DF0
    +14 struct _IRP *CurrentIrp = 00000000
    ...


    我们观察初始化时,看到 i8042prt 调用 IoCreateDevice 创建设备对象,并且 IoCreateDevice 会把新创建的这个设备对象,链入驱动的设备链中。

    现在我们对驱动对象和设备对象之间的联系,做一个总结,

    驱动调用 IoCreateDevice 创建设备对象,一个驱动创建的所有设备对象链成一个链,这个链以空表示结束。驱动对象通过 +04 struct _DEVICE_OBJECT *DeviceObject 可以找到这个链。设备对象通过 +0c struct _DEVICE_OBJECT *NextDevice 链在一起。设备对象通过 +08 struct _DRIVER_OBJECT *DriverObject 可以找到创建它的驱动的驱动对象。

    下面我们来讲讲设备栈。一个物理设备的驱动任务,通常由几个驱动程序一层一层的共同完成。每层一个设备对象,他们联系在一起,组成一个设备栈。一个设备栈上的设备对象,从上自下,联系在一起。从下自上,也联系在一起。我们以 ps/2 键盘驱动为例,使用 WinDbg 来观察它的设备栈,以及他们如何联系在一起。

    ps/2 键盘驱动的设备栈,大概就是这个样子

    kd> !devstack fe4f5020
    !DevObj !DrvObj !DevExt ObjectName
    fe4f5df0 \Driver\Kbdclass fe4f5ea8 KeyboardClass0
    > fe4f5020 \Driver\i8042prt fe4f50d8
    fe4dd730 \Driver\ACPI fe507468 0000000e
    !DevNode fe4fed68 :
    DeviceInst is "ACPI\PNP0303\4&5289e18&0"
    ServiceName is "i8042prt"

    最上面的 DEVICE_OBJECT 地址为 fe4f5df0,属于驱动 \Driver\Kbdclass
    中间的 DEVICE_OBJECT 地址为 fe4f5020,属于驱动 \Driver\i8042prt
    最下面的 DEVICE_OBJECT 地址为 fe4dd730,属于驱动 \Driver\ACPI

    下面我们看这3个设备对象,如何联系在一起。

    最上面一层的 DEVICE_OBJECT

    kd> !devobj fe4f5df0
    Device object (fe4f5df0) is for:
    KeyboardClass0 \Driver\Kbdclass DriverObject fe4f6330
    Current Irp fe43a1c8 RefCount 0 Type 0000000b Flags 00002044
    DevExt fe4f5ea8 DevObjExt fe4f5fd8
    ExtensionFlags (0000000000)
    AttachedTo (Lower) fe4f5020 \Driver\i8042prt
    Device queue is busy -- Queue empty.
    看到这个设备对象有名字,叫 KeyboardClass0 ,属于驱动 Kbdclass

    kd> !strct device_object fe4f5df0
    struct _DEVICE_OBJECT (sizeof=184)
    +00 int16 Type = 0003
    +02 uint16 Size = 01e8
    +04 int32 ReferenceCount = 00000000
    +08 struct _DRIVER_OBJECT *DriverObject = FE4F6330
    // 正是 kbdclass 的 DRIVER_OBJECT 的地址
    +0c struct _DEVICE_OBJECT *NextDevice = 00000000
    +10 struct _DEVICE_OBJECT *AttachedDevice = 00000000
    // 为空结束,表示上面没有其它设备对象了
    +14 struct _IRP *CurrentIrp = FE43A1C8
    ...
    +ae uint16 Spare1 = 0000
    +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4F5FD8
    // 它的 DEVOBJ_EXTENSION 在 FE4F5FD8
    +b4 void *Reserved = 00000000

    kd> !strct DEVOBJ_EXTENSION FE4F5FD8
    struct _DEVOBJ_EXTENSION (sizeof=36)
    +00 int16 Type = 000d
    +02 uint16 Size = 0000
    +04 struct _DEVICE_OBJECT *DeviceObject = FE4F5DF0
    +08 uint32 PowerFlags = 00000010
    +0c *Dope = 00000000
    +10 uint32 ExtensionFlags = 00000000
    +14 void *DeviceNode = 00000000
    +18 struct _DEVICE_OBJECT *AttachedTo = FE4F5020
    // 下面一层的设备对象为 FE4F5020
    +1c struct _LIST_ENTRY FileObjectList
    +1c struct _LIST_ENTRY *Flink = 00000000
    +20 struct _LIST_ENTRY *Blink = 00000000

    中间层的 DEVICE_OBJECT

    kd> !devobj fe4f5020
    Device object (fe4f5020) is for:
    \Driver\i8042prt DriverObject fe4f69f0
    Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
    DevExt fe4f50d8 DevObjExt fe4f5358
    ExtensionFlags (0xc0000000)
    Unknown flags 0xc0000000
    AttachedDevice (Upper) fe4f5df0 \Driver\Kbdclass
    AttachedTo (Lower) fe4dd730 \Driver\ACPI
    Device queue is not busy.
    看到这个设备对象没有名字,属于驱动 i8042prt

    kd> !strct device_object fe4f5020
    struct _DEVICE_OBJECT (sizeof=184)
    +00 int16 Type = 0003
    +02 uint16 Size = 0338
    +04 int32 ReferenceCount = 00000000
    +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0
    // 正是 i8042prt 的 DRIVER_OBJECT 的地址
    +0c struct _DEVICE_OBJECT *NextDevice = 00000000
    +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5DF0
    // 上面一层的设备对象
    +14 struct _IRP *CurrentIrp = 00000000
    ...
    +ae uint16 Spare1 = 0001
    +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4F5358
    // 它的 DEVOBJ_EXTENSION 在 FE4F5358
    +b4 void *Reserved = 00000000

    kd> !strct DEVOBJ_EXTENSION FE4F5358
    struct _DEVOBJ_EXTENSION (sizeof=36)
    +00 int16 Type = 000d
    +02 uint16 Size = 0000
    +04 struct _DEVICE_OBJECT *DeviceObject = FE4F5020
    +08 uint32 PowerFlags = 00000000
    +0c *Dope = 00000000
    +10 uint32 ExtensionFlags = c0000000
    +14 void *DeviceNode = 00000000
    +18 struct _DEVICE_OBJECT *AttachedTo = FE4DD730
    // 下面一层的设备对象
    +1c struct _LIST_ENTRY FileObjectList
    +1c struct _LIST_ENTRY *Flink = 00000000
    +20 struct _LIST_ENTRY *Blink = 00000000

    最下面一层的 DEVICE_OBJECT

    kd> !devobj fe4dd730
    Device object (fe4dd730) is for:
    0000000e \Driver\ACPI DriverObject fe4e8ad0
    Current Irp 00000000 RefCount 1 Type 00000032 Flags 00001040
    DevExt fe507468 DevObjExt fe4dd7e8 DevNode fe4fed68
    ExtensionFlags (0000000000)
    AttachedDevice (Upper) fe4f5020 \Driver\i8042prt
    Device queue is not busy.
    看到这个设备对象有名字,叫 0000000e ,属于驱动 acpi

    kd> !strct device_object fe4dd730
    struct _DEVICE_OBJECT (sizeof=184)
    +00 int16 Type = 0003
    +02 uint16 Size = 00b8
    +04 int32 ReferenceCount = 00000001
    +08 struct _DRIVER_OBJECT *DriverObject = FE4E8AD0
    // 正是 acpi 的 DRIVER_OBJECT 的地址
    +0c struct _DEVICE_OBJECT *NextDevice = FE4DD850
    +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5020
    // 上面一层的设备对象
    +14 struct _IRP *CurrentIrp = 00000000
    ...
    +ae uint16 Spare1 = 0001
    +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4DD7E8
    // 它的 DEVOBJ_EXTENSION 在 FE4DD7E8
    +b4 void *Reserved = 00000000

    kd> !strct DEVOBJ_EXTENSION FE4DD7E8
    struct _DEVOBJ_EXTENSION (sizeof=36)
    +00 int16 Type = 000d
    +02 uint16 Size = 0000
    +04 struct _DEVICE_OBJECT *DeviceObject = FE4DD730
    +08 uint32 PowerFlags = 00000010
    +0c *Dope = 00000000
    +10 uint32 ExtensionFlags = 00000000
    +14 void *DeviceNode = FE4FED68
    +18 struct _DEVICE_OBJECT *AttachedTo = 00000000
    // 为空结束,表示下面没有其它设备对象了
    +1c struct _LIST_ENTRY FileObjectList
    +1c struct _LIST_ENTRY *Flink = 00000000
    +20 struct _LIST_ENTRY *Blink = 00000000

    从上自下。\Device\KeyboardClass0(DRIVER_OBJECT 是 kbdclass)可以找到 没有名字地址为fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)。没有名字地址为fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)可以找到 \Device\0000000e(DRIVER_OBJECT 是 ACPI)。

    从下自上。\Device\0000000e(DRIVER_OBJECT 是 ACPI) 可以找到 没有名字地址为fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)。没有名字地址为fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)可以找到 \Device\KeyboardClass0(DRIVER_OBJECT 是 ACPI)。

    现在我们对设备栈上的设备对象之间的联系,做一个总结,

    设备栈上的设备对象,从上自下,通过 DEVICE_OBJECT 的 DEVOBJ_EXTENSION 的 +18 struct _DEVICE_OBJECT *AttachedTo 联系在一起。
    设备栈上的设备对象,从下自上,通过 DEVICE_OBJECT 的 +10 struct _DEVICE_OBJECT *AttachedDevice 联系在一起。

    在观察键盘驱动的初始化过程中,我们看到了设备栈是如何建立起来的。
    驱动 i8042prt ,驱动 kbdclass 分别调用 IoAttachDeviceToDeviceStack ,把自己相应的设备对象加入到键盘设备栈中。IoAttachDeviceToDeviceStack 会设置 DEVICE_OBJECT 的 DEVOBJ_EXTENSION 的 +18 struct _DEVICE_OBJECT *AttachedTo 和 DEVICE_OBJECT 的 +10 struct _DEVICE_OBJECT *AttachedDevice ,把两个对象联系在一起。并设置新加入的设备对象的 +30 char StackSize。

    晕了吧
     

  • 相关阅读:
    JS Ajax跨域访问
    CentOS 6.8 Java 环境搭建
    vue+vant ui+高德地图的选址组件
    vue和element全局loading
    axios简单的二次封装
    vuex的简单教程
    vue 使用 element ui动态添加表单
    Promise对象和async函数
    css不定高图文垂直居中的三种方法
    js点击复制文本
  • 原文地址:https://www.cnblogs.com/spinsoft/p/2555625.html
Copyright © 2011-2022 走看看